给 AI 接了 100 个工具最后全乱了——MCP 协议焊死,从 JSON-RPC 到三大原语一篇打通 Agent 与外部世界的标准接口

本文基于 MCP 协议规范(无状态化、server identity、异步操作等重大更新于 2025-11-25 规范引入,2026 年走向 1.0 稳定阶段),Python SDK 1.26+(FastMCP),TypeScript SDK 1.x。所有代码均经过实机验证。

本文非官方规范文档,内容基于公开资料与实机验证整理,请以 modelcontextprotocol.io 最新规范为准。

注:本文含 Mermaid 流程图,若阅读平台不渲染 Mermaid,请复制到支持 Mermaid 的编辑器(VS Code + Markdown Preview Enhanced、Typora 等)查看。

你是不是也遇到过这种翻车

你给 AI Agent 接了 5 个工具:查数据库、发邮件、读文件、调 Jira、搜索知识库。每个工具单独测都没问题。但上线一周后:

  • 工具越多越蠢。5 个工具的 schema 塞进上下文就占了 4000 token,模型还没干活就先晕了。加到 20 个工具,上下文窗口直接被工具定义占满。
  • 换模型全得重来。你的工具是按 OpenAI Function Calling 格式写的,换 Claude 就不认;换 DeepSeek 又是另一套 schema。N 个模型乘 M 个工具等于 N x M 套适配代码。
  • 工具没法复用。A 团队写了个"查订单"工具,B 团队的 Agent 想用,只能复制代码重新适配。工具成了消耗品,不是资产。
  • 安全审计为零。模型调了什么工具、传了什么参数、返回了什么敏感数据,没有统一记录。出了事故谁也说不清。

根本原因:你用"手写胶水代码"的方式做工具集成,没有标准协议。 就像 USB-C 出现之前,每个设备一根专用充电线,互不通用,抽屉塞满了线还是找不到能用的那根。

MCP(Model Context Protocol,模型上下文协议)就是 AI 时代的 USB-C 接口。

MCP 是什么

MCP 是由 Anthropic 于 2024 年 11 月开源的开放协议,用于标准化 AI 应用连接外部数据源、工具和服务的方式。2025 年 12 月 Anthropic 把它捐给了 Linux Foundation 旗下的 Agentic AI Foundation,从此成为厂商中立、社区治理的标准。Google、OpenAI、微软、亚马逊均为白金会员。

截至 2026 年 8 月:

指标 数值
官方规范版本 日期版本号持续演进(无状态化于 2025-11-25 引入,2026 进入 1.0 稳定)
GitHub Stars(modelcontextprotocol/servers) 86K+
社区公开 MCP Server 数量 10,000+ active(2025-12 官方口径,持续增长)
官方 SDK 月下载量(Python + TypeScript 合计) 9700 万+(2025-12 官方口径)
原生支持的 AI 应用 Claude、ChatGPT、Cursor、VS Code、Cline、Windsurf 等
Python SDK 版本 1.26+(v2 设计中)
TypeScript SDK 版本 1.x
Java SDK 版本 1.0.0(2026 年 3 月)

MCP 的设计灵感

MCP 的架构受 LSP(Language Server Protocol,语言服务器协议)启发。LSP 统一了编辑器和编程语言服务之间的通信——VS Code、Vim、Emacs 不需要为每种语言单独写插件,语言服务也不需要为每个编辑器单独适配。MCP 做的是同样的事,只不过服务对象从"编辑器与语言服务"变成了"AI 应用与外部上下文"。

MCP vs 传统 API 集成

对比维度 传统 Function Calling MCP
协议标准 每个模型自定义 schema 统一开放协议
工具复用 换框架重写 一套 Server 到处接
工具发现 手工注册 启动自动发现
部署方式 与 Agent 同进程 本地子进程 / 远程独立部署
安全审计 无统一方案 OAuth 2.1 + 输入验证
上下文管理 全部塞进 prompt 按需加载,渐进发现
跨模型 不支持 原生支持
N x M 问题 严重 一次实现永久可用

打个比方:传统 Function Calling 像给每个设备焊死一根线——换个插座就得重新焊。MCP 像统一用 USB-C 接口——外设只要符合协议就能即插即用,不用管里面是什么芯片。

核心架构:三大角色

JSON-RPC 2.0

JSON-RPC 2.0

JSON-RPC 2.0

调用

Host(宿主应用)
Claude / Cursor / VS Code

Client 1

Client 2

Client 3

Server 1
文件系统

Server 2
数据库

Server 3
GitHub API

大模型

Host(宿主)

Host 是 AI 应用本身——Claude Desktop、Cursor、VS Code、ChatGPT 或你自定义的 Agent 平台。Host 负责:

  • 管理用户界面和权限控制
  • 创建和管理 Client 实例
  • 聚合来自多个 Server 的上下文
  • 调用大模型并处理响应

Host 就像手机——它是用户直接操作的设备。

Client(客户端)

Client 住在 Host 内部,是连接 Server 的"USB-C 端口"。通常一个 Client 对应一个 Server,负责:

  • 与 Server 建立连接和协议握手
  • 转发工具调用请求
  • 管理安全边界

Client 就像手机上的 USB-C 接口——用户几乎不需要看到它,但它负责说协议、管连接。

Server(服务器)

Server 是提供外部能力的服务进程。它可以暴露文件系统、数据库、API、业务系统或其他工具能力。Server 负责:

  • 注册和暴露 Resources / Tools / Prompts
  • 执行工具调用并返回结果
  • 管理自身资源和状态

Server 就像插进来的外设——U 盘、充电器、显示器,只要接口对了就能用。

能力协商机制

Client 连接 Server 时,双方会先做能力协商(Capability Negotiation):

  1. Client 发送 initialize 请求,声明自己支持的能力(如 sampling、roots)
  2. Server 返回自己支持的能力(如 tools、resources、prompts)
  3. 双方只使用对方声明支持的功能,避免不兼容
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-11-25",
    "capabilities": {
      "roots": { "listChanged": true },
      "sampling": {}
    },
    "clientInfo": { "name": "my-agent", "version": "1.0.0" }
  }
}

协议基础:JSON-RPC 2.0

MCP 的通信协议是 JSON-RPC 2.0——一个轻量级的远程过程调用标准。所有消息都是 JSON 对象,通过三种类型交互:

请求(Request)

客户端发给服务端,期望得到响应:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "get_weather",
    "arguments": { "city": "北京" }
  }
}

响应(Response)

服务端处理完请求后返回:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{ "type": "text", "text": "北京今天晴,25°C" }]
  }
}

通知(Notification)

单向消息,不需要响应(id 字段省略):

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

标准错误码

错误码 含义 说明
-32700 Parse error JSON 解析失败
-32600 Invalid Request 请求格式不合法
-32601 Method not found 方法不存在或不可用
-32602 Invalid params 参数无效
-32603 Internal error 服务器内部错误

生命周期

Server Client Server Client 正常通信阶段 关闭阶段 initialize(声明能力 + 协议版本) initialize 响应(返回 Server 能力) notifications/initialized(确认完成) tools/list(列出工具) 工具列表 tools/call(调用工具) 工具结果 关闭连接

生命周期分三个阶段:

  1. 初始化:Client 发 initialize 请求,双方协商协议版本和能力。Client 发 notifications/initialized 确认。
  2. 正常通信:Client 调用 Server 的工具、读取资源、获取提示词。
  3. 关闭:连接断开,资源释放。

注意:自 2025-11-25 规范起,MCP 最大的变化之一是从有状态(Stateful)转向无状态(Stateless)。旧版依赖的 Session ID 被移除,Server 不再维护会话状态,每次请求都是独立的。这意味着如果你的 Server 依赖了 Session ID,必须迁移。

三大原语:Resources / Prompts / Tools

MCP Server 向 Client 暴露三类核心能力,称为"原语"(Primitives):

MCP Server

Resources(资源)
控制权:应用程序
只读数据

Prompts(提示词)
控制权:用户
模板和工作流

Tools(工具)
控制权:模型
可执行函数

Resources(资源)——应用程序控制

Resources 是只读的上下文数据,由应用程序(Host)决定何时读取。类似于网站上的文件——应用按需拉取。

资源类型

  • 直接资源:file:///path/to/file.txt
  • URI 模板资源:db://tables/{table_name}(参数化)

资源订阅:Client 可以订阅资源变更,当资源内容更新时 Server 主动推送通知。

Python 实现示例

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-server")


@mcp.resource("config://app-settings")
def get_settings() -> str:
    """返回应用配置"""
    return '{"theme": "dark", "language": "zh-CN"}'


@mcp.resource("db://tables/{table_name}")
def get_table_schema(table_name: str) -> str:
    """返回指定表的结构信息"""
    schemas = {
        "users": "id INT, name VARCHAR(100), email VARCHAR(200)",
        "orders": "id INT, user_id INT, amount DECIMAL(10,2), status VARCHAR(20)",
    }
    return schemas.get(table_name, f"表 {table_name} 不存在")

Prompts(提示词)——用户控制

Prompts 是预定义的提示词模板,由用户主动选择使用。类似于 IDE 中的代码模板——用户点一下就插入。

Python 实现示例

@mcp.prompt()
def code_review(language: str, code: str) -> str:
    """生成代码审查提示词"""
    return f"""请审查以下 {language} 代码,关注:
1. 安全漏洞(SQL 注入、XSS、硬编码密钥)
2. 性能问题(N+1 查询、不必要的循环)
3. 代码风格(命名规范、注释完整性)

代码:

{code}

"""

Tools(工具)——模型控制

Tools 是可被大模型调用的函数,由模型自主决定何时调用。这是最常用的原语——模型根据用户意图,自动选择合适的工具执行。

Python 实现示例

@mcp.tool()
def get_weather(city: str) -> str:
    """查询指定城市的当前天气

    Args:
        city: 城市名称,如"北京"、"上海"
    """
    # 实际项目中调用天气 API
    weather_db = {"北京": "晴 25°C", "上海": "多云 28°C"}
    return weather_db.get(city, f"未找到 {city} 的天气信息")


@mcp.tool()
def create_jira_ticket(title: str, description: str, priority: str = "medium") -> str:
    """在 Jira 中创建工单

    Args:
        title: 工单标题
        description: 工单描述
        priority: 优先级(high / medium / low)
    """
    # 实际项目中调用 Jira API
    return f"工单已创建:{title}(优先级:{priority})"

三大原语对比

维度 Resources Prompts Tools
控制权 应用程序 用户 模型
可执行 否(只读) 否(模板) 是(有副作用)
类比 文件 代码模板 函数调用
URI 格式 scheme://path prompt://name 无(Tools 按名称调用,不以 URI 寻址)
谁决定使用 Host 应用程序 用户手动选择 LLM 自主决定
典型场景 读配置、读数据库 schema 代码审查模板、周报模板 查天气、发邮件、创建工单

关键区别:Tools 可以有副作用(写数据库、发邮件、创建资源),Resources 是只读的。Tools 由模型决定调用,Resources 由应用程序决定读取,Prompts 由用户主动选择。

客户端功能

Roots(文件系统根目录)

Roots 是 Client 告诉 Server"你能访问哪些文件系统目录"的机制。Server 只能访问 Client 声明的 Roots 范围内的文件,防止越权访问。

{
  "method": "roots/list",
  "result": {
    "roots": [
      { "uri": "file:///home/user/project", "name": "项目目录" },
      { "uri": "file:///home/user/docs", "name": "文档目录" }
    ]
  }
}

Sampling(采样)

Sampling 是 Client 允许 Server 请求大模型生成文本的能力。这是一种"反向调用"——Server 向 Client 请求 LLM 推理,而不是 Client 向 Server 请求工具执行。

⚠️ 安全约束(务必遵守):Sampling 必须经过用户确认。Server 不能直接调用 LLM,它只能向 Client 发起请求,由 Client 决定是否执行以及用什么模型执行。

传输层

MCP 支持两种传输方式:

传输方式 适用场景 通信机制 部署方式
stdio 本地开发、IDE 集成 标准输入/输出 子进程
Streamable HTTP 远程部署、生产环境 HTTP POST + SSE 流 独立服务

stdio 传输

stdio 是最简单的传输方式——Server 作为 Host 的子进程运行,通过标准输入/输出交换 JSON-RPC 消息。

Python

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-server")

# ... 注册工具、资源、提示词 ...

if __name__ == "__main__":
    mcp.run(transport="stdio")

TypeScript

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const server = new McpServer({ name: "my-server", version: "1.0.0" });

// ... 注册工具 ...

const transport = new StdioServerTransport();
await server.connect(transport);

Streamable HTTP 传输

Streamable HTTP 用于远程部署场景。Server 作为独立的 HTTP 服务运行,Client 通过 HTTP POST 请求发送 JSON-RPC 消息,Server 通过 SSE(Server-Sent Events)流式返回响应。

这是 2025-03 版规范引入的,取代了旧的 HTTP+SSE 双端点方案。自 2025-11-25 规范起进一步无状态化——每个 HTTP 请求都是独立的,Server 不需要维护会话状态。

Python(FastMCP)

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("my-server")

# ... 注册工具 ...

if __name__ == "__main__":
    mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

TypeScript

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import express from "express";

const app = express();
app.use(express.json()); // 必须:解析 POST 的 JSON 请求体,否则 transport.handleRequest 收不到内容
const server = new McpServer({ name: "my-server", version: "1.0.0" });

// ... 注册工具 ...

app.post("/mcp", async (req, res) => {
    const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
    await server.connect(transport);
    await transport.handleRequest(req, res);
});

app.listen(3000);

传输选择指南

场景 推荐传输 原因
IDE 插件、本地工具 stdio 简单、零配置、进程隔离
远程 MCP Server 服务 Streamable HTTP 可远程访问、支持负载均衡
内网企业部署 stdio 数据不出本机,安全性高
公开 API 服务 Streamable HTTP 支持多客户端、可扩展
开发调试 stdio 快速启动、日志直接输出

安全机制

核心安全原则

MCP 的安全设计遵循"最小权限 + 显式同意"原则:

  • Server 只暴露必要的工具。不要把数据库的写权限暴露给一个只读查询的 Agent。
  • 用户必须确认敏感操作。工具调用前,Host 应弹窗让用户确认(尤其是有副作用的操作)。
  • Server 不信任 Client 的输入。所有输入参数必须验证。

身份验证

HTTP 传输(推荐 OAuth 2.1)

近年规范持续强化了对生产环境 OAuth 2.0 与 OIDC 部署的适配。MCP 服务器可以直接连接 Entra(微软企业身份管理)或 Okta 等企业身份系统,无需变通方案。

stdio 传输(环境变量)

stdio 传输不需要协议级身份验证——Server 作为 Host 的子进程运行,信任边界在操作系统层面。敏感信息通过环境变量传递:

import os

api_key = os.environ.get("MY_API_KEY")
if not api_key:
    raise ValueError("缺少 MY_API_KEY 环境变量")

输入验证

所有工具参数都应该验证。FastMCP 基于 Pydantic v2 自动验证类型,TypeScript SDK 用 Zod 做同样的事:

from pydantic import BaseModel, Field


class SearchParams(BaseModel):
    query: str = Field(..., min_length=1, max_length=500, description="搜索关键词")
    limit: int = Field(default=10, ge=1, le=100, description="返回结果数量")


@mcp.tool()
def search(params: SearchParams) -> str:
    """搜索知识库"""
    # FastMCP 自动验证参数,到这里 params 已经是合法的
    return f"搜索 {params.query},返回 {params.limit} 条结果"

安全检查清单

  • Server 只暴露必要的工具和资源
  • 所有工具参数有类型验证和范围约束
  • 敏感操作需要用户确认
  • API Key 通过环境变量传递,不硬编码
  • HTTP 传输启用 OAuth 2.1 身份验证
  • 工具调用有日志审计
  • Server 运行在最小权限的沙箱环境中
  • 定期审查暴露的工具列表

Python SDK 开发指南

安装

pip install mcp

完整服务器示例

from mcp.server.fastmcp import FastMCP
from pydantic import BaseModel, Field
import os
import json

mcp = FastMCP("knowledge-base-server")


# --- Tool:搜索知识库 ---
class SearchParams(BaseModel):
    query: str = Field(..., min_length=1, max_length=500, description="搜索关键词")
    limit: int = Field(default=10, ge=1, le=100, description="返回数量")


@mcp.tool()
def search_knowledge(params: SearchParams) -> str:
    """搜索内部知识库,返回相关文档摘要"""
    # 实际项目中连接向量数据库或搜索引擎
    results = [
        {"title": "MCP 入门指南", "score": 0.95},
        {"title": "FastMCP 最佳实践", "score": 0.88},
    ]
    return json.dumps(results, ensure_ascii=False)


# --- Resource:暴露配置 ---
@mcp.resource("config://server-info")
def get_server_info() -> str:
    """返回服务器配置信息"""
    return json.dumps({
        "name": "knowledge-base-server",
        "version": "1.0.0",
        "tools": ["search_knowledge"],
    }, ensure_ascii=False)


# --- Prompt:代码审查模板 ---
@mcp.prompt()
def review_code(language: str, code: str) -> str:
    """生成代码审查提示词"""
    return f"请审查以下 {language} 代码的安全性和性能:\n\n{code}"


# --- 生命周期管理 ---
@mcp.tool()
def health_check() -> str:
    """健康检查"""
    return "OK"


if __name__ == "__main__":
    # stdio 模式(本地开发)
    mcp.run(transport="stdio")

    # HTTP 模式(远程部署)
    # mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)

上下文注入

FastMCP 支持在工具函数中注入 Context 对象,用于日志记录、进度报告和资源访问:

from mcp.server.fastmcp import FastMCP, Context

mcp = FastMCP("my-server")


@mcp.tool()
async def long_task(query: str, ctx: Context) -> str:
    """长时间运行的任务,带进度报告"""
    await ctx.report_progress(0, "开始处理")

    # 模拟处理步骤
    for i in range(1, 4):
        await ctx.report_progress(i / 3, f"步骤 {i}/3")
        # ... 实际处理逻辑 ...

    await ctx.report_progress(1.0, "处理完成")
    return f"查询 {query} 的结果"

Pydantic v2 关键要点

FastMCP 基于 Pydantic v2 做参数验证,注意以下变化:

  • Field(...) 做参数约束,不用 Field(...) 的旧写法
  • BaseModel.model_validate() 替代了 BaseModel.parse_obj()
  • 类型提示直接写在函数签名里,FastMCP 自动提取 schema

TypeScript SDK 开发指南

安装

npm install @modelcontextprotocol/sdk

完整服务器示例

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const server = new McpServer({
    name: "knowledge-base-server",
    version: "1.0.0",
});

// --- Tool:搜索知识库 ---
server.tool(
    "search_knowledge",
    {
        query: z.string().min(1).max(500).describe("搜索关键词"),
        limit: z.number().int().min(1).max(100).default(10).describe("返回数量"),
    },
    async (params) => {
        const results = [
            { title: "MCP 入门指南", score: 0.95 },
            { title: "TypeScript SDK 实战", score: 0.88 },
        ];
        return {
            content: [{ type: "text", text: JSON.stringify(results) }],
        };
    }
);

// --- Resource ---
server.resource(
    "server-info",
    "config://server-info",
    async () => ({
        contents: [{
            uri: "config://server-info",
            text: JSON.stringify({
                name: "knowledge-base-server",
                version: "1.0.0",
            }),
        }],
    })
);

// --- 启动 ---
const transport = new StdioServerTransport();
await server.connect(transport);

Zod 验证关键要点

TypeScript SDK 用 Zod 做参数验证(对应 Python 的 Pydantic):

  • z.string() / z.number() / z.boolean() 定义基本类型
  • .min() / .max() / .describe() 添加约束和描述
  • Schema 定义直接内联在 server.tool() 参数里,不需要单独的类

最佳实践

命名规范

原语 命名风格 示例
Tool 名称 snake_case get_weathercreate_ticket
Resource URI scheme://path db://tables/usersfile:///path
Prompt 名称 snake_case code_reviewweekly_report
工具描述 清晰准确,说明用途和参数 查询指定城市的当前天气

响应格式

工具返回的内容用 content 数组包装,每项有 type 字段:

# 正常返回:直接返回字符串,FastMCP 会自动包装为 content
return "结果文本"

# 返回错误:抛出业务异常,FastMCP 会将其转为 isError(不要返回原始异常堆栈)
raise ValueError("查询失败:数据库不可用")

# 底层协议说明:MCP 在网络层确实以 {"content": [...], "isError": true} 形态传输,
# 但用 FastMCP 的 @mcp.tool() 装饰器时无需手写该结构,框架自动处理。

分页处理

工具返回大量数据时应该支持分页:

@mcp.tool()
def list_items(cursor: str = None, limit: int = 20) -> str:
    """列出项目,支持分页

    Args:
        cursor: 上一页返回的游标,首次请求不传
        limit: 每页数量
    """
    all_items = load_all_items()  # 实际从数据库加载
    start = int(cursor) if cursor else 0
    page = all_items[start:start + limit]
    next_cursor = str(start + limit) if start + limit < len(all_items) else None
    return json.dumps({
        "items": page,
        "next_cursor": next_cursor,
    }, ensure_ascii=False)

错误处理

@mcp.tool()
def risky_operation(param: str) -> str:
    """有风险的操作"""
    try:
        result = do_something(param)
        return result
    except ValueError as e:
        # 参数错误
        return f"参数错误:{e}"
    except PermissionError as e:
        # 权限不足
        return f"权限不足:{e}"
    except Exception as e:
        # ⚠️ 未知错误:不要暴露内部堆栈细节,返回友好提示
        return f"操作失败,请稍后重试"

代码复用原则

  • 一个 MCP Server 只负责一个领域(如数据库查询、文件管理、消息发送)
  • 通用功能抽成独立函数,不要在多个工具里复制粘贴
  • 配置通过环境变量传入,不要硬编码

生态与社区

官方 MCP 服务器

Anthropic 和社区维护了一批官方 MCP Server,覆盖常见场景:

Server 名称 功能 仓库
filesystem 文件系统读写 modelcontextprotocol/servers
git Git 操作 modelcontextprotocol/servers
github GitHub API modelcontextprotocol/servers
postgres PostgreSQL 查询 modelcontextprotocol/servers
sqlite SQLite 查询 modelcontextprotocol/servers
slack Slack 消息 modelcontextprotocol/servers
google-drive Google Drive modelcontextprotocol/servers
puppeteer 浏览器自动化 modelcontextprotocol/servers
brave-search Brave 搜索 modelcontextprotocol/servers
fetch HTTP 请求 modelcontextprotocol/servers

MCP 客户端

以下应用原生支持 MCP 协议,可以直接连接 MCP Server:

客户端 类型 MCP 支持
Claude Desktop 桌面 AI 助手 原生支持
ChatGPT AI 对话平台 原生支持
Cursor AI IDE 原生支持
VS Code(GitHub Copilot) IDE 原生支持
Cline VS Code 插件 原生支持
Windsurf AI IDE 原生支持
LangChain Agent 框架 原生支持
LlamaIndex Agent 框架 原生支持

协议版本历史

版本 日期 关键变化
初始版本 2024-11-25 Anthropic 开源 MCP
2025-03 2025-03 引入 Streamable HTTP,取代旧 HTTP+SSE
2025-11-25 2025-11-25 重大更新:无状态化、移除 Session ID、server identity、异步操作
1.0 稳定阶段 2026 年 MCP 走向 1.0 稳定,生态持续扩大(具体以官方公告为准)

排坑表

现象 原因 解决
Server 连不上 Client 报 connection refused Server 未启动或端口被占用 检查 Server 进程和端口;stdio 模式检查命令路径
工具不显示 Client 的工具列表为空 Server 未注册工具或 initialize 未完成 确认 @mcp.tool() 装饰器正确使用;检查 initialize 握手
无状态化迁移报错 升级后 Server 连不上 Session ID 被移除(2025-11-25 规范起),有状态 Server 不兼容 移除 Session ID 依赖,改为无状态设计
工具参数验证失败 报 Invalid params Pydantic / Zod 类型不匹配 检查参数类型声明;确保 Client 传的 JSON 类型与 Server 定义一致
stdio 模式无输出 Server 启动了但 Client 收不到数据 print() 输出污染了 stdio 通道 logging 模块记日志,不要用 print();日志输出到 stderr
HTTP 模式跨域 浏览器报 CORS 错误 Server 未配置 CORS 在 HTTP 服务层添加 CORS 中间件
工具太多上下文爆 模型上下文窗口被工具定义占满 全部工具 schema 一次性塞进 prompt 使用渐进发现(Progressive Discovery),按需加载工具定义
OAuth 认证失败 HTTP 模式报 401 Token 过期或配置错误 检查 OAuth 2.1 配置;确认 Token 有效期和刷新机制
Resource URI 不匹配 Client 请求资源返回 404 URI 格式不匹配 Server 注册的模板 确认 URI scheme 和 path 格式一致;检查 URI 模板参数
Pydantic v2 不兼容 报 BaseModel 错误 代码用了 Pydantic v1 的 API 迁移到 v2:model_validate() 替代 parse_obj()model_dump() 替代 dict()

什么情况不该用

简单单工具场景不需要 MCP。 如果你的 Agent 只需要一个工具(比如查天气),直接用 Function Calling 就行。MCP 的价值在于标准化和复用,单个工具引入 MCP 协议纯属过度设计。

对延迟极度敏感的场景要谨慎。 MCP 的 JSON-RPC 通信比直接函数调用多了一层序列化和网络开销。stdio 模式还好,HTTP 模式每个请求都有网络往返。如果要求毫秒级响应,直接内联调用更快。

不需要跨模型复用的项目用不上。 MCP 的核心卖点之一是"一次实现,跨模型通用"。如果你只用一个模型、一个框架,MCP 的标准化收益就不明显——LangChain 的 Tool 抽象已经够用了。

无状态化迁移成本要评估。 自 2025-11-25 规范起,MCP 转向无状态;如果你的 Server 依赖了 Session ID 和有状态连接,迁移到无状态版本需要重构。评估迁移成本和收益后再决定是否升级——旧版本短期内仍然可用。

不要把所有内部 API 都包成 MCP Server。 只把需要被多个 Agent 复用的、有独立业务含义的能力做成 MCP Server。内部的一次性脚本、临时的数据处理逻辑不值得封装。

不要用 MCP 替代普通的 REST API。 MCP 是为 AI Agent 设计的协议,不是通用的 API 网关。如果你的服务只被前端或后端调用、不涉及 AI,用 REST / GraphQL 就行。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐