为纪念 35 周年:《Terminator 2: Judgment Day》将在全球影院重映
2026-07-13
2026-07-14 0
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-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
任务二:调用高德 MCP + FileSystem MCP
两个任务都用到高德 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 的迭代过程更直观可读 |
@langchain/mcp-adapters 内部依赖了 @modelcontextprotocol/sdk,这是 MCP 协议的标准实现。MultiServerMCPClient 的核心工作:
command + args)或建立 HTTP 连接(url)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)MicrosoftEdgeApplicationmsedge.exe'
]
},
}
});
MultiServerMCPClient 接收一个 mcpServers 对象,每个 Server 用 key 标识,值是连接配置。调用 getTools() 后,它会自动连接所有 Server,拉取各自的 Tool 列表,合并成一个统一的 Tool 数组。Agent 完全不知道这些 Tool 来自不同的进程——它只看到一堆可用的 Tool。
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 通信。
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 可以独立部署在任何地方,语言无关。
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)MicrosoftEdgeApplicationmsedge.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 处理通信细节。
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 的返回值差异:
{ text: '文件内容' } 对象try-catch 包裹了工具调用,确保任何单个 Tool 失败不会导致整个 Agent 循环崩溃。错误信息通过 ToolMessage 返回给 LLM,让它可以决定下一步怎么处理(如重试、换参数、告知用户)。
Agent 执行的第一个任务是:
text
复制代码用户输入任务
↓
LLM 拆解:需要先搜索酒店,再打开浏览器展示图片
↓
【高德 MCP】搜索“宁波老外滩附近酒店”
→ 返回三个酒店的名称、地址、图片 URL
↓
【Chrome DevTools MCP】打开第一个酒店的图片 URL
→ 创建新 tab,导航到图片地址
↓
【Chrome DevTools MCP】将 tab 标题改为酒店名
↓
(重复以上两步,处理剩余两个酒店)
↓
任务完成



上图展示了最终执行结果:Edge 浏览器中三个 tab 分别显示三家酒店的图片,每个 tab 的标题已经被改为对应的酒店名(如“汉庭酒店”“喆啡酒店”等)。
这个任务展示了高德 MCP + Chrome DevTools MCP 的组合:一个负责获取信息,一个负责可视化展示。Agent 在两个 MCP Server 之间协调调用,完成了完整的“搜索 → 展示”工作流。
第二个任务是:
text
复制代码用户输入任务
↓
LLM 拆解:需要搜索酒店、规划路线、保存文档
↓
【高德 MCP】搜索“北京南站附近酒店”
→ 返回两个酒店的名称、地址、评分
↓
【高德 MCP】规划从天安门到北京南站的路线
→ 返回地铁、公交等多种方案
↓
【FileSystem MCP】将结果写入 markdown 文件
→ 保存到当前目录的 md 文件中
↓
任务完成
执行后生成了 北京南站周边酒店及路线规划.md 文件,内容包含:
下面最终生成内容:
| 项目 | 内容 |
|---|---|
| 地址 | 北京市丰台区 |
| 经纬度 | 116.378059, 39.867679 |
| 交通枢纽 | 地铁4号线、14号线、多路公交 |
| 项目 | 内容 |
|---|---|
| 地址 | 北京南站 F1 楼 1 层 1001 室 |
| 评分 | ⭐ 4.4 分 |
| 类型 | 经济型连锁酒店 |
| 特点 | 就在北京南站站内北广场,出站即达,极为便捷 |
| 项目 | 内容 |
|---|---|
| 地址 | 右外东滨河路东庄甲 6 号 |
| 评分 | ⭐ 4.4 分 |
| 类型 | 精品酒店(咖啡主题) |
| 特点 | 紧邻北京南站,步行约 7 分钟,环境雅致,有咖啡文化特色 |
复制代码北京南站出站
↓ 沿南站幸福路向西步行 98 米
↓ 向南步行 79 米
↓ 向东南步行 15 米
↓ 向东南步行 99 米
↓ 向西南步行 112 米
到达:汉庭酒店(北京南站北广场店)
复制代码北京南站出站
↓ 沿南站幸福路向东步行 88 米
↓ 步行 9 米后右转
↓ 沿南站幸福路向东步行 66 米
↓ 左转进入幸福二巷,向北步行 259 米
↓ 沿右安门东滨河路向东步行 86 米
↓ 沿东庄一巷向南步行 20 米
到达:喆啡酒店(北京南站店)
| 步骤 | 路线 | 时间 |
|---|---|---|
| ① | 从 天安门广场 步行至 前门站(约 10 分钟) | 约 10 分钟 |
| ② | 地铁 2 号线内环(前门 → 宣武门,1 站) | 约 6 分钟 |
| ③ | 站内换乘 地铁 4 号线(宣武门 → 北京南站,3 站) | 约 9 分钟 |
| ④ | 从 北京南站 A 北出口 出站 | 约 1 分钟 |
| 总计 | 约 38 分钟 |
复制代码天安门广场
↓ 步行 10 分钟
前门站(地铁2号线内环)
↓ 1 站(途经:和平门)
宣武门站(换乘4号线)
↓ 3 站(途经:菜市口、陶然亭)
北京南站(A北出口出站)
| 步骤 | 路线 |
|---|---|
| ① | 从天安门步行至 前门站 |
| ② | 乘坐 106 路(前门 → 北京南站,途经:大栅栏→珠市口南→天桥→北纬路→太平街→陶然桥北→南站幸福路) |
复制代码 ┌─────────────────────┐
│ 天安门 / 市中心 │
└──────────┬──────────┘
│
地铁2号线→4号线
公交106路等
│
┌──────────▼──────────┐
│ 北京南站 │
│ 116.378059,39.867679 │
└──┬──────────────┬───┘
│ │
步行403米 │ │ 步行528米
│ │
┌─────────────▼──┐ ┌──────▼────────────┐
│ 汉庭酒店(北广场店)│ │ 喆啡酒店(北京南站店) │
│ 评分:⭐4.4 │ │ 评分:⭐4.4 │
│ 站内北广场F1层 │ │ 右外东滨河路东庄甲6号│
└────────────────┘ └───────────────────┘
本路线规划由高德地图数据生成,信息仅供参考,实际出行请以实时路况为准。
这个任务展示了高德 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、组合结果。
npx -y 临时安装的方式有什么优缺点? 在什么场景下适合使用?