跳转到内容

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
将任意可流式传输 HTTP 服务器与非 OpenAI Responses 模型搭配使用2. 可流式传输的 HTTP
使用仅支持标准 I/O 协议的本地 MCP 服务器3. Stdio

Agents SDK 在内部使用 MCP TypeScript SDK v2 客户端。这并不要求您的 MCP 服务器迁移到 v2 服务器软件包。对于 stdio 和可流式传输 HTTP 连接,Agents SDK 会自动协商协议,并继续兼容使用 MCP TypeScript SDK v1 实现且支持兼容协议版本的现有服务器。

如果您的应用仅使用 Agents SDK 的 MCPServerStdioMCPServerStreamableHttpMCPServerSSE 类,则无需为实现这种兼容性而安装或桥接 MCP v1 和 v2 软件包。如果您希望采用 v2 MCP SDK API,请单独迁移由应用自行管理的 MCP SDK 对象;请参阅 MCP TypeScript SDK 的 v1 到 v2 迁移指南

托管工具会将整个往返过程交由模型处理。您的代码无需调用 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 回调批准或拒绝该工具调用。如果需要人工批准,可以像处理本地函数工具一样,使用 interruptions 并采用相同的人机协作(HITL)方式

远程 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 API 的非空列表,用于控制远程 MCP 工具能否直接调用、通过编程式工具调用,或通过这两种方式调用。
deferLoadingboolean仅适用于 Responses API 的远程 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 的对象形式接受可选的 alwaysnever 条目。每个条目都可以使用 toolNames 或工具的只读注解来选择工具。可选的 onApproval 回调接收当前运行上下文和审批项,然后返回一个 Promise,其中包含 approve 和可选的 reason

托管 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 工具的准备方式。

为智能体配置本地 MCP 工具
import { Agent, MCPServerStreamableHttp } from '@openai/agents';
const server = new MCPServerStreamableHttp({
url: 'https://your-own-domain-here/mcp',
name: 'Docs server',
});
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 服务器发布同名工具时发生冲突。
  • 在通过日志、追踪和错误消息公开由 URL 派生的服务器名称和传输错误之前,SDK 会移除 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自定义日志记录器。
authProviderOAuthClientProviderMCP 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 用于智能体。
  • 处理部分失败:检查 failed + errors,并决定继续还是重试。
  • 重试失败的服务器:调用 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"]
}
}

然后可以编写:

使用异步释放关闭已连接的 MCP 服务器
import { MCPServerStreamableHttp, connectMcpServers } from '@openai/agents';
async function main() {
const servers = [
new MCPServerStreamableHttp({
url: 'https://your-own-domain-here/mcp',
name: 'Docs server',
}),
];
await using mcpServers = await connectMcpServers(servers);
}
main().catch(console.error);

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

仅当您确信工具列表不会更改时才启用此功能。若要稍后使缓存失效,请在服务器实例上调用 invalidateToolsCache()。如果您通过 getAllMcpTools(...) 使用共享 MCP 工具缓存,也可以使用 invalidateServerToolsCache(serverName) 按服务器名称使缓存失效。

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

默认情况下,本地 MCP 工具会保留 MCP 服务器报告的工具名称。如果两个本地 MCP 服务器公开了同名工具,SDK 会引发工具名称重复错误,因为模型无法安全地在两者之间进行选择。

若要启用带有确定性服务器前缀的名称,请在智能体上设置 mcpConfig.includeServerInToolNames: true

为本地 MCP 工具名称添加服务器名称前缀
import { Agent, MCPServerStreamableHttp } from '@openai/agents';
const docsServer = new MCPServerStreamableHttp({
url: 'https://your-own-domain-here/docs/mcp',
name: 'docs',
});
const calendarServer = new MCPServerStreamableHttp({
url: 'https://your-own-domain-here/calendar/mcp',
name: 'calendar',
});
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,且不会超过 FunctionTool 实例的名称长度限制,也不会与同一智能体上的本地 FunctionTool 实例名称或已启用的交接名称冲突。此设置会影响所有本地 MCP 传输机制,包括可流式传输的 HTTP、SSE 和 stdio;远程 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',
});