MCP 連携
Model Context Protocol (MCP) は、アプリケーションが LLMs にツールとコンテキストを提供する方法を標準化するオープンなプロトコルです。MCP のドキュメントより:
MCP は、アプリケーションが LLMs にコンテキストを提供する方法を標準化するオープンプロトコルです。MCP は AI アプリケーション向けの USB‑C ポートのようなものだと考えてください。USB‑C がさまざまな周辺機器やアクセサリーにデバイスを接続する標準化された方法を提供するのと同様に、MCP は AI モデルをさまざまなデータソースやツールに接続する標準化された方法を提供します。
この SDK がサポートする MCP サーバーは 3 種類あります:
- Hosted MCP server tools – OpenAI Responses API によってツールとして使用されるリモート MCP サーバー
- Streamable HTTP MCP servers – Streamable HTTP トランスポート を実装するローカルまたはリモートサーバー
- Stdio MCP servers – 標準入出力経由でアクセスするサーバー(最も簡単な選択肢)
ユースケースに応じてサーバータイプを選択します:
| 必要なこと | 推奨オプション |
|---|---|
| 公開アクセス可能なリモートサーバーを既定の OpenAI responses モデルで呼ぶ | 1. Hosted MCP tools |
| 公開アクセス可能なリモートサーバーを使いつつ、ツール呼び出しはローカルで | 2. Streamable HTTP |
| ローカルで動作する Streamable HTTP サーバーを使う | 2. Streamable HTTP |
| OpenAI Responses 以外のモデルで任意の Streamable HTTP サーバーを使う | 2. Streamable HTTP |
| 標準 I/O プロトコルのみをサポートするローカル MCP サーバーを使う | 3. Stdio |
1. リモート MCP サーバーツール
Section titled “1. リモート MCP サーバーツール”組み込みツール(Hosted)は、往復の処理をすべてモデル側で行います。あなたのコードが MCP サーバーを呼び出す代わりに、OpenAI Responses API がリモートのツールエンドポイントを呼び出し、その結果をモデルへストリーミングします。
以下は組み込み MCP ツールを使う最も簡単な例です。hostedMcpTool ユーティリティ関数にリモート MCP サーバーのラベルと URL を渡すことで、組み込み 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 サーバー
Section titled “コネクタ対応の Hosted サーバー”Hosted MCP は OpenAI コネクタにも対応しています。serverUrl を指定する代わりに、コネクタの connectorId と authorization トークンを渡します。Responses API が認証を処理し、組み込み 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 + Streaming、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);コンストラクターは authProvider、requestInit、fetch、reconnectionOptions、sessionId などの MCP TypeScript‑SDK の追加オプションも受け付けます。詳細は MCP TypeScript SDK リポジトリ とそのドキュメントを参照してください。
3. Stdio MCP サーバー
Section titled “3. Stdio MCP サーバー”標準 I/O のみを公開するサーバーの場合は、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);その他の知識
Section titled “その他の知識”Streamable HTTP と Stdio サーバーでは、Agent が実行されるたびに利用可能なツールを検出するために list_tools() を呼ぶことがあります。この往復は、特にリモートサーバーではレイテンシーを増やす可能性があるため、MCPServerStdio または MCPServerStreamableHttp に cacheToolsList: true を渡してメモリ内に結果をキャッシュできます。
ツール一覧が変化しないと確信できる場合にのみ有効化してください。後でキャッシュを無効化するには、サーバーインスタンスで invalidateToolsCache() を呼び出します。
ツールのフィルタリング
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 – 上記の実行可能デモ