MCP 集成
Model Context Protocol (MCP) 是一个开放协议,用于标准化应用如何向 LLM 提供工具和上下文。摘自 MCP 文档:
MCP 是一个开放协议,用于标准化应用如何向 LLM 提供上下文。你可以把 MCP 想象成 AI 应用的 USB‑C 接口。就像 USB‑C 为设备连接各种外设提供了统一方式一样,MCP 为 AI 模型连接不同数据源和工具提供了标准化方式。
本 SDK 支持三种 MCP 服务器类型:
- Hosted MCP server tools(远程 MCP 服务器工具)——由 OpenAI Responses API 作为工具调用的远程 MCP 服务器
- Streamable HTTP MCP servers——实现了 Streamable HTTP 传输 的本地或远程服务器
- Stdio MCP servers——通过标准输入/输出访问的服务器(最简单的选项)
注意: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 |
1. Hosted MCP server tools
Section titled “1. Hosted MCP server tools”托管工具将整个往返流程交给模型完成。你的代码不直接调用 MCP 服务器,而是由 OpenAI Responses API 调用远程工具端点,并将结果流式回传给模型。
下面是使用托管 MCP 工具的最简单示例。你可以将远程 MCP 服务器的标签和 URL 传递给 hostedMcpTool 工具函数,便于创建托管 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 方法)运行智能体:
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);托管 MCP 选项参考
Section titled “托管 MCP 选项参考”hostedMcpTool(...) 同时支持 MCP 服务器 URL 和基于 connector 的服务器:
| 选项 | 类型 | 说明 |
|---|---|---|
serverLabel | string | 必需标签,用于在事件与追踪中标识托管 MCP 服务器。 |
serverUrl | string | 远程 MCP 服务器 URL(常规托管 MCP 服务器使用该项)。 |
connectorId | string | OpenAI connector id(针对基于 connector 的托管服务器,使用该项替代 serverUrl)。 |
authorization | string | 发送到托管 MCP 后端的可选授权令牌。 |
headers | Record<string, string> | 可选的额外请求头。 |
allowedTools | string[] | object | 向模型暴露的工具名白名单。传入 string[] 或 { toolNames?: string[] }。 |
requireApproval | 'never' | 'always' | object | 托管 MCP 工具调用的审批策略。使用对象形式可对各工具单独覆盖。默认为 'never'。 |
onApproval | (context, item) => Promise<{ approve: boolean; reason?: string }> | 当 requireApproval 需要审批处理时,用于编程式批准/拒绝的可选回调。 |
requireApproval 的对象形式:
{ always?: { toolNames: string[] }; never?: { toolNames: string[] };}基于 connector 的托管服务器
Section titled “基于 connector 的托管服务器”托管 MCP 也支持 OpenAI connectors。你无需提供 serverUrl,而是传入 connector 的 connectorId 和一个 authorization 令牌。Responses API 会处理认证,并通过托管 MCP 接口暴露该 connector 的工具。
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 令牌,该令牌授权基于 connector 的服务器调用 Calendar API。包含流式传输演示的可运行示例请参见 examples/connectors。
完整可运行的示例(托管工具/Streamable HTTP/stdio + 流式传输、HITL、onApproval)位于我们 GitHub 仓库中的 examples/mcp。
2. Streamable HTTP MCP servers
Section titled “2. Streamable HTTP MCP servers”当你的智能体直接与本地或远程的 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);构造函数选项:
| 选项 | 类型 | 说明 |
|---|---|---|
url | string | Streamable HTTP 服务器 URL。 |
name | string | 服务器的可选标签。 |
cacheToolsList | boolean | 缓存工具列表以降低延迟。 |
clientSessionTimeoutSeconds | number | MCP 客户端会话超时。 |
toolFilter | MCPToolFilterCallable | MCPToolFilterStatic | 过滤可用工具。 |
toolMetaResolver | MCPToolMetaResolver | 为每次调用注入 MCP _meta 请求字段。 |
errorFunction | MCPToolErrorFunction | null | 将 MCP 调用失败映射为模型可见文本。 |
timeout | number | 每次请求超时(毫秒)。 |
logger | Logger | 自定义日志记录器。 |
authProvider | OAuthClientProvider | 来自 MCP TypeScript SDK 的 OAuth 提供方。 |
requestInit | RequestInit | 请求的 Fetch 初始化选项。 |
fetch | FetchLike | 自定义 fetch 实现。 |
reconnectionOptions | StreamableHTTPReconnectionOptions | 重连调优选项。 |
sessionId | string | MCP 连接的显式会话 ID。 |
构造函数还接受其他 MCP TypeScript‑SDK 选项,如 authProvider、requestInit、fetch、reconnectionOptions 和 sessionId。详情参见 MCP TypeScript SDK 仓库及其文档。
3. Stdio MCP servers
Section titled “3. Stdio MCP servers”对于仅通过标准 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);构造函数选项:
| 选项 | 类型 | 说明 |
|---|---|---|
command / args | string / string[] | stdio 服务器的命令与参数。 |
fullCommand | string | command + args 的完整命令字符串替代方案。 |
env | Record<string, string> | 服务器进程的环境变量。 |
cwd | string | 服务器进程的工作目录。 |
cacheToolsList | boolean | 缓存工具列表以降低延迟。 |
clientSessionTimeoutSeconds | number | MCP 客户端会话超时。 |
name | string | 服务器的可选标签。 |
encoding | string | stdio 流的编码。 |
encodingErrorHandler | 'strict' | 'ignore' | 'replace' | 编码错误处理策略。 |
toolFilter | MCPToolFilterCallable | MCPToolFilterStatic | 过滤可用工具。 |
toolMetaResolver | MCPToolMetaResolver | 为每次调用注入 MCP _meta 请求字段。 |
errorFunction | MCPToolErrorFunction | null | 将 MCP 调用失败映射为模型可见文本。 |
timeout | number | 每次请求超时(毫秒)。 |
logger | Logger | 自定义日志记录器。 |
管理 MCP 服务器生命周期
Section titled “管理 MCP 服务器生命周期”当你需要使用多个 MCP 服务器时,可以使用 connectMcpServers 将它们连接在一起、跟踪失败并统一关闭。
该辅助函数返回一个带有 active、failed 和 errors 集合的 MCPServers 实例,你可以只将健康的服务器传递给智能体。
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 选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
connectTimeoutMs | number | null | 10000 | 每个服务器 connect() 的超时。使用 null 可禁用。 |
closeTimeoutMs | number | null | 10000 | 每个服务器 close() 的超时。使用 null 可禁用。 |
dropFailed | boolean | true | 从 active 中排除连接失败的服务器。 |
strict | boolean | false | 任一服务器连接失败即抛出异常。 |
suppressAbortError | boolean | true | 忽略类中止错误,同时仍会跟踪失败的服务器。 |
connectInParallel | boolean | false | 并发连接所有服务器,而非顺序连接。 |
mcpServers.reconnect(options) 支持:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
failedOnly | boolean | true | 仅重试失败的服务器(true),或重连所有服务器(false)。 |
异步释放(可选)
Section titled “异步释放(可选)”如果你的运行时支持 Symbol.asyncDispose,MCPServers 也支持 await using 模式。
在 TypeScript 中,请在 tsconfig.json 中启用 esnext.disposable:
{ "compilerOptions": { "lib": ["ES2018", "DOM", "esnext.disposable"] }}然后你可以这样写:
await using mcpServers = await connectMcpServers(servers);对于 Streamable HTTP 和 Stdio 服务器,每次运行一个 Agent 时都可能调用 list_tools() 来发现可用工具。由于这次往返可能会增加延迟(尤其是对远程服务器),你可以通过向 MCPServerStdio 或 MCPServerStreamableHttp 传入 cacheToolsList: true 将结果缓存在内存中。
只有在你确信工具列表不会变化时才启用该选项。若需稍后使缓存失效,可在服务器实例上调用 invalidateToolsCache()。
如果你通过 getAllMcpTools(...) 使用共享的 MCP 工具缓存,也可以通过服务器名调用 invalidateServerToolsCache(serverName) 来失效缓存。
对于高级用例,getAllMcpTools({ generateMCPToolCacheKey }) 允许你自定义缓存分区(例如,按服务器 + 智能体 + 运行上下文)。
你可以通过传入静态过滤器 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——上文提到的可运行演示。