MCP 連携
Model Context Protocol (MCP) は、アプリケーションが LLMs にツールとコンテキストを提供する方法を標準化するオープンなプロトコルです。MCP のドキュメントより:
MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools.
この SDK がサポートする MCP サーバーには 3 種類あります:
- リモート MCP サーバーツール – OpenAI Responses API がツールとして利用するリモート MCP サーバー
- Streamable HTTP MCP サーバー – Streamable HTTP トランスポート を実装するローカルまたはリモートのサーバー
- Stdio MCP サーバー – 標準入出力でアクセスするサーバー(最もシンプルな選択肢)
注: SDK にはレガシーな Server‑Sent Events トランスポート向けに
MCPServerSSEも含まれていますが、SSE は MCP プロジェクトにより非推奨となりました。新規の連携では Streamable HTTP か stdio を推奨します。
ユースケースに応じてサーバータイプを選択してください:
| 必要なこと | 推奨オプション |
|---|---|
| 公開アクセス可能なリモートサーバーを既定の OpenAI Responses モデルで呼び出したい | 1. リモート MCP サーバーツール |
| 公開アクセス可能なリモートサーバーを使いたいが、ツール呼び出しはローカルで開始したい | 2. Streamable HTTP |
| ローカルで動作する Streamable HTTP サーバーを使いたい | 2. Streamable HTTP |
| OpenAI Responses 以外のモデルで任意の Streamable HTTP サーバーを使いたい | 2. Streamable HTTP |
| 標準入出力プロトコルのみをサポートするローカル MCP サーバーと連携したい | 3. Stdio |
1. リモート MCP サーバーツール
Section titled “1. リモート MCP サーバーツール”Hosted ツールは、往復処理全体をモデル側に移します。あなたのコードが MCP サーバーを呼ぶ代わりに、OpenAI Responses API がリモートのツールエンドポイントを呼び出し、その結果をモデルへストリームします。
以下は Hosted MCP ツールを使う最も簡単な例です。hostedMcpTool ユーティリティ関数にリモート MCP サーバーのラベルと URL を渡すことで、Hosted MCP サーバーツールを作成できます。
import { Agent, hostedMcpTool } from '@openai/agents';
export const agent = new Agent({ name: 'MCP Assistant', instructions: 'You must always use the MCP tools to answer questions.', tools: [ hostedMcpTool({ serverLabel: 'gitmcp', serverUrl: 'https://gitmcp.io/openai/codex', }), ],});次に、run 関数(またはカスタマイズした Runner インスタンスの run メソッド)で Agent を実行できます:
import { run } from '@openai/agents';import { agent } from './hostedAgent';
async function main() { const result = await run( agent, 'Which language is the repo I pointed in the MCP tool settings written in?', ); console.log(result.finalOutput);}
main().catch(console.error);MCP の増分結果をストリーミングするには、Agent を実行するときに stream: true を渡します:
import { run } from '@openai/agents';import { agent } from './hostedAgent';
async function main() { const result = await run( agent, 'Which language is the repo I pointed in the MCP tool settings written in?', { stream: true }, );
for await (const event of result) { if ( event.type === 'raw_model_stream_event' && event.data.type === 'model' && event.data.event.type !== 'response.mcp_call_arguments.delta' && event.data.event.type !== 'response.output_text.delta' ) { console.log(`Got event of type ${JSON.stringify(event.data)}`); } } console.log(`Done streaming; final result: ${result.finalOutput}`);}
main().catch(console.error);オプションの承認フロー
Section titled “オプションの承認フロー”機微な操作については、各ツール呼び出しに人手による承認を求めることができます。requireApproval: 'always' または、ツール名ごとに 'never' / 'always' を指定するきめ細かいオブジェクトを渡します。
ツール呼び出しが安全かどうかをプログラムで判断できる場合は、onApproval コールバック を使って承認または拒否できます。人手による承認が必要な場合は、ローカルの 関数ツール と同様に interruptions を使った同じ 人間の介入(HITL) アプローチを使用できます。
import { Agent, run, hostedMcpTool, RunToolApprovalItem } from '@openai/agents';
async function main(): Promise<void> { const agent = new Agent({ name: 'MCP Assistant', instructions: 'You must always use the MCP tools to answer questions.', tools: [ hostedMcpTool({ serverLabel: 'gitmcp', serverUrl: 'https://gitmcp.io/openai/codex', // 'always' | 'never' | { never, always } requireApproval: { never: { toolNames: ['search_codex_code', 'fetch_codex_documentation'], }, always: { toolNames: ['fetch_generic_url_content'], }, }, }), ], });
let result = await run(agent, 'Which language is this repo written in?'); while (result.interruptions && result.interruptions.length) { for (const interruption of result.interruptions) { // Human in the loop here const approval = await confirm(interruption); if (approval) { result.state.approve(interruption); } else { result.state.reject(interruption); } } result = await run(agent, result.state); } console.log(result.finalOutput);}
import { stdin, stdout } from 'node:process';import * as readline from 'node:readline/promises';
async function confirm(item: RunToolApprovalItem): Promise<boolean> { const rl = readline.createInterface({ input: stdin, output: stdout }); const name = item.name; const params = item.arguments; const answer = await rl.question( `Approve running tool (mcp: ${name}, params: ${params})? (y/n) `, ); rl.close(); return answer.toLowerCase().trim() === 'y';}
main().catch(console.error);Hosted MCP のオプションリファレンス
Section titled “Hosted MCP のオプションリファレンス”hostedMcpTool(...) は MCP サーバー URL とコネクター連携サーバーの両方をサポートします:
| オプション | 型 | 備考 |
|---|---|---|
serverLabel | string | イベントやトレースで Hosted MCP サーバーを識別するための必須ラベル |
serverUrl | string | リモート MCP サーバーの URL(通常の Hosted MCP サーバーではこちらを使用) |
connectorId | string | OpenAI コネクター ID(コネクター連携の Hosted サーバーでは serverUrl の代わりにこちらを使用) |
authorization | string | Hosted MCP バックエンドに送信する任意の認可トークン |
headers | Record<string, string> | 追加のリクエストヘッダー(任意) |
allowedTools | string[] | object | モデルに公開するツール名の許可リスト。string[] または { toolNames?: string[] } を渡す |
requireApproval | 'never' | 'always' | object | Hosted MCP ツール呼び出しの承認ポリシー。ツール単位で上書きする場合はオブジェクト形式。既定は 'never' |
onApproval | (context, item) => Promise<{ approve: boolean; reason?: string }> | requireApproval が承認処理を要求する場合の、プログラムによる承認/拒否の任意コールバック |
requireApproval のオブジェクト形式:
{ always?: { toolNames: string[] }; never?: { toolNames: string[] };}コネクター連携の Hosted サーバー
Section titled “コネクター連携の Hosted サーバー”Hosted MCP は OpenAI コネクターにも対応しています。serverUrl を指定する代わりに、コネクターの connectorId と authorization トークンを渡します。Responses API が認証を処理し、Hosted MCP インターフェース経由でコネクターのツールを公開します。
import { Agent, hostedMcpTool } from '@openai/agents';
const authorization = process.env.GOOGLE_CALENDAR_AUTHORIZATION!;
export const connectorAgent = new Agent({ name: 'Calendar Assistant', instructions: "You are a helpful assistant that can answer questions about the user's calendar.", tools: [ hostedMcpTool({ serverLabel: 'google_calendar', connectorId: 'connector_googlecalendar', authorization, requireApproval: 'never', }), ],});この例では、環境変数 GOOGLE_CALENDAR_AUTHORIZATION に Google OAuth Playground で取得した OAuth トークンを保持し、コネクター連携サーバーが Calendar API を呼び出せるようにします。ストリーミングも実演する実行可能なサンプルは examples/connectors を参照してください。
完全な動作サンプル(Hosted ツール / Streamable HTTP / stdio + ストリーミング、HITL、onApproval)は、GitHub リポジトリの examples/mcp にあります。
2. Streamable HTTP MCP サーバー
Section titled “2. Streamable HTTP MCP サーバー”Agent がローカルまたはリモートの Streamable HTTP MCP サーバーと直接対話する場合は、サーバーの url、name と任意設定で MCPServerStreamableHttp を初期化します:
import { Agent, run, MCPServerStreamableHttp } from '@openai/agents';
async function main() { const mcpServer = new MCPServerStreamableHttp({ url: 'https://gitmcp.io/openai/codex', name: 'GitMCP Documentation Server', }); const agent = new Agent({ name: 'GitMCP Assistant', instructions: 'Use the tools to respond to user requests.', mcpServers: [mcpServer], });
try { await mcpServer.connect(); const result = await run(agent, 'Which language is this repo written in?'); console.log(result.finalOutput); } finally { await mcpServer.close(); }}
main().catch(console.error);コンストラクターのオプション:
| オプション | 型 | 備考 |
|---|---|---|
url | string | Streamable HTTP サーバーの URL |
name | string | サーバーの任意ラベル |
cacheToolsList | boolean | ツール一覧をキャッシュしてレイテンシーを削減 |
clientSessionTimeoutSeconds | number | MCP クライアントセッションのタイムアウト |
toolFilter | MCPToolFilterCallable | MCPToolFilterStatic | 利用可能なツールのフィルター |
toolMetaResolver | MCPToolMetaResolver | 呼び出し単位で MCP リクエストの _meta を付与 |
errorFunction | MCPToolErrorFunction | null | MCP 呼び出し失敗をモデルに見えるテキストへ変換 |
timeout | number | リクエスト単位のタイムアウト(ミリ秒) |
logger | Logger | カスタムロガー |
authProvider | OAuthClientProvider | MCP TypeScript SDK の OAuth プロバイダー |
requestInit | RequestInit | リクエスト用の Fetch 初期化オプション |
fetch | FetchLike | カスタム Fetch 実装 |
reconnectionOptions | StreamableHTTPReconnectionOptions | 再接続の調整オプション |
sessionId | string | MCP 接続の明示的なセッション ID |
このコンストラクターは、authProvider、requestInit、fetch、reconnectionOptions、sessionId などの追加の MCP TypeScript SDK オプションも受け付けます。詳細は MCP TypeScript SDK リポジトリ とそのドキュメントを参照してください。
3. Stdio MCP サーバー
Section titled “3. Stdio MCP サーバー”標準入出力のみを公開するサーバーには、fullCommand を指定して MCPServerStdio を初期化します:
import { Agent, run, MCPServerStdio } from '@openai/agents';import * as path from 'node:path';
async function main() { const samplesDir = path.join(__dirname, 'sample_files'); const mcpServer = new MCPServerStdio({ name: 'Filesystem MCP Server, via npx', fullCommand: `npx -y @modelcontextprotocol/server-filesystem ${samplesDir}`, }); await mcpServer.connect(); try { const agent = new Agent({ name: 'FS MCP Assistant', instructions: 'Use the tools to read the filesystem and answer questions based on those files. If you are unable to find any files, you can say so instead of assuming they exist.', mcpServers: [mcpServer], }); const result = await run(agent, 'Read the files and list them.'); console.log(result.finalOutput); } finally { await mcpServer.close(); }}
main().catch(console.error);コンストラクターのオプション:
| オプション | 型 | 備考 |
|---|---|---|
command / args | string / string[] | stdio サーバー用のコマンドと引数 |
fullCommand | string | command + args の代替となるフルコマンド文字列 |
env | Record<string, string> | サーバープロセス用の環境変数 |
cwd | string | サーバープロセスの作業ディレクトリ |
cacheToolsList | boolean | ツール一覧をキャッシュしてレイテンシーを削減 |
clientSessionTimeoutSeconds | number | MCP クライアントセッションのタイムアウト |
name | string | サーバーの任意ラベル |
encoding | string | stdio ストリームのエンコーディング |
encodingErrorHandler | 'strict' | 'ignore' | 'replace' | エンコーディングエラー処理の方針 |
toolFilter | MCPToolFilterCallable | MCPToolFilterStatic | 利用可能なツールのフィルター |
toolMetaResolver | MCPToolMetaResolver | 呼び出し単位で MCP リクエストの _meta を付与 |
errorFunction | MCPToolErrorFunction | null | MCP 呼び出し失敗をモデルに見えるテキストへ変換 |
timeout | number | リクエスト単位のタイムアウト(ミリ秒) |
logger | Logger | カスタムロガー |
MCP サーバーのライフサイクル管理
Section titled “MCP サーバーのライフサイクル管理”複数の MCP サーバーを扱う場合は、connectMcpServers を使って一括接続し、失敗を追跡し、まとめてクローズできます。
このヘルパーは active、failed、errors コレクションを持つ MCPServers インスタンスを返すため、エージェントには正常なサーバーだけを渡せます。
import { Agent, MCPServerStreamableHttp, connectMcpServers, run,} from '@openai/agents';
async function main() { const servers = [ new MCPServerStreamableHttp({ url: 'https://mcp.deepwiki.com/mcp', name: 'DeepWiki MCP Server', }), new MCPServerStreamableHttp({ url: 'http://localhost:8001/mcp', name: 'Local MCP Server', }), ];
const mcpServers = await connectMcpServers(servers, { connectInParallel: true, });
try { console.log(`Active servers: ${mcpServers.active.length}`); console.log(`Failed servers: ${mcpServers.failed.length}`); for (const [server, error] of mcpServers.errors) { console.warn(`${server.name} failed to connect: ${error.message}`); }
const agent = new Agent({ name: 'MCP lifecycle agent', instructions: 'Use MCP tools to answer user questions.', mcpServers: mcpServers.active, });
const result = await run( agent, 'Which language is the openai/codex repository written in?', ); console.log(result.finalOutput); } finally { await mcpServers.close(); }}
main().catch(console.error);ユースケース:
- 複数サーバーを同時に: すべてを並列接続し、エージェントには
mcpServers.activeを使用 - 部分的な失敗の処理:
failedとerrorsを検査し、続行か再試行かを判断 - 失敗サーバーの再試行:
mcpServers.reconnect()を呼ぶ(既定で失敗サーバーのみ再試行)
厳格な「全て成功か、さもなくば失敗」の接続や異なるタイムアウトが必要な場合は、connectMcpServers(servers, options) を使用して環境に合わせてオプションを調整してください。
connectMcpServers のオプション:
| オプション | 型 | 既定値 | 備考 |
|---|---|---|---|
connectTimeoutMs | number | null | 10000 | 各サーバーの connect() タイムアウト。無効化するには null |
closeTimeoutMs | number | null | 10000 | 各サーバーの close() タイムアウト。無効化するには null |
dropFailed | boolean | true | active から失敗サーバーを除外 |
strict | boolean | false | いずれかのサーバー接続が失敗したら例外を投げる |
suppressAbortError | boolean | true | 中断系エラーを無視しつつ、失敗サーバーは追跡 |
connectInParallel | boolean | false | 逐次ではなく全サーバーを同時に接続 |
mcpServers.reconnect(options) がサポートするオプション:
| オプション | 型 | 既定値 | 備考 |
|---|---|---|---|
failedOnly | boolean | true | 失敗サーバーのみ再試行するか(true)、全再接続か(false) |
非同期ディスポーザブル(任意)
Section titled “非同期ディスポーザブル(任意)”実行環境が Symbol.asyncDispose をサポートしている場合、MCPServers は await using パターンも使用できます。
TypeScript では、tsconfig.json で esnext.disposable を有効にします:
{ "compilerOptions": { "lib": ["ES2018", "DOM", "esnext.disposable"] }}その後、次のように書けます:
await using mcpServers = await connectMcpServers(servers);その他の知っておくべきこと
Section titled “その他の知っておくべきこと”Streamable HTTP と Stdio サーバーでは、Agent の各実行時に利用可能なツールを検出するため list_tools() を呼ぶ場合があります。この往復はレイテンシーを増やす可能性があり(特にリモートサーバーでは)、MCPServerStdio または MCPServerStreamableHttp に cacheToolsList: true を渡すことで、結果をメモリにキャッシュできます。
ツール一覧が変わらないことに自信がある場合にのみ有効化してください。後でキャッシュを無効にするには、サーバーインスタンスで invalidateToolsCache() を呼びます。
getAllMcpTools(...) による共有 MCP ツールキャッシュを使用している場合は、invalidateServerToolsCache(serverName) でサーバー名単位でも無効化できます。
高度なケースでは、getAllMcpTools({ generateMCPToolCacheKey }) により、(サーバー + エージェント + 実行コンテキストなどで)キャッシュの分割方法をカスタマイズできます。
ツールのフィルタリング
Section titled “ツールのフィルタリング”createMCPToolStaticFilter による静的フィルター、またはカスタム関数を渡すことで、各サーバーから公開されるツールを制限できます。以下は両方のアプローチを組み合わせた例です:
import { MCPServerStdio, MCPServerStreamableHttp, createMCPToolStaticFilter, MCPToolFilterContext,} from '@openai/agents';
interface ToolFilterContext { allowAll: boolean;}
const server = new MCPServerStdio({ fullCommand: 'my-server', toolFilter: createMCPToolStaticFilter({ allowed: ['safe_tool'], blocked: ['danger_tool'], }),});
const dynamicServer = new MCPServerStreamableHttp({ url: 'http://localhost:3000', toolFilter: async ({ runContext }: MCPToolFilterContext, tool) => (runContext.context as ToolFilterContext).allowAll || tool.name !== 'admin',});- Model Context Protocol – 公式仕様
- examples/mcp – 上記で参照した実行可能な デモ