跳转到内容

MCP 集成

Model Context Protocol (MCP) 是一种开放协议,用于标准化应用向 LLM 提供工具和上下文的方式。根据 MCP 文档:

MCP 是一种开放协议,用于标准化应用向 LLM 提供上下文的方式。可以把 MCP 看作 AI 应用的 USB-C 接口。正如 USB-C 提供了一种标准化方式,将设备连接到各种外设和配件,MCP 也提供了一种标准化方式,将 AI 模型连接到不同的数据源和工具。

此 SDK 支持三种类型的 MCP 服务器:

  1. 远程 MCP 服务器工具——由 OpenAI Responses API 作为工具使用的远程 MCP 服务器
  2. 可流式传输的 HTTP MCP 服务器——实现了可流式传输 HTTP 传输机制的本地或远程服务器
  3. Stdio MCP 服务器——通过标准输入/输出访问的服务器(最简单的选项)

注意:SDK 还包含用于旧版服务器发送事件传输机制的 MCPServerSSE,但 MCP 项目已弃用 SSE。对于新的集成,请优先使用可流式传输 HTTP 或 stdio。

请根据您的使用场景选择服务器类型:

您的需求推荐选项
使用默认 OpenAI Responses 模型调用可公开访问的远程服务器1. 托管 MCP 工具
使用可公开访问的远程服务器,但在本地触发工具调用2. 可流式传输 HTTP
使用在本地运行的可流式传输 HTTP 服务器2. 可流式传输 HTTP
通过非 OpenAI Responses 模型使用任意可流式传输 HTTP 服务器2. 可流式传输 HTTP
使用仅支持标准 I/O 协议的本地 MCP 服务器3. Stdio

托管工具会将整个往返过程交给模型处理。您的代码无需调用 MCP 服务器,而是由 OpenAI Responses API 调用远程工具端点,并将结果流式传回模型。

以下是使用托管 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 方法)运行智能体:

使用托管 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

使用托管 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 回调批准或拒绝工具调用。如果需要人工审批,可以采用与本地函数工具相同的人机协作(HITL)方法,通过 interruptions 实现。

远程 MCP 服务器工具的人工干预
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);

hostedMcpTool(...) 同时支持 MCP 服务器 URL 和基于连接器的服务器:

选项类型说明
serverLabelstring必填标签,用于在事件和追踪中标识托管 MCP 服务器。
serverUrlstring远程 MCP 服务器 URL(用于常规托管 MCP 服务器)。
connectorIdstringOpenAI 连接器 ID(对于基于连接器的托管服务器,使用此选项代替 serverUrl)。
authorizationstring可选的授权令牌,将发送到托管 MCP 后端。
headersRecord<string, string>可选的额外请求标头。
allowedToolsstring[] | object向模型公开的工具名称允许列表。传入 string[]{ toolNames?: string[] }
allowedCallers('direct' | 'programmatic')[]仅适用于 Responses 的非空列表,用于控制托管 MCP 工具是可以直接调用、通过程序化工具调用,还是两种方式均可。
deferLoadingboolean仅适用于 Responses 的托管 MCP 工具延迟加载。要求在同一智能体中使用 toolSearchTool()
requireApproval'never' | 'always' | object托管 MCP 工具调用的审批策略。使用对象形式可以按工具覆盖策略。默认为 'never'
onApproval审批回调可选回调,用于在 requireApproval 要求处理审批时以编程方式批准或拒绝。

如果希望模型通过工具搜索按需加载托管 MCP 服务器的工具定义,而不是预先公开这些定义,请设置 deferLoading: true。此功能仅适用于 OpenAI Responses API,要求在同一请求中使用 toolSearchTool(),并且应配合 GPT-5.4 及之后受支持的模型版本使用。有关完整的延迟加载配置,请参阅工具指南

如果托管 MCP 工具只能从模型生成的 JavaScript 中调用,请设置 allowedCallers: ['programmatic'];如果两种路径都允许,请同时包含 'direct''programmatic'。还需将 programmaticToolCallingTool() 添加到同一智能体。当程序调用 MCP 工具时,现有的 requireApprovalonApproval 策略仍然适用。有关完整配置,请参阅程序化工具调用

requireApproval 的对象形式:

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

onApproval 签名:

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

托管 MCP 也支持 OpenAI 连接器。无需提供 serverUrl,只需传入连接器的 connectorIdauthorization 令牌。之后,Responses API 会处理身份验证,并通过托管 MCP 接口公开连接器的工具。

基于连接器的托管 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

完整可运行的示例(托管工具/可流式传输 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 服务器发布同名工具时发生冲突。
  • 在通过日志、追踪和错误消息公开信息之前,SDK 会从基于 URL 派生的服务器名称和传输错误中移除 URL 凭据、查询参数和片段。如果需要稳定的服务器标签,请设置明确、唯一且不包含机密信息的 name
  • 如果不同的 URL 派生服务器名称在移除凭据、查询参数和片段后变得相同,并且这些服务器发布了相同的工具名称,则配置会在模型请求之前失败。请为这些服务器设置明确、唯一且不包含机密信息的 name 值。

当智能体直接与本地或远程的可流式传输 HTTP MCP 服务器通信时,请使用服务器的 urlname 和任意可选设置实例化 MCPServerStreamableHttp

使用可流式传输 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);

构造函数选项:

选项类型说明
urlstring可流式传输 HTTP 服务器 URL。
namestring服务器的可选标签。
cacheToolsListboolean缓存工具列表以降低延迟。
clientSessionTimeoutSecondsnumberMCP 客户端会话的超时时间。
toolFilterMCPToolFilterCallable | MCPToolFilterStatic筛选可用工具。
toolMetaResolverMCPToolMetaResolver注入每次调用的 MCP _meta 请求字段。
useStructuredContentboolean如果 MCP structuredContent 可用且结果不是错误,则使用其 JSON 序列化形式作为模型可见输出。默认为 false
customDataExtractorMCPToolCustomDataExtractor将仅供 SDK 使用的 JSON 元数据附加到发出的本地 MCP 工具输出项。回调可以读取 MCP 结果的 _metastructuredContentisError 和模型可见的工具输出。
errorFunctionMCPToolErrorFunction | null将 MCP 调用失败映射为模型可见文本。
timeoutnumber每个请求的超时时间(毫秒)。
loggerLogger自定义日志记录器。
authProviderOAuthClientProvider来自 MCP TypeScript SDK 的 OAuth 提供程序。
requestInitRequestInit请求的 Fetch 初始化选项。
fetchFetchLike自定义 fetch 实现。
reconnectionOptionsStreamableHTTPReconnectionOptions重连调整选项。
sessionIdstringMCP 连接的显式会话 ID。

构造函数还接受其他 MCP TypeScript SDK 选项,例如 authProviderrequestInitfetchreconnectionOptionssessionId。有关详情,请参阅 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 服务器的命令和参数。
fullCommandstring完整命令字符串,可替代 command + args
envRecord<string, string>服务器进程的环境变量。
cwdstring服务器进程的工作目录。
cacheToolsListboolean缓存工具列表以降低延迟。
clientSessionTimeoutSecondsnumberMCP 客户端会话的超时时间。
namestring服务器的可选标签。
encodingstringstdio 流的编码。
encodingErrorHandler'strict' | 'ignore' | 'replace'编码错误处理策略。
toolFilterMCPToolFilterCallable | MCPToolFilterStatic筛选可用工具。
toolMetaResolverMCPToolMetaResolver注入每次调用的 MCP _meta 请求字段。
useStructuredContentboolean如果 MCP structuredContent 可用且结果不是错误,则使用其 JSON 序列化形式作为模型可见输出。默认为 false
customDataExtractorMCPToolCustomDataExtractor将仅供 SDK 使用的 JSON 元数据附加到发出的本地 MCP 工具输出项。回调可以读取 MCP 结果的 _metastructuredContentisError 和模型可见的工具输出。
errorFunctionMCPToolErrorFunction | null将 MCP 调用失败映射为模型可见文本。
timeoutnumber每个请求的超时时间(毫秒)。
loggerLogger自定义日志记录器。

使用多个 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
  • 部分失败处理:检查 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)。

重新连接之前,MCPServers 会关闭选定的服务器。它只会重新连接成功关闭的服务器;清理失败的信息仍可通过 failederrors 获取。

如果您的运行时支持 Symbol.asyncDisposeMCPServers 也支持 await using 模式。在 TypeScript 中,请在 tsconfig.json 中启用 esnext.disposable

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

然后可以这样编写:

await using mcpServers = await connectMcpServers(servers);

对于可流式传输 HTTPStdio 服务器,每次运行 Agent 时,都可能调用 list_tools() 来发现可用工具。由于该往返过程可能增加延迟,特别是对于远程服务器,因此可以向 MCPServerStdioMCPServerStreamableHttp 传入 cacheToolsList: true,在内存中缓存结果。

仅当您确信工具列表不会发生变化时,才应启用此选项。之后如需使缓存失效,请在服务器实例上调用 invalidateToolsCache()。如果通过 getAllMcpTools(...) 使用共享 MCP 工具缓存,还可以使用 invalidateServerToolsCache(serverName) 按服务器名称使缓存失效。

对于高级场景,getAllMcpTools({ generateMCPToolCacheKey }) 允许您自定义缓存分区方式,例如按服务器、智能体和运行上下文划分。

默认情况下,本地 MCP 工具会保留 MCP 服务器报告的工具名称。如果两个本地 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 安全要求,不会超出函数工具名称长度限制,并且会避免与同一智能体上的本地函数工具名称及已启用的交接名称冲突。此设置仅影响本地可流式传输 HTTP 和 stdio MCP 工具;托管 MCP 工具会保留其托管服务器标签和工具元数据。

您可以通过 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',
});