Realtime セッションにツールを追加すると、モデルがリアルタイムの会話中にデータを検索したり、アクションを実行したり、サービスを呼び出したりできるようになります。クライアントが WebRTC データチャネルと WebSocket のどちらを使用する場合も、ツールの構成には同じイベントインターフェースを使用します。
アプリケーション側でツールを実行して結果を返す場合は、関数ツールを使用します。Realtime API にリモートのツールサーバーへの接続を任せる場合は、MCP ツールを使用します。
ツールの種類の選択
| ツールの種類 | 使用する場面 | 実行主体 |
|---|---|---|
function | アプリケーションがビジネスロジック、承認チェック、または非公開システムへのアクセスを担う場合。 | クライアントまたはサーバーが関数呼び出しを受け取り、function_call_output を返します。 |
server_url を指定した mcp | リモート MCP サーバーが公開するツールをモデルに呼び出させたい場合。 | Realtime API がリモート MCP サーバーを呼び出します。 |
connector_id を指定した mcp | 既存のモデルでレガシーの組み込みコネクタを使用する場合。 | Realtime API が、指定された認可情報を使ってコネクタを呼び出します。 |
ツールは 次の 2 か所のいずれかに追加します。
- セッション全体でツールを利用できるようにする場合は、
session.updateのsession.toolsを使い、 セッションレベル で追加します。 - 1 ターンだけツールが必要な場合は、
response.createのresponse.toolsを使い、 レスポンスレベル で追加します。
関数ツールの設定
アプリケーション内でツールを実行する場合は、関数ツールが基本的な選択肢です。モデルが関数呼び出しの引数を出力し、アプリケーションのコードがアクションを実行して、function_call_output アイテムで結果を返します。
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1",
tools: [
{
type: "function",
name: "lookup_order",
description: "Look up an order by its order number.",
parameters: {
type: "object",
properties: {
order_number: {
type: "string",
description: "The customer-facing order number.",
},
},
required: ["order_number"],
},
},
],
tool_choice: "auto",
},
};
ws.send(JSON.stringify(event));モデルが関数を呼び出したら、関数呼び出しアイテムを受け取り、アプリケーションのロジックを実行してから、出力を返します。
const event = {
type: "conversation.item.create",
item: {
type: "function_call_output",
call_id: functionCall.call_id,
output: JSON.stringify({
status: "shipped",
delivery_date: "2026-05-09",
}),
},
};
ws.send(JSON.stringify(event));
ws.send(JSON.stringify({ type: "response.create" }));Function Calling の流れをイベントごとに詳しく説明した手順については、会話の管理を参照してください。
MCP ツールの設定
MCP ツールは、リモート MCP サーバー経由で利用できるツールがすでにある場合や、既存のモデルでレガシーの組み込みコネクタを使用する場合に役立ちます。関数ツールとは異なり、MCP ツールは Realtime API 自体が実行します。
Realtime の MCP ツールは、次の構造で定義します。
type: "mcp"server_labelserver_urlまたはconnector_idのいずれか- 任意の
authorizationとheaders - 任意の
allowed_tools - 任意の
require_approval - 任意の
server_description
次の例では、ドキュメント用の MCP サーバーをセッション全体で利用できるようにします。
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-2.1",
output_modalities: ["text"],
tools: [
{
type: "mcp",
server_label: "openai_docs",
server_url: "https://developers.openai.com/mcp",
allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));レガシーコネクタ
connector_id は、2026 年 9 月 1 日より後にリリースされたモデルでは非推奨です。
リモート MCP サーバーに接続するには server_url を使用します。
また、 tunnel_id を使用すると、セキュア MCP トンネルを介してローカル MCP サーバーに接続できます。
既存のモデルでは、引き続きコネクタがサポートされます。
以下の例では、この日付より前にリリースされた
gpt-realtime-1.5 を使用します。
組み込みコネクタも同じ MCP ツールの構造を使用しますが、server_url の代わりに connector_id を渡します。
たとえば、Google Calendar では connector_googlecalendar を使用します。
Realtime では、これらの組み込みコネクタを、予定やメールの検索・読み取りなどの
読み取りアクションに使用します。ユーザーの OAuth アクセストークンを authorization に渡し、
可能であれば allowed_tools を使って
利用できるツールを絞り込みます。
const event = {
type: "session.update",
session: {
type: "realtime",
model: "gpt-realtime-1.5",
output_modalities: ["text"],
tools: [
{
type: "mcp",
server_label: "google_calendar",
connector_id: "connector_googlecalendar",
authorization: "<google-oauth-access-token>",
allowed_tools: ["search_events", "read_event"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));リモート MCP サーバーは
会話のコンテキスト全体を自動的に受け取るわけではありませんが、
モデルがツール呼び出しで送信するデータはすべて参照できます。
allowed_tools で利用できるツールを絞り込み、
自動実行を許可しないアクションには必ず承認を求めてください。
Realtime の MCP 処理フロー
Realtime の function ツールとは異なり、リモート MCP ツールは Realtime API 自体が実行します。 クライアントがリモートツールを実行することはなく 、function_call_output を返すこともありません。代わりに、クライアントはアクセスを設定し、MCP のライフサイクルイベントを受信します。また、サーバーから承認を求められた場合は、必要に応じて承認応答を送信します。
一般的な処理の流れは次のとおりです。
typeがmcpのtoolsエントリを含めて、session.updateまたはresponse.createを送信します。- サーバーがツールのインポートを開始し、
mcp_list_tools.in_progressを送出します。 - ツール一覧の取得中は、モデルはまだ読み込まれていないツールを呼び出せません。それらのツールに依存するターンを開始する前に待機する場合は、
mcp_list_tools.completedを待ちます。item.typeがmcp_list_toolsのconversation.item.doneイベントで、実際にインポートされたツールの名前を確認できます。インポートに失敗すると、mcp_list_tools.failedを受信します。 - ユーザーが発話するかテキストを送信すると、クライアントによって、またはセッション設定に従って自動的に、レスポンスが作成されます。
- モデルが MCP ツールを選択すると、
response.mcp_call_arguments.deltaとresponse.mcp_call_arguments.doneを受信します。 - 承認が必要な場合、サーバーは
item.typeがmcp_approval_requestの会話アイテムを追加します。クライアントは、mcp_approval_responseアイテムで応答する必要があります。 - ツールの実行が始まると、
response.mcp_call.in_progressを受信します。成功した場合は、その後item.typeがmcp_callのresponse.output_item.doneイベントを受信します。失敗した場合は、response.mcp_call.failedを受信します。 - レスポンスの
response.doneは、そのレスポンスに含まれる MCP 呼び出しが完了する前に届くことがあります。レスポンスと、それに含まれるすべての MCP 呼び出しが完了したら、response.createイベントを再度送信し、モデルが結果を使って会話を続けられるようにします。モデルが追加の MCP 呼び出しを行った場合は、この手順を繰り返します。Realtime API は、これらの後続レスポンスを自動的には作成しません。
次のイベントハンドラーは、MCP の主なライフサイクルイベントをログに記録します。後続レスポンスの管理は行いません。
function parseRealtimeEvent(rawMessage) {
if (typeof rawMessage === "string") {
return JSON.parse(rawMessage);
}
if (typeof rawMessage?.data === "string") {
return JSON.parse(rawMessage.data);
}
return JSON.parse(rawMessage.toString());
}
function getOutputText(item) {
if (item.type !== "message") return "";
return (item.content ?? [])
.filter((part) => part.type === "output_text")
.map((part) => part.text)
.join("");
}
ws.on("message", (rawMessage) => {
const event = parseRealtimeEvent(rawMessage);
switch (event.type) {
case "mcp_list_tools.in_progress":
console.log("Listing MCP tools for item:", event.item_id);
break;
case "mcp_list_tools.completed":
console.log("MCP tool listing complete for item:", event.item_id);
break;
case "mcp_list_tools.failed":
console.error("MCP tool listing failed for item:", event.item_id);
break;
case "conversation.item.done":
if (event.item.type === "mcp_list_tools") {
const names = event.item.tools.map((tool) => tool.name).join(", ");
console.log(`MCP tools ready on ${event.item.server_label}: ${names}`);
}
if (event.item.type === "mcp_approval_request") {
console.log(
"Approval required for:",
event.item.name,
event.item.arguments
);
}
break;
case "response.mcp_call_arguments.done":
console.log("Final MCP call arguments:", event.arguments);
break;
case "response.mcp_call.in_progress":
console.log("Running MCP tool for item:", event.item_id);
break;
case "response.mcp_call.failed":
console.error("MCP tool call failed for item:", event.item_id);
break;
case "response.output_item.done":
if (event.item.type === "mcp_call") {
console.log(
`MCP output from ${event.item.server_label}.${event.item.name}:`,
event.item.output
);
}
if (event.item.type === "message") {
console.log("Assistant:", getOutputText(event.item));
}
break;
case "response.done":
console.log("Realtime turn complete.");
break;
}
});よくあるエラー
mcp_list_tools.failed:Realtime API がリモートサーバーまたはコネクタからツールをインポートできませんでした。server_urlまたはconnector_id、認証、サーバーへの接続状況、およびallowed_toolsに指定したツール名を確認してください。response.mcp_call.failed:モデルがツールを選択しましたが、ツール呼び出しが完了しませんでした。イベントのペイロードと、その後のmcp_call項目を調べ、MCP プロトコル、実行、通信のエラーがないか確認してください。mcp_approval_requestに対応するmcp_approval_responseがありません:クライアントが明示的に承認または拒否するまで、ツール呼び出しは続行できません。mcp_list_tools.in_progressがまだ進行中の状態でターンが開始されます:そのターンで使用できるのは、すでに読み込みが完了したツールだけです。- レスポンスで
tool_choice: "required"を使用していますが、現在利用可能なツールがありません:モデルが呼び出せるツールがない状態です。mcp_list_tools.completedを待ち、少なくとも 1 つのツールがインポートされたことを確認するか、ツールを必要としないターンではtool_choiceに別の値を使用してください。 - インポートの開始前に MCP ツール定義の検証が失敗します:よくある原因は、同じ
tools配列内でのserver_labelの重複、server_urlとconnector_idの両方の設定、最初のセッション作成リクエストでの両方の省略、無効なconnector_idの使用、またはauthorizationとheaders.Authorizationの両方の送信です。コネクタの場合、headers.Authorizationは一切送信しないでください。
MCP ツール呼び出しの承認または拒否
ツールに承認が必要な場合、Realtime API は会話に mcp_approval_request 項目を挿入します。 続行するには、item.type が mcp_approval_response の新しい conversation.item.create イベントを送信してください。
function approveMcpRequest(approvalRequestId) {
const event = {
type: "conversation.item.create",
item: {
id: `mcp_approval_${approvalRequestId}`,
type: "mcp_approval_response",
approval_request_id: approvalRequestId,
approve: true,
},
};
ws.send(JSON.stringify(event));
}リクエストを拒否する場合は、approve を false に設定し、必要に応じて reason を含めてください。
単一のレスポンスでのみ MCP を使用
MCP を 単一のターンでのみ利用可能にする場合は、同じ MCP ツールオブジェクトを session.tools ではなく response.tools に追加します。
const event = {
type: "response.create",
response: {
output_modalities: ["text"],
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Which transport should I use for browser clients in the Realtime API?",
},
],
},
],
tools: [
{
type: "mcp",
server_label: "openai_docs",
server_url: "https://developers.openai.com/mcp",
allowed_tools: ["search_openai_docs", "fetch_openai_doc"],
require_approval: "never",
},
],
},
};
ws.send(JSON.stringify(event));これは、単一のレスポンスだけが外部コンテキストを必要とする場合や、ターンごとに異なる MCP サーバーを使用する場合に便利です。
定義済みのサーバーラベルの再利用
server_label は、現在の Realtime セッション内でツール定義を識別する固定のハンドルです。
サーバーまたはコネクタを一度定義する際に、
server_label と、server_url または connector_id を指定しておけば、その後の session.update または
response.create イベントでは、同じ server_label だけを参照できます。
Realtime API は以前の定義を再利用するため、
ツールオブジェクト全体を再送信する必要はありません。
const event = {
type: "response.create",
response: {
output_modalities: ["text"],
input: [
{
type: "message",
role: "user",
content: [
{
type: "input_text",
text: "Check my schedule for this afternoon.",
},
],
},
],
// Reuses the google_calendar connector defined earlier in this session.
tools: [
{
type: "mcp",
server_label: "google_calendar",
},
],
},
};
ws.send(JSON.stringify(event));この再利用は同じセッション内に限られます。新しい Realtime セッションを開始する場合は、サーバーがツール一覧をインポートできるよう、MCP 定義全体を再送信してください。