·MCP 服务器
MCP 2026 实战讲解——它解决了什么、Host/Client/Server 三角关系、tools / resources / prompts 三大原语、stdio 与 Streamable HTTP 传输选型、2026 年生态三层图景(Host / Server / 目录),以及五个高频误区澄清,附 TypeScript 最小服务器实战。
什么是模型上下文协议(MCP)?从概念到搭建你的第一个服务器(2026)
模型上下文协议(Model Context Protocol,简称 MCP)是 Anthropic 在 2024 年 11 月开源、2025-2026 年快速成为生态事实标准的 AI 助手与外部工具之间的 JSON-RPC 2.0 协议。它通过统一的 client-server 架构,让任意 LLM Host(Claude Desktop / Claude Code / Cursor / Zed 等)能发现并调用任意 MCP Server——数据库、文件系统、浏览器、Slack、GitHub——无需为每个工具重写集成代码。本文基于 MCP 2025-11-25 规范版本,梳理协议架构、与函数调用的边界、本地到生产的迁移路径,并跑通一个 TypeScript 服务器示例。
TL;DR
- MCP 是 client-server 架构的 JSON-RPC 2.0 协议——Host 是 client,外部工具进程是 server
- 三大原语:tools(可调用函数)/ resources(可读取数据)/ prompts(可复用模板)
- 两种传输:stdio(本地进程,OS 边界即信任)+ Streamable HTTP(远端,需要 OAuth 2.1)
- 与函数调用的区别:MCP 是协议层而非 SDK 层——同一个 server 可被多个 Host 调用
- 2026 年状态:MCP 已成 Claude 生态事实标准;claudemap.org 收录 80+ 服务器
MCP 解决了什么问题
在 MCP 出现之前,要让一个助手访问外部世界,意味着你要写大量定制的胶水代码。每家模型厂商的函数调用格式都略有不同;而你想暴露的每一个工具——数据库、文件系统、某个 SaaS API——都要为每一个可能调用它的客户端单独打包。一个为某个助手写的文件系统工具,换一个助手往往得重写。
MCP 为这类集成定义了一套与客户端无关的统一协议。你把工具写一次,封装成 MCP 服务器;任何兼容 MCP 的客户端(Claude Desktop、Claude Code、Cursor、自研 Agent)都能调用它。反过来也一样:一个支持 MCP 的 Agent 可以访问任何 MCP 服务器,而不必关心服务器内部是怎么实现的。
你可以把它理解成「AI 工具界的 USB-C」——一个标准插头,把工具和模型解耦开来。
核心术语
MCP 的名词不多,理清之后,后面的内容会豁然开朗。
- Host(宿主)——用户直接交互的应用。Claude Desktop、Claude Code、某个 IDE 插件都是 Host。Host 拥有对话过程,也掌握安全边界。
- Client(客户端)——宿主内部的一个协议对象,与某一个服务器保持一对一连接。一个连了五个服务器的 Host,会跑五个 Client。
- Server(服务器)——一个向外暴露能力的小程序,通过协议与 Client 通信。服务器通常轻量且聚焦,例如「文件系统」「GitHub」「Postgres」。
- Tool(工具)——模型可以决定调用的函数,包含名字、用 JSON Schema 描述的入参,以及一个返回内容给模型的处理器。工具是 MCP 服务器让模型「行动」的方式。
- Resource(资源)——模型可以读取的结构化数据,用 URI 寻址。日志文件、数据库行、配置文档都可以是资源。资源是 MCP 服务器让模型「读取」的方式。
- Prompt(提示模板)——服务器发布的可复用、可带参的提示词模板。客户端可以在 UI 里展示它们(比如放在斜杠命令选择器里)。
一个服务器可以任意组合暴露工具、资源和提示模板。大多数真实服务器以工具为主。
在这些名词之下,MCP 本质上就是承载在传输层之上的 JSON-RPC 2.0 消息流。你实际会遇到两种传输方式:stdio(Host 把服务器作为子进程拉起,通过标准输入输出通信)和 HTTP + Server-Sent Events(服务器作为远端进程运行)。本地开发几乎总是用 stdio。
MCP 与函数调用
MCP 并不是函数调用的竞争对手——两者处在不同的层级。
函数调用是模型的一种能力:模型发出一个结构化的请求来调用某个具名函数,调用方执行它并把结果返回。它由各家模型厂商各自定义。
MCP 则是一种集成协议:它标准化了 Host 如何发现可用的函数、服务器如何描述这些函数,以及结果如何回流。当一个 MCP Host(比如 Claude)决定调用某个工具时,它内部仍然使用函数调用——MCP 只是为它提供了一种统一的方式去「知道这个工具存在」并「触达实现这个工具的服务器」。
简而言之:函数调用是模型使用的「机制」,MCP 是把许多服务器与许多 Host 连起来、免去定制胶水的「管道」。
动手写第一个 MCP 服务器
我们来搭一个最小但真实的。会暴露两个工具:add 把两个数字相加,echo 原样返回你发的字符串。使用官方 TypeScript SDK 和 stdio 传输。
1. 初始化项目
mkdir mcp-demo && cd mcp-demo
npm init -y
npm install @modelcontextprotocol/sdk zod
npm pkg set type="module"
之所以设 "type": "module",是因为 SDK 以 ESM 形式发布;而加 zod,是因为高层 Server API 用 Zod schema 来描述工具入参。
2. 写服务器
创建 index.js:
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-server",
version: "1.0.0",
});
// 求和工具。第三个参数是用 Zod 描述的入参 schema,
// SDK 会据此推导出 JSON Schema。
server.tool(
"add",
{ a: z.number(), b: z.number() },
async ({ a, b }) => ({
content: [{ type: "text", text: String(a + b) }],
}),
);
// 原样回显字符串,附带一段可选的描述。
server.tool(
"echo",
{ message: z.string() },
async ({ message }) => ({
content: [{ type: "text", text: message }],
}),
);
const transport = new StdioServerTransport();
await server.connect(transport);
几点值得注意:
new McpServer({ name, version })注册了服务器的身份,Host 会把它展示给用户。server.tool(name, schema, handler)是高层辅助函数。handler 会收到经过校验的参数,且必须返回{ content: [...] },其中每个 content 项都有type(通常是"text")。StdioServerTransport把服务器接到标准输入输出上,这样 Host 就能把它作为子进程拉起。
3. 不依赖 Host 先做测试
SDK 自带一个交互式的 MCP Inspector,可以让你在接任何 Host 之前,先在浏览器 UI 里调用工具:
npx @modelcontextprotocol/inspector node index.js
打开它打印的 URL,找到 add 工具,用 a: 2、b: 3 调用一次。如果看到返回 5,说明你的服务器跑通了。
把它连到 Claude Desktop
Claude Desktop 通过一个配置文件来发现服务器。macOS 上它在 ~/Library/Application Support/Claude/claude_desktop_config.json(Windows 上是 %APPDATA%\Claude\claude_desktop_config.json)。在 mcpServers 下加一条,指向你服务器的绝对路径:
{
"mcpServers": {
"demo": {
"command": "node",
"args": ["/绝对路径/mcp-demo/index.js"]
}
}
}
重启 Claude Desktop,打开对话,问:「用 add 工具算一下 7 加 35。」Claude 会决定调用你的 add 工具,执行后回答 42。输入框旁边的锤子图标可以确认你的工具已被加载。
而这同一份服务器代码,无需改动,也能在任何其他兼容 MCP 的 Host 里跑——Claude Code(通过 .mcp.json)、Cursor 等等。这种可移植性正是 MCP 最大的回报。
继续深入
基础打通后,自然的下一步是:
- 用
server.resource(...)添加资源,暴露可读数据,比如更新日志或目录列表。 - 用
server.prompt(...)添加提示模板,发布可复用的斜杠命令式模板。 - 把传输方式换成 HTTP + SSE,让服务器能跑在远端,而不是每次会话都被拉起。
- 浏览生态——ClaudeMap 收录了数十个 MCP 服务器(文件系统、GitHub、Postgres、浏览器等),可以作为参考实现来安装和研究。
从一个工具起步,用 Inspector 确认往返正常,再接到某个 Host 上。MCP 的设计刻意收窄,所以从「hello world」到「能用的服务器」之间,距离很短。
MCP 协议架构:Host / Client / Server 三角关系
理解 MCP 怎么「工作」的关键,是看清 MCP 架构规范 里的三个角色。这三角关系与很多人下意识以为的「一对一」不同:
| 角色 | 是什么 | 例子 | |---|---|---| | Host | LLM 应用本身;负责用户界面、模型推理、调用 LLM API | Claude Desktop、Claude Code、Cursor、Zed、Cline | | MCP Client | Host 内嵌的协议客户端;每个 Server 一个 Client 实例 | Claude Desktop 启动时会为每个配置的 server fork 一个 client | | MCP Server | 提供 tools / resources / prompts 的外部进程 | 文件系统 server、Postgres server、Slack server |
关键事实:Host 与 Server 之间是多对多关系。一个 Claude Desktop 实例可以同时连接 20+ 个 MCP server(文件系统 + 数据库 + Slack + GitHub + 浏览器等);同一个 GitHub MCP server 也可以被 Claude Desktop、Claude Code、Cursor 同时调用。这是 MCP 与传统函数调用最大的区别——后者通常是「为每个 LLM 应用定制一套工具代码」,前者是「写一次 server,所有 Host 都能用」。
2025-11-25 规范 引入了MCP Server Registry 作为发现层(见 concepts/transports):client 可以查询稳定的 URL 而不是靠手动配置。这是 MCP 「走向产品级」的关键一步。
三类原语:tools / resources / prompts 的边界
MCP 把 server 暴露的能力拆成三类原语,每类的语义、调用方式、安全模型都不同(参考 concepts/architecture)。这与「一个万能函数」的常见误解相反:
Tools(最常用)—— 模型可以主动调用的函数。Tool 有 name / description / inputSchema 三个核心字段;调用后拿到结构化结果。如 query_database(sql: string) / send_email(to: string, body: string)。
Resources(数据暴露)—— 模型可以读取但不能「调用」的数据块。Resource 是只读的、带 URI 的、有 mimeType 的内容(文件、文档、查询结果快照)。如 file:///logs/app.log / postgres://tables/users。
Prompts(用户显式触发的模板)—— 不是模型自己选,而是用户通过 / 命令显式调用的预制提示词模板。如 /review-pr 会展开成一个完整的 PR review 模板。
| 原语 | 谁触发 | 副作用 | 典型场景 |
|---|---|---|---|
| Tools | 模型自动(按 description 匹配) | 通常有副作用(写数据库、发邮件) | 业务逻辑调用 |
| Resources | 模型自动(按 URI 匹配) | 只读,无副作用 | 文件读取、查询快照 |
| Prompts | 用户显式(/ 命令) | 无副作用,纯模板 | 复用工作流 |
易错点:把「读配置」做成 tool 而不是 resource。Tool 暗示「可以重复调用、会有副作用」,resource 才是「读取数据」的正解。如果一个工具纯只读且可缓存,把它降级为 resource 会让 Host 知道可以批量预取。
从本地到生产:传输层与信任边界
concepts/transports 定义了 MCP 的两种传输方式,选择传输 = 选择信任模型。
stdio(本地默认):Host 把 server 当作自己的子进程跑。OS 进程边界就是信任边界——server 能访问 Host 用户的全部权限。这是低摩擦的本地开发模型,没有网络攻击面。
Streamable HTTP(远端部署):server 跑在一台独立的机器上,通过 HTTP POST + SSE(Server-Sent Events)与 client 通信。鉴权从 OS 边界切换到 OAuth 2.1 + Bearer Token——意味着 server 面对的是公开网络,必须显式授权(参考 spec authorization 与 RFC 8707 Resource Indicators)。
| 维度 | stdio | Streamable HTTP |
|---|---|---|
| 鉴权 | 无(OS 进程边界) | OAuth 2.1 + Bearer |
| 部署 | 必须与 Host 同机 | 任意机器,HTTPS |
| 会话状态 | 进程内变量 | Mcp-Session-Id header |
| 性能 | 子进程 fork + JSON-RPC 解析 | 网络往返 + TLS 握手 |
| 适用 | 单用户本地工具 | 团队 / SaaS 部署 |
决策原则:
- 个人 / CLI / 内部工具:stdio
- 团队共享 / SaaS / 多 Host 复用:Streamable HTTP
- 跨域联邦 / 公共目录:Streamable HTTP + MCP Registry(modelcontextprotocol/registry)
把 stdio 搬到 HTTP 不是「换端口」——是重新设计信任边界。任何 stdio 服务器的「我本地能跑」上线后都会在 OAuth、session、Origin 校验处翻车——这些是 security best practices 的核心话题。
MCP 生态一览:Host、Server 与目录(2026)
理解协议之后,值得退一步看整个生态的形状——它由三层构成:
Host 层:MCP 与客户端无关,任何实现协议的应用都能调用同一台 server。到 2026 年,主流 Host 已经覆盖三类形态:通用聊天(Claude Desktop)、编程工具(Claude Code、Cursor、Zed 等),以及自研 Agent(用官方 SDK 把 MCP client 嵌进自己的程序)。同一台 filesystem server,在这三类 Host 里都能用——这是 MCP 与「某家应用的私有插件体系」最本质的差别。
Server 层:生态里绝大多数 server 聚在几个高频类别——数据库与数据平台、开发协作(GitHub、Sentry、项目管理)、浏览器自动化、云服务与可观测性、以及文件系统/搜索这类通用能力。官方维护的参考实现(modelcontextprotocol/servers)覆盖最基础的几类,社区实现则远多于官方。选 server 的第一原则不是「功能全」,而是最小权限:只接当前任务需要的类别(理由见上面的信任边界)。
目录与发现层:server 多了之后,「去哪找、怎么信」成了新问题——官方 registry 提供登记与发现,第三方目录(如 Smithery)提供索引与一键配置。本站的资源库按这六个类别维护带评注的目录,收录前每条 URL 都做可用性与迁移核验。
五个高频误区
误区 1:「MCP 服务器是 Claude Desktop 的插件」。 事实:协议与 Host 无关(见生态一览),同一台 server 可以被聊天应用、IDE、CLI 和你自己的程序调用。为「某一个 Host」写 server 是常见的短视设计。
误区 2:「resources 是给模型读的」。 事实:tools 由模型控制(模型决定何时调用),resources 由应用控制(UI/宿主决定把什么注入上下文)。把本该做成 resource 的数据做成 tool,等于把「用户主动给」写成了「模型主动要」——权限方向完全反了。
误区 3:「一个 server 就是一个工具」。 事实:一台 server 可以聚合多组 tools、resources 与 prompts——GitHub server 同时带读 issue、建 PR、查 workflow 等几十个工具。决定拆分粒度的是部署与权限边界,不是工具数量。
误区 4:「接了 MCP,集成就安全了」。 事实:MCP 标准化的是通信,不是授权。server 拿到的凭据、能触达的数据仍然需要你按最小权限配置;远程 server 还有 OAuth、令牌透传等一整条安全清单(见授权与 OAuth 指南)。
误区 5:「写 server 必须用 TypeScript」。 事实:官方 SDK 覆盖 TypeScript、Python、Go、Kotlin、Rust、C#、Swift、Java——选你团队最熟的栈即可,协议是语言无关的 JSON-RPC。
常见问题
模型上下文协议(MCP)是免费的吗?
是的。MCP 是 Anthropic 以宽松许可证开源的一项开放标准,其规范和官方 TypeScript、Python SDK 都是开源的。任何人都可以免费构建兼容 MCP 的服务器或客户端。
调用 MCP 服务器必须用 Claude 吗?
不需要。MCP 与客户端无关。任何支持该协议的 Host——Claude Desktop、Claude Code、Cursor、Zed,或你用 SDK 自研的 Agent——都能调用同一个 MCP 服务器,无需改动服务器代码。
MCP 能传图片、PDF 吗?resource 限不限于文本?
可以。MCP resource 的 mimeType 字段支持 image/png / image/jpeg / application/pdf / text/* 等标准 MIME;client 在 resources/read 拿到 base64 内容后渲染。多模态内容(如截图、扫描件)通过 tool 返回的 content 数组也能传。关键约束:JSON-RPC 2.0 单条消息限制在合理大小(典型 ≤ 数十 MB),所以 PDF / 图片走 Files API 上传再传 file_id 比直接 base64 更稳。
一个项目里能同时用 stdio 和 HTTP server 吗?
能。Host 配置里可以混合不同 transport 的 server:文件系统走 stdio、Slack 走远程 HTTP。client 端无感知——它只看到统一 JSON-RPC 接口。前提:每个 server 独立 session、互相不影响。但要注意 total token budget——20+ 个 server 的 tools/list 在系统提示里就占几 K token,超过 Host 的 listing 预算会被折叠或截断。
MCP 和函数调用(function calling)有什么区别?
函数调用是模型发出结构化请求的能力;MCP 是一种集成协议,标准化了 Host 如何发现服务器、服务器如何描述工具、结果如何回流。当 Claude 调用 MCP 工具时,内部仍然使用函数调用——MCP 提供的是连接众多服务器与众多 Host 的管道。
Host 与 MCP 服务器之间是如何传输数据的?
MCP 使用承载在传输层之上的 JSON-RPC 2.0 消息。常见两种传输:stdio(Host 把服务器作为子进程拉起,通过标准输入输出通信)和 HTTP + Server-Sent Events(服务器远端运行时使用)。本地开发几乎总是用 stdio。
官方参考资料
- MCP 2025-06-18 官方规范
- MCP 文档 — Concepts/Architecture(Host-Client-Server 三角)
- MCP 文档 — Concepts/Transports(stdio + Streamable HTTP)
- MCP 文档 — Develop/Build Server
- MCP 文档 — Learn/Architecture(生态位)
- MCP 教程 — 用 LLM 一步步构建 server
- MCP Inspector 调试工具
- Anthropic — Introducing MCP(2024-11 原始公告)
本文基于截至 2026 年 8 月的 MCP 2025-11-25 规范版本,相关 API 可能演进;建议每 6 个月查一次规范版本号。
本文基于截至 2026 年 7 月的公开信息,相关 API 可能演进。