LangChain 集成 MCP 全链路实战:MultiServerMCPClient 自动获取工具与 Resource 资源注入
英文标题:LangChain 集成 MCP 全链路实战:MultiServerMCPClient 自动获取工具与 Resource 资源注入
本文实战演示如何使用 LangChain 的 MultiServerMCPClient 自动连接 MCP Server,一行代码获取所有工具与资源。文章对比了手动集成的繁琐,解释了 MCP Resource 作为 RAG 之外自动注入上下文的概念,并给出从 Server 注册 Tool 与 Resource 到 Client 读取、注入 SystemMessage 的完整代码流程。多 Server 统一管理的示例进一步展示了跨进程、跨语言的工具协作价值,对 AI Agent 开发者实现解耦与工程化有直接参考意义。
4.8 KB
中文
LangChain 集成 MCP 全链路实战:MultiServerMCPClient 自动获取工具与 Resource 资源注入
之前我们手写了一个 MCP Server,注册了
query_user工具。但如果要把它接入 LangChain Agent,需要手动写代码获取工具、绑定模型吗?@langchain/mcp-adapters的MultiServerMCPClient给出了答案:一行代码自动获取所有工具和资源,让 MCP Server 和 LangChain Agent 无缝衔接。本文从Resource资源概念出发,完整解析 MCP 全链路集成。
前言
在之前的手写 MCP Server 文章中,我们实现了一个数据库查询 Server,注册了 query_user 工具。要把它接入 LangChain Agent,常规思路是:手动启动 MCP Server → 通过 stdio 通信 → 解析 JSON-RPC 消息 → 转换成 LangChain Tool 对象 → 绑定到模型。
太麻烦了。
@langchain/mcp-adapters 包的出现解决了这个问题。它提供了 MultiServerMCPClient,可以自动连接多个 MCP Server、自动获取所有工具和资源 ,然后用一行代码接入你的 LangChain 工作流。
同时,本文还会介绍 MCP 中一个被忽略但非常重要的概念——Resource(资源) 。它不仅是 Tool 的补充,更是 RAG 之外丰富 LLM 上下文的另一种手段。
一、为什么需要 MultiServerMCPClient?
1.1 手动集成的麻烦
const child = spawn('node', ['my-mcp-server.mjs'], { stdio: 'pipe' });
1.2 MultiServerMCPClient 的一行解决
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
const mcpClient = new MultiServerMCPClient({ mcpServers: { 'my-mcp-server': { command: 'node', args: ['/path/to/my-mcp-server.mjs'] } } });
const tools = await mcpClient.getTools();
const modelWithTools = model.bindTools(tools);
核心价值 :
| 手动集成 | MultiServerMCPClient |
|---|---|
| 手动启动子进程 | 自动 spawn |
| 手动发送 JSON-RPC | 自动协议通信 |
| 手动解析返回格式 | 自动格式转换 |
| 手动构造 Tool 对象 | 自动 getTools() |
| 一个 Server 一套代码 | 一个 Client 管理多个 Server |
二、MCP Resource:RAG 之外丰富上下文的手段
2.1 Tool vs Resource 的区别
在 MCP 中,有两种扩展 LLM 上下文的方式:
| 概念 | 作用 | 触发时机 | 类比 |
|---|---|---|---|
| Tool | 让 LLM 做 更多 | LLM 主动判断并调用 | 人的手(执行动作) |
| Resource | 让 LLM 知道 更多 | 自动注入上下文 | 人的记忆(提供知识) |
2.2 Resource 的本质
Resource(资源)是 MCP Server 向 Agent 暴露的静态知识片段 。它们可以是:
- 项目文档(README、API 文档)
- 使用指南、配置说明
- 代码规范、开发手册
- 内部知识库文章
这些资源在 Agent 启动时自动获取 ,作为 SystemMessage 的一部分注入到 LLM 的上下文中,让 LLM 在回答问题时拥有更多背景知识。
2.3 Resource vs RAG
笔记中提到了一个精准的对比:
| 维度 | Resource | RAG |
|---|---|---|
| 触发方式 | 启动时自动注入 | 查询时实时检索 |
| 数据量 | 较小(文档级别) | 较大(知识库级别) |
| 适用场景 | 使用指南、配置、规范 | 海量文档、FAQ |
| 上下文窗口 | 受 LLM 上下文限制 | 可以很大(检索后摘要) |
Resource: Agent 启动 → 读取 docs: → LLM 始终知道"这个 Server 是做什么的"
RAG: 用户提问 → 向量化查询 → 检索相关文档 → 注入 Prompt → LLM 根据检索结果回答
Resource 是 RAG 之外丰富上下文的另一种手段 ——适合那些不需要检索、但需要 LLM 始终知道的小段文档。
三、实战:完整的 MCP Server + Resource + MultiServerMCPClient
3.1 MCP Server 端:注册 Tool + Resource
my-mcp-server.mjs :
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { z } from 'zod';
const database = { users: { '001': { id: '001', name: '祖豪', email: 'zh@qq.com', role: 'admin' }, '002': { id: '002', name: '光光', email: 'gg@qq.com', role: 'user' }, '003': { id: '003', name: '小红', email: 'xh@qq.com', role: 'user' }, } };
const server = new McpServer({ name: 'my-mcp-server', version: '1.0.0' });
server.registerTool('query_user', {
description: '查询数据库中的用户信息',
inputSchema: {
userId: z.string().describe('用户ID, 例如:001, 002, 003')
}
}, async ({ userId }) => {
const user = database.users[userId];
if (!user) {
return {
content: [{ type: 'text', text: 用户 ID ${userId} 不存在。可用的ID: 001, 002, 003 }]
};
}
return {
content: [{
type: 'text',
text: 用户 ${user.id} 的信息:姓名:${user.name}, 邮箱:${user.email}, 角色:${user.role}
}]
};
});
server.registerResource(
'使用指南',
'docs://guide',
{
description: 'MCP Server 使用指南',
mimeType: 'text/plain'
},
async () => {
return {
contents: [{
uri: 'docs://guide',
mimeType: 'text/plain',
text: MCP Server 使用指南 功能:提供用户查询等工具。 使用:在 Cursor 等 MCP Client 中通过自然语言对话, Client 会自动调用相应工具。
}]
};
}
);
const transport = new StdioServerTransport(); await server.connect(transport);
Resource 注册的关键点 :
| 参数 | 说明 |
|---|---|
name |
资源名称(LLM 可见) |
uri |
统一资源标识符(如 docs://guide) |
metadata |
描述和 MIME 类型 |
handler |
返回资源内容的异步函数 |
3.2 LangChain 客户端:MultiServerMCPClient
langchain-mcp-test.mjs :
import 'dotenv/config'; import { MultiServerMCPClient } from '@langchain/mcp-adapters'; import { ChatOpenAI } from '@langchain/openai'; import chalk from 'chalk'; import { HumanMessage, SystemMessage, ToolMessage } from '@langchain/core/messages';
const model = new ChatOpenAI({ modelName: 'deepseek-v4-pro', apiKey: process.env.DEEPSEEK_API_KEY, temperature: 0, configuration: { baseURL: 'https://api.deepseek.com/v1', }, });
const mcpClient = new MultiServerMCPClient({ mcpServers: { 'my-mcp-server': { command: 'node', args: ['/path/to/my-mcp-server.mjs'] } } });
const tools = await mcpClient.getTools();
console.log(获取到 ${tools.length} 个工具);
const res = await mcpClient.listResources(); let resourceContent = ''; for (const [serverName, resources] of Object.entries(res)) { for (const resource of resources) { const content = await mcpClient.readResource(serverName, resource.uri); resourceContent += content[0].text; } } console.log(resourceContent, '---------------');
const modelWithTools = model.bindTools(tools);
3.3 Resource 注入 SystemMessage
async function runAgentWithTools(query, maxIterations = 30) { const messages = [
new SystemMessage(resourceContent),
new HumanMessage(query)
];
for (let i = 0; i < maxIterations; i++) {
console.log(chalk.bgGreen(正在等待AI思考, 第${i}轮....));
const response = await modelWithTools.invoke(messages);
messages.push(response);
if (!response.tool_calls || response.tool_calls.length === 0) {
console.log(`\n AI 最终回复: \n ${response.content}`);
return response.content;
}
console.log(chalk.bgBlue(`检测到 ${response.tool_calls.length} 个工具调用`));
console.log(chalk.bgBlue(`工具调用: ${response.tool_calls.map(t => t.name).join(', ')}`));
for (const toolCall of response.tool_calls) {
const foundTool = tools.find(t => t.name === toolCall.name);
if (foundTool) {
const toolResult = await foundTool.invoke(toolCall.args);
messages.push(new ToolMessage({
content: toolResult,
tool_call_id: toolCall.id
}));
}
}
}
return messages[messages.length - 1].content; }
await runAgentWithTools('查一下用户002的信息');
await runAgentWithTools('MCP Server的使用指南是什么?');
3.4 资源释放:mcpClient.close()
await mcpClient.close();
为什么必须 close()?
node langchain-mcp-test.mjs → 启动主进程 → MultiServerMCPClient 内部 spawn 子进程 → 子进程启动 my-mcp-server.mjs(stdio 连接) → 主进程通过 stdio 和子进程通信
如果不 close(): → 子进程一直运行 → 主进程退出后,子进程变成"孤儿进程" → 占用系统资源
close() 的作用: → 关闭 stdio 通信通道 → 终止子进程 → 释放所有相关资源
四、完整链路架构图
┌─────────────────────────────────────────────────────────────────────┐ │ LangChain + MCP 全链路架构 │ ├─────────────────────────────────────────────────────────────────────┤ │ LangChain 客户端(langchain-mcp-test.mjs) │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ MultiServerMCPClient │ │ │ │ ├── mcpClient.getTools() → 自动获取所有 Tool │ │ │ │ ├── mcpClient.listResources() → 列出所有 Resource │ │ │ │ ├── mcpClient.readResource() → 读取 Resource 内容 │ │ │ │ └── mcpClient.close() → 释放资源 │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ ↓ stdio(JSON-RPC) │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ ChatOpenAI + bindTools(tools) │ │ │ │ SystemMessage(resourceContent) ← Resource 注入上下文 │ │ │ │ ReAct 循环:invoke → tool_calls → ToolMessage → invoke │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ ↓ ┌─────────────────────────────────────────────────────────────────────┐ │ MCP Server(my-mcp-server.mjs) │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ registerTool('query_user') │ │ │ │ → 查询 database.users │ │ │ │ │ │ │ │ registerResource('使用指南', 'docs://guide') │ │ │ │ → 返回静态文档内容 │ │ │ └──────────────────────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────────┘
五、从单个 Server 到多个 Server
MultiServerMCPClient 的核心优势之一就是支持多个 MCP Server :
const mcpClient = new MultiServerMCPClient({ mcpServers: { 'user-db': { command: 'node', args: ['/path/to/user-db-server.mjs'] }, 'file-system': { command: 'node', args: ['/path/to/filesystem-server.mjs'] }, 'weather-api': { command: 'node', args: ['/path/to/weather-server.mjs'] } } });
const tools = await mcpClient.getTools();
多 Server 的价值 :
| Server | 负责 | 语言 |
|---|---|---|
| user-db | 用户数据查询 | Node.js |
| file-system | 文件读写 | Node.js |
| weather-api | 天气查询 | Python |
Agent 只需要一个 MultiServerMCPClient,就能同时调用三个 Server 的工具——跨进程、跨语言、统一管理 。
知识树
LangChain 集成 MCP 全链路实战 ├── MultiServerMCPClient 核心价值 │ ├── 自动 spawn 子进程 │ ├── 自动 JSON-RPC 通信 │ ├── 自动格式转换 │ └── 自动 getTools() ├── MCP Resource(资源) │ ├── Tool vs Resource 区别(做 vs 知道) │ ├── Resource vs RAG 对比(启动注入 vs 实时检索) │ ├── registerResource(name, uri, meta, handler) │ └── Resource 注入 SystemMessage ├── 完整链路 │ ├── Server 端:registerTool + registerResource │ ├── Client 端:MultiServerMCPClient │ │ ├── getTools() → bindTools │ │ ├── listResources() + readResource() │ │ └── close() → 释放资源 │ └── ReAct 循环:SystemMessage(resource) + HumanMessage ├── 审查纠正 │ ├── registerTool handler 参数({userId} 对象解构) │ ├── Resource URI 拼写一致性 │ ├── Promise.all 风险提示 │ └── chalk.bgBlue 重复调用 └── 进阶:多 Server 统一管理
结语
从手写 MCP Server 到 LangChain MultiServerMCPClient,我们完成了 MCP 集成的最后一公里:
- MCP Server :注册 Tool + Resource,独立运行
- MultiServerMCPClient :自动获取工具和资源,一行代码接入
- Resource 注入 :静态文档自动成为 SystemMessage,丰富 LLM 上下文
- 资源释放 :
mcpClient.close()防止子进程泄漏
这套组合的价值在于:MCP Server 的开发者专注于工具实现,LangChain Agent 的开发者专注于业务逻辑,两者通过标准协议解耦 。
MultiServerMCPClient不是简单的封装——它代表了 AI 工程化的一个趋势:让协议层处理通信细节,让开发者专注于创造价值。
参考与拓展阅读:
@langchain/mcp-adapters官方文档- MCP 协议规范(Model Context Protocol Specification)
- 《MCP 跨进程工具调用深度解析》—— LangChain Tool 的局限与 MCP 解耦
- 《手写 MCP Server 全栈实战》—— Node.js + Zod 构建工具
- 《从零手写 AI Agent》—— LangChain Tool 注册入门
English / 原文
LangChain 集成 MCP 全链路实战:MultiServerMCPClient 自动获取工具与 Resource 资源注入
之前我们手写了一个 MCP Server,注册了
query_user工具。但如果要把它接入 LangChain Agent,需要手动写代码获取工具、绑定模型吗?@langchain/mcp-adapters的MultiServerMCPClient给出了答案:一行代码自动获取所有工具和资源,让 MCP Server 和 LangChain Agent 无缝衔接。本文从Resource资源概念出发,完整解析 MCP 全链路集成。
前言
在之前的手写 MCP Server 文章中,我们实现了一个数据库查询 Server,注册了 query_user 工具。要把它接入 LangChain Agent,常规思路是:手动启动 MCP Server → 通过 stdio 通信 → 解析 JSON-RPC 消息 → 转换成 LangChain Tool 对象 → 绑定到模型。
太麻烦了。
@langchain/mcp-adapters 包的出现解决了这个问题。它提供了 MultiServerMCPClient,可以自动连接多个 MCP Server、自动获取所有工具和资源 ,然后用一行代码接入你的 LangChain 工作流。
同时,本文还会介绍 MCP 中一个被忽略但非常重要的概念——Resource(资源) 。它不仅是 Tool 的补充,更是 RAG 之外丰富 LLM 上下文的另一种手段。
一、为什么需要 MultiServerMCPClient?
1.1 手动集成的麻烦
const child = spawn('node', ['my-mcp-server.mjs'], { stdio: 'pipe' });
1.2 MultiServerMCPClient 的一行解决
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
const mcpClient = new MultiServerMCPClient({
mcpServers: {
'my-mcp-server': {
command: 'node',
args: ['/path/to/my-mcp-server.mjs']
}
}
});
const tools = await mcpClient.getTools();
const modelWithTools = model.bindTools(tools);
核心价值 :
| 手动集成 | MultiServerMCPClient |
|---|---|
| 手动启动子进程 | 自动 spawn |
| 手动发送 JSON-RPC | 自动协议通信 |
| 手动解析返回格式 | 自动格式转换 |
| 手动构造 Tool 对象 | 自动 getTools() |
| 一个 Server 一套代码 | 一个 Client 管理多个 Server |
二、MCP Resource:RAG 之外丰富上下文的手段
2.1 Tool vs Resource 的区别
在 MCP 中,有两种扩展 LLM 上下文的方式:
| 概念 | 作用 | 触发时机 | 类比 |
|---|---|---|---|
| Tool | 让 LLM 做 更多 | LLM 主动判断并调用 | 人的手(执行动作) |
| Resource | 让 LLM 知道 更多 | 自动注入上下文 | 人的记忆(提供知识) |
2.2 Resource 的本质
Resource(资源)是 MCP Server 向 Agent 暴露的静态知识片段 。它们可以是:
- 项目文档(README、API 文档)
- 使用指南、配置说明
- 代码规范、开发手册
- 内部知识库文章
这些资源在 Agent 启动时自动获取 ,作为 SystemMessage 的一部分注入到 LLM 的上下文中,让 LLM 在回答问题时拥有更多背景知识。
2.3 Resource vs RAG
笔记中提到了一个精准的对比:
| 维度 | Resource | RAG |
|---|---|---|
| 触发方式 | 启动时自动注入 | 查询时实时检索 |
| 数据量 | 较小(文档级别) | 较大(知识库级别) |
| 适用场景 | 使用指南、配置、规范 | 海量文档、FAQ |
| 上下文窗口 | 受 LLM 上下文限制 | 可以很大(检索后摘要) |
Resource:
Agent 启动 → 读取 docs:
→ LLM 始终知道"这个 Server 是做什么的"
RAG:
用户提问 → 向量化查询 → 检索相关文档 → 注入 Prompt
→ LLM 根据检索结果回答
Resource 是 RAG 之外丰富上下文的另一种手段 ——适合那些不需要检索、但需要 LLM 始终知道的小段文档。
三、实战:完整的 MCP Server + Resource + MultiServerMCPClient
3.1 MCP Server 端:注册 Tool + Resource
my-mcp-server.mjs :
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';
const database = {
users: {
'001': { id: '001', name: '祖豪', email: 'zh@qq.com', role: 'admin' },
'002': { id: '002', name: '光光', email: 'gg@qq.com', role: 'user' },
'003': { id: '003', name: '小红', email: 'xh@qq.com', role: 'user' },
}
};
const server = new McpServer({
name: 'my-mcp-server',
version: '1.0.0'
});
server.registerTool('query_user', {
description: '查询数据库中的用户信息',
inputSchema: {
userId: z.string().describe('用户ID, 例如:001, 002, 003')
}
}, async ({ userId }) => {
const user = database.users[userId];
if (!user) {
return {
content: [{ type: 'text', text: `用户 ID ${userId} 不存在。可用的ID: 001, 002, 003` }]
};
}
return {
content: [{
type: 'text',
text: `用户 ${user.id} 的信息:姓名:${user.name}, 邮箱:${user.email}, 角色:${user.role}`
}]
};
});
server.registerResource(
'使用指南',
'docs://guide',
{
description: 'MCP Server 使用指南',
mimeType: 'text/plain'
},
async () => {
return {
contents: [{
uri: 'docs://guide',
mimeType: 'text/plain',
text: `
MCP Server 使用指南
功能:提供用户查询等工具。
使用:在 Cursor 等 MCP Client 中通过自然语言对话,
Client 会自动调用相应工具。
`
}]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
Resource 注册的关键点 :
| 参数 | 说明 |
|---|---|
name |
资源名称(LLM 可见) |
uri |
统一资源标识符(如 docs://guide) |
metadata |
描述和 MIME 类型 |
handler |
返回资源内容的异步函数 |
3.2 LangChain 客户端:MultiServerMCPClient
langchain-mcp-test.mjs :
import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import {
HumanMessage,
SystemMessage,
ToolMessage
} from '@langchain/core/messages';
const model = new ChatOpenAI({
modelName: 'deepseek-v4-pro',
apiKey: process.env.DEEPSEEK_API_KEY,
temperature: 0,
configuration: {
baseURL: 'https://api.deepseek.com/v1',
},
});
const mcpClient = new MultiServerMCPClient({
mcpServers: {
'my-mcp-server': {
command: 'node',
args: ['/path/to/my-mcp-server.mjs']
}
}
});
const tools = await mcpClient.getTools();
console.log(`获取到 ${tools.length} 个工具`);
const res = await mcpClient.listResources();
let resourceContent = '';
for (const [serverName, resources] of Object.entries(res)) {
for (const resource of resources) {
const content = await mcpClient.readResource(serverName, resource.uri);
resourceContent += content[0].text;
}
}
console.log(resourceContent, '---------------');
const modelWithTools = model.bindTools(tools);
3.3 Resource 注入 SystemMessage
async function runAgentWithTools(query, maxIterations = 30) {
const messages = [
new SystemMessage(resourceContent),
new HumanMessage(query)
];
for (let i = 0; i < maxIterations; i++) {
console.log(chalk.bgGreen(`正在等待AI思考, 第${i}轮....`));
const response = await modelWithTools.invoke(messages);
messages.push(response);
if (!response.tool_calls || response.tool_calls.length === 0) {
console.log(`\n AI 最终回复: \n ${response.content}`);
return response.content;
}
console.log(chalk.bgBlue(`检测到 ${response.tool_calls.length} 个工具调用`));
console.log(chalk.bgBlue(`工具调用: ${response.tool_calls.map(t => t.name).join(', ')}`));
for (const toolCall of response.tool_calls) {
const foundTool = tools.find(t => t.name === toolCall.name);
if (foundTool) {
const toolResult = await foundTool.invoke(toolCall.args);
messages.push(new ToolMessage({
content: toolResult,
tool_call_id: toolCall.id
}));
}
}
}
return messages[messages.length - 1].content;
}
await runAgentWithTools('查一下用户002的信息');
await runAgentWithTools('MCP Server的使用指南是什么?');
3.4 资源释放:mcpClient.close()
await mcpClient.close();
为什么必须 close()?
node langchain-mcp-test.mjs
→ 启动主进程
→ MultiServerMCPClient 内部 spawn 子进程
→ 子进程启动 my-mcp-server.mjs(stdio 连接)
→ 主进程通过 stdio 和子进程通信
如果不 close():
→ 子进程一直运行
→ 主进程退出后,子进程变成"孤儿进程"
→ 占用系统资源
close() 的作用:
→ 关闭 stdio 通信通道
→ 终止子进程
→ 释放所有相关资源
四、完整链路架构图
┌─────────────────────────────────────────────────────────────────────┐
│ LangChain + MCP 全链路架构 │
├─────────────────────────────────────────────────────────────────────┤
│ LangChain 客户端(langchain-mcp-test.mjs) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ MultiServerMCPClient │ │
│ │ ├── mcpClient.getTools() → 自动获取所有 Tool │ │
│ │ ├── mcpClient.listResources() → 列出所有 Resource │ │
│ │ ├── mcpClient.readResource() → 读取 Resource 内容 │ │
│ │ └── mcpClient.close() → 释放资源 │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ ↓ stdio(JSON-RPC) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ ChatOpenAI + bindTools(tools) │ │
│ │ SystemMessage(resourceContent) ← Resource 注入上下文 │ │
│ │ ReAct 循环:invoke → tool_calls → ToolMessage → invoke │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────────────┐
│ MCP Server(my-mcp-server.mjs) │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ registerTool('query_user') │ │
│ │ → 查询 database.users │ │
│ │ │ │
│ │ registerResource('使用指南', 'docs://guide') │ │
│ │ → 返回静态文档内容 │ │
│ └──────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
五、从单个 Server 到多个 Server
MultiServerMCPClient 的核心优势之一就是支持多个 MCP Server :
const mcpClient = new MultiServerMCPClient({
mcpServers: {
'user-db': {
command: 'node',
args: ['/path/to/user-db-server.mjs']
},
'file-system': {
command: 'node',
args: ['/path/to/filesystem-server.mjs']
},
'weather-api': {
command: 'node',
args: ['/path/to/weather-server.mjs']
}
}
});
const tools = await mcpClient.getTools();
多 Server 的价值 :
| Server | 负责 | 语言 |
|---|---|---|
| user-db | 用户数据查询 | Node.js |
| file-system | 文件读写 | Node.js |
| weather-api | 天气查询 | Python |
Agent 只需要一个 MultiServerMCPClient,就能同时调用三个 Server 的工具——跨进程、跨语言、统一管理 。
知识树
LangChain 集成 MCP 全链路实战
├── MultiServerMCPClient 核心价值
│ ├── 自动 spawn 子进程
│ ├── 自动 JSON-RPC 通信
│ ├── 自动格式转换
│ └── 自动 getTools()
├── MCP Resource(资源)
│ ├── Tool vs Resource 区别(做 vs 知道)
│ ├── Resource vs RAG 对比(启动注入 vs 实时检索)
│ ├── registerResource(name, uri, meta, handler)
│ └── Resource 注入 SystemMessage
├── 完整链路
│ ├── Server 端:registerTool + registerResource
│ ├── Client 端:MultiServerMCPClient
│ │ ├── getTools() → bindTools
│ │ ├── listResources() + readResource()
│ │ └── close() → 释放资源
│ └── ReAct 循环:SystemMessage(resource) + HumanMessage
├── 审查纠正
│ ├── registerTool handler 参数({userId} 对象解构)
│ ├── Resource URI 拼写一致性
│ ├── Promise.all 风险提示
│ └── chalk.bgBlue 重复调用
└── 进阶:多 Server 统一管理
结语
从手写 MCP Server 到 LangChain MultiServerMCPClient,我们完成了 MCP 集成的最后一公里:
- MCP Server :注册 Tool + Resource,独立运行
- MultiServerMCPClient :自动获取工具和资源,一行代码接入
- Resource 注入 :静态文档自动成为 SystemMessage,丰富 LLM 上下文
- 资源释放 :
mcpClient.close()防止子进程泄漏
这套组合的价值在于:MCP Server 的开发者专注于工具实现,LangChain Agent 的开发者专注于业务逻辑,两者通过标准协议解耦 。
MultiServerMCPClient不是简单的封装——它代表了 AI 工程化的一个趋势:让协议层处理通信细节,让开发者专注于创造价值。
参考与拓展阅读:
@langchain/mcp-adapters官方文档- MCP 协议规范(Model Context Protocol Specification)
- 《MCP 跨进程工具调用深度解析》—— LangChain Tool 的局限与 MCP 解耦
- 《手写 MCP Server 全栈实战》—— Node.js + Zod 构建工具
- 《从零手写 AI Agent》—— LangChain Tool 注册入门
如果本文帮你理解了 LangChain 与 MCP 的集成方式和 Resource 资源的概念,欢迎点赞 + 收藏。你在用 MCP 接入什么工具?欢迎在评论区交流讨论 👇
#MCP #LangChain #MultiServerMCPClient #Resource #AIAgent #掘金技术社区