文章进阶AI 生成初稿 · deepseek-chat

MCP 初探:让工具可插拔

从开发者视角拆解 MCP:它是什么协议、为什么需要它、和自建工具函数的关系,以及一个最小可运行的接入思路与边界,帮你在自研 Agent 里判断该不该用它。

约 6 分钟发布于 2026年9月12日更新于 上次校对 2026年9月12日 · shelter123
本文目录

TL;DR

  • MCP(Model Context Protocol)是一套把「模型/Agent 能调用的工具与上下文」从应用里解耦出来的开放协议,本质是让工具可插拔。
  • 它解决的痛点不是「怎么调函数」,而是「同一批工具要在多个 Agent、多个宿主、多个模型之间复用」时的重复适配问题。
  • 自建工具函数和 MCP 不是替代关系:前者是能力实现,后者是能力的对外暴露与发现约定。
  • 最小接入思路是「先写一个 MCP server 暴露一个工具,再让宿主通过 stdio 连上它」,其余交给官方 SDK。
  • 是否引入 MCP,取决于你是否需要跨宿主复用与生态工具;单应用内的一两个工具,自建往往更省事。

前置知识

读这篇之前,你最好已经理解 Agent 的工具调用(tool use / function calling)基本流程:模型输出一个结构化的调用意图,你的代码执行它,再把结果喂回模型。如果还没接触过,可以先看本路径里讲工具调用的那篇《Agent 工具实战》,它会先把「模型怎么决定调用哪个工具」讲清楚。

需要的基础:

  • 能读懂 JSON,理解「工具 = 名称 + 描述 + 参数 schema」这种描述方式;
  • 写过一个最小的工具调用循环(哪怕只有一两个工具);
  • 会用命令行启动一个进程,知道 stdin/stdout 是什么。

不需要的基础(明确划掉,降低门槛):

  • 不需要读过 MCP 规范全文,本文只讲它解决的问题和最小用法;
  • 不需要搭建过完整的 MCP 生态,也不用先理解所有传输方式;
  • 不需要换模型或换框架,MCP 与具体模型厂商无关。

零基础?先读小白故事线《如果 Agent 是新来的实习生》,用类比建立直觉,再回来读这篇。

正文

先说清楚 MCP 到底是个什么东西

MCP 全称 Model Context Protocol,中文常译为「模型上下文协议」。它由 Anthropic 在 2024 年底提出并开源,定位是一套开放标准,用来规范「AI 应用」和「外部能力提供方」之间怎么对话。截至 2026-09-12,它已经形成相对稳定的规范版本与多语言 SDK。

要理解它,先分清两个角色:

  • 宿主(host)/ 客户端(client):你写的那个 Agent 应用,或者 Claude Desktop、IDE 插件这类现成应用。它负责和模型对话,决定什么时候需要外部能力。
  • 服务端(server):一个独立进程或服务,对外声明「我能提供哪些工具、哪些资源、哪些提示模板」,并在被调用时真正执行。

MCP 规定的就是这两者之间的通信格式与生命周期:怎么握手、怎么列出可用工具、怎么发起一次调用、怎么返回结果、怎么报错。它管的是「接口约定」,不管「工具内部怎么实现」——你的 server 里那行真正干活的代码,MCP 不关心。

一个容易被忽略的点:MCP 不只暴露「工具(tools)」。它同时定义了资源(resources),即可以被读取的数据,比如文件、数据库记录;以及提示(prompts),即预置的提示模板。工具是「模型主动调用去产生副作用或取数」,资源是「应用按需读取的上下文」。初学阶段你几乎只会用到 tools,但知道这三类东西并存,能帮你后面看懂规范。

它解决的是什么问题:从「能调用」到「可复用」

假设你已经写好了一个查天气的工具函数,接进了自己的 Agent,一切正常。现在问题来了:

  • 你又写了一个新 Agent,想用同一个天气工具,于是把代码复制过去;
  • 你换了个宿主应用(比如从自研脚本换成某个 IDE 插件),发现它的工具接入方式和你的不一样,得重写适配层;
  • 同事写了个很好用的数据库查询工具,你想拿来用,但它的参数约定和你的框架对不上。

这些问题的共同点是:能力的实现没问题,能力的「被发现」和「被接入」每次都要重做一遍。这就是 MCP 瞄准的痛点。它把「工具怎么描述自己、怎么被调用」抽成统一协议,于是同一个 server 可以被任何支持 MCP 的宿主直接连上,不需要为每个宿主写一份适配代码。

用一个类比:在 MCP 之前,每个 Agent 框架都像一台用自家充电口的设备,工具得配专属线;MCP 想做的是把接口统一成 USB-C——线不变,设备随便换。这个类比不完美(协议比充电口复杂得多),但它抓住了核心:标准化带来可插拔

需要说清楚边界:MCP 并不提升模型「选对工具」的能力。工具描述写得含糊,换什么协议都还是会选错。协议解决的是工程复用问题,不是模型能力问题。

和自建工具函数是什么关系

这是最容易混淆的地方,值得单独讲。两者不在同一层:

  • 自建工具函数是「能力本身」:一段真正执行查询、写文件、发请求的代码。
  • MCP server 是「能力的包装与暴露」:它内部往往就是调用你那批自建函数,只是额外按协议把工具列表和调用入口暴露出去。

所以正确的理解不是「用 MCP 取代自建工具」,而是「把自建工具通过 MCP 暴露,从而能被更多宿主复用」。你完全可以在 server 内部继续用原来的函数,一行逻辑都不用改。

那什么时候不该用 MCP?

  • 你的工具只在一个应用里用,没有复用需求——直接自建更简单,少一层进程和协议开销;
  • 你追求极致低延迟,多一次跨进程通信不划算;
  • 你的工具需要深度访问宿主内存里的对象,跨进程反而别扭。

反过来,什么时候值得引入:

  • 同一批工具要在多个 Agent 或宿主之间共享;
  • 你想直接接入社区已有的 MCP server,而不是自己重写一遍;
  • 你希望工具的生命周期(启动、发现、调用、关闭)有统一约定,而不是散落在各处。

最小接入思路:一个 server,一个工具

下面给的是骨架,不是完整实现。目标是让你看懂「一个 MCP server 长什么样」,跑通细节以官方 SDK 文档为准。

MCP 支持多种传输方式,本地进程最常用的是 stdio:宿主把你的 server 当子进程启动,通过标准输入输出交换 JSON-RPC 消息。这个设计的好处是 server 不需要开端口、不需要处理网络,天然适合本地工具。

用官方 TypeScript SDK 写一个只暴露一个工具的 server,大致是这样:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({ name: "demo", version: "0.1.0" });

server.tool(
  "get_weather",
  "查询指定城市的当前天气",
  { city: z.string().describe("城市名,例如 Beijing") },
  async ({ city }) => ({
    content: [{ type: "text", text: `${city}: 晴,24°C` }],
  })
);

await server.connect(new StdioServerTransport());

这段代码里值得注意的三点:

  1. server.tool 的第二个参数是给模型看的描述,写清楚它直接决定模型会不会选对工具;
  2. 第三个参数是参数 schema,这里用 zod 声明,SDK 会把它转成模型能理解的 JSON Schema;
  3. 返回值是一个 content 数组,文本结果放在 type: "text" 的项里——这是协议规定的返回形状。

宿主侧要做的事同样简单:在它的配置里声明「启动这个命令作为 MCP server」,剩下的握手、列工具、转发调用都由宿主和 SDK 完成。以配置文件形式接入时,通常是这样一段声明:

{
  "mcpServers": {
    "demo": {
      "command": "node",
      "args": ["/absolute/path/to/server.js"]
    }
  }
}

注意 commandargs 指向的是你编译或直接可执行的 server 入口,路径建议写绝对路径,避免宿主工作目录不同导致找不到文件。

最后提醒一个实践细节:stdio 传输下,不要往 stdout 打印调试日志。stdout 被协议消息占用了,你随手一个 console.log 会污染消息流,导致宿主解析失败。调试信息请走 stderr。

边界与官方延伸

MCP 是协议,不是银弹。几个需要提前知道的边界:

  • 安全责任在宿主和 server 双方。协议本身不校验你的工具是否安全,一个能执行任意命令的 server 接进 Agent,风险就真实存在。涉及写操作、命令执行、外部网络请求的工具,务必自己做权限与确认设计。
  • 工具描述质量决定实际效果。协议统一了格式,但描述文字是自然语言,写得模糊照样选错工具。
  • 生态仍在演进。截至 2026-09-12,规范与 SDK 都在持续更新,接入前建议以官方文档的当前版本为准,不要照抄旧博客里的写法。
  • 不是所有场景都需要。前面已经说过,单应用、少量工具时自建更直接。引入协议是有成本的,收益来自复用。

想继续深入,官方文档是最好的起点:规范全文、各语言 SDK、以及一批可直接接入的示例 server,都在 modelcontextprotocol.io。完整实现与最新 API 以官方文档为准,本文只负责帮你建立判断框架。

延伸阅读

站内搜索

    搜索为本站本地索引增强;正文浏览不依赖 JavaScript。