目前最火AI协议-> MCP 协议实战:从原理到落地,让 AI 拥有"超能力"

前言

2026 年最火的 AI 协议是什么?

MCP(Model Context Protocol)------模型上下文协议。

几乎所有 AI 产品都在接入:Cursor、Claude、豆包、Trae...

今天我们从原理出发,实战接入高德地图 MCP文件系统 MCP浏览器控制 MCP,彻底搞懂 MCP 的本质。


一、MCP 是什么?

1.1 从"聊天"到"干活"

diff 复制代码
豆包手机 AI Agent 的全新体验:
- 不再只是 chat
- 帮我们把活干了

传统 AI 的局限:

能力 传统 AI MCP 加持后
聊天 ✅ 可以 ✅ 可以
查地图 ❌ 不能 ✅ 调用高德地图
读写文件 ❌ 不能 ✅ 操作本地文件
控制浏览器 ❌ 不能 ✅ 打开 Chrome
查数据库 ❌ 不能 ✅ 查询 MySQL

MCP 的本质:

ini 复制代码
MCP = AI 的"USB 接口"

就像 USB 让各种设备可以连接电脑一样,MCP 让 AI 可以连接各种外部服务。

1.2 MCP 的定义

复制代码
Model Context Protocol(模型上下文协议)

25 年最火的协议,定义了模型和外界服务之间的通信标准。

核心思想:

  • 标准化:统一的协议格式,一次开发,到处使用
  • 可扩展:任何人都可以开发 MCP Server
  • 安全:权限控制,用户授权

MCP 的架构:

arduino 复制代码
┌─────────────┐
│   AI 模型    │  ← 大脑(LLM)
└──────┬──────┘
       │
       ▼
┌─────────────┐
│  MCP Client │  ← 客户端(Cursor/Trae/你的代码)
└──────┬──────┘
       │
       ├──────────────┬──────────────┐
       ▼              ▼              ▼
┌──────────┐   ┌──────────┐   ┌──────────┐
│ 高德地图  │   │ 文件系统  │   │ 浏览器   │
│   MCP    │   │   MCP    │   │   MCP    │
└──────────┘   └──────────┘   └──────────┘

三个角色:

角色 职责 例子
AI 模型 思考和决策 GPT-4、Claude、Qwen
MCP Client 协议适配、工具调用 Cursor、你的代码
MCP Server 提供具体能力 高德地图、文件系统

二、MCP 的两种接入方式

2.1 Stdio 方式(本地进程)

js 复制代码
{
  command: "npx",
  args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]
}

特点:

  • 启动一个本地进程
  • 通过标准输入/输出(stdin/stdout)通信
  • 适合本地工具(文件系统、数据库等)

2.2 HTTP 方式(远程服务)

js 复制代码
{
  url: "https://mcp.amap.com/mcp?key=YOUR_API_KEY"
}

特点:

  • 连接远程服务
  • 通过 HTTP 请求通信
  • 适合云服务(地图、天气、API 等)

对比:

方式 通信方式 适用场景 性能
Stdio 本地进程 本地工具
HTTP 网络请求 云服务 受网络影响

三、实战:接入三个 MCP Server

3.1 项目结构

bash 复制代码
mcp-test/
├── main.mjs              # 主程序
├── package.json
├── .env                  # 环境变量(API Key)
└── beijing_south_station_hotels.md  # AI 生成的文档

3.2 完整代码

js 复制代码
// main.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";

// 1. 初始化 AI 模型
const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

// 2. 配置多个 MCP Server
const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    // 高德地图 MCP(HTTP 方式)
    "amap-maps-streamableHTTP": {
      url: `https://mcp.amap.com/mcp?key=${process.env.AMAP_MAPS_API_KEY}`,
    },
    // 文件系统 MCP(Stdio 方式)
    filesystem: {
      command: "npx",
      args: [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "D:\\workspace\\lesson_zp\\ai\\agent\\mcp_in_action\\mcp-test",
      ],
    },
    // 浏览器控制 MCP(Stdio 方式)
    "chrome-devtools": {
      command: "npx",
      args: ["-y", "chrome-devtools-mcp@latest"],
    },
  },
});

// 3. 获取所有工具
const tools = await mcpClient.getTools();
const modelWithTools = model.bindTools(tools);

// 4. Agent 循环
async function runAgentWithTools(query, maxIterations = 30) {
  const messages = [new HumanMessage(query)];
  
  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen("⏳正在等待AI思考..."));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

    // 5. 如果没有工具调用,返回最终结果
    if (!response.tool_calls || response.tool_calls.length === 0) {
      console.log(`\n AI 最终回复:\n ${response.content}\n`);
      return response.content;
    }

    // 6. 处理工具调用
    console.log(
      chalk.bgBlue(`🔍 检测到 ${response.tool_calls.length} 个工具调用`)
    );
    console.log(
      chalk.bgBlue(
        `🔍 工具调用: ${response.tool_calls.map((t) => t.name).join(", ")}`
      )
    );

    // 7. 执行每个工具
    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;
        if (typeof toolResult === "string") {
          contentStr = toolResult;
        } else if (toolResult && toolResult.text) {
          contentStr = toolResult.text;
        }
        messages.push(
          new ToolMessage({
            content: contentStr,
            tool_call_id: toolCall.id,
          })
        );
      }
    }
  }
  return messages[messages.length - 1].content;
}

// 8. 执行任务
await runAgentWithTools(`
北京南站附近的3个酒店,拿到酒店照片,展开浏览器,展示每个酒店的图片
每个tab一个url展示,并且把那个页面标题改为酒店名
`);

await mcpClient.close();

四、逐行解析

4.1 初始化 AI 模型

js 复制代码
const model = new ChatOpenAI({
  modelName: process.env.MODEL_NAME,
  apiKey: process.env.OPENAI_API_KEY,
  configuration: {
    baseURL: process.env.OPENAI_BASE_URL,
  },
});

逐行解析:

js 复制代码
modelName: process.env.MODEL_NAME,
  • 从环境变量读取模型名称
  • 可以是 gpt-4qwen-maxdeepseek-chat
js 复制代码
apiKey: process.env.OPENAI_API_KEY,
  • API 密钥,用于身份验证
  • 不要硬编码在代码中,使用 .env 文件
js 复制代码
configuration: {
  baseURL: process.env.OPENAI_BASE_URL,
}
  • API 基础 URL
  • 如果使用国内模型(如 Qwen),需要修改为对应的 baseURL

为什么用环境变量?

  • 安全性:API Key 不会泄露到代码仓库
  • 灵活性:不同环境使用不同配置
  • 标准化:12-Factor App 最佳实践

4.2 配置 MCP Server

js 复制代码
const mcpClient = new MultiServerMCPClient({
  mcpServers: {
    "amap-maps-streamableHTTP": {
      url: `https://mcp.amap.com/mcp?key=${process.env.AMAP_MAPS_API_KEY}`,
    },
    filesystem: {
      command: "npx",
      args: [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "D:\\workspace\\lesson_zp\\ai\\agent\\mcp_in_action\\mcp-test",
      ],
    },
    "chrome-devtools": {
      command: "npx",
      args: ["-y", "chrome-devtools-mcp@latest"],
    },
  },
});

逐行解析:

js 复制代码
"amap-maps-streamableHTTP": {
  url: `https://mcp.amap.com/mcp?key=${process.env.AMAP_MAPS_API_KEY}`,
}
  • 高德地图 MCP,使用 HTTP 方式
  • url:MCP Server 的地址
  • key:高德地图 API Key,需要在高德开放平台申请
js 复制代码
filesystem: {
  command: "npx",
  args: [
    "-y",
    "@modelcontextprotocol/server-filesystem",
    "D:\\workspace\\lesson_zp\\ai\\agent\\mcp_in_action\\mcp-test",
  ],
}
  • 文件系统 MCP,使用 Stdio 方式
  • command: "npx":使用 npx 运行
  • args
    • -y:自动确认安装
    • @modelcontextprotocol/server-filesystem:官方文件系统 MCP 包
    • 最后一个参数:允许访问的目录路径
js 复制代码
"chrome-devtools": {
  command: "npx",
  args: ["-y", "chrome-devtools-mcp@latest"],
}
  • 浏览器控制 MCP
  • chrome-devtools-mcp@latest:使用最新版本
  • 可以控制 Chrome 浏览器(打开页面、点击、输入等)

三个 MCP Server 对比:

Server 方式 功能 用途
高德地图 HTTP 查地点、路线、POI 地理信息查询
文件系统 Stdio 读写文件 生成文档、保存结果
浏览器控制 Stdio 控制 Chrome 展示内容、自动化操作

4.3 获取工具并绑定

js 复制代码
const tools = await mcpClient.getTools();
const modelWithTools = model.bindTools(tools);

逐行解析:

js 复制代码
const tools = await mcpClient.getTools();
  • 从所有 MCP Server 获取工具列表
  • 每个工具包含:名称、描述、参数 schema
  • 例如:maps_geo(地理编码)、maps_direction(路线规划)等
js 复制代码
const modelWithTools = model.bindTools(tools);
  • 将工具绑定到 AI 模型
  • AI 可以根据用户请求,自动选择调用哪个工具
  • 这就是 Function Calling(函数调用)机制

Function Calling 流程:

arduino 复制代码
用户:北京南站附近的酒店
  ↓
AI 思考:需要调用地图工具
  ↓
AI 输出:调用 maps_search_around 工具
  ↓
MCP Client:执行工具,返回结果
  ↓
AI 思考:根据结果生成回复
  ↓
最终回复:推荐 3 个酒店...

4.4 Agent 循环

js 复制代码
async function runAgentWithTools(query, maxIterations = 30) {
  const messages = [new HumanMessage(query)];
  
  for (let i = 0; i < maxIterations; i++) {
    console.log(chalk.bgGreen("⏳正在等待AI思考..."));
    const response = await modelWithTools.invoke(messages);
    messages.push(response);

逐行解析:

js 复制代码
const messages = [new HumanMessage(query)];
  • 创建消息数组,初始包含用户的问题
  • HumanMessage:用户消息
  • 后续会不断追加 AI 回复和工具结果
js 复制代码
for (let i = 0; i < maxIterations; i++) {
  • Agent 循环,最多执行 30 次
  • 防止无限循环(AI 一直调用工具)
js 复制代码
const response = await modelWithTools.invoke(messages);
messages.push(response);
  • 调用 AI 模型,传入所有历史消息
  • AI 会返回:
    • 纯文本回复(结束)
    • 工具调用(继续循环)

4.5 判断是否结束

js 复制代码
if (!response.tool_calls || response.tool_calls.length === 0) {
  console.log(`\n AI 最终回复:\n ${response.content}\n`);
  return response.content;
}

逐行解析:

js 复制代码
if (!response.tool_calls || response.tool_calls.length === 0) {
  • 检查 AI 是否调用了工具
  • 如果没有工具调用,说明 AI 已经给出最终答案
js 复制代码
console.log(`\n AI 最终回复:\n ${response.content}\n`);
return response.content;
  • 输出最终回复
  • 返回结果,结束函数

4.6 处理工具调用

js 复制代码
console.log(
  chalk.bgBlue(`🔍 检测到 ${response.tool_calls.length} 个工具调用`)
);
console.log(
  chalk.bgBlue(
    `🔍 工具调用: ${response.tool_calls.map((t) => t.name).join(", ")}`
  )
);

解析:

  • 输出检测到的工具调用数量
  • 输出工具名称列表
  • 使用 chalk 库给日志上色,便于调试

4.7 执行工具

js 复制代码
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;
    if (typeof toolResult === "string") {
      contentStr = toolResult;
    } else if (toolResult && toolResult.text) {
      contentStr = toolResult.text;
    }
    messages.push(
      new ToolMessage({
        content: contentStr,
        tool_call_id: toolCall.id,
      })
    );
  }
}

逐行解析:

js 复制代码
for (const toolCall of response.tool_calls) {
  • 遍历所有工具调用
  • AI 可能一次调用多个工具
js 复制代码
const foundTool = tools.find((t) => t.name === toolCall.name);
  • 根据工具名称找到对应的工具实例
js 复制代码
const toolResult = await foundTool.invoke(toolCall.args);
  • 执行工具,传入参数
  • 返回工具执行结果
js 复制代码
let contentStr;
if (typeof toolResult === "string") {
  contentStr = toolResult;
} else if (toolResult && toolResult.text) {
  contentStr = toolResult.text;
}
  • 处理工具返回结果
  • 可能是字符串,也可能是对象(包含 text 属性)
js 复制代码
messages.push(
  new ToolMessage({
    content: contentStr,
    tool_call_id: toolCall.id,
  })
);
  • 创建 ToolMessage,包含工具结果
  • tool_call_id:关联到对应的工具调用
  • 追加到消息历史,供 AI 继续思考

消息类型:

类型 用途 例子
HumanMessage 用户输入 "北京南站附近的酒店"
AIMessage AI 回复 "我来帮你查询..."
ToolMessage 工具结果 "找到 3 个酒店..."
SystemMessage 系统提示 "你是一个助手..."

4.8 执行任务

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

await mcpClient.close();

逐行解析:

js 复制代码
await runAgentWithTools(`...`);
  • 执行 Agent,传入复杂任务
  • 任务包含多个步骤:
    1. 查询北京南站附近的酒店
    2. 获取酒店照片
    3. 打开浏览器展示
    4. 修改页面标题
js 复制代码
await mcpClient.close();
  • 关闭 MCP Client
  • 释放资源,断开连接

五、执行流程

5.1 完整流程图

erlang 复制代码
用户输入:北京南站附近的3个酒店...
  ↓
AI 思考:需要调用地图工具
  ↓
调用 maps_search_around(高德地图 MCP)
  ↓
返回:3 个酒店信息
  ↓
AI 思考:需要获取酒店照片
  ↓
调用 maps_photo(高德地图 MCP)
  ↓
返回:照片 URL
  ↓
AI 思考:需要打开浏览器展示
  ↓
调用 chrome_navigate(浏览器 MCP)
  ↓
打开 3 个 Tab,展示照片
  ↓
调用 chrome_set_document_title(浏览器 MCP)
  ↓
修改页面标题
  ↓
AI 思考:任务完成
  ↓
最终回复:已完成,展示了 3 个酒店...

5.2 实际输出示例

erlang 复制代码
⏳正在等待AI思考...
🔍 检测到 1 个工具调用
🔍 工具调用: maps_search_around

⏳正在等待AI思考...
🔍 检测到 3 个工具调用
🔍 工具调用: maps_photo, maps_photo, maps_photo

⏳正在等待AI思考...
🔍 检测到 3 个工具调用
🔍 工具调用: chrome_navigate, chrome_navigate, chrome_navigate

⏳正在等待AI思考...
🔍 检测到 3 个工具调用
🔍 工具调用: chrome_set_document_title, chrome_set_document_title, chrome_set_document_title

⏳正在等待AI思考...

AI 最终回复:
已完成,展示了 3 个酒店的图片:
1. 米家青年酒店(北京南站店)
2. 汉庭酒店(北京南站护城河店)
3. 如家酒店(北京南站店)

六、生成的文档

AI 还会自动生成一个 Markdown 文档:

markdown 复制代码
# 北京南站附近酒店及交通指南

## 北京南站位置信息

- **名称**: 北京南站
- **地址**: 北京市丰台区
- **坐标**: 116.378059, 39.867679

## 推荐酒店

### 1. 米家青年酒店(北京南站店)

- **地址**: 右外东庄21号楼
- **坐标**: 116.377765, 39.868995
- **评分**: 3.6分
- **距离北京南站**: 约304米步行
- **步行时间**: 约4分钟

### 2. 汉庭酒店(北京南站护城河店)

- **地址**: 开阳路6号院1号楼
- **评分**: 4.6分
- **距离北京南站**: 约851米步行
- **步行时间**: 约11分钟

这个文档是怎么生成的?

  1. AI 调用高德地图 MCP,获取酒店信息
  2. AI 调用文件系统 MCP,创建 Markdown 文件
  3. AI 将信息整理成结构化文档

七、扩展:MCP 的未来

7.1 MCP 生态

diff 复制代码
MCP Server 生态(部分):

官方提供:
- filesystem(文件系统)
- postgres(数据库)
- sqlite(数据库)
- puppeteer(浏览器自动化)

第三方提供:
- 高德地图(地理信息)
- 百度搜索(搜索引擎)
- GitHub(代码仓库)
- Slack(即时通讯)
- Notion(笔记)
- ...

7.2 MCP vs 传统 API

特性 传统 API MCP
标准化 每个 API 不同 统一协议
开发成本 需要适配每个 API 一次开发,到处使用
AI 集成 需要手动编写调用逻辑 AI 自动选择工具
生态 分散 统一生态

7.3 MCP 的应用场景

markdown 复制代码
1. AI 编程助手(Cursor/Trae)
   - 读写文件
   - 执行命令
   - 搜索代码

2. AI 办公助手
   - 查地图、订酒店
   - 发邮件、发消息
   - 操作 Excel、PPT

3. AI 数据分析
   - 查询数据库
   - 生成报表
   - 可视化图表

4. AI 自动化
   - 控制浏览器
   - 操作手机 App
   - 定时任务

八、总结

核心要点

  1. MCP = AI 的"USB 接口",让 AI 可以连接各种外部服务
  2. 两种接入方式:Stdio(本地)和 HTTP(远程)
  3. 三个角色:AI 模型、MCP Client、MCP Server
  4. Function Calling:AI 自动选择并调用工具
  5. Agent 循环:思考 → 调用工具 → 获取结果 → 继续思考

实战收获

通过这个项目,我们实现了:

  • ✅ 接入高德地图 MCP(HTTP 方式)
  • ✅ 接入文件系统 MCP(Stdio 方式)
  • ✅ 接入浏览器控制 MCP(Stdio 方式)
  • ✅ 实现 Agent 循环,自动调用多个工具
  • ✅ 完成复杂任务:查酒店 → 获取照片 → 打开浏览器 → 修改标题

MCP 的价值

arduino 复制代码
传统 AI:只能聊天
MCP 加持:可以干活

从"Chat AI"到"Agent AI"的跨越

相关推荐
胡萝卜术1 小时前
从逐一合并到多路归并:力扣23「合并K个升序链表」的三种解法进化之路
前端·javascript·面试
KaifuZeng1 小时前
模电面试问题汇总三
单片机·嵌入式硬件·面试·模电
仙逆GPT1 小时前
Codex客户端找不到GPT-5.6模型怎么办?版本、配置和入口排查
chatgpt·ai编程·codex·sol·gpt-5.6
weedsfly1 小时前
前端开发中的策略模式——告别 if-else 的优雅之道
前端·javascript·面试
许我半盏清茶1 小时前
基于 Ollama + Vectra + MCP 从零搭建本地 RAG 知识库
javascript·人工智能·mcp
anyup1 小时前
30 分钟用 Trae Work + 魔珐星云做出会讲故事的 AI 3D 具身交互智能数字人
前端·ai编程·trae
前端双越老师1 小时前
AI 编程普及,初学者还要不要学习基础语法?
agent·ai编程·全栈
薛定猫AI2 小时前
【技术干货】多模型AI编程代理实战:用Python统一接入Claude Opus 4.8
人工智能·python·ai编程
怕浪猫2 小时前
第13章 评估与评测:如何衡量Agent的好坏
langchain·openai·ai编程