基于MCP协议搭建全链路智能Agent:地图检索+浏览器自动化+本地文件操控实战

前言

在AI Agent快速迭代的当下,单纯的大模型对话已经无法满足落地自动化业务 的需求。真正可用的智能Agent,核心能力是大模型语义理解 + 标准化工具调用 + 多端能力联动

MCP(Model Context Protocol)协议的出现,让各类工具服务可以标准化接入AI模型。本文基于 LangChain + DeepSeek大模型 + 多MCP Server 架构,同时接入高德云端MCP、本地文件系统MCP、Chrome调试MCP,实现地图检索、本地文件处理、浏览器自动化的全链路智能Agent实战,所有代码可直接部署运行。

一、核心技术架构

1.1 MCP 双通信模式

MCP 客户端支持两种官方标准通信模式,可同时混用:

  • stdio 本地进程模式:通过 npx 拉起本地子进程,适用于本地文件读写、本地浏览器操控等本地工具
  • SSE 云端远程模式:长连接流式通信,适用于高德官方在线托管MCP服务

1.2 整体架构组成

本次智能Agent分为四层解耦架构:

  1. 大模型层:DeepSeek-V4-Pro,负责自然语言拆解、工具选择、多轮迭代决策、结果汇总

  2. 协议调度层:LangChain MCP-Adapters,统一兼容 stdio / SSE 双模式MCP,自动发现并调度工具

  3. 工具能力层

    1. 高德地图MCP(SSE云端):POI检索、周边查询、路线规划、地理编码
    2. 文件系统MCP(stdio本地):限定目录读写、文件创建、文档导出
    3. Chrome DevTools MCP(stdio本地):浏览器自动化、标签页管理、页面操作
  4. 业务执行层:自动完成语义拆解、工具调用、数据获取、可视化展示、资源释放的完整闭环

二、三大 MCP Server 能力介绍

2.1 高德地图MCP(SSE云端远程服务)

高德开放平台官方托管MCP服务,无需本地部署、无需启动进程,通过URL+Key鉴权即可使用,支持酒店POI查询、地点检索、路径规划、地理编码等12项核心地图能力,高可用、免运维。

2.2 文件系统MCP(stdio本地服务)

官方标准本地文件操作服务,支持目录沙箱权限限制,仅允许指定文件夹读写,可自动创建目录、写入Markdown文档、持久化任务结果。

2.3 Chrome DevTools MCP(stdio本地服务)

轻量化浏览器自动化工具,基于Chrome远程调试协议,无需笨重的爬虫框架,支持新建标签页、跳转URL、修改网页标题等操作。

前置运行条件:启动Chrome远程调试端口

ini 复制代码
chrome --remote-debugging-port=9222

三、完整可运行代码(已修复全部BUG)

以下为最终生产级代码,修复语法、变量、返回值、资源释放等所有问题,开箱即用。

javascript 复制代码
import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';

// 初始化 DeepSeek 大模型
const model = new ChatOpenAI({
  modelName: 'deepseek-v4-pro',
  apiKey: process.env.DEEPSEEK_API_KEY!,
  temperature: 0,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  },
});

// 多MCP客户端:云端SSE高德 + 本地stdio文件/浏览器
const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    // 高德云端MCP:SSE远程模式
    'amap-maps': {
      url: "https://mcp.amap.com/mcp?key=54643235fb4ea7bf19021875a1685b41"
    },
    // 文件系统MCP:本地沙箱读写
    'filesystem': {
      command: 'npx',
      args: [
        '-y',
        '@modelcontextprotocol/server-filesystem',
        'C:/Users/Administrator/Desktop/ZHUYI_AI/ai/agent_in_action/remote-mcp'
      ]
    },
    // Chrome浏览器自动化MCP
    'chrome-devtools': {
      command: 'npx',
      args: ['-y', 'chrome-devtools-mcp@latest']
    }
  }
});

/**
 * MCP Agent 多轮迭代执行器
 */
async function runAgentWithTools(query: string, maxIterations = 30) {
  const tools = await mcpClient.getTools();
  const modelWithTools = model.bindTools(tools);
  const messages = [new HumanMessage(query)];

  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen.white(`【第${i+1}轮迭代】`));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    // 无工具调用则任务结束
    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log(chalk.bgRed.white(`【AI最终结果】${response.content}`));
      return response.content;
    }

    console.log(chalk.bgBlue.white(`【调用工具】${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);
        
        // 统一兼容所有MCP返回格式
        let contentStr: string;
        if (typeof toolResult === 'string') {
          contentStr = toolResult;
        } else if (toolResult && toolResult.text) {
          contentStr = toolResult.text;
        } else {
          contentStr = JSON.stringify(toolResult, null, 2);
        }

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

  return messages.at(-1)?.content || '任务完成';
}

// 程序入口
async function main() {
  try {
    await runAgentWithTools(
      "北京南站附近的酒店,最近的 3 个酒店,拿到酒店图片,打开浏览器,每个tab一个url展示图片,并且把每个页面标题改为对应酒店名称"
    );
  } catch (err) {
    console.error('【任务异常】', err);
  } finally {
    await mcpClient.close();
    console.log(chalk.green('【所有MCP连接已关闭】'));
  }
}

main();

四、代码逐段深度解析

4.1 依赖导入模块

本段统一引入项目所需核心依赖,分别负责环境变量读取、MCP多服务管理、大模型调用、日志美化和对话消息结构体定义,是整个项目的基础支撑。

javascript 复制代码
import 'dotenv/config';
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
import { ChatOpenAI } from '@langchain/openai';
import chalk from 'chalk';
import { HumanMessage, ToolMessage } from '@langchain/core/messages';

核心作用

  • dotenv/config:自动读取项目环境变量,统一管理密钥与配置,避免硬编码
  • MultiServerMCPClient:LangChain 多MCP统一客户端,支持同时管理远程、本地多类MCP服务
  • ChatOpenAI:兼容OpenAI协议的大模型调用实例,适配DeepSeek模型
  • chalk:终端彩色日志输出,区分迭代、工具调用、异常信息,日志更直观
  • 消息结构体:规范用户指令、工具返回结果的消息格式,构建标准对话上下文

4.2 大模型实例初始化

本段完成 DeepSeek 大模型的实例创建与参数配置,固定模型能力风格,适配自动化Agent场景。

php 复制代码
const model = new ChatOpenAI({
  modelName: 'deepseek-v4-pro',
  apiKey: process.env.DEEPSEEK_API_KEY!,
  temperature: 0,
  configuration: {
    baseURL: 'https://api.deepseek.com/v1',
  },
});

核心作用

  • 指定高阶模型 deepseek-v4-pro,保障复杂任务拆解、多工具联动决策能力
  • temperature: 0:关闭模型随机性,保证自动化任务稳定、可复现
  • 自定义请求地址,适配DeepSeek接口,兼容OpenAI调用规范
  • 读取环境变量密钥,保证项目安全性

4.3 多MCP服务客户端配置

本段是项目核心配置,同时挂载云端SSE远程MCP本地stdio进程MCP三类服务,统一管理所有工具能力。

css 复制代码
const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    'amap-maps': {
      url: "https://mcp.amap.com/mcp?key=54643235fb4ea7bf19021875a1685b41"
    },
    'filesystem': {
      command: 'npx',
      args: [
        '-y',
        '@modelcontextprotocol/server-filesystem',
        'C:/Users/Administrator/Desktop/ZHUYI_AI/ai/agent_in_action/remote-mcp'
      ]
    },
    'chrome-devtools': {
      command: 'npx',
      args: ['-y', 'chrome-devtools-mcp@latest']
    }
  }
});

核心作用

  • 高德地图MCP:基于云端SSE长连接,无需本地进程,提供地图检索、POI查询能力
  • 文件系统MCP:本地子进程运行,沙箱目录限制,安全实现本地文件读写、文档生成
  • Chrome MCP:本地拉起调试服务,实现浏览器自动化操控

4.4 核心Agent多轮迭代函数

本段是智能Agent的任务调度核心,实现「模型决策→工具调用→结果回传→多轮迭代」的完整闭环。

ini 复制代码
async function runAgentWithTools(query: string, maxIterations = 30) {
  const tools = await mcpClient.getTools();
  const modelWithTools = model.bindTools(tools);
  const messages = [new HumanMessage(query)];

  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen.white(`【第${i+1}轮迭代】`));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log(chalk.bgRed.white(`【AI最终结果】${response.content}`));
      return response.content;
    }

    console.log(chalk.bgBlue.white(`【调用工具】${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);
        
        let contentStr: string;
        if (typeof toolResult === 'string') {
          contentStr = toolResult;
        } else if (toolResult && toolResult.text) {
          contentStr = toolResult.text;
        } else {
          contentStr = JSON.stringify(toolResult, null, 2);
        }

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

  return messages.at(-1)?.content || '任务完成';
}

核心作用

  • 自动加载所有MCP工具并绑定大模型,让模型自主识别、选择工具
  • 循环迭代机制:限制最大迭代次数,避免任务死循环
  • 自动终止判断:模型无需调用工具时,自动结束任务并输出结果
  • 统一返回值兼容:适配不同MCP服务的返回格式,避免解析报错
  • 上下文闭环:工具结果回传给模型,支撑下一轮决策,实现复杂多步骤任务

4.5 程序入口与资源释放

本段为项目统一启动入口,处理异常捕获与资源优雅释放,保证程序稳定运行。

javascript 复制代码
async function main() {
  try {
    await runAgentWithTools(
      "北京南站附近的酒店,最近的 3 个酒店,拿到酒店图片,打开浏览器,每个tab一个url展示图片,并且把每个页面标题改为对应酒店名称"
    );
  } catch (err) {
    console.error('【任务异常】', err);
  } finally {
    await mcpClient.close();
    console.log(chalk.green('【所有MCP连接已关闭】'));
  }
}

main();

核心作用

  • 封装异步入口函数,规避Node.js顶层await语法问题
  • 全局异常捕获,单步骤报错不会导致程序直接崩溃
  • finally强制释放MCP连接,杜绝端口占用、进程残留、内存泄漏
  • 传入自然语言任务,实现零代码业务开发,纯语义驱动自动化

五、常见报错与修复方案

5.1 高德MCP配置错误

问题:使用 command / npx 本地进程方式配置高德MCP

解决方案:高德为云端SSE服务,仅支持 url+key 配置,无需本地进程

5.2 变量未定义报错 client is not defined

问题:错误书写变量名 client.close()

解决方案:统一使用 mcpClient.close() 释放连接

5.3 工具返回值 undefined 报错

问题:不同MCP服务返回数据结构不统一

解决方案:通过三段式类型判断,全量兼容字符串、文本对象、普通JSON对象

5.4 Chrome MCP 调用超时

问题:未开启Chrome远程调试端口

解决方案:命令行启动带调试端口的Chrome再运行项目

5.5 顶层 await 语法报错

问题:Node.js 非模块环境不支持全局await

解决方案:封装标准 async main 函数作为程序入口

六、整体运行流程

  1. 启动带远程调试端口的Chrome浏览器
  2. 程序加载DeepSeek模型与三组MCP服务能力
  3. 大模型自动拆解自然语言任务,调用高德MCP获取周边酒店及图片信息
  4. 调用Chrome MCP自动新建标签页、展示图片、修改页面标题
  5. 任务执行完毕,自动关闭所有MCP连接,释放资源

七、总结

本文基于 LangChain + 双模式MCP架构,实现了纯自然语言驱动的地图查询与浏览器自动化智能Agent。通过标准化MCP协议,无需手动封装接口,即可快速落地多工具联动的AI自动化场景,架构轻量化、可扩展性强,可适配本地生活、数据可视化、自动化办公等各类业务场景。

相关推荐
研☆香2 小时前
闭包实战避坑指南
javascript
你怎么知道我是队长2 小时前
JavaScript 的控制语句介绍
开发语言·javascript·ecmascript
用户44014549314193 小时前
Spring Boot 3.x 异步编程实战:从 @Async 到虚拟线程
javascript
wangruofeng4 小时前
终端里 rm 一下文件就没了,macOS 怎么删文件才进废纸篓
javascript·命令行·apple
小妖6664 小时前
React input 输入卡顿问题
前端·javascript·react.js
李明卫杭州6 小时前
Vue2 portal-target 组件与 Vue3 的针对性优化
前端·javascript·vue.js
你怎么知道我是队长7 小时前
JavaScript的函数介绍
开发语言·前端·javascript
weedsfly7 小时前
观察者模式 vs 发布-订阅模式:从概念到实战,一次讲清楚
前端·javascript·面试
咪饭只吃一小碗7 小时前
告别微调成本!用 RAG 本地向量库解决大模型私有领域数据接入
javascript·后端·面试