MCP 模型上下文协议:用统一标准连接大模型与外部世界

大模型很强,但它被困在信息的孤岛里:数据躺在数据库、网盘、工单系统、代码仓库里,模型本体碰不到。过去每接一个数据源,工程师就要为它单独写一套对接代码;十几个模型要接十几个工具,工作量就是十乘十。MCP(Model Context Protocol,模型上下文协议)要解决的正是这个问题——它把「大模型如何调用外部能力」抽象成一个开放标准,让「一次实现、处处复用」成为可能。本文先讲清楚 MCP 是什么、由谁提出,再拆解它的架构与核心原语,最后用官方 Python SDK 写一个能跑起来的最小服务器。

一、MCP 是什么

MCP 是一个开源的开放标准,用来把 AI 应用(如 Claude、各类编码助手)安全地连接到外部系统:内容仓库、业务工具、开发环境,乃至数据库与本地文件。官方给了一个很形象的比喻——把 MCP 理解为 AI 应用的「USB-C 接口」:正如 USB-C 用统一物理与电气规范连接各种设备,MCP 用统一协议连接 AI 应用与千差万别的外部系统。

MCP 由 Anthropic 在 2024 年 11 月 25 日正式开源发布。官方公告明确指出,MCP 的创建者是 Anthropic 的 David Soria Parra 与 Justin Spahr-Summers,并以开源协作项目的方式对外运营。发布当天同步开放了三部分内容:

  • MCP 规范与多语言 SDK(托管在 GitHub 组织 modelcontextprotocol 下);
  • Claude 桌面端的本地 MCP 服务器支持;
  • 一批开箱即用的官方 MCP 服务器实现(覆盖 Google Drive、Slack、GitHub、Git、Postgres、Puppeteer 等)。

二、为什么需要 MCP:从 N×M 到一次接入

在 MCP 出现之前,每让一个 AI 应用读一种新的数据源,团队往往要写一套专属的「连接器」。假设有 N 个模型/客户端、M 个工具/数据源,理想情况下就要维护 N×M 套集成代码。每一套都要处理鉴权、数据格式、错误重试,维护成本随规模平方级膨胀,而且无法在应用之间复用。

MCP 的思路是把「集成」这件事标准化:工具方只要实现一个符合规范的 MCP 服务器,任何支持 MCP 的客户端都能连上它。原先的 N×M 碎片,被收敛为 N 个客户端加 M 个服务器,即「一次实现、处处复用」。正如 Anthropic 公告所说,MCP 用单一协议取代了碎片化集成,让 AI 系统在不同工具与数据集之间保持上下文,形成更可持续的架构。

三、架构:Host、Client 与 Server

MCP 采用经典的客户端-服务器架构,规范定义了三个核心角色。

角色定义

  • MCP Host(主机):协调并管理一个或多个 MCP 客户端的 AI 应用程序,例如 Claude Code、Claude Desktop、Visual Studio Code。Host 是用户直接面对的「AI 应用」。
  • MCP Client(客户端):Host 内部的组件,负责维护与某个 MCP 服务器的连接,并为 Host 拉取上下文。Host 会为每一个连接的服务器创建一个专属 Client。
  • MCP Server(服务器):向 MCP 客户端提供上下文的程序。它运行在本地或远程均可,本质上就是一个「能力提供方」,可以暴露工具、资源与提示模板。

用一句话串起来:用户在 Host 里对话,Host 通过内部的 Client 连上 Server,Server 把数据或能力以统一协议回传,Host 再交给模型使用。

传输层 Transport

角色之间怎么通信,由传输层规定。当前 MCP 主要支持两种传输机制:

  • Stdio transport(标准输入/输出传输):通过标准输入/输出流在同一台机器的本地进程间直接通信,没有网络开销、性能最优。典型的「本地服务器」(如 filesystem server)就用 stdio,通常由 Host 在本机拉起、服务单一客户端。
  • Streamable HTTP transport(可流式 HTTP 传输):客户端到服务器的消息走 HTTP POST,并可选地借助 Server-Sent Events(SSE)实现流式能力。它支持远程服务器通信,并可使用标准 HTTP 鉴权(Bearer Token、API Key、自定义请求头),协议推荐用 OAuth 获取令牌。典型的「远程服务器」(如 Sentry MCP server)用它,可同时服务多个客户端。

无论哪种传输,上层消息都被统一为 JSON-RPC 2.0 格式,传输层对它透明。也就是说,服务器和客户端只要按 JSON-RPC 交换消息即可,底层是走 stdin 还是走 HTTP 由传输层决定。

四、核心原语:Tools、Resources、Prompts

MCP 服务器向客户端暴露能力时,主要围绕三种「原语」(primitive)。它们的控制方不同,理解这一点很关键。

Tools(工具)

Tools 是服务器暴露、供语言模型调用的函数,让模型能与外部系统交互——查数据库、调 API、做计算等。每个工具由唯一的 name 标识,并携带描述其参数的 inputSchema(JSON Schema)。

工具是「模型控制」(model-controlled)的:模型可以基于上下文自动发现并调用。出于安全,协议建议保持「人在回路」,在调用前向用户明确展示并请其确认。一个支持工具的服务器必须在能力声明里带上 tools,并响应客户端的 tools/list(列举)与 tools/call(调用)请求。

Resources(资源)

Resources 是服务器向客户端共享的「上下文数据」,例如文件内容、数据库 schema、应用专有信息。每个资源由唯一 URI(如 file://git://https://)标识。

资源是「应用驱动」(application-driven)的:由 Host 决定如何把资源纳入上下文——可以在界面里以树形列表让用户显式选择,也可以按启发式或模型的选择自动纳入。客户端通过 resources/list 发现资源、通过 resources/read 读取内容。资源还可带注解(audience、priority、lastModified)提示客户端如何使用。

Prompts(提示模板)

Prompts 是服务器暴露的「预设提示模板」,把结构化的消息与指令交给模型。客户端能发现可用提示、取回其内容,并传入参数做定制。

提示是「用户控制」(user-controlled)的:由用户显式触发(例如以斜杠命令唤起),但模板内容由服务器定义。客户端通过 prompts/list 列举、通过 prompts/get 取回具体提示。取回的提示消息可包含文本、图片、音频,以及指向 Resources 的链接或内嵌资源。

一句话区分三者:Tools 是「模型去调用外部动作」,Resources 是「把外部数据喂给模型」,Prompts 是「把预设的交互模板交给用户触发」。

五、MCP 与 Function Calling 的关系与区别

很多人会把 MCP 和 Function Calling 混为一谈,二者其实处在不同层面。

  • Function Calling 是「模型能力」:指模型本身能够识别「该调用哪个函数、填什么参数」,并输出结构化调用请求。它解决的是「模型会不会发命令」的问题,属于推理与格式化能力,与具体传输方式无关。
  • MCP 是「传输与集成标准」:规定 Host、Client、Server 之间用什么消息格式(JSON-RPC 2.0)、走什么传输(stdio / Streamable HTTP)、如何列举和调用工具/资源/提示。它解决的是「模型发出的命令如何安全、统一地抵达真实系统并得到结果」的问题。

二者是互补而非替代关系。典型链路是:模型先用 Function Calling 能力决定「我要调 add(a, b)」,Host 再通过 MCP 客户端把这次调用按协议发给对应的 MCP 服务器,服务器执行后把结果沿原路返回,Host 再交给模型继续推理。没有 MCP,Function Calling 仍可用,但每个工具都得自己写对接;有了 MCP,Function Calling 决定的动作就能落在任意符合规范的服务器上,复用性大幅提升。

六、实战:用官方 Python SDK 写一个最简 MCP Server

讲完概念,我们动手写一个最小可运行的 MCP 服务器,只暴露一个加法工具。下面基于当前官方 Python SDK(v2)的 MCPServer 高层 API。

环境准备

推荐用 Python 3.10 及以上。安装 SDK(带命令行工具):

# 使用 uv(官方推荐)
uv add "mcp[cli]"

# 或使用 pip 安装
pip install "mcp[cli]"

[cli] 会附带 mcp 命令行(用于 mcp dev / mcp run);若只需在代码里调用 SDK,单独 pip install mcp 即可。

最小服务器代码

新建 server.py,内容如下:

from mcp.server import MCPServer

# 创建一个名为 Demo 的 MCP 服务器实例
mcp = MCPServer("Demo")


@mcp.tool()
def add(a: int, b: int) -> int:
    """计算两个整数的和。

    Args:
        a: 第一个加数
        b: 第二个加数
    """
    return a + b


if __name__ == "__main__":
    # 以标准输入/输出(stdio)传输方式启动,适合本地进程集成
    mcp.run(transport="stdio")

关键点:

  • @mcp.tool() 装饰一个普通函数,就把函数暴露成 MCP 工具;
  • 函数的类型注解与 docstring 会被 SDK 自动转成协议所需的 inputSchema 与描述,无需手写 JSON Schema;
  • MCPServer("Demo") 中的 "Demo" 是服务器名称。

运行与调试

本地调试时,用官方命令行把服务器挂到 MCP Inspector(一个可视化调试界面)上:

mcp dev server.py

若要直接以某种传输方式常驻运行,可用:

# 本地进程间通信(默认)
mcp run server.py --transport stdio

# 远程/跨网络,走可流式 HTTP
mcp run server.py --transport streamable-http

客户端如何连接

在另一个进程里,客户端通过官方 Client 连接服务器并调用工具。下面以 Streamable HTTP 传输为例(服务器需先以 --transport streamable-http 启动在 8000 端口):

import asyncio

from mcp import Client


async def main() -> None:
    # 通过可流式 HTTP 传输连接到运行在 8000 端口的服务器
    async with Client("http://localhost:8000/mcp") as client:
        result = await client.call_tool("add", {"a": 1, "b": 2})
        print(result.structured_content)  # 输出: {'result': 3}


asyncio.run(main())

对于 stdio 传输,Host(如 Claude Desktop、VS Code)通常会在本机自动拉起 server.py 子进程并通过标准输入输出与之通信,开发者只需在 Host 的配置里登记服务器的启动命令即可,无需手写客户端连接代码。

小结

  • MCP 是 Anthropic 于 2024 年 11 月开源的开放标准,目标是用统一协议替代「每个模型对接每个工具」的 N×M 碎片集成。
  • 架构上是 Host 管理 Client、Client 连接 Server 的客户端-服务器模型;传输层支持本地 stdio 与远程 Streamable HTTP(可流式 SSE)。
  • 三种核心原语各司其职:Tools(模型调用动作)、Resources(喂给模型的上下文数据)、Prompts(用户触发的预设模板)。
  • MCP 是「传输与集成标准」,Function Calling 是「模型能力」,二者互补:前者把后者的调用安全送达真实系统。
  • 用官方 Python SDK 的 MCPServer@mcp.tool(),几行代码就能暴露一个可被发现、被调用的工具,并通过 mcp 命令行或 Client 接入。

参考与延伸阅读

本文累计阅读