コンテンツにスキップ

MCP 連携

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

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

この 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. リモート MCP サーバーツール
公開アクセス可能なリモートサーバーを使用しつつ、ツール呼び出しはローカルでトリガーする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 ユーティリティ関数に渡すことができ、これはリモート 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: 'deepwiki',
serverUrl: 'https://mcp.deepwiki.com/mcp',
}),
],
});

次に、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 { isOpenAIResponsesRawModelStreamEvent, 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 (
isOpenAIResponsesRawModelStreamEvent(event) &&
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: 'deepwiki',
serverUrl: 'https://mcp.deepwiki.com/mcp',
// 'always' | 'never' | { never, always }
requireApproval: {
never: {
toolNames: ['read_wiki_structure', 'read_wiki_contents'],
},
always: {
toolNames: ['ask_question'],
},
},
}),
],
});
let result = await run(
agent,
'For the repository openai/codex, tell me the primary programming language.',
);
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 とコネクター連携サーバーの両方をサポートします。

オプションメモ
serverLabelstringイベントとトレースでリモート MCP サーバーを識別する必須ラベル。
serverUrlstringリモート MCP サーバー URL(通常の Hosted MCP サーバーにはこれを使用します)。
connectorIdstringOpenAI コネクター ID(コネクター連携の Hosted サーバーでは serverUrl の代わりにこれを使用します)。
authorizationstringHosted MCP バックエンドに送信される任意の認可トークン。
headersRecord<string, string>任意の追加リクエストヘッダー。
allowedToolsstring[] | objectモデルに公開するツール名の許可リスト。string[] または { toolNames?: string[] } を渡します。
deferLoadingbooleanHosted MCP ツール向けの Responses 専用の遅延読み込み。同じエージェント内に toolSearchTool() が必要です。
requireApproval'never' | 'always' | objectHosted MCP ツール呼び出しの承認ポリシー。ツールごとの上書きにはオブジェクト形式を使用します。デフォルトは 'never' です。
onApproval承認コールバックrequireApproval が承認処理を必要とする場合の、プログラムによる承認/拒否用の任意のコールバック。

Hosted MCP サーバーのツール定義を事前に公開する代わりに、ツール検索経由でオンデマンドにモデルに読み込ませたい場合は、deferLoading: true を設定します。これは OpenAI Responses API でのみ機能し、同じリクエスト内に toolSearchTool() が必要で、GPT-5.4 以降のサポート対象モデルリリースで使用する必要があります。遅延読み込み設定の詳細については、ツール を参照してください。

requireApproval のオブジェクト形式:

{
always?: { toolNames: string[] };
never?: { toolNames: string[] };
}

onApproval のシグネチャ:

async function onApproval(
context,
item,
): Promise<{
approve: boolean;
reason?: string;
}> {}

コネクター連携の Hosted サーバー

Section titled “コネクター連携の Hosted サーバー”

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 にあります。

トランスポートの選択に加えて、Agent.mcpConfig を設定することで、ローカル MCP ツールの準備方法を調整できます。

const agent = new Agent({
name: 'Assistant',
mcpServers: [server],
mcpConfig: {
// Try to convert MCP tool schemas to strict JSON schema.
convertSchemasToStrict: true,
// Set to null to raise MCP tool failures instead of returning model-visible error text.
errorFunction: null,
// Prefix local MCP tool names with their server name.
includeServerInToolNames: true,
},
});

メモ:

  • convertSchemasToStrict はベストエフォートです。スキーマを変換できない場合は、元のスキーマが使用されます。
  • errorFunction は、MCP ツール呼び出しの失敗をモデルにどのように提示するかを制御します。
  • errorFunction が未設定の場合、SDK はデフォルトのツールエラーフォーマッターを使用します。
  • サーバーレベルの errorFunction 値は、そのサーバーについて Agent.mcpConfig.errorFunction を上書きします。
  • includeServerInToolNames はオプトインです。有効にすると、各ローカル MCP ツールは、決定的なサーバー接頭辞付きの名前でモデルに公開されます。これは、複数の 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://mcp.deepwiki.com/mcp',
name: 'DeepWiki MCP Server',
});
const agent = new Agent({
name: 'DeepWiki Assistant',
instructions: 'Use the tools to respond to user requests.',
mcpServers: [mcpServer],
});
try {
await mcpServer.connect();
const result = await run(
agent,
'For the repository openai/codex, tell me the primary programming language.',
);
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 プロバイダー。
requestInitRequestInitリクエストの fetch 初期化オプション。
fetchFetchLikeカスタム fetch 実装。
reconnectionOptionsStreamableHTTPReconnectionOptions再接続の調整オプション。
sessionIdstringMCP 接続の明示的なセッション ID。

コンストラクターは、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 local package',
fullCommand: `pnpm exec mcp-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 インスタンスを返すため、正常なサーバーのみをエージェントに渡せます。

複数の MCP サーバーの管理
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 オプション:

オプションデフォルトメモ
connectTimeoutMsnumber | null10000各サーバーの connect() のタイムアウト。無効にするには null を使用します。
closeTimeoutMsnumber | null10000各サーバーの close() のタイムアウト。無効にするには null を使用します。
dropFailedbooleantrue失敗したサーバーを active から除外します。
strictbooleanfalseいずれかのサーバーの接続に失敗した場合に例外を投げます。
suppressAbortErrorbooleantrue失敗したサーバーは追跡しつつ、abort 相当のエラーを無視します。
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 HTTP および Stdio サーバーでは、Agent が実行されるたびに、利用可能なツールを検出するため list_tools() を呼び出す場合があります。そのラウンドトリップは、特にリモートサーバーに対してレイテンシを増やす可能性があるため、MCPServerStdio または MCPServerStreamableHttpcacheToolsList: true を渡すことで、結果をメモリ内にキャッシュできます。

ツール一覧が変わらないと確信できる場合にのみ有効にしてください。後でキャッシュを無効化するには、サーバーインスタンスで invalidateToolsCache() を呼び出します。getAllMcpTools(...) 経由の共有 MCP ツールキャッシュを使用している場合は、invalidateServerToolsCache(serverName) でサーバー名を指定して無効化することもできます。

高度なケースでは、getAllMcpTools({ generateMCPToolCacheKey }) により、キャッシュの分割方法(たとえばサーバー + エージェント + 実行コンテキスト単位)をカスタマイズできます。

デフォルトでは、ローカル MCP ツールは MCP サーバーから報告されたツール名を保持します。2 つのローカル MCP サーバーが同じツール名を公開している場合、モデルが安全に選択できないため、SDK は重複したツール名のエラーを発生させます。

決定的なサーバー接頭辞付きの名前を使用するには、エージェントで mcpConfig.includeServerInToolNames: true を設定します。

const agent = new Agent({
name: 'Assistant',
mcpServers: [docsServer, calendarServer],
mcpConfig: {
includeServerInToolNames: true,
},
});

この設定では、docs サーバーの search ツールはモデルに mcp_docs__search として公開され、calendar サーバーの search ツールは mcp_calendar__search として公開されます。SDK は引き続き、元のサーバー上の元の MCP ツール名を呼び出します。

生成される名前は ASCII セーフで、関数ツール名の制限内に収まり、同じエージェント上のローカル関数ツール名および有効なハンドオフ名との衝突を回避します。この設定が影響するのは、ローカルの Streamable HTTP および stdio MCP ツールだけです。Hosted MCP ツールは、Hosted サーバーラベルとツールメタデータを保持します。

各サーバーから公開されるツールを制限するには、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',
});