コンテンツにスキップ

MCP 連携

Model Context Protocol (MCP) は、アプリケーションが LLM にツールやコンテキストを提供する方法を標準化するオープンプロトコルです。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 つのタイプがあります:

  1. リモート MCP サーバーツールOpenAI Responses API によりツールとして利用されるリモート MCP サーバー
  2. Streamable HTTP MCP サーバーStreamable HTTP transport を実装するローカルまたはリモートのサーバー
  3. Stdio MCP サーバー – 標準入出力を介してアクセスするサーバー(最もシンプルな選択肢)

注意: この SDK にはレガシーの Server‑Sent Events トランスポート向けに MCPServerSSE も含まれますが、SSE は MCP プロジェクトにより非推奨になりました。新規の統合では Streamable HTTP または stdio を優先してください。

ユースケースに応じてサーバータイプを選んでください:

必要なこと推奨オプション
公開アクセス可能なリモートサーバーをデフォルトの 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 ツールを使う最も簡単な例です。hostedMcpTool ユーティリティ関数にリモート MCP サーバーのラベルと URL を渡すことで、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 メソッド)でエージェントを実行できます:

Run with hosted MCP tools
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 を渡します:

Run with hosted MCP tools (streaming)
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) アプローチを使えます。

Human in the loop with hosted MCP tools
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 インターフェース経由で公開します。

Connector-backed hosted MCP tool
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 をインスタンス化します:

Run with Streamable HTTP MCP servers
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);

コンストラクターオプション:

オプション備考
urlstringStreamable HTTP サーバーの URL
namestringサーバーの任意ラベル
cacheToolsListbooleanツール一覧をキャッシュして遅延を低減
clientSessionTimeoutSecondsnumberMCP クライアントセッションのタイムアウト
toolFilterMCPToolFilterCallable | MCPToolFilterStatic利用可能なツールのフィルタ
toolMetaResolverMCPToolMetaResolver呼び出しごとの MCP _meta リクエストを注入
errorFunctionMCPToolErrorFunction | nullMCP 呼び出し失敗をモデル可視なテキストに変換
timeoutnumberリクエスト単位のタイムアウト(ミリ秒)
loggerLoggerカスタムロガー
authProviderOAuthClientProviderMCP TypeScript SDK の OAuth プロバイダー
requestInitRequestInitFetch の初期化オプション
fetchFetchLikeカスタム fetch 実装
reconnectionOptionsStreamableHTTPReconnectionOptions再接続の調整オプション
sessionIdstringMCP 接続用の明示的なセッション ID

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

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

Run with Stdio MCP servers
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 / argsstring / string[]stdio サーバー用のコマンド + 引数
fullCommandstringcommand + args の代替となるフルコマンド文字列
envRecord<string, string>サーバープロセスの環境変数
cwdstringサーバープロセスのカレントディレクトリ
cacheToolsListbooleanツール一覧をキャッシュして遅延を低減
clientSessionTimeoutSecondsnumberMCP クライアントセッションのタイムアウト
namestringサーバーの任意ラベル
encodingstringstdio ストリームのエンコーディング
encodingErrorHandler'strict' | 'ignore' | 'replace'エンコーディングエラー時の戦略
toolFilterMCPToolFilterCallable | MCPToolFilterStatic利用可能なツールのフィルタ
toolMetaResolverMCPToolMetaResolver呼び出しごとの MCP _meta リクエストを注入
errorFunctionMCPToolErrorFunction | nullMCP 呼び出し失敗をモデル可視なテキストに変換
timeoutnumberリクエスト単位のタイムアウト(ミリ秒)
loggerLoggerカスタムロガー

MCP サーバーのライフサイクル管理

Section titled “MCP サーバーのライフサイクル管理”

複数の MCP サーバーを扱う場合は、connectMcpServers を使って一括で接続し、失敗を追跡し、まとめてクローズできます。 このヘルパーは activefailederrors コレクションを持つ MCPServers インスタンスを返すため、エージェントには正常なサーバーだけを渡せます。

Manage multiple MCP servers
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 を使用
  • 部分的な失敗の処理: failederrors を確認して、継続や再試行を判断
  • 失敗サーバーの再試行: mcpServers.reconnect() を呼ぶ(デフォルトで失敗サーバーのみ再試行)

厳格な「全て成功かゼロか」の接続や、異なるタイムアウトが必要な場合は、connectMcpServers(servers, options) を使い、環境に合わせてオプションを調整してください。

connectMcpServers のオプション:

オプション既定値備考
connectTimeoutMsnumber | null10000各サーバーの connect() のタイムアウト。無効化は null
closeTimeoutMsnumber | null10000各サーバーの close() のタイムアウト。無効化は null
dropFailedbooleantrueactive から失敗したサーバーを除外
strictbooleanfalseいずれかのサーバー接続が失敗したら例外を投げる
suppressAbortErrorbooleantrue中断系エラーを無視しつつ失敗サーバーは追跡
connectInParallelbooleanfalse全サーバーを逐次ではなく同時に接続

mcpServers.reconnect(options) がサポートするオプション:

オプション既定値備考
failedOnlybooleantrue失敗サーバーのみ再試行(true)か、全サーバー再接続(false

実行環境が Symbol.asyncDispose をサポートしていれば、MCPServersawait using パターンもサポートします。 TypeScript では、tsconfig.jsonesnext.disposable を有効にします:

{
"compilerOptions": {
"lib": ["ES2018", "DOM", "esnext.disposable"]
}
}

次のように書けます:

await using mcpServers = await connectMcpServers(servers);

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

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

createMCPToolStaticFilter による静的フィルタ、またはカスタム関数を渡して、各サーバーから公開するツールを制限できます。以下は両方のアプローチを示す複合例です:

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