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。

相关推荐
福兮说7 小时前
前端下载大文件,点了按钮半天没反应:fetch + blob 的三个问题和三种替代写法
前端·javascript·性能优化·文件下载
GreenTea7 小时前
我把 Agent 的 while 循环拆掉了:一种你可能没想到的 Agent 架构
前端·后端·架构
科技观察哨7 小时前
六足平台选型与纳米定位系统集成:HEB-640六自由度位移台在半导体光刻对准中的参数边界与国产替代评估
前端·人工智能
niucloud-admin8 小时前
JAVA V6 多商户商城 开发文档——web前端
前端
颜进强8 小时前
16 · NestJS LifecycleEvents 生命周期事件:五个钩子、三条边界,和 rag-server 的优雅停机
前端·后端·ai编程
今年下半年9 小时前
【VUE】整合腾讯地图、自定义区域边界、村委名称及资产统计(放大显示资产点位)
前端·javascript·vue.js
郑州光合科技余经理9 小时前
同城电商系统:库存变更怎么同步到订单
java·开发语言·前端·后端·uni-app·php·ai编程
前端snow11 小时前
ai agent --- DeepAgents 中间件
前端
data analyse 45612 小时前
报表能自定义的国内统计工具有哪些
前端·数据分析