远程 MCP 多 Server 编排:一个指令让 Agent 同时操控地图、浏览器和文件系统

摘要:从单一 stdio MCP 到同时接入高德地图、Chrome DevTools、FileSystem 四个 Server,一个北京南站酒店搜索加浏览器展示的实战,展示 MCP 多 Server 编排的完整流程。


上一篇文章拆解了 MCP 协议的核心机制------一个本地的 stdio MCP Server,通过跨进程通信让 Agent 调用外部工具。但 MCP 真正的威力不在于"一个 Server",而在于多个 Server 同时接入,让 Agent 获得跨越多个领域的能力组合。

MCP 本质上还是 tool,只不过包了一层进程,可以通过 stdio 和 HTTP 来访问。这个"包了一层"带来一个巨大的好处:任何人都可以开发基于 MCP 协议的 Server,然后直接被其他人复用。 高德地图的 MCP Server 可以做位置查询和路线规划,Chrome DevTools 的 MCP Server 可以控制浏览器打开网页和截图,FileSystem 的 MCP Server 可以读写本地文件。把这些 Server 同时接入一个 Agent,它就能完成"搜酒店 → 打开浏览器展示 → 保存截图到本地"这种跨领域的工作流。

本文用一个实际案例串联起来:查询北京南站附近最近的 3 个酒店,在浏览器中打开每个酒店的图片,并把页面标题改为酒店名。


四种 MCP Server 的接入方式

MultiServerMCPClient 支持同时配置多个 MCP Server,每个 Server 的接入方式不同------有的通过 HTTP 远程调用,有的通过本地 stdio 进程,有的通过 npx 拉取 npm 包后启动:

javascript 复制代码
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';

const model = new ChatOpenAI({
    modelName: 'deepseek-v4-pro',
    apiKey: process.env.DEEPSEEK_API_KEY,
    configuration: {
        baseURL: process.env.DEEPSEEK_BASE_URL,
    },
});

const mcpClient = new MultiServerMCPClient({
    mcpServers: {
        'amap-maps': {
            // 远程 HTTP MCP ------ 高德地图
            url: 'https://mcp.amap.com/mcp?key=f403bd38acafd014cffe95e54193a419',
        },
        'my-mcp-server': {
            // 本地 stdio MCP ------ 自定义工具
            command: 'node',
            args: [
                'F:/workspace/zzd_ai/ai/agent_in_action/mcp-demo/src/my-mcp-server.mjs',
            ],
        },
        'chrome-devtools': {
            // npx MCP ------ 浏览器控制
            command: 'npx',
            args: ['-y', 'chrome-devtools-mcp@latest'],
        },
        'filesystem': {
            // npx MCP ------ 文件系统操作
            command: 'npx',
            args: [
                '-y',
                '@modelcontextprotocol/server-filesystem',
                'F:/workspace/zzd_ai/ai/agent_in_action/remote-mcp/src',
            ],
        },
    },
});

四种配置方式对应了四种不同的接入场景:

Server 接入方式 场景
amap-maps HTTP 远程 URL 第三方服务提供的 MCP,无需本地安装,直接通过 HTTP 调用
my-mcp-server 本地 Node 进程 自己开发的 MCP Server,通过 stdio 与本机 Agent 通信
chrome-devtools npx 拉取 社区发布的 npm 包,npx -y 自动下载最新版并启动
filesystem npx 拉取 + 参数 同上,但额外传入工作目录参数,限制文件操作范围

npx -y 中的 -y 参数表示自动确认安装,避免交互式提示阻塞 Agent 的启动流程。chrome-devtools-mcp@latest 中的 @latest 确保每次启动都使用最新版本。


多 Server 并行:一个指令打通三个领域

配置好四个 Server 后,getTools() 会返回所有 Server 注册的工具集合。Agent 拿到这个工具列表后,就能在 ReAct 循环中自主选择调用哪个 Server 的哪个工具。

给 Agent 的任务指令:

javascript 复制代码
await runAgentWithTools(`北京南站附近的酒店,最近的 3 个酒店,
    拿到酒店图片,打开浏览器,展示每个酒店的图片,每个 tab 一个 url 展示,
    并且在把那个页面标题改为酒店名`);

这个任务看似简单,实际上涉及三个完全不同领域的操作:

  1. 地理位置查询(高德 MCP):搜索"北京南站"附近的酒店,返回酒店名称、坐标和图片 URL
  2. 浏览器控制(Chrome DevTools MCP):打开浏览器,为每个酒店创建新标签页,导航到图片 URL,修改页面标题
  3. 文件读写(FileSystem MCP):可能将酒店信息保存为本地文件,作为后续步骤的输入

ReAct 循环会驱动 Agent 在"思考 → 行动 → 观察"之间反复迭代。Agent 需要先调用高德 MCP 获取酒店列表,拿到图片 URL 后,再调用 Chrome DevTools MCP 打开浏览器并操作标签页。每一步的观察结果会影响下一步的决策------比如高德返回了 3 个酒店的信息,Agent 才知道需要打开 3 个标签页。


工具返回值的处理:字符串还是对象

多 Server 场景下,不同 MCP Server 返回的工具结果格式不尽相同,这是一个容易被忽略的工程细节。有些 Server 返回纯字符串,有些返回结构化对象(如 { text: "..." }):

javascript 复制代码
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);
        let contentStr;

        // MCP tool 返回一般是字符串
        if (typeof toolResult === 'string') {
            contentStr = toolResult;
        }
        // 还有可能是对象,比如 filesystem 返回 { text: "..." }
        else if (toolResult && toolResult.text) {
            contentStr = toolResult.text;
        }

        messages.push(new ToolMessage({
            content: contentStr,
            tool_call_id: toolCall.id,
        }));
    }
}

这段兼容逻辑背后的原因是:MCP 协议规范了 Server 和 Client 之间的通信格式,但不同 Server 的实现者对返回值的封装方式不同。高德 MCP 可能直接返回纯文本的 JSON 字符串,而 FileSystem MCP 可能返回 { text: "文件内容" } 的结构化对象。Agent 端需要同时兼容两种格式,否则就会出现 [object Object] 被注入到 LLM 上下文中的情况。

ToolMessagecontent 必须是字符串,因为 LLM 只能理解文本。如果工具返回的是对象,直接传给 LLM 会变成无意义的 [object Object]


MCP 生态:从自己造轮子到直接复用

回到 MCP 协议的最大价值------复用。在 MCP 出现之前,如果你想在 Agent 中集成高德地图的能力,需要自己阅读高德 API 文档,写 HTTP 请求封装,定义 zod Schema,处理错误。如果你想控制浏览器,需要自己封装 Playwright 或 Puppeteer,暴露给 Agent 调用。

有了 MCP 协议之后,这些工作社区已经帮你做好了。你只需要在 MultiServerMCPClient 中配置一行 URL 或 npx 命令,Agent 就能直接获得这些能力。这种模式带来的变化可以用一个表格来对比:

维度 手写工具集成 MCP 协议复用
高德地图集成 阅读 API 文档 → 写 HTTP 封装 → 定义 Schema → 注册工具 一行 url 配置
浏览器控制 封装 Playwright → 暴露工具 → 维护代码 一行 npx chrome-devtools-mcp@latest
文件系统操作 fs 模块自己写 → 处理边界情况 一行 npx @modelcontextprotocol/server-filesystem
跨项目复用 复制粘贴代码,手动适配 同一个配置,换项目直接用

MCP 正在催生一个类似 npm 生态的工具市场------高德地图 MCP、Chrome DevTools MCP、FileSystem MCP、GitHub MCP、Slack MCP,每个 Server 都是一个独立维护的"工具包",可以被任何 Agent 通过标准协议调用。


总结

MCP 多 Server 编排的核心价值,可以用一句话概括:把多个专业领域的工具能力通过标准协议聚合到一个 Agent 中,让 LLM 在 ReAct 循环中自主编排调用顺序,完成跨领域的复杂任务。

四个关键要点:

  1. 三种接入方式 :HTTP 远程(URL)、本地 stdio(command + args)、npx 拉取(npm 包),覆盖了从第三方服务到社区工具到自研 Server 的所有场景
  2. 多 Server 并行getTools() 返回所有 Server 的工具集合,Agent 在 ReAct 循环中自主选择调用哪个 Server 的哪个工具,无需人工编排调用顺序
  3. 返回值兼容:不同 MCP Server 的返回值格式可能不同(字符串 vs 对象),Agent 端需要做类型判断和格式转换,确保传给 LLM 的内容始终是文本
  4. 生态复用:MCP 让工具开发从"每个项目自己造轮子"变成"社区共享、一行配置即用",高德地图、Chrome DevTools、FileSystem 都是现成的例子

MCP 协议正在把 AI Agent 从"单工具"推向"多工具协同"的新阶段。一个 Agent 接入的 MCP Server 越多,它能完成的任务就越复杂,能跨越的领域就越广。 而这一切,只需要在配置文件中多加几行。**

相关推荐
冬奇Lab16 小时前
MCP 系列(07):企业级部署——安全、认证与版本管理
人工智能·llm·mcp
xn71331 天前
别再把 MCP Roots 当安全沙箱:一个符号链接就能逃逸目录
人工智能·后端·mcp
xyj29175964111 天前
在Trae中配置数据库MCP
数据库·ai·mcp
孟无岐1 天前
LayaAir-MCP 插件上手指南:让 AI 直接操控你的 LayaAir IDE
ai编程·游戏开发·mcp·layaair·workbuddy·layaair-mcp
YIAN2 天前
从手写 Agent 工具到 MCP 协议:一文搞懂大模型跨进程跨语言工具调用
后端·agent·mcp
SLD_Allen2 天前
20个 Agent 工程概念(系统能力篇)
agent·hooks·沙箱·mcp·fde
冬奇Lab3 天前
MCP 系列(05):Resources 和 Prompts 进阶——动态数据、参数化 URI 与多轮模板
人工智能·llm·mcp
先吃饱再说3 天前
组合多个远程 MCP Server:让 Agent 同时调用高德地图、Chrome DevTools 和文件系统
langchain·llm·mcp
先吃饱再说3 天前
跨进程调用工具:MCP + LangChain 让 Agent 不再“锁死”在单一语言
langchain·llm·mcp