MCP 集成
Model Context Protocol (MCP) 是一个开放协议,用于规范应用如何向 LLM 提供工具和上下文。摘自 MCP 文档:
MCP 是一个开放协议,用于规范应用如何向 LLM 提供上下文。可以把 MCP 想象成面向 AI 应用的 USB‑C 接口。就像 USB‑C 为你的设备与各类外设配件的连接提供了标准化方式,MCP 也为 AI 模型连接不同数据源与工具提供了标准化方式。
本 SDK 支持三种 MCP 服务器类型:
- Hosted MCP server tools——由 OpenAI Responses API 作为工具调用的远程 MCP 服务器
- Streamable HTTP MCP servers——实现了Streamable HTTP 传输的本地或远程服务器
- 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 |
1. 托管 MCP 服务器工具
Section titled “1. 托管 MCP 服务器工具”托管工具将整个往返交互交给模型处理。你的代码无需调用 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
方法)运行该 Agent:
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
实现。
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.rawItem.name; const params = item.rawItem.providerData?.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);
由连接器支持的托管服务器
Section titled “由连接器支持的托管服务器”托管 MCP 也支持 OpenAI 连接器。你无需提供 serverUrl
,改为传入连接器的 connectorId
和一个 authorization
令牌。Responses API 将处理身份验证,并通过托管 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
。
我们在 GitHub 仓库中的 examples/mcp 提供了完整可运行的示例(托管工具/Streamable HTTP/stdio + 流式传输、HITL、onApproval)。
2. Streamable HTTP MCP 服务器
Section titled “2. Streamable HTTP MCP 服务器”当你的 Agent 直接与本地或远程的 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);
构造函数还接受其他 MCP TypeScript‑SDK 选项,如 authProvider
、requestInit
、fetch
、reconnectionOptions
和 sessionId
。详见 MCP TypeScript SDK 仓库及其文档。
3. Stdio MCP 服务器
Section titled “3. Stdio MCP 服务器”对于仅通过标准 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);
其他注意事项
Section titled “其他注意事项”对于 Streamable HTTP 和 Stdio 服务器,每次运行 Agent
时可能会调用 list_tools() 来发现可用工具。由于该往返会带来延迟——尤其是对远程服务器——你可以通过向 MCPServerStdio
或 MCPServerStreamableHttp
传入 cacheToolsList: 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',});
- Model Context Protocol——官方规范。
- examples/mcp——上述可运行的 演示。