从 0 开发
MCP Server
大模型再聪明,没有外部工具也只能「纸上谈兵」——查不了实时股价、改不了本地文件、连不上内网数据库。Model Context Protocol(MCP) 把「AI 能调什么」写成标准协议,让你写一次 Server、多 Host 复用。本文面向全栈开发者与 Agent 工程师,从环境搭建到生产部署,覆盖 Tools / Resources / Prompts 全实现、MCP 对比 Function Calling 决策表、ChromaDB 知识库实战,以及五步 Mac 隔离开发验收清单。
📋 本文目录
01 · 引言:AI 缺工具,MCP 来补
2026 年的 Agent 已经能写代码、做推理、规划多步任务,但没有外部工具就仍是封闭系统:它不知道你 Git 仓库里最新的 PR 状态,无法替你执行 SELECT * FROM orders WHERE status='pending',更不能在 Slack 里 @同事。传统做法是每家模型宿主各自实现 Function Calling,每个 SaaS 又要为 Claude、GPT、Gemini 写一套适配器——集成成本随 N×M 线性爆炸。
MCP(Model Context Protocol) 由 Anthropic 于 2024 年 11 月开源,定位是「大模型与外部世界的 USB-C 插头」:你实现一个符合规范的 Server,Cursor、Claude Desktop、OpenClaw 等 Host 都能加载,无需重复写胶水。若你已读过站内 MCP 为何成为 AI 时代的 HTTP 协议,本文是它的动手版——从 pip install mcp 到 Docker 上线,全程可跟做。
本文结构:三大开发痛点 → MCP 架构与 JSON-RPC 生命周期 → 对比 OpenAI FC / LangChain 决策表 → Hello World → Tools → Resources → Prompts 递进实现 → HTTP+SSE 部署 → ChromaDB 知识库实战 → Mac 隔离开发验收。
02 · 三大开发痛点
1. 每家宿主一套工具方言。 OpenAI 的 tools 数组、Anthropic 的 tool_use 块、Google 的 Function Declaration——Schema 字段名、错误回传格式各不相同。把同一个「查订单」能力接到三个宿主,往往要写三份包装层。MCP 把工具注册、能力描述、调用语义统一到 JSON-RPC,Write Once, Run Everywhere。
2. 本地凭证与权限边界模糊。 MCP Server 常需读文件系统、调内网 API、持有 OAuth Token。在主力笔记本混装十几个 Server 与多款 IDE,一次误配就可能把生产 Key 写进测试 cron。与 OpenClaw MCP 接入与安全配置 同理,需要可丢弃的沙箱环境先验收再上线。
3. 调试链路长、错误难定位。 从 Host 发起到 Server 执行,中间经过 Client 转发、STDIO 管道或 HTTP 长连接——任何一环配置错误都表现为「工具不可用」或「Connection closed」。没有 Inspector 与单元测试,排查往往靠猜。
03 · 什么是 MCP:架构与演进
从 Function Calling 到 MCP 的三段演进
第一阶段(2023):Function Calling。 OpenAI 在 GPT-4 中引入工具调用,模型输出 JSON 指定函数名与参数,由应用层执行。问题是 Schema 嵌在 Prompt 或闭源 SDK,无法跨宿主复用。
第二阶段(2024 初):Plugins / Actions。 ChatGPT Plugins、GPT Actions 把 HTTP 端点包装成工具,降低了接入门槛,但仍是宿主私有生态,且依赖 OpenAPI 静态描述,Agent 无法在运行时动态发现新 Server。
第三阶段(2024 11 月至今):MCP。 Anthropic 发布开放规范 + 参考 SDK,Host / Client / Server 三层解耦,10,000+ 社区 Server 在 18 个月内涌现,OpenAI、Google、Microsoft 于 2026 年全线跟进。
Client-Server 架构与三大能力
┌─────────────────────────────────────────────────────────────┐
│ Host(Cursor / Claude Desktop / OpenClaw) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ MCP Client │ │ MCP Client │ │ MCP Client │ │
│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
└─────────┼────────────────┼────────────────┼─────────────────┘
│ JSON-RPC │ JSON-RPC │ JSON-RPC
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ MCP Server A │ │ MCP Server B │ │ MCP Server C │
│ Tools │ │ Resources │ │ Prompts │
│ Resources │ │ Tools │ │ Tools │
└──────────────┘ └──────────────┘ └──────────────┘
- Tools(工具):模型可主动调用的函数,如
read_file、query_database、send_http_request。带 JSON Schema 输入描述,返回结构化或文本结果。 - Resources(资源):模型可被动读取的上下文,如配置文件、日志片段、数据库 schema 快照。通过 URI 标识(
file:///project/README.md),由 Client 按需拉取。 - Prompts(提示模板):预置的多轮对话模板,如「代码审查」「SQL 生成」,Host 可一键注入,减少重复 Prompt 工程。
JSON-RPC 2.0 与传输层
所有 MCP 消息统一为 JSON-RPC 2.0。常见方法包括 initialize、tools/list、tools/call、resources/list、resources/read、prompts/list、prompts/get。
// 连接生命周期:initialize → initialized → 业务调用 → 关闭// 1. Client 发起握手{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": { "name": "cursor", "version": "1.0" } } }// 2. Server 响应能力集{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2024-11-05", "capabilities": { "tools": {} }, "serverInfo": { "name": "my-server", "version": "0.1.0" } } }// 3. 调用工具{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "say_hello", "arguments": { "name": "MacDate" } } }
传输层两种主流模式:STDIO(Host 以子进程拉起 Server,stdin/stdout 传 JSON-RPC,适合本地开发)与 HTTP + SSE(远程 Server、多租户网关,Client 通过 SSE 收 Server 推送)。2026 年规范还引入了 Streamable HTTP,进一步简化双向流式通信。
04 · MCP vs OpenAI FC vs LangChain 对比表
选型时常见疑问:「我已有 OpenAI Function Calling,还要 MCP 吗?」「LangChain Tool 够不够用?」下表从架构师视角对比三者:
| 维度 | OpenAI Function Calling | LangChain Tools | MCP |
|---|---|---|---|
| 定位 | 单模型宿主内置能力 | Python 框架层工具抽象 | 跨宿主开放协议 |
| 发现机制 | 静态 Schema 嵌入请求 | 代码内注册,运行时枚举 | 运行时 tools/list(机读) |
| 跨 Host 复用 | 仅 OpenAI API / ChatGPT | 需重写各宿主适配器 | 一次实现,多 Host 加载 |
| Resources / Prompts | 无原生支持 | 通过 Retriever / Template 模拟 | 协议级一等公民 |
| 传输 | HTTP API 内嵌 | 进程内调用 | STDIO / HTTP+SSE / Streamable HTTP |
| 生态规模(2026 中) | 宿主私有 | 数千 PyPI 集成 | 10,000+ Server |
| 适用场景 | 纯 OpenAI 栈快速验证 | 自研 Agent 框架内编排 | 多 Host、企业 Catalog、长期维护 |
硬核数据快照: 采用 MCP 统一工具层的团队,报告集成成本下降 38%–55%;同一 Server 接到 Cursor 与 Claude Desktop 的重复开发工作量减少约 70%;公网扫描显示未授权暴露的 MCP Server 约 1,000+——部署前必须在隔离环境验收权限边界。
05 · 开发环境搭建
Python vs TypeScript 选型
官方 SDK 覆盖 Python(mcp) 与 TypeScript(@modelcontextprotocol/sdk)。Python 侧 FastMCP 装饰器语法简洁,适合数据工程与 AI 脚本;TypeScript 适合 Node 生态与前端团队。本文以 Python + FastMCP 为主,TS 读者可对照 SDK 文档平移概念。
虚拟环境与项目结构
mkdir my-mcp-server && cd my-mcp-serverpython3 -m venv .venvsource .venv/bin/activatepip install "mcp[cli]" pydantic httpx chromadb
推荐目录结构:
my-mcp-server/├── server.py # FastMCP 入口├── tools/ # 各工具模块│ ├── calculator.py│ ├── filesystem.py│ ├── http_client.py│ ├── database.py│ └── datetime_tool.py├── resources/ # Resource 处理器├── prompts/ # Prompt 模板├── tests/ # pytest 单元测试├── pyproject.toml└── Dockerfile
MCP Inspector、Cursor 与 Claude Desktop
MCP Inspector 是官方调试 UI,可独立连接 STDIO 或 HTTP Server,可视化 tools/list 与 tools/call:
npx @modelcontextprotocol/inspector python server.py
Cursor 在 ~/.cursor/mcp.json(或项目级 .cursor/mcp.json)注册 Server。Claude Desktop 使用 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)。二者格式类似,下文 Hello World 节给出完整示例。
06 · Hello World:第一个 MCP Server
用 FastMCP 实现最小可运行 Server,包含一个 say_hello 工具:
# server.pyfrom mcp.server.fastmcp import FastMCPmcp = FastMCP("hello-server")@mcp.tool()def say_hello(name: str = "World") -> str: """向指定名称打招呼。""" return f"Hello, {name}! MCP Server is running."if __name__ == "__main__": mcp.run()
本地启动与 Inspector 验证:
python server.py# 另开终端npx @modelcontextprotocol/inspector python server.py
在 Inspector 中点击 Connect → List Tools → 调用 say_hello 并传入 {"name": "MacDate"},应返回问候语。
Cursor 配置示例
// ~/.cursor/mcp.json{ "mcpServers": { "hello-server": { "command": "/path/to/my-mcp-server/.venv/bin/python", "args": ["/path/to/my-mcp-server/server.py"] } }}
Claude Desktop 配置结构相同,路径改为上述 macOS 配置文件。重启 Host 后,在对话中应能看到 say_hello 工具可用。若你同时在 OpenClaw 网关侧管理 MCP,请对照 OpenClaw MCP 接入与安全配置 统一审批模板。
07 · Tools:五种典型工具实现
Tool 结构与 Pydantic 输入校验
FastMCP 用 Python 类型注解自动生成 JSON Schema。复杂参数可用 Pydantic BaseModel:
from pydantic import BaseModel, Fieldclass CalcInput(BaseModel): expression: str = Field(description="数学表达式,如 2+3*4")@mcp.tool()def calculator(input: CalcInput) -> str: """安全计算器,仅允许数字与四则运算。""" import re if not re.match(r'^[\d\s+\-*/().]+$', input.expression): raise ValueError("非法字符") return str(eval(input.expression))
五种工具一览
| 工具名 | 用途 | 关键实现 |
|---|---|---|
calculator |
安全四则运算 | 正则白名单 + eval 沙箱 |
read_file |
读取工作区文件 | 路径规范化 + 根目录约束 |
http_get |
代理 HTTP 请求 | httpx 异步 + 超时/域名白名单 |
query_db |
只读 SQL 查询 | sqlite3 / asyncpg + 参数化 |
current_time |
返回指定时区时间 | zoneinfo + ISO 8601 格式 |
文件工具示例
from pathlib import PathWORKSPACE = Path("/safe/workspace").resolve()@mcp.tool()def read_file(path: str) -> str: """读取工作区内文件内容。""" target = (WORKSPACE / path).resolve() if not str(target).startswith(str(WORKSPACE)): raise ValueError("路径越界") return target.read_text(encoding="utf-8")
异步工具与错误处理
IO 密集型工具应使用 async def,FastMCP 会自动调度:
@mcp.tool()async def http_get(url: str) -> str: """GET 请求,5 秒超时。""" import httpx async with httpx.AsyncClient(timeout=5.0) as client: try: resp = await client.get(url) resp.raise_for_status() return resp.text[:8000] except httpx.HTTPError as e: return f"HTTP 错误: {e}"
错误应返回可读文本而非裸抛异常(除非参数校验失败),便于模型在对话中向用户解释并重试。
08 · Resources:只读上下文
Resource vs Tool 的分工
Tool 是模型主动决策调用的动作(副作用:写文件、发 HTTP、改数据库)。Resource 是模型按需读取的上下文(无副作用:配置文件、schema 文档、日志 tail)。Host 可在对话开始时预拉 Resource,减少 Token 浪费。
URI Scheme 与静态/动态 Resource
- 静态 Resource:固定 URI,如
config://app/settings.json,内容相对固定。 - 动态 Resource:URI 带参数或使用 Resource Template,如
log://app/{date},内容随请求变化。 - 文件系统 Server:官方
@modelcontextprotocol/server-filesystem将目录映射为file://Resource,适合只读暴露项目文档。
@mcp.resource("config://app/settings")def get_settings() -> str: """返回应用配置 JSON。""" import json return json.dumps({"env": "production", "debug": False})@mcp.resource("schema://db/{table_name}")def get_table_schema(table_name: str) -> str: """动态返回指定表的 DDL。""" return f"CREATE TABLE {table_name} (...);"
09 · Prompts:可复用对话模板
Prompts 让 Host 一键注入多轮对话结构,减少重复 Prompt 工程。与 Cursor 的 Agent Skill 互补:Skill 编排「何时用什么能力」,MCP Prompt 提供「标准对话骨架」。
@mcp.prompt()def code_review_prompt(language: str = "Python") -> str: """生成代码审查 Prompt 模板。""" return f"""你是一位资深 {language} 代码审查专家。请按以下结构审查用户提交的代码:1. 安全漏洞(SQL 注入、路径遍历、密钥硬编码)2. 性能问题(N+1 查询、阻塞 IO)3. 可读性与命名4. 测试覆盖建议请用中文输出,每条发现附带行号与修复建议。"""
多轮 Prompt 可通过返回多条 Message 实现:FastMCP 支持 list[PromptMessage],第一条设 system 角色,后续设 user 角色,Host 按序注入对话历史。
10 · HTTP 传输与安全
STDIO vs HTTP+SSE 对比
| 维度 | STDIO | HTTP + SSE | Streamable HTTP(2026) |
|---|---|---|---|
| 部署位置 | 本地子进程 | 远程服务器 / 容器 | 远程,单端点双向流 |
| 多 Client 共享 | 每 Host 独立进程 | 多 Client 连同一 Server | 同左,连接管理更简 |
| 认证 | 进程级(谁启动谁负责) | Bearer Token / mTLS / OAuth | 同 HTTP+SSE |
| 适用场景 | 桌面 Host、敏感本地工具 | 企业内网、SaaS 网关 | 新部署首选 |
| 负载均衡 | 不适用 | 需会话粘性 | 改进中 |
HTTP Server 启动示例(FastMCP):
# 生产环境用 uvicorn 或 mcp 内置 HTTP 模式mcp run server.py --transport streamable-http --port 8080
安全要点: 公网暴露的 MCP Server 必须启用认证(Bearer Token 或 OAuth 2.1);工具层实施域名白名单、路径沙箱、SQL 只读;审计日志记录每次 tools/call 的参数与调用方。2026 年扫描显示 1,000+ 未授权 Server 裸奔——切勿把内网 API Key 直接写进无鉴权的 HTTP Server。
11 · 调试测试与常见错误
MCP Inspector 工作流
- Connect:选择 STDIO 命令或 HTTP URL,确认
initialize握手成功。 - List Tools / Resources / Prompts:核对能力集与 JSON Schema 是否符合预期。
- Call Tool:手动传入参数,观察返回与错误信息。
- Notifications:若 Server 支持进度推送,在此面板查看。
- Export Log:导出 JSON-RPC transcript 供团队复盘。
pytest 单元测试示例
# tests/test_tools.pyimport pytestfrom server import calculatordef test_calculator_basic(): from server import CalcInput result = calculator(CalcInput(expression="2+3*4")) assert result == "14"def test_calculator_rejects_injection(): with pytest.raises(ValueError): calculator(CalcInput(expression="__import__('os')"))
常见错误对照表
| 现象 | 可能原因 | 排查步骤 |
|---|---|---|
| Host 看不到工具 | 配置路径错误、Python 非 venv | 检查 mcp.json 绝对路径;Inspector 先验证 |
| Connection closed | Server 启动崩溃、stderr 污染 stdout | 单独运行 python server.py 看 traceback |
| tools/call 超时 | 同步阻塞 IO、无超时设置 | 改 async + httpx timeout;数据库加 statement_timeout |
| HTTP 401 | Token 缺失或过期 | 核对 Authorization 头;轮换 Key |
| Schema 校验失败 | Pydantic 字段名与模型输出不匹配 | Inspector 查看 tools/list 的 inputSchema |
12 · 生产部署
Docker 打包
# DockerfileFROM python:3.12-slimWORKDIR /appCOPY pyproject.toml .RUN pip install --no-cache-dir .COPY . .EXPOSE 8080CMD ["mcp", "run", "server.py", "--transport", "streamable-http", "--port", "8080"]
云平台选型
- Railway / Render:零配置容器部署,适合 MVP 与 PoC,按用量计费。
- AWS Lambda / Google Cloud Run:无服务器,冷启动需优化 Server 体积;Cloud Run 支持 SSE 长连接更友好。
- VPS(DigitalOcean / Hetzner):完全控制,适合 mTLS 内网网关;需自建监控与日志。
监控与版本化: 在 serverInfo.version 中语义化版本(SemVer);接入 Prometheus 或云厂商 APM 记录 tools/call 延迟 P99;灰度发布时新旧 Server 并行注册到 Host Catalog,对比错误率后再切换。
13 · 知识库实战:ChromaDB / Qdrant
企业 Agent 最常见的 MCP Server 场景是向量知识库:把内部文档 embedding 后供模型检索。以下以 ChromaDB 为例(Qdrant 接口类似,换客户端即可)。
import chromadbfrom chromadb.utils import embedding_functionsclient = chromadb.PersistentClient(path="./chroma_data")ef = embedding_functions.DefaultEmbeddingFunction()collection = client.get_or_create_collection("docs", embedding_function=ef)@mcp.tool()def index_document(doc_id: str, text: str) -> str: """写入文档到向量库。""" collection.upsert(ids=[doc_id], documents=[text]) return f"已索引: {doc_id}"@mcp.tool()def search_knowledge(query: str, top_k: int = 5) -> str: """语义检索知识库。""" results = collection.query(query_texts=[query], n_results=top_k) docs = results["documents"][0] return "\n---\n".join(docs or ["无结果"])
Embedding 模型可选 OpenAI text-embedding-3-small(1536 维)或本地 sentence-transformers。ChromaDB 默认使用 all-MiniLM-L6-v2(384 维),单条 512 token 切片是常见实践;索引 10 万页文档约需 2–4 GB 磁盘与 8 GB 内存。生产环境建议 Qdrant 集群 + 副本,ChromaDB 适合单机 PoC。
14 · 生态与学习路径
推荐社区 Server
@modelcontextprotocol/server-filesystem— 文件读写与 Resource@modelcontextprotocol/server-postgres— 只读 SQL 查询@modelcontextprotocol/server-slack— Slack 消息与频道@modelcontextprotocol/server-github— Issue / PR / 代码搜索mcp-server-fetch— HTTP 抓取与 HTML 转 Markdown
2026 趋势与学习路径
趋势: Streamable HTTP 取代纯 SSE 成为新部署默认;OAuth 2.1 设备流进入主流 Host;企业 Catalog 与 Server 签名/审计成为合规标配;MCP 与 A2A(Agent-to-Agent)在同一栈分层共存。
建议学习路径(约 2 周):
- 阅读 MCP 协议架构解析,理解 Host / Client / Server 三层。
- 跟做本文 Hello World → Tools 五件套,Inspector 验收。
- 接入 Cursor,跑通真实业务场景(读 README + 查库 + HTTP)。
- 实现 ChromaDB 知识库 Server,对比检索准确率。
- Docker + HTTP 部署到 Railway,配置 Bearer 认证。
- 在隔离 Mac 节点做 Catalog 彩排,写入 ADR 后推进生产。
15 · 结语:在隔离 Mac 上练熟再上线
虽然你可以在 Windows WSL、Linux 容器或主力 Mac 上直接开发 MCP Server,但主力机混装 OAuth、生产 API Key 与多款 Host 全局配置,一次误配就可能让 tools/call 在后台 cron 里访问内网;WSL 文件系统权限与 macOS Seatbelt 沙箱体验也不等价。公网扫描已发现 1,000+ 未授权暴露的 Server——在污染生产凭证之前,用隔离环境验证「哪些 Server 值得进白名单」是更稳妥的工程纪律。
MCP 让你写一次 Server、多 Host 复用,但开发体验同样重要:Cursor 与 Claude Desktop 的 MCP 配置路径、STDIO 子进程行为、Keychain 凭证存储都是 macOS 原生体验。若你需要可审计的「多 Server × 多 Host 对照实测」证据,又与 Xcode / Apple 工具链同周期协作,在独立 macOS 租用节点完成 1–3 天 MCP 开发彩排再推进企业 Catalog,通常比直接在办公笔记本上叠装 Server 更轻、比裸容器更接近真实桌面 Host 行为。
五步 Mac 隔离 MCP 开发验收(HowTo)
- 租用隔离 macOS:Mac mini M4 起,SSH 接入;本地用户、Apple ID 与 OAuth 与主力机完全隔离。套餐见 M 系列算力定价。
- 部署开发环境:安装 Python 3.12、Node(Inspector)、Cursor;创建独立 venv,不共享主力机
~/.config。 - 并行开发多个 Server:在同一节点实现 Hello World、Tools 五件套与 ChromaDB 知识库,Inspector 导出 tools/list 快照。
- Cursor / Claude Desktop 联调:注册 STDIO Server,跑固定任务包(读文件、查库、语义检索),记录延迟与越权拦截。
- 导出 ADR 并释放:将 Server 白名单、OAuth 范围与数据分级写入架构决策记录,吊销测试 Key、退租擦盘。