コンテンツにスキップ

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 トランスポート を実装するローカルまたはリモートのサーバー
  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 tools は、ラウンドトリップ全体をモデル内に押し込みます。コードが 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 以降のサポート対象モデルリリースで使用する必要があります。完全な deferred-loading 設定については、ツール を参照してください。

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 tools / 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 サーバーが同じ名前のツールを公開する場合の衝突を回避しやすくなります。

Agent が 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 リクエストフィールドを注入します。
customDataExtractorMCPToolCustomDataExtractor生成されるローカル MCP ツール出力アイテムに、SDK 専用の JSON メタデータを付与します。コールバックは、MCP 結果の _metastructuredContentisError、およびモデルから見えるツール出力を読み取れます。
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 リクエストフィールドを注入します。
customDataExtractorMCPToolCustomDataExtractor生成されるローカル MCP ツール出力アイテムに、SDK 専用の JSON メタデータを付与します。コールバックは、MCP 結果の _metastructuredContentisError、およびモデルから見えるツール出力を読み取れます。
errorFunctionMCPToolErrorFunction | nullMCP 呼び出しの失敗を、モデルから見えるテキストへマッピングします。
timeoutnumberリクエストごとのタイムアウト(ミリ秒)です。
loggerLoggerカスタムロガーです。

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

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

複数の MCP サーバーを扱う場合は、connectMcpServers を使用してそれらをまとめて接続し、失敗を追跡し、1 か所でクローズできます。このヘルパーは、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中断に類似したエラーを無視しつつ、失敗したサーバーは引き続き追跡します。
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 }) によってキャッシュ分割をカスタマイズできます(たとえば、サーバー + エージェント + 実行コンテキストごと)。

サーバープレフィックス付きツール名

Section titled “サーバープレフィックス付きツール名”

デフォルトでは、ローカル 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',
});