コンテンツにスキップ

MCP 連携

Model Context Protocol (MCP) は、アプリケーションが LLM にツールとコンテキストを提供する方法を標準化するオープンプロトコルです。MCP のドキュメントより:

MCP は、アプリケーションが LLM にコンテキストを提供する方法を標準化するオープンプロトコルです。MCP は AI アプリケーションにとっての USB‑C ポートのようなものだと考えてください。USB‑C がデバイスをさまざまな周辺機器やアクセサリに接続する標準化された方法を提供するように、MCP は AI モデルを異なるデータソースやツールに接続する標準化された方法を提供します。

この SDK がサポートする MCP サーバーは 3 種類あります:

  1. Hosted MCP server toolsOpenAI Responses API によってツールとして使用されるリモート MCP サーバー
  2. Streamable HTTP MCP serversStreamable HTTP トランスポート を実装するローカルまたはリモートのサーバー
  3. 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

組み込みツール(Hosted)は、往復の処理全体をモデル側で行います。あなたのコードが MCP サーバーを呼び出す代わりに、OpenAI Responses API がリモートのツールエンドポイントを呼び出し、その結果をモデルにストリーミングします。

以下は hosted MCP ツールを使う最も簡単な例です。リモート MCP サーバーのラベルと URL を hostedMcpTool ユーティリティ関数に渡します。これは hosted MCP サーバーツールの作成に便利です。

hostedAgent.ts
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 メソッド)でエージェントを実行できます:

Hosted MCP ツールで実行
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 を渡します:

Hosted MCP ツールで実行(ストリーミング)
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);

機微な操作では、個々のツール呼び出しに人による承認を要求できます。requireApproval: 'always' か、ツール名から 'never'/'always' への詳細なマッピングオブジェクトを渡します。

ツール呼び出しが安全かどうかをプログラムで判定できる場合は、onApproval コールバック を使ってツール呼び出しを承認または拒否できます。人による承認が必要な場合は、ローカルの 関数ツール と同様に interruptions を使った同じ 人間の介入(HITL) アプローチを使用できます。

Hosted MCP ツールでの Human in the loop(人間の介入)
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 は OpenAI コネクタにも対応しています。serverUrl を指定する代わりに、コネクタの connectorIdauthorization トークンを渡します。Responses API が認証を処理し、hosted MCP インターフェースを通じてコネクタのツールを公開します。

コネクタ対応の 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 にあります。

エージェントがローカルまたはリモートの Streamable HTTP MCP サーバーと直接通信する場合は、サーバーの urlname、必要に応じた設定で MCPServerStreamableHttp を初期化します:

Streamable HTTP MCP サーバーで実行
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);

このコンストラクタは、authProviderrequestInitfetchreconnectionOptionssessionId などの MCP TypeScript SDK の追加オプションも受け付けます。詳細は MCP TypeScript SDK リポジトリ とそのドキュメントを参照してください。

標準 I/O のみを公開するサーバーでは、fullCommand を指定して MCPServerStdio を初期化します:

Stdio MCP サーバーで実行
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);

Streamable HTTPStdio のサーバーでは、Agent が実行されるたびに使用可能なツールを検出するために list_tools() を呼ぶ場合があります。この往復はレイテンシーを増やす可能性があり(特にリモートサーバーで)、MCPServerStdio または MCPServerStreamableHttpcacheToolsList: true を渡すことで結果をメモリにキャッシュできます。

ツール一覧が変わらないと確信できる場合にのみ有効化してください。後からキャッシュを無効化するには、サーバーインスタンスで invalidateToolsCache() を呼びます。

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',
});