跳到主要内容

理解 MCP

·1388 字·7 分钟

理解 MCP #

MCP 概述 #

MCP(模型上下文协议)是一个开源标准协议,让 AI 应用(如 Claude、ChatGPT)能够统一连接外部数据源、工具和工作流。类比 USB-C 接口——为 AI 与外部系统的交互提供标准化的连接方式。MCP 专注于上下文交换协议本身,不干涉 AI 应用如何使用 LLM 或管理上下文,保持了高度的灵活性与可扩展性。

MCP 能做什么:

  • AI 助手接入日历、笔记等个人数据
  • 根据 Figma 设计稿直接生成网页应用
  • 企业聊天机器人连接多个数据库进行数据分析
  • AI 操控 Blender 建模并驱动 3D 打印机

为什么重要:

  • 开发者:降低 AI 应用的开发复杂度
  • AI 应用:接入更丰富的数据和工具生态,提升能力
  • 终端用户:获得能访问个人数据、代为执行任务的更强大 AI

重要资源:

  1. 官方文档 — MCP 官网,含架构说明、规范和教程
  2. 示例服务器 — 官网提供可直接使用的服务器示例,覆盖数据库、文件系统、Web API 等场景
  3. 社区精选服务器 — GitHub 上的 awesome-mcp-servers,持续更新的各类 MCP 服务器合集
  4. MCP 客户端列表 — GitHub 上的awesome-mcp-clients,多语言、多框架的客户端实现参考
  5. MCP For Beginners — 微软出品的MCP入门教程,通过Rust、Python和TypeScript等语言的实践代码示例学习MCP
  6. 探索更多的MCP服务器:
    • https://glama.ai/, 一个集成的多模态 AI 客户端与开源工具平台。它提供了一个统一的聊天界面,让用户可以同时对比、调用多个主流人工智能模型,并以拥有大量 MCP(模型上下文协议)服务器资源而知名。
    • https://mcp.so/,一个社区驱动的平台,旨在收集和整理第三方 MCP(Model Context Protocol)服务器资源。
    • https://mcpservers.org/,一个专注于 MCP服务器的资源平台
    • https://www.reddit.com/r/mcp/,reddit的MCP资源频道
    • https://lobehub.com/zh/mcp,lobehub的MCP服务器市场

MCP的架构 #

参与者 #

MCP Host(AI 应用)
    ├── MCP Client 1  ──→  MCP Server A(本地,如文件系统)
    ├── MCP Client 2  ──→  MCP Server B(本地,如数据库)
    └── MCP Client 3  ──→  MCP Server C(远程,如 Sentry)
  • MCP Host:AI 应用本体(如 Claude Desktop、VS Code、Cursor等)
  • MCP Client:由 Host 创建,每个 Server 对应一个专属 Client
  • MCP Server:提供上下文数据的程序,可以在本地或远程运行

两层协议 #

层次职责
数据层基于 JSON-RPC 2.0,定义消息结构、生命周期管理、原语(Tools/Resources/Prompts)、通知机制
传输层负责通信信道与认证,屏蔽底层细节

传输层两种方式:

  • Stdio:标准输入输出,用于本地进程通信,性能最优
  • Streamable HTTP:HTTP POST + SSE,用于远程服务器,支持 OAuth 认证

核心设计原则 #

  • 一个 Host → 多个 Client → 多个 Server
  • 数据层协议统一,传输层可替换
  • 有状态协议,需要生命周期管理(初始化 → 能力协商 → 通信 → 终止)

JSON-RPC 2.0 #

JSON-RPC 是一个无状态、轻量级的远程过程调用(RPC)协议,使用 JSON(RFC 4627)作为数据格式。这个规范简洁而强大,广泛应用于各种 API 和微服务架构中。详细规范:https://www.jsonrpc.org/specification

基本概念 #

核心特点:

  • 简单轻量:规范精简,易于实现和理解
  • 传输无关:可在 HTTP、WebSocket、TCP 等任何传输协议上使用
  • 无状态:每个请求独立完整,不依赖上下文
  • 支持批量:可一次发送多个请求,提高效率

消息分类:

    ├─── 请求/响应模型
    │       ├─── 请求对象 (Request),需要服务器响应的调用
    │       ├─── 响应对象 (Response),对请求的响应,可以响应结果或者错误
    │       └─── 通知对象 (Notification),不需要响应的单项请求
    └─── 批量处理
            └─── 批量调用 (Batch),多个请求和响应一起发送

角色定义:

  • 客户端(Client):发起请求对象,处理响应对象
  • 服务器(Server):处理请求对象,发起响应对象

通信流程:

sequenceDiagram participant Client as 客户端 participant Server as 服务器 Note over Client,Server: 标准请求-响应 Client->>Server: Request (with id) Server->>Client: Response (with id) Note over Client,Server: 通知(无响应) Client->>Server: Notification (no id) Note over Client,Server: 批量调用 Client->>Server: Batch Request [req1, req2, ...] Server->>Client: Batch Response [res1, res2, ...]

数据结构 #

使用JSON数据结构,用对象封装消息。

请求对象(Request Object) #

示例:

{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": [42, 23],
  "id": 1
}

字段说明:

字段类型必需说明
jsonrpcString协议版本,必须是 “2.0”
methodString要调用的方法名
paramsArray/Object方法参数(结构化值)
idString/Number/Null请求标识符,通知时省略

响应对象(Response Object) #

成功响应示例:

{
  "jsonrpc": "2.0",
  "result": 19,
  "id": 1
}

字段说明:

字段类型必需说明
jsonrpcString必须是 “2.0”
resultAny方法返回的结果
idString/Number/Null与请求对应的 ID

错误响应示例:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": 1
}

字段说明:

字段类型必需说明
jsonrpcString必须是 “2.0”
errorObject错误对象
idString/Number/Null与请求对应的 ID

错误对象(Error Object)

字段类型必需说明
codeNumber错误代码(整数)
messageString错误简短描述
dataAny附加错误信息

预定义错误码

代码消息含义
-32700Parse error解析 JSON 失败
-32600Invalid Request请求对象无效
-32601Method not found方法不存在
-32602Invalid params参数无效
-32603Internal error内部错误
-32000 至 -32099Server error服务器自定义错误

通知(Notification) #

通知是不需要响应的特殊请求,通过省略 id 字段来标识:

{
  "jsonrpc": "2.0",
  "method": "update",
  "params": [1, 2, 3, 4, 5]
}

批量调用(Batch) #

可以将多个请求对象放在一个数组中发送:

批量请求:

[
  {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
  {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
  {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"}
]

批量响应:

[
  {"jsonrpc": "2.0", "result": 7, "id": "1"},
  {"jsonrpc": "2.0", "result": 19, "id": "2"}
]

注意:通知不会在批量响应中出现。

MCP的数据层协议 #

MCP使用 JSON-RPC 2.0 作为底层协议,支持请求/响应和单向通知两种消息模式,定义客户端和服务器之间交换消息的具体格式,确保双方能听懂对方。

生命周期管理 #

有状态协议,连接建立时需进行能力协商,确定双方支持的功能。

原语(Primitives) #

服务端原语(Server → Client):

原语说明
Tools可执行函数,如文件操作、API 调用
Resources上下文数据源,如文件内容、数据库记录
Prompts可复用的交互模板

每种原语均支持 */list 发现、*/get 获取,Tools 额外支持 tools/call 执行。

客户端原语(Client → Server):

原语说明
Sampling服务器请求客户端 LLM 生成内容
Elicitation服务器向用户请求额外输入或确认
Logging服务器向客户端发送调试日志

跨切面原语

  • Tasks(实验性):支持长时间运行任务的状态追踪与延迟结果获取

通知机制 #

服务器状态变化时(如工具列表更新),主动推送 JSON-RPC 通知消息,无需客户端轮询,实现实时同步。

数据层交互示例 #

本节通过 JSON-RPC 2.0 消息,逐步演示 MCP 客户端与服务端的交互过程,涵盖生命周期管理、工具操作和通知机制

1. 初始化(生命周期管理) #

MCP 连接建立时,客户端通过发送 initialize 请求进行能力协商握手,以协商双方支持的功能。

如下是一次请求和响应的消息报文:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "elicitation": {}
    },
    "clientInfo": {
      "name": "example-client",
      "version": "1.0.0"
    }
  }
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": {
      "tools": {
        "listChanged": true
      },
      "resources": {}
    },
    "serverInfo": {
      "name": "example-server",
      "version": "1.0.0"
    }
  }
}

完成三件事:

  • 版本协商:通过 protocolVersion 确保双方协议版本兼容,不兼容则断开连接
  • 能力发现:通过 capabilities 声明各自支持的原语和功能,避免调用不支持的操作。
    • 客户端声明支持 elicitation,即可接收服务器发起的用户交互请求
    • 服务端声明支持 tools(含 listChanged: true,可推送工具列表变更通知)和 resources(可处理资源列表与读取请求)
  • 身份交换:通过 clientInfo / serverInfo 传递身份信息,用于调试和兼容性判断

初始化成功后,客户端发送 notifications/initialized 通知表示就绪:

{
  "jsonrpc": "2.0",
  "method": "notifications/initialized"
}

在 AI 应用中的工作方式

初始化时,AI 应用的 MCP 客户端管理器连接所有配置的 Server,缓存其能力信息,后续据此判断哪个 Server 能提供所需功能(工具、资源、提示词)以及是否支持实时更新。

2. 工具发现(原语) #

连接建立后,客户端发送 tools/list 请求发现可用工具,在调用工具前先了解服务端有哪些工具

如下是一次请求和响应的消息报文:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "calculator_arithmetic",
        "title": "Calculator",
        "description": "Perform mathematical calculations including basic arithmetic, trigonometric functions, and algebraic operations",
        "inputSchema": {
          "type": "object",
          "properties": {
            "expression": {
              "type": "string",
              "description": "Mathematical expression to evaluate (e.g., '2 + 3 * 4', 'sin(30)', 'sqrt(16)')"
            }
          },
          "required": ["expression"]
        }
      },
      {
        "name": "weather_current",
        "title": "Weather Information",
        "description": "Get current weather information for any location worldwide",
        "inputSchema": {
          "type": "object",
          "properties": {
            "location": {
              "type": "string",
              "description": "City name, address, or coordinates (latitude,longitude)"
            },
            "units": {
              "type": "string",
              "enum": ["metric", "imperial", "kelvin"],
              "description": "Temperature units to use in response",
              "default": "metric"
            }
          },
          "required": ["location"]
        }
      }
    ]
  }
}

客户端发送 tools/list 请求,服务器响应所有可用工具的元数据数组。每个工具对象包含四个关键字段:

  • name:工具唯一标识符,用于调用
  • title:面向用户的可读名称
  • description:工具功能及使用场景说明
  • inputSchema:JSON Schema 定义,描述输入参数的类型与约束

在 AI 应用中的工作方式

AI 应用从所有已连接的 MCP Server 获取工具列表,合并为统一的工具注册表供 LLM 使用,使其了解可执行的操作并在对话中自动生成相应的工具调用。

3. 工具执行(原语) #

发现工具后,客户端通过 tools/call 方法携带参数请求执行具体工具

如下是一次请求和响应的消息报文:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "weather_current",
    "arguments": {
      "location": "San Francisco",
      "units": "imperial"
    }
  }
}
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Current weather in San Francisco: 68°F, partly cloudy with light winds from the west at 8 mph. Humidity: 65%"
      }
    ]
  }
}

工具执行的关键要素:

  • name:必须与发现阶段返回的工具名完全一致,确保客户端与服务端之间类型安全、通信明确。
  • arguments:按 inputSchema 传入参数,分必填和可选
  • JSON-RPC 2.0:使用唯一 id 关联请求与响应

响应结构:

  • content 数组支持多种类型(文本、图片等),通过 type 字段区分
  • 结构化输出可直接作为 LLM 的上下文使用

在 AI 应用中的工作方式

AI 应用可动态调用服务端功能,并将结构化响应集成进 LLM 对话。LLM 决定调用工具时,AI 应用拦截请求 → 路由至对应 MCP Server → 执行 → 将结果返回 LLM,使其能访问实时数据并操作外部世界。

4. 实时通知 #

工具列表变化时,Server 主动推送 notifications/tools/list_changed(无需响应),客户端收到通知后,会重新请求tools/list 刷新工具列表,形成刷新循环,确保本地工具信息始终最新。

如下是通知的消息报文:

{
  "jsonrpc": "2.0",
  "method": "notifications/tools/list_changed"
}

关键特性:

  • 无需响应:无 id 字段,遵循 JSON-RPC 2.0 通知语义
  • 能力驱动:仅限初始化时声明 listChanged: true 的服务端发送
  • 事件驱动:服务端根据内部状态变化主动推送,连接动态响应

通知机制的价值:

  • 动态适应:工具可随服务端状态、权限等变化动态增减
  • 高效:无需轮询,变更时主动推送
  • 一致性:确保客户端始终掌握最新能力信息
  • 实时同步:该机制不限于工具,覆盖所有 MCP 原语

在 AI 应用中的工作方式

AI 应用收到工具变更通知后,立即刷新工具注册表并更新 LLM 的可用能力,确保对话中始终能使用最新工具。

MCP Server #

MCP Server是通过标准化协议向 AI 应用暴露特定能力的程序,可以运行在本地或者远程,通过 stdio 或者 http 与 Client 通讯,提供三大核心功能:

功能说明控制方
工具 ToolsLLM 主动调用的函数,可写数据库、调 API、修改文件模型
资源 Resources只读数据源,提供上下文信息,如文件、数据库结构应用
提示 Prompts预置指令模板,引导模型使用特定工具和资源用户

Tools #

工具(Tools)让 AI 模型能够执行操作,每个工具定义明确的输入输出,模型根据上下文决定何时调用。基于 JSON Schema 定义的接口,每个工具执行单一操作,执行前可要求用户确认。

协议方法:

方法用途返回值
tools/list发现可用工具包含 schema 的工具定义数组
tools/call执行指定工具工具执行结果

工具(Tools)由模型自动发现和调用,但 MCP 通过多种机制确保人工监督。为保障安全,应用可通过以下机制实现用户管控:UI 展示可用工具、执行前弹窗确认、预授权安全操作、记录执行日志。

Resources #

资源(Resources)为 AI 应用提供结构化的信息访问,供应用检索后作为上下文传递给模型。本质是暴露文件、API、数据库等数据,每个资源有唯一 URI 和 MIME 类型,支持两种模式:

  • 直接资源:固定 URI,如 calendar://events/2024
  • 资源模板:动态 URI,如 travel://activities/{city}/{category}

协议方法:

方法用途返回值
resources/list列出可用资源资源描述符数组
resources/templates/list发现资源模板资源模板定义数组
resources/read获取资源内容带元数据的资源数据
resources/subscribe监听资源变更订阅确认

资源(Resources)由AI应用驱动,界面形式自由,常见模式有:树形/列表浏览、搜索过滤、智能推荐、手动批量选择。协议不强制规定 UI 形式,支持预览、上下文感知推荐及与现有文件浏览器集成。

Prompts #

提示(Prompts)是可复用的参数化模板,帮助用户更好地使用 MCP 服务器。需用户主动调用(非自动触发),可引用资源和工具构建完整工作流,并支持参数补全。

协议方法:

方法用途返回值
prompts/list发现可用提示提示描述符数组
prompts/get获取提示详情包含参数的完整提示定义

提示(Prompts)由用户主动调用,实现者可自由设计界面,核心原则:易于发现、描述清晰、参数验证、模板透明展示。常见 UI 形式:斜杠命令(/plan-vacation)、命令面板、快捷按钮、右键菜单。

开发 MCP Server #

准备环境 #

在WSL2的Ubuntu24中开发。需要如下工具

新建 MCP Server #

新建一个项目:

uv init mcp-server
cd mcp-server

添加依赖的包:

uv add mcp

main.py 文件中添加如下源码:

from mcp.server.fastmcp import FastMCP

# Create an MCP server
mcp = FastMCP("Demo")


# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
    """Add two numbers"""
    return a + b

# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
    """Get a personalized greeting"""
    return f"Hello, {name}!"


# Main execution block - this is required to run the server
if __name__ == "__main__":
    mcp.run()

这是一个简单的MCP Server,默认的传输方式是 stdio,提供了两个功能:

  • 一个工具 add ,输入两个整数参数,返回两数之和。例如
  • 一个资源模板get_greeting ,注册了一个带参数的资源地址模板greeting://{name},当访问某个名字时,会返回对应问候语。例如 greeting://Alice 会返回Hello, Alice!

用 uv 启动这个 MCP Server,启动后会阻塞:

uv run main.py

使用 MCP Inspector 调试 #

MCP Inspector 是一个用于 测试和调试 MCP(Model Context Protocol)服务器 的交互式开发工具。基于NodeJS开发,具有如下特点:

  • 可直接通过 npx 启动
  • 可以连接服务器,测试各项功能
  • 查看服务器发送的通知和日志
  • 适合本地开发、联调和排查问题
  • 帮助开发者快速验证 MCP 服务器能力是否正常

启动 MCP Inspector:

 npx @modelcontextprotocol/inspector

启动后会自动在浏览器中打开界面:

左侧是连接配置区域,选择传输方式,填写对应的参数,然后点击「Connect」按钮,就可以连接到 MCP Server。对应STDIO的服务器,Command和 Arguments按照服务进程的名称填写,这样它才能找到这个进程,然后通过STDIO与之通讯。连接成功后,在右侧会显示显示调试工具和通讯过程的报文。首先就是连接初始化时的报文:

进入Tools页面,可以点击「List Tools」列出可用的工具,选择相应的工具后,可以填写输入参数,运行工具,查看结果和通讯报文:

在Cursor中使用MCP Server #

markitdown 为例,这是微软开源的Python工具,用于将各种文件转换为 Markdown。同时提供markitdown-mcp ,一个本地运行的轻量级 MCP Server,支持三种传输协议:

  • stdio:标准输入输出
  • Streamable HTTP:流式 HTTP
  • SSE:服务器推送事件

核心功能只有一个工具:convert_to_markdown(uri),可将 http:https:file:data: 等 URI 指向的内容转换为 Markdown 格式。

推荐在Docker中运行这个MCP Server(https://hub.docker.com/r/mcp/markitdown),Docker 容器本身支持 stdio 透传。

先安装:

# 安装 docker image
> docker pull mcp/markitdown

# 安装后确认
> docker images
                                                                                                i Info →   U  In Use
IMAGE                   ID             DISK USAGE   CONTENT SIZE   EXTRA
mcp/markitdown:latest   66579f88f7fe       1.53GB          405MB

在Cursor的MCP Server配置文件(~/.cursor/mcp.json)中添加如下内容:

{
  "mcpServers": {
    "markitdown": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "-v",
        "/home/lsc/workspace:/workdir",
        "mcp/markitdown:latest"
      ]
    }
  }
}

说明:

  • -i(interactive):保持 stdin 开启,是 stdio 通信的关键参数
  • mcp/markitdown:latest是安装的image的名称。
  • /home/lsc/workspace:/workdir 表示把本地的 /home/lsc/workspace 挂载到docker镜像的 /workdir ,这样才可以访问本地文件。

启动 Cursor时,会解析MCP配置文件,然后启动docker容器。以Cursor CLI为例,启动后执行/mcp list命令可以列出所有的MCP服务(根据提示,可能需要使能一些权限):

> agent


  Cursor Agent
  v2026.05.20-2b5dd59
  Use /plan to plan execution and reach the right outcome faster.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 MCP Servers (1 servers)

 User
  → markitdown - enabled (Enter to view details)
  
 ↑/↓ to navigate • Enter to select • Esc to close

选中以后,按Enter查看详情:

 markitdown
 Status: enabled
 Command: docker
 1 tools

  View Tools  Manage Server (tab to cycle)

 → convert_to_markdown (uri)
 
 Tab to switch sections • ↑/↓ to navigate • Enter to act • Esc to go back

选中View Tools可以看到支持一个Tools:convert_to_markdown (uri),再按Enter可以查看 Tools的详情:

 convert_to_markdown
 markitdown
 Params: uri

 Input schema
 {
   "type": "object",
   "properties": {
     "uri": {
       "title": "Uri",
       "type": "string"
     }
   },
   "required": [
     "uri"
   ],
   "title": "convert_to_markdownArguments"
 }

 ↑/↓ to scroll schema • Esc to go back

在对话中输入提示词,会自动触发转换,例如“将 https://docs.kernel.org/i2c/summary.html 转换为markdown”:

  Cursor Agent
  v2026.05.20-2b5dd59
  Use /plan to iterate on an implementation plan before code changes.


  > convert to markdown: https://docs.kernel.org/i2c/summary.html , save ./i2c-summary.md


  正在将内核文档页面转换为 Markdown 并保存到 i2c-summary.md。

    markitdown convert_to_markdown

  正在清理 Sphinx 侧边栏导航,生成适合独立阅读的 Markdown 文档并保存。