组合多个远程 MCP Server:让 Agent 同时调用高德地图、Chrome DevTools 和文件系统
摘要:一个 Agent 如果能同时调用高德地图查位置、用 Chrome DevTools 打开网页、用 FileSystem 写入文件,它就能完成多么复杂的任务?本文用 LangChain 的 MultiServerMCPClient 连接多个 MCP Server——本地、远程 HTTP、stdio 三种方式全涵盖——构建一个能跨进程调用多种工具的 Agent。
📑 目录
- MCP 的核心价值:跨进程调用
- 项目目标:两个任务,展示 MCP 的组合威力
- 环境准备与依赖包详解
- MultiServerMCPClient:同时连接多个 Server
- 配置详解:本地、远程 HTTP、stdio 三种方式
- Agent 循环:处理不同类型的 Tool 返回值
- 任务一:搜索酒店 + 浏览器展示图片
- 任务二:搜索酒店 + 路线规划 + 保存文档
- 一点总结
- 互动讨论
MCP 的核心价值:跨进程调用
MCP(Model Context Protocol)的本质还是 Tool,但它给 Tool 包了一层进程,可以通过 stdio 或 HTTP 来跨进程访问。
这意味着什么?
text
┌─────────────────────────────────────────────────────────────┐
│ 本地 Tool(之前的方式) │
│ ┌─────────────┐ │
│ │ Agent │── 直接调用 ──▶ Tool(同进程) │
│ └─────────────┘ │
│ 问题:Tool 只能在本项目中使用,换语言/换项目就要重写 │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ MCP Tool(现在的方式) │
│ ┌─────────────┐ MCP协议 ┌──────────────────────┐ │
│ │ Agent │── stdio/HTTP ──▶│ MCP Server(独立进程)│ │
│ └─────────────┘ └──────────────────────┘ │
│ 优势:Tool 独立部署,跨语言、跨进程、跨项目复用 │
└─────────────────────────────────────────────────────────────┘
[此处插入图片:BC43E74C-94F4-4C46-811C-AC2102221D81.png]
有了 MCP 协议后,任何人都可以开发基于这个协议的 MCP Server,然后直接被复用。高德地图有 MCP Server,Chrome DevTools 有 MCP Server,FileSystem 也有 MCP Server——把它们组合在一起,Agent 的能力边界就被极大地扩展了。
项目目标:两个任务,展示 MCP 的组合威力
在 mcp-test.mjs 中,我配置了四个 MCP Server,让 Agent 同时拥有多种能力:
| MCP Server | 连接方式 | 能力 |
|---|---|---|
my-mcp-server | stdio(本地进程) | 查询用户信息(自定义) |
amap-maps-http | HTTP(远程服务) | 高德地图:位置查询、路线规划、POI 搜索 |
fileSystem | stdio(npx 临时安装) | 读写本地文件 |
chrome-devtools | stdio(npx 临时安装) | 控制浏览器:打开页面、截图、点击元素 |
这张图清晰展示了 Agent 通过 MCP Adapter 连接多个 MCP Server 的架构——高德 MCP 走 HTTP,Chrome DevTools 和 FileSystem 走 stdio,所有 Tool 统一汇聚到 Agent。
项目执行了两个任务,分别展示 MCP 的不同组合方式:
任务一:调用高德 MCP + Chrome DevTools MCP
“告诉我宁波老外滩附近的三个酒店,拿到酒店图片,打开我的默认浏览器(Edge),展示每个酒店的图片,每个 tab 一个 url 展示,并且把那个页面标题改为酒店名”
任务二:调用高德 MCP + FileSystem MCP
“北京南站附近的2个酒店,以及去的路线,路线规划生成文档保存到当前目录的一个 md 文件”
两个任务都用到高德 MCP,但第二个任务用 FileSystem 保存文档,第一个任务用 Chrome DevTools 操作浏览器——展示了 MCP 工具的可组合性。
环境准备与依赖包详解
bash
pnpm i @langchain/mcp-adapters @langchain/openai dotenv chalk
各依赖包的作用
| 包名 | 版本 | 作用 |
|---|---|---|
@langchain/mcp-adapters | 最新 | LangChain 官方 MCP 适配器,提供 MultiServerMCPClient,让 Agent 连接 MCP Server |
@langchain/openai | 最新 | LangChain 的 OpenAI 兼容接口,用于调用大模型(DeepSeek 兼容 OpenAI 接口) |
dotenv | 最新 | 读取 .env 文件中的环境变量,如 DEEPSEEK_API_KEY |
chalk | 最新 | 终端输出着色,让 Agent 的迭代过程更直观可读 |
核心 SDK 说明
@langchain/mcp-adapters 内部依赖了 @modelcontextprotocol/sdk,这是 MCP 协议的标准实现。MultiServerMCPClient 的核心工作:
- 根据配置启动子进程(
command+args)或建立 HTTP 连接(url) - 通过 MCP 协议与 Server 握手,获取所有 Tool 列表
- 将 MCP Tool 包装成 LangChain Tool 格式,统一返回
MultiServerMCPClient:同时连接多个 Server
javascript
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
const mcpClient = new MultiServerMCPClient({
mcpServers: {
'my-mcp-server': {
command: 'node',
args: ['src/my-mcp-server.mjs'],
cwd: 'D:/workspace/yjs_ai/ai/agent_in_action/mcp-demo',
},
'amap-maps-http': {
url: 'https://mcp.amap.com/mcp?key=15b9da040ee6a3242f4708b7e3a6ea31',
},
'fileSystem': {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', 'D:/workspace/yjs_ai/ai/agent_in_action/remote-mcp'],
},
'chrome-devtools': {
command: 'npx',
args: [
'-y',
'chrome-devtools-mcp@latest',
'--executablePath',
'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
]
},
}
});
MultiServerMCPClient 接收一个 mcpServers 对象,每个 Server 用 key 标识,值是连接配置。调用 getTools() 后,它会自动连接所有 Server,拉取各自的 Tool 列表,合并成一个统一的 Tool 数组。Agent 完全不知道这些 Tool 来自不同的进程——它只看到一堆可用的 Tool。
配置详解:本地、远程 HTTP、stdio 三种方式
1. 本地 stdio Server(自定义)
javascript
'my-mcp-server': {
command: 'node',
args: ['src/my-mcp-server.mjs'],
cwd: 'D:/workspace/yjs_ai/ai/agent_in_action/mcp-demo',
}
command:启动子进程的命令,这里是nodeargs:传递给命令的参数数组,即运行哪个文件cwd:子进程的工作目录,确保相对路径正确解析
这种方式适合自定义业务逻辑的 Tool,用 Node.js 编写,通过 stdio 通信。
2. 远程 HTTP Server(高德地图)
javascript
'amap-maps-http': {
url: 'https://mcp.amap.com/mcp?key=15b9da040ee6a3242f4708b7e3a6ea31',
}
url:MCP Server 的 HTTP 端点地址key:高德 API 密钥,用于身份认证和计费
这张图对比了两种跨进程调用方式:通过 stdio 调用本地 Java 进程,通过 HTTP 调用远程 Java 服务。高德 MCP 走的是 HTTP 路线——Agent 发送 HTTP 请求到高德服务器,服务器返回结果。远程 HTTP 方式的优势是 Server 可以独立部署在任何地方,语言无关。
3. stdio Server(npx 临时安装)
javascript
'fileSystem': {
command: 'npx',
args: ['-y', '@modelcontextprotocol/server-filesystem', 'D:/workspace/yjs_ai/ai/agent_in_action/remote-mcp'],
},
'chrome-devtools': {
command: 'npx',
args: [
'-y',
'chrome-devtools-mcp@latest',
'--executablePath',
'C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe'
]
}
npx -y 会在运行时临时安装指定的 npm 包,-y 参数自动确认所有提示,无需手动交互。执行后自动清理,不用提前安装依赖,非常方便。
chrome-devtools-mcp 是官方 MCP Server,支持任何基于 Chromium 的浏览器。--executablePath 指定了 Edge 浏览器的可执行文件路径,让 MCP Server 控制 Edge 浏览器而不是默认的 Chrome。
这张图展示了 Agent 调用本地 MCP Server(stdio)和远程 MCP Server(HTTP)的完整流程——Agent 通过 tool.invoke() 调用,底层由 MCP Adapter 处理通信细节。
Agent 循环:处理不同类型的 Tool 返回值
MultiServerMCPClient.getTools() 返回的 Tool 数组统一了接口,但不同 MCP Server 的返回值格式可能不同:
javascript
const tools = await mcpClient.getTools();
const modelWithTools = model.bindTools(tools);
for (const toolCall of response.tool_calls) {
const foundTool = tools.find(t => t.name === toolCall.name);
if (foundTool) {
try {
const toolResult = await foundTool.invoke(toolCall.args);
let contentStr;
// 返回值可能是纯字符串
if (typeof toolResult === 'string') {
contentStr = toolResult;
// fileSystem 返回的是对象,包含 text 字段
} else if (toolResult && toolResult.text) {
contentStr = toolResult.text;
// 其他情况序列化为 JSON
} else {
contentStr = JSON.stringify(toolResult);
}
messages.push(new ToolMessage({
content: contentStr,
tool_call_id: toolCall.id
}));
} catch (err) {
// 工具执行失败,返回错误信息给 LLM
messages.push(new ToolMessage({
content: `工具执行失败: ${err.message}`,
tool_call_id: toolCall.id
}));
}
}
}
不同 MCP Server 的返回值差异:
- 高德 MCP:返回 JSON 对象,包含位置、酒店、路线等信息
- fileSystem MCP:返回
{ text: '文件内容' }对象 - chrome-devtools MCP:返回操作结果字符串或对象
try-catch 包裹了工具调用,确保任何单个 Tool 失败不会导致整个 Agent 循环崩溃。错误信息通过 ToolMessage 返回给 LLM,让它可以决定下一步怎么处理(如重试、换参数、告知用户)。
任务一:搜索酒店 + 浏览器展示图片
Agent 执行的第一个任务是:
“告诉我宁波老外滩附近的三个酒店,拿到酒店图片,打开我的默认浏览器(Edge),展示每个酒店的图片,每个 tab 一个 url 展示,并且把那个页面标题改为酒店名”
执行流程
text
用户输入任务
↓
LLM 拆解:需要先搜索酒店,再打开浏览器展示图片
↓
【高德 MCP】搜索“宁波老外滩附近酒店”
→ 返回三个酒店的名称、地址、图片 URL
↓
【Chrome DevTools MCP】打开第一个酒店的图片 URL
→ 创建新 tab,导航到图片地址
↓
【Chrome DevTools MCP】将 tab 标题改为酒店名
↓
(重复以上两步,处理剩余两个酒店)
↓
任务完成
上图展示了最终执行结果:Edge 浏览器中三个 tab 分别显示三家酒店的图片,每个 tab 的标题已经被改为对应的酒店名(如“汉庭酒店”“喆啡酒店”等)。
这个任务展示了高德 MCP + Chrome DevTools MCP 的组合:一个负责获取信息,一个负责可视化展示。Agent 在两个 MCP Server 之间协调调用,完成了完整的“搜索 → 展示”工作流。
任务二:搜索酒店 + 路线规划 + 保存文档
第二个任务是:
“北京南站附近的2个酒店,以及去的路线,路线规划生成文档保存到当前目录的一个 md 文件”
执行流程
text
用户输入任务
↓
LLM 拆解:需要搜索酒店、规划路线、保存文档
↓
【高德 MCP】搜索“北京南站附近酒店”
→ 返回两个酒店的名称、地址、评分
↓
【高德 MCP】规划从天安门到北京南站的路线
→ 返回地铁、公交等多种方案
↓
【FileSystem MCP】将结果写入 markdown 文件
→ 保存到当前目录的 md 文件中
↓
任务完成
执行后生成了 北京南站周边酒店及路线规划.md 文件,内容包含:
- 北京南站的位置信息(地址、经纬度)
- 两个推荐酒店(汉庭酒店、喆啡酒店)的地址、评分、特点
- 详细的路线规划(步行路线、地铁路线、公交路线)
- 路线规划总览图(ASCII 地图)
- 出行小贴士
下面最终生成内容:
🚄 北京南站周边酒店及路线规划
生成时间:2025年
数据来源:高德地图
一、北京南站位置信息
| 项目 | 内容 |
|---|---|
| 地址 | 北京市丰台区 |
| 经纬度 | 116.378059, 39.867679 |
| 交通枢纽 | 地铁4号线、14号线、多路公交 |
二、推荐酒店
🏨 酒店一:汉庭酒店(北京南站北广场店)
| 项目 | 内容 |
|---|---|
| 地址 | 北京南站 F1 楼 1 层 1001 室 |
| 评分 | ⭐ 4.4 分 |
| 类型 | 经济型连锁酒店 |
| 特点 | 就在北京南站站内北广场,出站即达,极为便捷 |
🏨 酒店二:喆啡酒店(北京南站店)
| 项目 | 内容 |
|---|---|
| 地址 | 右外东滨河路东庄甲 6 号 |
| 评分 | ⭐ 4.4 分 |
| 类型 | 精品酒店(咖啡主题) |
| 特点 | 紧邻北京南站,步行约 7 分钟,环境雅致,有咖啡文化特色 |
三、路线规划
路线①:北京南站 → 汉庭酒店(北广场店)
🚶 步行约 403 米 · 约 5 分钟
北京南站出站
↓ 沿南站幸福路向西步行 98 米
↓ 向南步行 79 米
↓ 向东南步行 15 米
↓ 向东南步行 99 米
↓ 向西南步行 112 米
到达:汉庭酒店(北京南站北广场店)
路线②:北京南站 → 喆啡酒店(北京南站店)
🚶 步行约 528 米 · 约 7 分钟
北京南站出站
↓ 沿南站幸福路向东步行 88 米
↓ 步行 9 米后右转
↓ 沿南站幸福路向东步行 66 米
↓ 左转进入幸福二巷,向北步行 259 米
↓ 沿右安门东滨河路向东步行 86 米
↓ 沿东庄一巷向南步行 20 米
到达:喆啡酒店(北京南站店)
路线③:天安门 → 北京南站(公共交通推荐)
🚇 全程约 38 分钟 · 约 6 公里
🅰️ 方案一:地铁(推荐·最快)
| 步骤 | 路线 | 时间 |
|---|---|---|
| ① | 🚶 从 天安门广场 步行至 前门站(约 10 分钟) | 约 10 分钟 |
| ② | 🚇 地铁 2 号线内环(前门 → 宣武门,1 站) | 约 6 分钟 |
| ③ | 🚇 站内换乘 地铁 4 号线(宣武门 → 北京南站,3 站) | 约 9 分钟 |
| ④ | 🚶 从 北京南站 A 北出口 出站 | 约 1 分钟 |
| 总计 | 约 38 分钟 |
天安门广场
↓ 步行 10 分钟
前门站(地铁2号线内环)
↓ 1 站(途经:和平门)
宣武门站(换乘4号线)
↓ 3 站(途经:菜市口、陶然亭)
北京南站(A北出口出站)
🅱️ 方案二:公交 106 路
| 步骤 | 路线 |
|---|---|
| ① | 🚶 从天安门步行至 前门站 |
| ② | 🚌 乘坐 106 路(前门 → 北京南站,途经:大栅栏→珠市口南→天桥→北纬路→太平街→陶然桥北→南站幸福路) |
四、路线规划总览图
┌─────────────────────┐
│ 天安门 / 市中心 │
└──────────┬──────────┘
│
🚇 地铁2号线→4号线
🚌 公交106路等
│
┌──────────▼──────────┐
│ ★ 北京南站 ★ │
│ 116.378059,39.867679 │
└──┬──────────────┬───┘
│ │
🚶 步行403米 │ │ 🚶 步行528米
│ │
┌─────────────▼──┐ ┌──────▼────────────┐
│ 汉庭酒店(北广场店)│ │ 喆啡酒店(北京南站店) │
│ 评分:⭐4.4 │ │ 评分:⭐4.4 │
│ 站内北广场F1层 │ │ 右外东滨河路东庄甲6号│
└────────────────┘ └───────────────────┘
五、出行小贴士
- 🚇 地铁优先:北京南站是地铁 4 号线和 14 号线的换乘站,去往北京各区域非常方便
- 🏨 汉庭酒店适合赶早班车/晚到站的旅客,出站即达
- ☕ 喆啡酒店环境更有特色,步行约 7 分钟,适合想稍作休整的旅客
- 💡 北京南站周边餐饮、便利店齐全,出行前可提前购齐所需物品
本路线规划由高德地图数据生成,信息仅供参考,实际出行请以实时路况为准。
这个任务展示了高德 MCP + FileSystem MCP 的组合:一个负责获取位置和路线数据,一个负责持久化保存。Agent 完成了“搜索 → 规划 → 保存”的完整工作流,结果以文档形式保留下来。
一点总结
通过这个项目,我理解了:
-
MCP 的本质是跨进程 Tool 调用:通过 stdio(本地)或 HTTP(远程)实现。
-
MultiServerMCPClient:LangChain 提供的适配器,可以同时连接多个 MCP Server,统一管理 Tool。
-
三种连接方式:
command + args + cwd:启动本地 Node.js 进程(stdio)url:连接远程 HTTP 服务npx -y:临时安装并执行 npm 包
-
返回值类型处理:不同 MCP Server 返回格式不同,需要做类型判断和转换,配合
try-catch确保稳定性。 -
MCP 的组合威力:高德地图 + Chrome DevTools + FileSystem 组合起来,Agent 能完成“搜索 → 获取信息 → 打开浏览器 → 保存文档”的完整工作流。
-
任务驱动的 Agent 设计:给 Agent 一个自然语言任务,它会自动拆解、调用合适的 MCP Server、组合结果。
互动讨论
- MCP 和普通 Tool 的核心区别是什么? 为什么说 MCP 让 Tool 变得“可复用”?
- stdio 和 HTTP 两种通信方式分别适合什么场景? 本地和远程的边界在哪里?
npx -y临时安装的方式有什么优缺点? 在什么场景下适合使用?- 任务一中 Agent 需要调用两个 MCP Server,它是如何协调顺序的? 如果酒店搜索失败了,浏览器还会打开吗?
- 高德 MCP + Chrome DevTools + FileSystem 的组合还能完成什么自动化任务?
📌 一点心得:MCP 最大的价值不是“让 Agent 能调用 Tool”,而是“让任何人开发的 Tool 都能被任何 Agent 调用”。这种解耦让工具生态可以独立发展,Agent 的能力边界也随之无限扩展。