MCP 到底解决了什么问题:从协议设计到官方 Python SDK 最小实现

MCP 到底解决了什么问题:从协议设计到官方 Python SDK 最小实现

把大模型接到外部工具上,过去是件重复劳动。每个应用要为每个数据源单独写一套对接逻辑:N 个模型应用乘以 M 个工具,就是 N×M 份互不复用的胶水代码。Model Context Protocol(MCP)想做的事很朴素------定一套标准协议,工具方只实现一次 Server,模型应用只实现一次 Client,把 N×M 降成 N+M。

MCP 由 Anthropic 在 2024 年 11 月开源,底层用 JSON-RPC 2.0。它不是某个模型的私有接口,而是一层传输格式与消息语义的约定。

三个角色,两种传输

一次 MCP 交互里有三方:

  • Host:用户实际使用的应用,比如某个 IDE 或桌面客户端。
  • Client:Host 内部为每个 Server 维护的连接器,一对一。
  • Server:你要暴露能力的一方,也是本文要写的东西。

Server 能向外暴露三类原语。Tools 是可被模型调用的函数,通常带副作用,比如查数据库、发请求;Resources 是可被读取的数据,只读、类似 HTTP 的 GET;Prompts 是预置的提示词模板。

传输层目前两种:stdio 走本地进程的标准输入输出,适合把 Server 当子进程拉起;streamable-http 走 HTTP,用于远程。消息格式统一是 JSON-RPC 2.0。

官方 Python SDK 里的 FastMCP

官方 Python SDK 包名就叫 mcp。2024 年 FastMCP 1.0 被并入这个官方 SDK,成了写 Server 的标准方式。它的核心思路是:你只写带类型标注和 docstring 的普通函数,schema 生成和参数校验交给框架。

装包:

bash 复制代码
pip install "mcp[cli]"

一个最小可运行的 Server:

python 复制代码
# server.py
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("demo")

@mcp.tool()
def add(a: int, b: int) -> int:
    """把两个整数相加"""
    return a + b

if __name__ == "__main__":
    mcp.run()  # 默认使用 stdio 传输

就这些。@mcp.tool() 会读函数的类型标注自动生成 JSON Schema,读 docstring 作为工具描述交给模型,你不用手写任何参数解析或校验代码。

类型标注是怎么变成协议里的接口契约的

模型要决定「该不该调这个工具、传什么参数」,靠的是 Server 声明的 name、description 和 inputSchema。FastMCP 的映射很直接:函数名变成 tool name,docstring 变成 description,类型标注变成 inputSchema。

所以类型标注在这里不是可有可无的注解,它直接决定了模型看到的接口。写 a: int 和不写,对模型是两种信息量。参数复杂时可以用 Pydantic 模型或 typing 里的结构类型,FastMCP 一样能转成对应 schema。

再加一个只读资源

Tools 用来做事,Resources 用来读数据。区别在于 Resource 应当无副作用、可缓存,语义更接近 GET:

python 复制代码
@mcp.resource("config://app")
def get_config() -> str:
    """返回应用配置"""
    return "log_level=INFO"

Resource 用 URI 标识,这里是 config://app,Client 按 URI 来拉。把读和写分开,是为了让客户端能对只读数据做缓存和权限控制。

跑起来,连上,调试

stdio 模式下,Server 本质就是个从 stdin 读、往 stdout 写 JSON-RPC 的进程,由 Client 拉起。本地调试可以用官方 CLI:

bash 复制代码
mcp dev server.py

它会起一个可视化的 Inspector,让你在浏览器里手动列出 tools、填参数、看返回,不用先接真实模型。排查 schema 对不对,这一步很省事。

要做成远程 Server,换传输即可:

python 复制代码
mcp = FastMCP("demo", host="0.0.0.0", port=8000)
mcp.run(transport="streamable-http")

几个容易被忽略的客观事实

MCP 不会让模型变聪明。它只标准化了工具接入这一层。模型该不该调、调得对不对,仍取决于工具描述写得好不好,以及模型本身的能力。

Tools 带副作用,安全边界在 Server 侧。协议不替你鉴权。一个能删库的 tool 暴露出去,模型------或者诱导模型的恶意输入------就可能触发它。危险操作要在 Server 里自己加确认和权限校验,别指望客户端替你拦。

stdio 只适合本地。跨机必须用 HTTP 传输,并自己解决认证,协议本身不规定鉴权方案。

描述即接口。同一个函数,docstring 和类型标注写清楚与否,直接影响模型的调用准确率。这部分投入的回报是最高的。

小结

MCP 的价值不在花哨,而在只实现一次。用官方 Python SDK,一个可用的 Server 就是几个带类型标注的函数,加一行 mcp.run()。真正要花心思的地方不在框架,而在两点:工具描述写得够不够准、副作用工具的权限边界守得够不够严。这两点做扎实,比接多少个工具都重要。

参考:MCP 官方 Python SDK(github.com/modelcontextprotocol/python-sdk)、官方文档 py.sdk.modelcontextprotocol.io

相关推荐
用户059540174461 小时前
用了半年 LangChain Memory,才发现记忆总“串台”——3 个自动化测试避坑指南
前端·css
大爱编程♡1 小时前
Vue3基础
前端·javascript·vue.js
weedsfly1 小时前
防抖与节流:从原理到 React Hook 封装
前端·javascript·面试
甜味弥漫1 小时前
React 从类组件到 Hooks:为什么 Hooks 改变了 React?
前端·javascript·react.js
天蓝色的鱼鱼1 小时前
让 AI 写代码半年后,我发现了几个藏在项目里的安全隐患
前端·javascript·ai编程
随风一样自由2 小时前
【前端+跨端技术新格局】Tauri vs Electron 完整性能对比(2026实测数据+底层原理)
前端·javascript·electron
L-影2 小时前
Pydantic 模型:为你的 Web 数据装上“安检系统”
前端
Reload.2 小时前
GJ航司,验证码网易易盾 JS逆向 纯算轨迹
开发语言·前端·javascript
L-影2 小时前
FastAPI 请求头与 Cookie:Web 世界的“身份证”与“通行证”
前端·fastapi