连接 (Connections)
LangChain 中 MCP 的连接生命周期、多服务器、部署扩展、协议版本与缓存。
MCPAdapter 可发现 MCP 工具并保持其连接处于开启状态,以便你的智能体可以在多次调用之间复用它们。通过 listTools() 或 listToolsets() 发现工具,并在应用程序使用完毕后关闭适配器。
选择保持适配器处于开启状态的时长:
| 场景 | 模式 | 前往 |
|---|---|---|
| 脚本或智能体调用 | 创建适配器,运行智能体,然后在 finally 中关闭 | 连接生命周期 |
| 长周期 Worker | 复用单个适配器并在关机时关闭 | 扩展部署 |
有关各个服务器的连接选项,请参阅传输方式。
连接生命周期
构建适配器会校验其配置,但不会立即建立连接。listTools()、listToolsets()、getClient() 以及资源方法在执行发现操作时才会建立连接。在智能体使用这些工具期间,请保持适配器处于开启状态。
要发现工具、运行智能体并释放连接,请将 MCP 服务器的 HTTP URL 传递给 runAgent:
import { MCPAdapter } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";
async function runAgent(serverUrl: string) {
const adapter = new MCPAdapter({
servers: { weather: { url: serverUrl } },
});
try {
const tools = await adapter.listTools();
const agent = createAgent({
model: "claude-sonnet-5",
tools,
});
const result = await agent.invoke({
messages: [{ role: "user", content: "What is the weather in Oslo?" }],
});
console.log(result.messages.at(-1)?.text);
} finally {
await adapter.close();
}
}打开此示例的公开 LangSmith 运行记录。
close() 会中止正在进行的适配器工作,关闭其连接并清除其缓存。你可以再次调用 listTools() 以打开新的连接,但必须使用新返回的工具。先前返回的工具仍会保留已关闭的客户端。
多服务器
servers 中每个具名条目都会获得其独立的连接、身份验证和协议模式。单个适配器可以同时连接到 HTTP 和 stdio 服务器。
要从这两种传输方式中发现工具,请将日历服务器的 HTTP URL 和文件服务器的脚本路径传递给 listServerTools:
import { MCPAdapter } from "@langchain/mcp-adapters";
async function listServerTools(calendarUrl: string, filesServerPath: string) {
const adapter = new MCPAdapter({
servers: {
calendar: { url: calendarUrl },
files: { command: "node", args: [filesServerPath] },
},
});
try {
const toolsets = await adapter.listToolsets();
console.log(toolsets.calendar.map((tool) => tool.name));
const fileTools = await adapter.listTools("files");
console.log(fileTools.map((tool) => tool.name));
} finally {
await adapter.close();
}
}打开此示例的公开 LangSmith 运行记录。
listToolsets() 按服务器名称对工具进行分组。listTools() 返回单个数组;传入某个服务器名称或名称数组可选择返回哪些工具。筛选仅作用于返回结果,但发现操作仍会联系每一个已配置的服务器。未被选择的服务器如果发生故障,仍可能导致调用失败。
适配器默认会在工具名称前加上其服务器名称作为前缀,例如 calendar_search 和 files_search。设置 prefixToolNameWithServerName: false 可保留原始名称。如果所选工具中包含重复名称,listTools() 会抛出异常。
OpenAI 和 Anthropic 的工具名称仅接受字母、数字、_ 和 -(^[a-zA-Z0-9_-]+$),OpenAI 最多支持 64 个字符,Anthropic 最多支持 128 个字符。适配器不会对超出这些限制的前缀名称进行自动重命名,因此请保持服务器名称简短,且不要包含点号和空格。
在顶层设置 defaultToolTimeout(以毫秒为单位)可将其应用于每个服务器的工具;该设置会优先于服务器自身的 defaultToolTimeout。
扩展部署
在模块作用域(即图工厂函数外部)创建适配器。每次工厂调用都可以发现当前工具目录,并使用共享连接构建智能体:
import { MCPAdapter } from "@langchain/mcp-adapters";
import { createAgent } from "langchain";
const servers = {
weather: { url: "https://example.com/mcp" },
};
const adapter = new MCPAdapter({ servers });
export async function makeGraph() {
const tools = await adapter.listTools([], { cacheMode: "refresh" });
return createAgent({
model: "claude-sonnet-5",
tools,
});
}打开此示例的公开 LangSmith 运行记录。
在多次运行之间保持适配器处于开启状态。在应用程序关机、且所有活动运行均已结束后,再将其关闭。对于使用不同用户凭据的运行,请参阅按用户身份验证。
默认情况下,发现操作在遇到连接失败时会抛出异常。设置 onConnectionError: "ignore",或提供一个正常返回的回调函数,以继续处理其余服务器。非身份验证失败会导致该连接在后续发现中被跳过,即使使用 cacheMode: "refresh" 也是如此。在再次发现之前,请关闭适配器以清除已跳过的连接。身份验证失败则会在下一次发现时重试。
当配置为 mode: "legacy" 时,stdio 服务器支持 restart 设置,HTTP 和 SSE 服务器支持 reconnect 设置。重启后,请再次调用 listTools() 并使用新返回的工具;重启前返回的工具仍会保持已关闭的连接。
现代 MCP 服务器不保存会话,因此它们的副本可以运行在任何负载均衡器之后。带有会话的遗留服务器仍然需要配置粘性路由以指向特定的单个副本。运行多个副本的现代服务器必须在它们之间共享同一个 requestState 签名密钥,否则路由到其他副本的引导(elicitation)应答将会被拒绝。请参阅 MCP TypeScript SDK 文档中的使用编解码器保护 requestState。
缓存
MCP SDK 为工具列表提供了内存缓存。在服务器的 ttlMs 提示仍然有效的情况下,重复执行发现操作可以避免网络请求。如果没有提供正值的 ttlMs,发现操作将重新获取该列表。
使用 cacheMode 来控制 listTools() 和 listToolsets() 如何读取响应缓存:
"use"(默认):当存在有效的缓存工具列表时直接使用,否则重新获取并存储。"refresh":获取全新的工具列表并更新缓存。"bypass":获取全新的工具列表,既不读取也不更新响应缓存。
要刷新所有已配置服务器的工具,请传入一个空的服务器选择数组以及发现选项:
const tools = await adapter.listTools([], { cacheMode: "refresh" });当服务器描述符未发生变化时,适配器还会复用已转换的 LangChain 工具包装器。重新发现会返回当前最新的工具;它不会更新现有智能体的工具列表。请使用新返回的工具构建下一个智能体。
协议版本
适配器会针对每个服务器单独协商 MCP 协议。默认的 mode: "auto" 支持在同一个适配器中同时连接现代和遗留服务器。
遗留版本时代以 initialize 握手开始。现代版本时代则使用 server/discover 来发现服务器能力。当需要强制要求特定版本时代时,可以覆盖 mode:
import { MCPAdapter } from "@langchain/mcp-adapters";
async function listToolsAcrossEras(modernUrl: string, legacyUrl: string) {
const adapter = new MCPAdapter({
servers: {
current: { url: modernUrl, mode: "modern" },
legacy: { url: legacyUrl, mode: "legacy" },
},
});
try {
const tools = await adapter.listTools();
console.log(tools.map((tool) => tool.name));
} finally {
await adapter.close();
}
}打开此示例的公开 LangSmith 运行记录。
每个服务器的 mode 会独立控制其协议协商:
"auto"(默认):尝试使用当前最新协议,如果是仅支持遗留版本的服务器则自动降级。"modern":要求协议版本为2026-07-28,并在不支持时直接报错失败,而不是降级到遗留 MCP。"legacy":跳过现代协议探测,直接使用遗留客户端接口。
在 "auto" 模式下,如果基于 URL 的服务器对 Streamable HTTP 请求响应 404 或 405,则会通过 SSE 进行重试:先在相同的 URL 上尝试,随后将末尾的 /mcp 替换为 /sse 后重试。在 "legacy" 模式下,任何 4xx 错误都会触发降级,除非设置了 automaticSSEFallback: false。
setLoggingLevel() 仅适用于遗留协议;当连接的服务器已协商为现代协议时调用它会抛出异常;此时请改为在各个现代服务器上单独配置 logLevel。
