跳到主要内容

MCP知识体系与实战指南

生成日期:2026-05-09
资料口径:联网核对官方来源后整理。MCP 官方规范当前最新版本为 2025-11-25。优先采用 Model Context Protocol 官方站点、官方 GitHub SDK、Anthropic/OpenAI 官方文档。

阅读目标:先建立 MCP 的完整认知框架,再能独立写一个本地 MCP Server、接入客户端、调试、做安全评审,并判断什么时候该做本地 stdio、什么时候该做远程 Streamable HTTP。


1. 一句话理解 MCP

MCP(Model Context Protocol)是一个开放协议,用标准方式把 LLM 应用连接到外部数据、工具和工作流。

它解决的问题不是“怎么调用某个模型”,而是:

  • LLM 应用如何发现外部能力。
  • 外部系统如何声明可用工具、资源、提示词。
  • 工具参数、返回值、错误、权限、生命周期如何标准化。
  • 本地工具和远程服务如何用统一协议接入不同 AI 客户端。

可以把 MCP 理解为 AI 应用生态里的“上下文与工具连接协议”。类似 LSP 统一编辑器和语言服务的连接方式,MCP 统一 LLM Host 和外部能力的连接方式。


2. 先把术语讲清楚

2.1 三个核心角色

用户
|
v
Host:AI 应用,例如 Claude Desktop、IDE、ChatGPT、内部 Agent 平台
|
| 一个 Host 可以管理多个 MCP Client 连接
v
Client:Host 内部的连接器,每个 Client 通常对应一个 Server 会话
|
| JSON-RPC 2.0 over stdio / Streamable HTTP
v
Server:暴露工具、资源、提示词等能力的程序或远程服务
  • Host:用户实际使用的 AI 产品或 Agent 容器,负责 UI、用户授权、模型调用、连接生命周期。
  • Client:Host 内部实现 MCP 协议的一端,负责与一个 MCP Server 通信。
  • Server:提供能力的一端,可以是本地进程,也可以是远程 HTTP 服务。

2.2 MCP Server 能暴露什么

Server 主要暴露三类能力:

能力控制方用途例子
Tools模型可发起,Host 应要求用户确认高风险动作执行动作、查询 API、计算search_docscreate_ticketquery_db
Resources应用/用户/模型按实现选择读取给模型补上下文文件、数据库 schema、文档片段、日志
Prompts用户显式选择更合理可复用提示词模板代码审查模板、SQL 诊断模板

Client 也可以暴露能力给 Server:

能力方向用途
RootsClient -> Server告诉 Server 可访问的工作区边界
SamplingServer -> Client -> LLMServer 请求 Client 代为调用模型
ElicitationServer -> Client -> 用户Server 通过 Client 向用户要额外信息

3. MCP 的分层知识体系

3.1 Base Protocol

MCP 基于 JSON-RPC 2.0:

  • Request:有 id,期待 Response。
  • Response:同一个 id 返回 resulterror
  • Notification:没有 id,不期待响应。
  • 消息必须 UTF-8 编码。
  • MCP 的 id 不能是 null,同一会话内请求方不能复用请求 ID。

MCP 还规定了生命周期:

  1. Client 建立传输连接。
  2. Client 发送 initialize,声明协议版本、客户端信息、能力。
  3. Server 返回协议版本、服务端信息、能力。
  4. Client 发送 initialized 通知。
  5. 双方进入正常交互阶段。
  6. 结束连接,释放资源。

3.2 Capability Negotiation

MCP 的能力必须协商。不要假设对方支持某功能。

常见能力:

  • Server:toolsresourcespromptsloggingcompletionstasks
  • Client:rootssamplingelicitationtasks

工程原则:

  • Server 没声明 tools,Client 不该调用 tools/list
  • Client 没声明 sampling,Server 不该发 sampling/createMessage
  • 支持 listChanged 才发送列表变更通知。
  • 支持 tasks 才做异步任务增强请求。

3.3 Schema

MCP 大量使用 JSON Schema:

  • 工具输入:inputSchema
  • 工具结构化输出:outputSchema
  • elicitation 表单:受限制的 JSON Schema 子集。
  • 默认 schema dialect:JSON Schema 2020-12
  • 显式 $schema 可以指定别的 dialect,但实现至少应支持 2020-12。

实战建议:

  • 工具参数 schema 要严格,尽量 additionalProperties: false
  • 不要把自然语言描述当校验逻辑。
  • 对外部输入做二次校验,schema 只是第一层。
  • 返回结构化数据时同时提供 structuredContent 和可读 content,兼容旧客户端。

4. 传输层:stdio 与 Streamable HTTP

4.1 stdio

stdio 是本地 MCP Server 最常见的传输方式。

机制:

  • Host/Client 启动 Server 子进程。
  • Client 写 Server 的 stdin。
  • Server 写 stdout。
  • 每行是一条 JSON-RPC 消息。
  • 日志只能写 stderr 或文件,不能写 stdout。

适用场景:

  • 本地文件系统工具。
  • 本地 Git/代码库工具。
  • 只给单个用户本机使用的工具。
  • IDE、桌面应用、CLI Agent。

关键禁忌:

  • Python 不要 print() 到 stdout,除非明确输出 MCP JSON-RPC。
  • TypeScript 不要 console.log() 到 stdout。
  • 日志用 stderr、标准 logging、文件日志。

4.2 Streamable HTTP

Streamable HTTP 是远程/生产部署更重要的传输方式。官方规范中它取代了早期的 HTTP+SSE 传输。

机制:

  • Server 提供一个 MCP endpoint,例如 /mcp
  • Client 用 HTTP POST 发送 JSON-RPC 消息。
  • Server 可以返回 JSON,也可以返回 SSE 流。
  • Client 可以 GET endpoint 来接收 Server 主动消息。
  • 支持 session、恢复、重连、轮询式 SSE。

适用场景:

  • 多用户远程 MCP 服务。
  • 企业内统一工具平台。
  • SaaS 给 AI Host 提供官方 MCP Server。
  • ChatGPT/Claude API 等远程连接。

生产要求:

  • 必须校验 Origin,防 DNS rebinding。
  • 本地 HTTP Server 默认绑定 127.0.0.1,不要裸绑 0.0.0.0
  • 远程 Server 必须做认证授权。
  • 浏览器客户端要正确设置 CORS,并暴露 Mcp-Session-Id

5. Server Features:Tools、Resources、Prompts

5.1 Tools

Tools 是 MCP 最常用、也最危险的能力。它让模型能调用外部函数。

工具定义包含:

  • name:唯一名称,建议只用 ASCII 字母、数字、_-.
  • title:给 UI 展示的人类可读名称。
  • description:功能说明,会影响模型是否调用。
  • inputSchema:参数 JSON Schema。
  • outputSchema:可选,结构化输出 schema。
  • annotations:可选的行为描述,不应被无条件信任。
  • execution.taskSupport:是否支持 task-augmented execution。

常用协议方法:

  • tools/list:列工具。
  • tools/call:调用工具。
  • notifications/tools/list_changed:工具列表变更通知。

工具错误分两类:

  • Protocol Error:未知工具、请求结构错误、协议级错误。
  • Tool Execution Error:业务错误、输入不合法、外部 API 失败,返回 isError: true,模型可能据此自我修正后重试。

设计工具的核心原则:

  • 小而准:一个工具只做一个明确动作。
  • 参数强约束:枚举、格式、范围、必填字段都写进 schema。
  • 描述写“何时使用/何时不用”,不要只写“调用某 API”。
  • 高风险写操作必须让 Host/用户可确认。
  • readwrite 分开,不要一个工具既查又改。
  • 不要把密钥、内部路径、系统提示词塞进 tool description。

5.2 Resources

Resources 是 Server 暴露给 Client 的上下文数据。每个 resource 用 URI 唯一标识。

典型资源:

  • file:///repo/README.md
  • git://repo/commit/abc123
  • db://analytics/schema/orders
  • docs://product/api/auth

常用协议方法:

  • resources/list:列资源。
  • resources/read:读资源内容。
  • resources/templates/list:列参数化 URI 模板。
  • resources/subscribe:订阅资源变更。
  • notifications/resources/updated:资源更新。
  • notifications/resources/list_changed:资源列表更新。

Resource 内容可以是:

  • text:文本。
  • blob:base64 二进制。

实战建议:

  • 大文档不要一次塞完整,优先暴露搜索工具 + fetch 工具。
  • URI 要稳定,便于缓存和引用。
  • MIME type 要准确,例如 text/markdownapplication/json
  • 私有资源必须按用户身份过滤。
  • 不要让 Resource 绕过 Tool 的权限控制。

5.3 Prompts

Prompts 是 Server 提供的可复用提示词模板,通常由用户显式选择。

常用协议方法:

  • prompts/list:列模板。
  • prompts/get:按参数生成 prompt messages。
  • notifications/prompts/list_changed:模板列表变更。

适用场景:

  • 固化高质量工作流,例如“代码审查”“生成迁移方案”“事故复盘”。
  • 把团队内部方法论封装为可选择模板。
  • 将 Resource 嵌入 Prompt,形成可靠上下文。

Prompt 设计建议:

  • 模板参数要少,参数名明确。
  • 输出格式要求写清楚。
  • 不要把敏感策略或密钥写进 prompt。
  • 让用户能看见并选择,而不是暗中自动注入。

6. Client Features:Roots、Sampling、Elicitation

6.1 Roots

Roots 是 Client 告诉 Server 的文件系统边界。

作用:

  • Server 可以知道当前工作区有哪些目录。
  • Server 应只在这些边界内读写。
  • Roots 变更时,Client 可通知 Server。

实战建议:

  • 本地文件工具必须把 roots 当权限边界,而不是 UI 提示。
  • 路径要 canonicalize,防 ..、symlink、大小写绕过。
  • 默认最小权限,只暴露当前项目,不暴露整个 home 目录。

6.2 Sampling

Sampling 允许 Server 请求 Client 代为调用 LLM。

典型用途:

  • Server 内部需要模型判断,但不想持有模型 API key。
  • Server 想把部分推理交给 Host 控制的模型。
  • Server 实现复杂 agentic workflow。

安全原则:

  • 用户应能查看和拒绝 sampling 请求。
  • 用户应能查看/编辑即将发给模型的 prompt。
  • Server 不应假设可以访问任意模型。
  • Client 应控制模型选择、token、权限和可见上下文。

最新规范点:

  • 2025-11-25 增强了 sampling 的 tool calling 支持。
  • includeContext: "thisServer" / "allServers" 属于 soft-deprecated,用时要谨慎。

6.3 Elicitation

Elicitation 允许 Server 通过 Client 向用户索取额外信息。

两种模式:

  • Form mode:Client 展示表单,收集结构化非敏感信息。
  • URL mode:跳转到外部 URL,处理敏感凭据、OAuth、支付等流程。

重点:

  • Form mode 不能索要密码、API key、access token、支付凭据。
  • 敏感信息必须走 URL mode,且用户要看到目标域名并授权跳转。
  • Server 不能只靠 session ID 绑定敏感状态,应绑定真实用户身份或授权上下文。

7. 2025-11-25 规范重点变化

这一版相对 2025-06-18 的关键变化:

  • 增强授权服务器发现,支持 OpenID Connect Discovery。
  • tools/resources/prompts/resource templates 增加 icons 元数据。
  • 授权流增加基于 WWW-Authenticate 的增量 scope consent。
  • 明确工具命名建议。
  • Elicitation enum/schema 更贴近标准 JSON Schema。
  • 新增 URL mode elicitation。
  • Sampling 支持 tool calling。
  • 新增 OAuth Client ID Metadata Documents,作为推荐 client registration 机制之一。
  • 新增实验性 Tasks,用于持久请求、轮询和延迟结果获取。
  • JSON Schema 2020-12 成为默认 dialect。
  • Streamable HTTP 的 Origin 校验、SSE 轮询/恢复说明更明确。
  • 安全最佳实践更新。

8. Tasks:异步和长任务

Tasks 是 2025-11-25 新增的实验能力,适合耗时任务。

适用场景:

  • 大文件索引。
  • 批量数据导入。
  • 长时间报表计算。
  • 异步外部 API workflow。

基本模型:

  1. 请求方在原请求参数里加 task
  2. 接收方立即返回 taskId 和状态。
  3. 请求方用 tasks/get 查状态。
  4. 完成后用 tasks/result 取结果。
  5. 可选 notifications/tasks/status 主动通知状态变化。
  6. 可用 tasks/cancel 取消。

状态:

  • working
  • input_required
  • completed
  • failed
  • cancelled

安全要求:

  • taskId 必须不可预测。
  • 有授权上下文时,task 必须绑定用户/客户端身份。
  • tasks/list 只能返回当前请求方有权访问的任务。
  • 没有身份绑定能力的服务,不建议声明 tasks.list
  • 设置 TTL、并发上限、轮询限流、审计日志。

9. 授权与安全体系

9.1 授权

MCP Authorization 主要针对 HTTP-based transport。stdio 不走这套授权,通常从环境变量或本地配置取凭据。

HTTP MCP 中:

  • MCP Server 作为 OAuth Resource Server。
  • MCP Client 作为 OAuth Client。
  • Authorization Server 负责用户认证和发 token。
  • 规范基于 OAuth 2.1、RFC 8414、RFC 7591、RFC 9728、OAuth Client ID Metadata Documents 等标准子集。

生产建议:

  • 远程 MCP Server 默认要求 HTTPS。
  • token audience 必须绑定到 MCP Server。
  • 不要做 token passthrough。
  • scope 最小化。
  • 每个用户、每个客户端、每个下游 API 单独记录授权关系。

9.2 高风险攻击面

风险解释防护
Prompt Injection外部网页/邮件/文档夹带恶意指令,诱导模型调用工具泄露数据工具最小权限、写操作确认、敏感数据隔离、输出过滤
Confused DeputyMCP proxy 代用户访问第三方 API 时,被恶意 client 借权per-client consent、严格 redirect URI、CSRF state、scope 展示
Token PassthroughServer 接受不是发给自己的 token 并转发禁止;校验 issuer/audience/scope
SSRF恶意 Server 让 Client 拉内网/metadata URLHTTPS、私网 IP 阻断、redirect 校验、egress proxy
Session Hijacking攻击者拿到 session ID 后冒用session 不当认证凭据;绑定用户;安全随机;过期轮换
Local Server Compromise一键安装/启动本地恶意命令展示完整命令、用户确认、危险命令警告、沙箱
Tool Definition Abuse工具描述或 annotation 欺骗 Host/模型不信任未知 Server 的 annotations;用户确认高风险操作

9.3 安全评审清单

上线前逐项检查:

  • Server 来源可信,依赖包可信。
  • 本地 stdio Server 没有向 stdout 写日志。
  • HTTP Server 校验 Origin
  • 本地 HTTP Server 只绑定 127.0.0.1
  • 远程 HTTP Server 只走 HTTPS。
  • 每个 tool 都有严格 inputSchema
  • 写操作 tool 独立命名,且明显可识别。
  • destructive 操作需要用户确认。
  • 不在 tool description/resource/prompt 中暴露密钥。
  • 不接受未发给本 MCP Server 的 token。
  • token 校验 issuer、audience、scope、expiry。
  • task、session、resource 都绑定用户授权上下文。
  • SSRF 防护覆盖 OAuth metadata discovery 和 redirect。
  • 日志脱敏,避免记录 access token、API key、用户隐私。
  • 对外部 API 设置 timeout、重试、限流、熔断。
  • 有审计日志:谁在什么时候调用了什么 tool,输入输出摘要是什么。

10. 实战一:Python 写一个本地 MCP Server

目标:写一个本地知识库工具,暴露两个工具:

  • search_notes(keyword):搜索当前目录下 .md 文件名和内容。
  • read_note(path):读取指定 Markdown 文件。

10.1 创建项目

uv init mcp-notes-server
cd mcp-notes-server
uv add "mcp[cli]"

10.2 写 server.py

from pathlib import Path
from typing import Any

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("notes-server")

ROOT = Path.cwd().resolve()


def safe_path(path: str) -> Path:
candidate = (ROOT / path).resolve()
if ROOT not in candidate.parents and candidate != ROOT:
raise ValueError("path is outside the allowed workspace")
return candidate


@mcp.tool()
def search_notes(keyword: str, limit: int = 20) -> list[dict[str, Any]]:
"""Search markdown notes in the current workspace by keyword."""
if not keyword.strip():
raise ValueError("keyword must not be empty")

results: list[dict[str, Any]] = []
for file in ROOT.rglob("*.md"):
if len(results) >= limit:
break
try:
text = file.read_text(encoding="utf-8", errors="ignore")
except OSError:
continue
if keyword.lower() in file.name.lower() or keyword.lower() in text.lower():
results.append(
{
"path": str(file.relative_to(ROOT)),
"title": file.stem,
"preview": text[:300],
}
)
return results


@mcp.tool()
def read_note(path: str) -> str:
"""Read a markdown note by relative path within the workspace."""
file = safe_path(path)
if file.suffix.lower() != ".md":
raise ValueError("only markdown files are allowed")
if not file.exists() or not file.is_file():
raise FileNotFoundError("file not found")
return file.read_text(encoding="utf-8", errors="ignore")


@mcp.resource("notes://index")
def notes_index() -> str:
"""List markdown files in the workspace."""
files = sorted(str(p.relative_to(ROOT)) for p in ROOT.rglob("*.md"))
return "\n".join(files)


@mcp.prompt()
def summarize_note(path: str) -> str:
return (
"请阅读这篇笔记,输出:核心观点、关键概念、可行动清单、"
f"未解决问题。笔记路径:{path}"
)


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

10.3 本地运行

uv run server.py

stdio Server 直接运行后会等待 MCP JSON-RPC 输入,不会像普通 Web 服务那样输出提示信息。

10.4 用 MCP Inspector 调试

npx @modelcontextprotocol/inspector uv --directory /ABSOLUTE/PATH/mcp-notes-server run server.py

在 Inspector 里检查:

  • Tools tab 是否出现 search_notesread_note
  • Resource tab 是否出现 notes://index
  • Prompt tab 是否出现 summarize_note
  • 调用 search_notes 是否返回结构清晰结果。
  • 输入非法路径,例如 ../../.ssh/id_rsa,是否被拒绝。

10.5 接入 Claude Desktop

macOS 配置文件:

~/Library/Application Support/Claude/claude_desktop_config.json

Windows 配置文件:

%APPDATA%\Claude\claude_desktop_config.json

示例:

{
"mcpServers": {
"notes": {
"command": "uv",
"args": [
"--directory",
"/ABSOLUTE/PATH/mcp-notes-server",
"run",
"server.py"
]
}
}
}

重启 Claude Desktop 后,让它搜索某个关键词或读取某篇笔记。


11. 实战二:TypeScript 写一个 MCP Server

适用:Node.js 生态、npm 分发、前端/平台团队更熟悉 TypeScript 的情况。

版本注意:TypeScript SDK 官方仓库的 main README 已经展示 v2 分包 API,并明确说明 v2 仍处于 pre-alpha;同时仓库 release 页显示 v1.x 仍是生产推荐线。下面示例按当前官方 README 的 v2 分包 API 编写,用于学习最新结构;生产项目应根据目标 Host 和 SDK 稳定性,优先 pin 官方推荐的稳定 v1.x,或在评估后再使用 v2。

11.1 创建项目

mkdir mcp-notes-ts
cd mcp-notes-ts
npm init -y
npm install @modelcontextprotocol/server zod@4
npm install -D typescript @types/node

package.json

{
"type": "module",
"scripts": {
"build": "tsc"
}
}

tsconfig.json

{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"outDir": "dist",
"rootDir": "src",
"strict": true,
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}

11.2 写 src/index.ts

import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { readFile, readdir } from "node:fs/promises";
import { resolve, relative, join } from "node:path";
import * as z from "zod/v4";

const root = process.cwd();

function safePath(input: string): string {
const candidate = resolve(root, input);
const rel = relative(root, candidate);
if (rel.startsWith("..") || rel === ".." || rel.startsWith("/")) {
throw new Error("path is outside the allowed workspace");
}
return candidate;
}

async function listMarkdownFiles(dir: string): Promise<string[]> {
const entries = await readdir(dir, { withFileTypes: true });
const files: string[] = [];

for (const entry of entries) {
const full = join(dir, entry.name);
if (entry.isDirectory()) {
files.push(...(await listMarkdownFiles(full)));
} else if (entry.isFile() && entry.name.endsWith(".md")) {
files.push(full);
}
}

return files;
}

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

server.registerTool(
"read_note",
{
description: "Read a markdown note by relative path inside the current workspace.",
inputSchema: z.object({
path: z.string().min(1),
}),
},
async ({ path }) => {
const full = safePath(path);
if (!full.endsWith(".md")) {
return {
isError: true,
content: [{ type: "text", text: "Only markdown files are allowed." }],
};
}
const text = await readFile(full, "utf8");
return {
content: [{ type: "text", text }],
};
},
);

server.registerTool(
"list_notes",
{
description: "List markdown note paths in the current workspace.",
inputSchema: z.object({}),
},
async () => {
const files = await listMarkdownFiles(root);
const paths = files.map((file) => relative(root, file));
return {
structuredContent: { paths },
content: [{ type: "text", text: JSON.stringify({ paths }, null, 2) }],
};
},
);

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

11.3 构建和调试

npm run build
npx @modelcontextprotocol/inspector node dist/index.js

stdio 模式下不要用 console.log() 打日志;需要日志用 console.error()


12. 实战三:远程 Streamable HTTP Server

Python 官方 SDK 支持 Streamable HTTP:

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("remote-notes", stateless_http=True, json_response=True)


@mcp.tool()
def ping() -> dict[str, str]:
"""Health check tool."""
return {"status": "ok"}


if __name__ == "__main__":
mcp.run(transport="streamable-http")

默认路径通常是:

http://localhost:8000/mcp

远程上线要补齐:

  • TLS/HTTPS。
  • OAuth 或企业内认证。
  • Origin 校验。
  • CORS 白名单。
  • rate limit。
  • structured logs。
  • health check。
  • per-user authorization。
  • deployment secrets 管理。

13. 实战四:给 OpenAI / Anthropic 这类 Host 使用

13.1 Anthropic Messages API MCP connector

Anthropic 官方 Messages API 支持直接连接远程 MCP Server,但有边界:

  • 需要 beta header。
  • 支持远程 URL Server。
  • 目前重点支持 MCP tools。
  • 本地 stdio Server 不能被 API 直接连接。
  • 可配置 allowlist/denylist/per-tool settings。
  • OAuth token 由 API 调用方先获取并传入。

适合:

  • 你有公网 HTTPS MCP Server。
  • 你只需要暴露工具给 Claude API。
  • 不需要 Client 侧 roots、本地文件、prompts/resources 的完整控制。

13.2 OpenAI ChatGPT Apps / Responses API

OpenAI 官方文档中,远程 MCP Server 可用于 ChatGPT Apps、deep research、API integrations。

典型数据类 MCP Server 需要实现:

  • search:返回候选结果。
  • fetch:按 ID 拉取完整内容和引用。

Responses API 使用 MCP 工具时,核心配置类似:

{
"tools": [
{
"type": "mcp",
"server_label": "docs",
"server_url": "https://example.com/sse/",
"allowed_tools": ["search", "fetch"],
"require_approval": "never"
}
]
}

注意:

  • Deep research/API 场景通常要求远程可访问。
  • 对自定义 MCP Server 要格外关注 prompt injection 和写操作风险。
  • 不要连接未知第三方代理的“某某官方服务 MCP”,优先选择服务商自己托管的官方 Server。

14. MCP Server 设计范式

14.1 工具粒度

差设计:

manage_database(query: string)

问题:权限过大、语义不清、不可审计。

好设计:

list_tables()
describe_table(table: enum)
run_readonly_query(sql: string)
create_report(name: string, query_id: string)

优势:

  • Host 能做更清晰的权限和确认。
  • 模型更容易选对工具。
  • 日志和审计更准确。
  • 更容易做 schema 校验。

14.2 Read 与 Write 分离

只读工具:

  • search_docs
  • get_customer
  • list_orders
  • preview_email

写操作工具:

  • send_email
  • refund_order
  • delete_file
  • create_jira_ticket

写操作必须:

  • 名称明确。
  • 参数明确。
  • 支持 dry-run 或 preview。
  • 有用户确认。
  • 有幂等键或重复提交保护。

14.3 Search + Fetch 模式

面向文档、知识库、RAG 的 MCP Server 推荐采用:

  1. search(query, filters):返回短列表,包含 id/title/url/snippet
  2. fetch(id):返回完整内容、引用、元数据。

好处:

  • 降低上下文浪费。
  • 便于 deep research 类 Host 多轮检索。
  • 结果可引用。
  • 权限更容易按文档粒度控制。

14.4 Structured Output

如果工具返回数据给后续程序使用,应提供结构化输出:

{
"structuredContent": {
"order_id": "ord_123",
"status": "paid",
"amount": 199.0
},
"content": [
{
"type": "text",
"text": "{\"order_id\":\"ord_123\",\"status\":\"paid\",\"amount\":199.0}"
}
]
}

同时保留 content 是为了兼容旧客户端和模型可读性。


15. 调试方法论

15.1 先用 Inspector

npx @modelcontextprotocol/inspector <command> <args>

检查项:

  • initialize 是否成功。
  • capabilities 是否符合预期。
  • tools/resources/prompts 是否能列出来。
  • tool schema 是否正确。
  • 非法输入是否返回 isError: true 或合理协议错误。
  • stdout 是否被日志污染。
  • notifications 是否正常。

15.2 再接真实 Host

连接真实 Host 前先确认:

  • 绝对路径正确。
  • 运行命令在普通终端能启动。
  • 依赖已安装。
  • 环境变量存在。
  • API key 不写进配置文件。
  • Server 不依赖交互式输入。

15.3 常见问题

问题可能原因处理
Host 找不到工具Server 未启动、initialize 失败、capability 未声明用 Inspector 看握手
JSON parse errorstdout 混入日志日志改 stderr
tool 调用后无响应外部 API 卡住timeout、错误捕获
路径读取越权未做 canonicalizeresolve 后检查 roots
HTTP 被网页攻击未校验 Origin403 拒绝非法 Origin
Claude/ChatGPT 不调用工具描述不清、schema 太宽、工具名不语义化重写 tool description

16. 学习路线

阶段 1:基本认知

  • 搞清 Host / Client / Server。
  • 理解 tools/resources/prompts。
  • 理解 stdio 和 Streamable HTTP。
  • 用 Inspector 连一个现成 filesystem server。

阶段 2:本地实战

  • 写一个 Python FastMCP Server。
  • 暴露 2 个只读工具。
  • 接入 Claude Desktop 或支持 MCP 的 IDE。
  • 加路径安全检查。

阶段 3:生产化

  • 改造成 Streamable HTTP。
  • 加 OAuth 或内部认证。
  • 加结构化日志、审计、限流、监控。
  • 做 tool 风险分级。

阶段 4:生态集成

  • 适配 OpenAI/Anthropic 的远程 MCP 接入。
  • 实现 search/fetch 模式。
  • 发布 server metadata。
  • 设计企业内部 MCP Registry 或聚合层。

17. 权威资料索引

官方规范与文档:

官方 SDK:

主流平台官方接入文档:


18. 最后给一个判断框架

当你想做一个 MCP 集成时,先回答这 8 个问题:

  1. 这是本地能力还是远程服务?
  2. 主要是只读数据,还是会执行写操作?
  3. 用 tools、resources、prompts 中的哪一种最自然?
  4. 是否需要 search/fetch 两段式?
  5. 是否需要用户授权、OAuth、scope?
  6. 是否有 prompt injection 后可能造成的数据泄漏或破坏?
  7. 是否有长任务,需要 Tasks?
  8. 目标 Host 支持哪些 MCP 能力?不要只按协议理想状态设计。

最保守的默认方案:

  • 本地个人工具:stdio + 最小 roots + Inspector 调试。
  • 企业内部工具:Streamable HTTP + OAuth/SSO + 审计日志 + allowlist。
  • 文档知识库:search + fetch + read-only tools + 引用元数据。
  • 有写操作的业务系统:read/write 分离 + preview + confirmation + idempotency key。