MCP 深度拆解:当大模型长出「万能接口」——从 Host/Client/Server 三角色、Tools/Resources/Prompts 原语到 Streamable HTTP 与生产级 Server 的工程全貌(2026)
如果说 2025 年是「大模型会聊天」的年份,那么 2026 年就是「大模型会动手」的年份。而让大模型真正长出手脚的那根神经,叫 MCP(Model Context Protocol,模型上下文协议)。本文不堆术语,不抄文档,从工程视角把 MCP 拆成三层:协议内核(JSON-RPC 2.0)、角色拓扑(Host/Client/Server)、原语抽象(Tools/Resources/Prompts),再手撸一个生产级 Server,最后聊清楚鉴权、有状态/无状态、分页、可观测性这些只有踩过坑才知道的东西。
一、背景:那个被所有人忽略的 M×N 问题
在 MCP 出现之前,如果你想让你的大模型「能查数据库、能读文件、能调 Jira、能发 Slack」,你的真实处境是这样的:
- 模型 A(Claude)要接工具 1、工具 2、工具 3……
- 模型 B(GPT)要接工具 1、工具 2、工具 3……
- 模型 C(本地 Ollama)也要接……
于是你得到了 M 个模型 × N 个工具 = M×N 套集成代码。每一套都得自己处理:参数怎么传、错误怎么回、鉴权怎么做、上下文怎么塞。这就是业界常说的 M×N 集成噩梦。
更糟的是,每一家对「function calling」的定义都略有不同。OpenAI 的 tool 格式、Anthropic 的 tool_use 格式、Google 的 function_declarations 格式,字段名、嵌套结构、强制 required 规则都不一样。你每换一个模型,集成代码就得重写一遍。
MCP 的破局思路极其「工程师」:不解决模型侧,解决工具侧。它在模型与外部系统之间插了一层标准协议,让「工具」只用实现一次 MCP Server,就能被任何支持 MCP 的 Host(Claude Desktop、Cursor、VS Code、Cherry Studio……)即插即用。
这就是为什么社区爱用那句比喻:MCP 是 AI 世界的 USB-C 接口。
- USB-C 之前:每根线一个头,充电器、显示器、硬盘各搞各的。
- USB-C 之后:一个口通吃。
- MCP 之前:每个 Agent 框架自己造一套工具调用协议。
- MCP 之后:一个 Server,所有 Host 通用。
但注意一个关键事实:MCP 不解决「模型之间怎么协作」,那是 A2A(Agent2Agent)协议的活儿。MCP 解决的是「一个 Agent 怎么用工具和数据」。这两层经常被初学者混淆——本文后面会专门讲清边界。
为什么是 2026 年才爆发?
technically MCP 是 Anthropic 在 2024 年底开源的。但它真正在 2026 年成为事实标准,有三个催化因素:
- Agent 化浪潮:单纯聊天已经不够,产品都在做「能自主调用工具完成任务」的 Agent,工具接入需求爆炸。
- SDK 成熟:官方 Python / TypeScript SDK 在 2025–2026 年快速迭代,FastMCP 这类封装让写 Server 从「几十行样板」降到「几行装饰器」。
- 远程传输补齐:早期只有 stdio(本地子进程)和 SSE(有状态、易断),2025 年末推出的 Streamable HTTP 传输让「远程 MCP Server」真正可生产化,使得 SaaS 化 MCP(比如「官方 GitHub MCP」「官方 Slack MCP」)成为可能。
理解了背景,我们进入协议内核。
二、核心概念:三个角色 + 两层抽象 + 一组原语
2.1 三个角色(Role)
MCP 的拓扑非常清晰,记住这三个人就够了:
| 角色 | 是什么 | 典型例子 |
|---|---|---|
| Host(宿主) | 用户直接交互的 AI 应用,负责编排一个或多个 Client,并持有模型 | Claude Desktop、Cursor、VS Code Copilot、Cherry Studio |
| Client(客户端) | 由 Host 创建,维护与某个 Server 的一对一专用连接,负责协议握手与消息转发 | Host 内部为每个 Server 起的一个连接对象 |
| Server(服务器) | 真正封装外部能力的程序,提供工具、资源、提示 | 你写的 PostgreSQL MCP、官方 Filesystem MCP、GitHub MCP |
一个关键不变量:一个 Host 可以连多个 Server,但每个 Client 只跟一个 Server 说话,是一对一专用连接。这意味着 Server 之间互不感知,Host 负责把多个 Server 的能力汇总后交给模型。
把这三者的关系想象成公司:
- Host 是「老板」,决定要完成什么任务;
- Client 是「老板对每个外包团队的专属对接人」;
- Server 是「外包团队」,各有专长。
2.2 两层抽象(Layering)
MCP 协议在逻辑上分两层,理解这点对排查问题至关重要:
- 数据层(Data Layer):定义「说什么」。基于 JSON-RPC 2.0,包括生命周期管理、
initialize握手、核心原语(Tools/Resources/Prompts)和各种通知(notification)。 - 传输层(Transport Layer):定义「怎么传」。负责连接建立、消息分帧(framing)、授权。可以是 stdio、Streamable HTTP 等。
这套分层的好处是:协议语义与传输解耦。你完全可以用同一套 Tool 定义,既跑在本地 stdio 上,也跑在远程 HTTP 上,业务逻辑零改动。
2.3 四大核心原语(Primitives)
MCP 把「Server 能给模型提供的能力」抽象成几个原语。最常用的是前三个:
Tools(工具)——模型可主动调用的函数
Tools 是模型可以主动决定调用的函数,比如「执行一条 SQL」「调用天气 API」「创建 Jira issue」。每个 Tool 必须有:
name:唯一名description:给模型看的说明(极其重要,模型靠它决定要不要调)inputSchema:JSON Schema 描述入参
注意区分:Tools 是「模型 Pull 触发」还是「Server Push」? 是模型在推理时自主决定调用的(模型产生一个 tool_call,Host 执行后把结果回灌给模型继续推理)。这是 MCP 与 Resources 最大的区别。
Resources(资源)——可被读取的上下文数据
Resources 是被动的、可被读取的数据,类似 REST 里的 GET 一个资源。比如:
file:///logs/app.logschema://users(某张表的结构)db://query-result/123
模型通常通过「用户显式引用」或 Host 自动注入来访问 Resources。Resources 用 URI 寻址,支持 {占位符} 模板(比如 schema://{table})。
Prompts(提示模板)——可复用的交互脚手架
Prompts 是预定义的、参数化的提示词模板,用户或模型可以「一键调用」。比如「分析这张表并生成优化建议」这个流程,可以被固化为一个 Prompt,带 table 参数。它解决的是「常用交互模式复用」问题,而不是「动态执行」。
Sampling / Roots / Elicitation(进阶原语)
- Sampling:让 Server 反向请求 Host「帮我调一次模型」(Server → Host → LLM)。这打破了「只有 Host 能调模型」的单向关系,使 Server 内部也能做推理(比如让模型总结一段长文本)。这是 MCP 里最容易被忽视但极其强大的能力。
- Roots:Host 告诉 Server「你被授权访问的根路径有哪些」(比如
file:///home/me/projects)。是细粒度授权的承载。 - Elicitation:Server 在运行中向用户主动收集额外信息(补充参数),而不是默默失败。适合需要用户确认或补充输入的场景。
工程建议:新手先吃透 Tools + Resources + Prompts 三件套,Sampling/Roots/Elicitation 在做到「生产级多租户」时再上。
三、架构分析:扒开 JSON-RPC 2.0 与握手细节
3.1 所有消息都是 JSON-RPC 2.0
MCP 的每一条消息都是标准 JSON-RPC 2.0 帧。三种形态:
// 1) 请求(Request):带 id,期望收到对应的响应
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": { "name": "run_query", "arguments": { "sql": "SELECT 1" } }
}
// 2) 响应(Response):与请求的 id 对应,要么 result 要么 error
{
"jsonrpc": "2.0",
"id": 1,
"result": { "content": [{ "type": "text", "text": "[{\"?column?\":1}]" }] }
}
// 3) 通知(Notification):无 id,单向,发出即忘,不期望响应
{
"jsonrpc": "2.0",
"method": "notifications/resources/updated",
"params": { "uri": "schema://users" }
}
这一点非常关键:因为底层是 JSON-RPC,MCP 的所有交互都可以被清晰地日志化、重放、调试。你抓到一条 tools/call 请求,就完全知道模型想干嘛。这是它相比「各家私有 function calling」最大的工程优势之一。
3.2 握手:initialize 是重中之重
任何 MCP 连接建立后,Client 必须先发 initialize,Server 回 InitializeResult,然后 Client 发 notifications/initialized 通知「我准备好了」,之后才进入正常操作阶段。这个顺序绝不能乱。
// Client → Server: initialize
{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18", // 客户端支持的最高协议版本
"capabilities": { "tools": { "listChanged": true } },
"clientInfo": { "name": "my-host", "version": "1.0.0" }
}
}
// Server → Client: InitializeResult
{
"jsonrpc": "2.0",
"id": 0,
"result": {
"protocolVersion": "2025-06-18", // 协商后的版本(取双方都支持的最高)
"capabilities": {
"tools": { "listChanged": true },
"resources": {},
"prompts": {}
},
"serverInfo": { "name": "pg-analytics", "version": "0.1.0" }
}
}
// Client → Server: 通知进入操作阶段(无 id)
{ "jsonrpc": "2.0", "method": "notifications/initialized" }
能力协商(Capability Negotiation) 是这里最容易被忽略的设计:双方各自声明自己支持哪些原语、哪些可选特性(比如 tools.listChanged 表示 Server 会在工具列表变化时主动通知)。如果 Server 没声明 resources 能力,Client 就绝不会去调用 resources/read,省得一堆 404 式错误。这种设计让「渐进式生态」成为可能——老 Server 不支持新特性也不会崩。
3.3 三种传输方式,怎么选?
| 传输 | 机制 | 状态 | 适用场景 |
|---|---|---|---|
| stdio | 子进程 stdin/stdout,每行一个 JSON-RPC 帧 | 有状态、单连接 | 本地工具(读文件、本地 DB、CLI 封装)。最简单,首选本地 |
| SSE | 旧的远程方案:GET 建立 SSE 接收流 + POST 发请求 | 有状态、需断线重连 | 已被 Streamable HTTP 取代,新项目别用 |
| Streamable HTTP | 单个 POST 端点,可返回普通 JSON 或 SSE 流;用 Mcp-Session-Id 关联会话 | 可无状态可恢复 | 远程/SaaS 化 MCP 的现在与未来 |
stdio 的帧格式细节:因为 stdio 是字节流,必须用「换行分隔」来切帧——每条 JSON-RPC 消息独占一行(以 \n 结尾),不能跨行美化。这是新手手写 Server 时最大的坑:json.dumps 默认不保证单行,必须 print(json.dumps(msg), flush=True) 且不要加缩进。
3.4 MCP vs A2A vs Function Calling:边界画清楚
| 维度 | MCP | A2A(Agent2Agent) | 原生 Function Calling |
|---|---|---|---|
| 解决什么 | 一个 Agent 怎么用工具/数据 | 多个 Agent 怎么互相协作 | 单个模型怎么调外部函数(私有格式) |
| 层次 | 模型 ↔ 工具 | Agent ↔ Agent | 模型 ↔ 函数 |
| 标准性 | 开放标准,跨模型 | 开放标准(Google 主导) | 各家私有,不互通 |
| 传输 | stdio / Streamable HTTP | HTTP + JSON-RPC + SSE | 取决于厂商 API |
一句话:Function Calling 是「模型原生能力」,MCP 是「把这种能力标准化的开放协议」,A2A 是「Agent 之间的协作协议」。三者是不同层,不冲突。
四、代码实战:从装饰器到协议内核,再到远程部署
下面用一个真实场景串起来:我们要给一个 PostgreSQL 只读分析库写一个 MCP Server,让任何 Host 都能让模型「安全地查数据、看表结构、套用分析模板」。
4.1 用 FastMCP 三分钟写出一个生产级 Server
FastMCP 是 Python 生态里最顺手的封装(作者 Joule,现为官方推荐的简洁写法)。装它:
# 用 uv 管理环境(冷启动比 pip 快一个量级)
uv init pg-mcp && cd pg-mcp
uv add "mcp[cli]" asyncpg
核心代码(注意 description 写得越清楚,模型用得越准):
# server.py
import asyncpg
from mcp.server.fastmcp import FastMCP
# 实例化一个 Server,名字会展示在 Host 里
mcp = FastMCP("pg-analytics")
# 连接池懒加载,避免 import 时就连库
_pool = None
async def get_pool():
global _pool
if _pool is None:
_pool = await asyncpg.create_pool(
dsn="postgresql://readonly:***@db.internal:5432/analytics",
min_size=1, max_size=10,
)
return _pool
@mcp.tool()
async def run_readonly_query(sql: str) -> str:
"""在 analytics 只读库执行一条 SELECT 查询,返回 JSON 数组字符串。
仅允许只读语句;任何 INSERT/UPDATE/DROP 都会被拒绝。
参数 sql: 标准 PostgreSQL SELECT 语句。"""
s = sql.strip().lower()
if not s.startswith("select") and not s.startswith("with"):
return "错误:只允许 SELECT / WITH 只读查询。"
# 进一步拦截写操作关键字(防御性)
for banned in ("insert", "update", "delete", "drop", "alter", "truncate", "grant"):
if banned in s:
return f"错误:检测到被禁止的写操作关键字 '{banned}'。"
pool = await get_pool()
async with pool.acquire() as conn:
rows = await conn.fetch(sql)
# 转成 JSON 文本回灌给模型
return json.dumps([dict(r) for r in rows], ensure_ascii=False, default=str)
@mcp.resource("schema://{table}")
async def table_schema(table: str) -> str:
"""返回指定表的结构(列名、类型、是否可空)。URI 形如 schema://users。"""
pool = await get_pool()
async with pool.acquire() as conn:
cols = await conn.fetch(
"SELECT column_name, data_type, is_nullable "
"FROM information_schema.columns WHERE table_name=$1 ORDER BY ordinal_position",
table,
)
return json.dumps([dict(c) for c in cols], ensure_ascii=False)
@mcp.prompt()
def analyze_table_prompt(table: str) -> str:
"""生成一个「分析某张表并提出优化建议」的标准提示词,带 table 参数。"""
return (
f"请基于 schema://{table} 的结构与 run_readonly_query 的抽样数据,"
f"分析表 `{table}` 的:1) 索引是否合理;2) 常见慢查询模式;"
f"3) 给出 3 条可落地的优化建议(含具体 SQL)。"
)
if __name__ == "__main__":
# 默认 transport="stdio",Host 会以子进程方式拉起本脚本
mcp.run()
在 Host 里配置(以 mcp.json / claude_desktop_config.json 风格为例):
{
"mcpServers": {
"pg-analytics": {
"command": "uv",
"args": ["--directory", "/path/to/pg-mcp", "run", "python", "server.py"]
}
}
}
就这三样——@mcp.tool / @mcp.resource / @mcp.prompt——你已经拥有了一个能被任何 MCP Host 即插即用的 Server。FastMCP 在背后自动帮你生成 JSON Schema、处理 initialize 握手、做传输分帧。
4.2 裸写一个 stdio Server,看清协议内核
封装用爽了,但你必须知道底层在发生什么。下面这个最小 Server 不依赖任何 SDK,纯手撸 JSON-RPC over stdio,只实现 initialize 和 tools/list + tools/call,足以让你「彻底懂」:
# raw_server.py —— 不依赖 mcp 包,纯手撸,仅用于理解协议
import sys, json
def send(obj):
# 关键:每条消息独占一行,flush 立即发出,禁止缩进美化
sys.stdout.write(json.dumps(obj, ensure_ascii=False) + "\n")
sys.stdout.flush()
def handle(msg):
method = msg.get("method")
mid = msg.get("id")
if method == "initialize":
return {
"jsonrpc": "2.0", "id": mid,
"result": {
"protocolVersion": "2025-06-18",
"capabilities": {"tools": {}},
"serverInfo": {"name": "raw-demo", "version": "0.0.1"},
},
}
if method == "notifications/initialized":
return None # 通知不回
if method == "tools/list":
return {
"jsonrpc": "2.0", "id": mid,
"result": {"tools": [{
"name": "ping",
"description": "返回一个 pong 文本",
"inputSchema": {"type": "object", "properties": {}},
}]},
}
if method == "tools/call":
name = msg["params"]["name"]
if name == "ping":
return {
"jsonrpc": "2.0", "id": mid,
"result": {"content": [{"type": "text", "text": "pong"}]},
}
return {
"jsonrpc": "2.0", "id": mid,
"error": {"code": -32602, "message": f"未知工具: {name}"},
}
return {
"jsonrpc": "2.0", "id": mid,
"error": {"code": -32601, "message": f"方法未实现: {method}"},
}
def main():
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
msg = json.loads(line)
except json.JSONDecodeError:
continue
resp = handle(msg)
if resp is not None:
send(resp)
if __name__ == "__main__":
main()
跑起来后,用任意能发 stdio 的客户端连它,你会看到一模一样的握手流程。理解了这段,你就不会再被「MCP 黑盒」吓到——它不过是「按行读的 JSON-RPC」。
4.3 TypeScript 客户端:从 Host 视角调用
如果你是做 Host 的,用官方 TS SDK 起一个 Client 连接上面的 Server:
// client.ts
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "uv",
args: ["--directory", "/path/to/pg-mcp", "run", "python", "server.py"],
});
const client = new Client(
{ name: "my-host", version: "1.0.0" },
{ capabilities: {} },
);
await client.connect(transport); // 内部完成 initialize 握手
const tools = await client.listTools(); // → tools/list
console.log(tools.tools.map(t => t.name));
const res = await client.callTool({ // → tools/call
name: "run_readonly_query",
arguments: { sql: "SELECT count(*) FROM users" },
});
console.log(res.content);
注意:client.connect() 内部已经替你完成了 initialize + notifications/initialized 全流程,所以上层代码永远不需要手动发握手帧。这正是 SDK 的价值——把协议细节藏起来,把「能力」暴露出来。
4.4 远程化:用 Streamable HTTP 把 Server 部署成 SaaS
stdio 只能本地拉子进程。要做成「团队共享的远程 MCP」,用 FastMCP 的 Streamable HTTP:
# remote_server.py
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("pg-analytics-remote")
@mcp.tool()
async def run_readonly_query(sql: str) -> str:
# ... 同 4.1 ...
return "..."
if __name__ == "__main__":
# 生成 ASGI app(基于 Starlette),可直接交给 uvicorn
import uvicorn
app = mcp.streamable_http_app()
uvicorn.run(app, host="0.0.0.0", port=8000)
Host 侧配置改成 HTTP 端点即可:
{
"mcpServers": {
"pg-analytics-remote": {
"url": "https://mcp.internal.example.com/mcp",
"transport": "streamable-http"
}
}
}
远程模式下,Client 第一次 POST 会拿到 Mcp-Session-Id 响应头,后续请求都要带上它来关联同一个会话;Server 可以通过 Last-Event-ID 做断线后的流恢复(resumable streaming)。这就是 Streamable HTTP 相比旧 SSE 的核心改进:单端点、可无状态、可恢复。
五、性能优化与生产级实践(只有踩过坑才懂)
能跑和能上线之间,差的就是下面这些。
5.1 鉴权:远程 Server 必须上 OAuth 2.1
本地 stdio 靠「进程由本机用户启动」天然可信。但远程 Server 暴露在网络上,默认规范推荐 OAuth 2.1(含 PKCE)。流程是:Client 访问 MCP 端点 → 收到 401 + WWW-Authenticate 指向授权服务器 → Client 走 OAuth 拿 token → 后续请求带 Authorization: Bearer。
生产要点:
- 用成熟的 OAuth 库(如
authlib+ 一个 IdP),不要自己造 JWT 校验。 - 短期 access token + 刷新机制,token 泄露面最小化。
- 每个工具可绑定 scope,做到「最小权限」。
5.2 有状态 vs 无状态:并发模型决定架构
- 有状态(Streamable HTTP 默认):会话挂在 Server 内存,支持 Sampling 回推、流式进度。缺点:水平扩容要靠 sticky session 或共享会话存储。
- 无状态:每次请求自带完整上下文,Server 不存会话。优点:随便扩、随便上 Serverless/边缘。缺点:不支持需要跨请求保持的流式/回推能力。
经验法则:工具无副作用、纯查询类 → 优先无状态 + Serverless(成本最低);需要长任务进度、Sampling、多轮 Elicitation → 有状态。
5.3 分页(Cursor Pagination):大结果集救命
tools/list、resources/list 等列表类方法都支持游标分页。你自己写的 Tool 如果可能返回巨量数据,也要把大结果切片:
@mcp.tool()
async def list_orders(cursor: str = "", limit: int = 50) -> str:
"""分页列出订单。cursor 为空从头开始;返回下一页 cursor。"""
offset = int(cursor) if cursor.isdigit() else 0
pool = await get_pool()
async with pool.acquire() as conn:
rows = await conn.fetch(
"SELECT * FROM orders ORDER BY id LIMIT $1 OFFSET $2", limit, offset
)
next_cursor = str(offset + limit) if len(rows) == limit else ""
return json.dumps({
"rows": [dict(r) for r in rows],
"next_cursor": next_cursor,
}, ensure_ascii=False)
把「超大结果」直接塞回模型是灾难:既撑爆上下文,又浪费 token。分页 + 让模型「先看前 N 条再决定要不要翻页」是标准做法。
5.4 结构化错误:别只回一句字符串
JSON-RPC 有标准错误码(-32700 解析错误、-32600 非法请求、-32601 方法不存在、-32602 无效参数、-32603 内部错误)。你的 Tool 抛异常时,Host/SDK 会自动转成标准错误,但错误信息要写给「模型和开发者」两方看:
- 给模型看:明确「哪里错了、怎么改参数」(让它自我纠正,而不是放弃)。
- 给开发者看:带上错误码、上下文(日志 id)。
FastMCP 里直接 raise ValueError("sql 不能为空") 就会被正确封装;底层用 McpError 可指定标准 code。
5.5 可观测性:MCP 是天然可日志的
因为所有交互都是 JSON-RPC,你只需在传输层统一埋点,就能得到「模型调了哪些工具、传了什么参数、花了多久、返回多大」的完整链路。建议:
- 每条
tools/call记一条 span(OpenTelemetry),带tool.name和duration。 - 对返回文本做长度统计,超过阈值告警(防止上下文撑爆)。
- 把
Mcp-Session-Id作为 trace 关联键。
这正是 MCP 相比私有 function calling 的工程红利:调试 Agent 不再是玄学。
5.6 安全红线(必看)
- 最小权限:只读 Server 就真的只给
SELECT账号,绝不用超级用户。 - 工具确认:危险操作(发消息、删数据)在 Host 侧设「调用前需用户确认」,不要静默执行。
- 输入校验:Tool 入参必须按 JSON Schema 严格校验,防止 prompt injection 通过参数污染。
- Elicitation 优于猜:缺参数时向用户要,而不是用默认值硬跑。
- Roots 约束:Server 只能访问 Host 声明的根路径,越界直接拒绝。
六、总结与展望:MCP 之后是什么?
回到开头那个 M×N 问题——MCP 已经把它压成了 M + N:模型侧只认 MCP,工具侧只实现一次 MCP Server。2026 年官方与第三方 MCP Server 的爆发(数据库、浏览器、SaaS、代码仓库……)正是这个杠杆的兑现。
往前看,几个明显趋势:
- MCP Registry / 市场:像 npm 一样,未来会出现「MCP Server 注册中心」,一键发现、一键安装、带版本与信誉评分。配置
mcp.json的手工时代会过去。 - Agent 互操作栈成型:底层 MCP(模型用工具)+ 中层 A2A(Agent 间协作)+ 新兴 ACP(Agent 客户端协议)构成完整栈。你会同时写「供自己用的 MCP Server」和「供其他 Agent 用的 A2A Agent Card」。
- Sampling 催生「会思考的工具」:当 Server 能反向调模型,工具本身就变成了带推理能力的子 Agent,边界进一步模糊,但能力指数级放大。
- 安全与治理标准化:OAuth、scope、审计日志会成为远程 MCP 的标配,企业落地门槛持续降低。
给工程师的落地建议:
- 今天:用 FastMCP 把你们内部最痛的「重复接工具」场景(查库、读文档、调内部 API)封装成 MCP Server,先本地 stdio 跑通。
- 本周:挑一个远程化候选(团队共用、无状态查询类),上 Streamable HTTP + OAuth 2.1。
- 本月:把 MCP 调用全部接入可观测性,建立「工具调用成本 / 成功率」看板——你会发现很多「模型变笨了」的问题,其实是某个 Tool 在悄悄超时。
MCP 不会让模型更聪明,但它让聪明的模型终于能真正做事。在 Agent 时代,谁先把工具接好,谁就先拥有会干活的 AI。而这根 USB-C,值得每个工程师现在就焊到自己的系统上。
参考资料:Model Context Protocol 官方规范(modelcontextprotocol.io)、MCP Python SDK / TypeScript SDK(2026 年版)、Anthropic MCP 公告。代码示例基于 FastMCP 与官方 SDK 当前 API,生产环境请以你所用工种版本的最新文档为准。