MCP 入门到自建:协议原理 + MCPHub 管理 + 自己写一个
MCP(Model Context Protocol)从 2024 年下半年开始火,到现在 Claude / Cursor / VSCode / Cherry Studio 几乎全都接入。但很多人对它的理解还停留在”装个 MCP 就能让 AI 用工具”——其实它的设计非常有意思。
这篇把 MCP 的角色、协议、部署方式讲透,再演示用 MCPHub 管理多 MCP + 用 Python 写一个最小的 MCP server。
一、MCP 是什么
MCP (Model Context Protocol):模型上下文协议。不是软件,是一套规则——定义 AI 模型如何与外部工具、服务、数据安全高效地交互。
类比:
- MCP 之于 AI = USB 接口之于硬件
- MCP server = 不同的 USB 设备(鼠标、键盘、U 盘)
- MCP client = 主板上的 USB 控制器
- AI 模型 = 用户
核心思想:把”AI 模型”和”工具/数据/提示”解耦,让 AI 能随意接任何工具。
二、角色 + 概念
Claude Desktop / Cursor / IDE] --> C[MCP Client
负责通信] C <-->|JSON-RPC| S1[MCP Server 1
文件系统] C <-->|JSON-RPC| S2[MCP Server 2
GitHub API] C <-->|JSON-RPC| S3[MCP Server 3
数据库] S1 --> D1[本地文件] S2 --> R1[github.com] S3 --> D2[Postgres]
| 角色 | 说明 |
|---|---|
| MCP Host | 跑 AI 模型 + MCP Client 的应用:Claude Desktop / Cursor / Cherry Studio / VS Code |
| MCP Client | 集成在 Host 里,负责连接和调用 MCP Server |
| MCP Server | 提供具体功能的程序,可以访问本地数据 / 远程服务 / 自定义逻辑 |
| Local Data Source | MCP Server 能访问的本地数据(文件 / 数据库) |
| Remote Service | MCP Server 通过网络调用的服务(Web API 等) |
MCP Server 暴露三类东西给 AI:
| 类型 | 含义 | 例子 |
|---|---|---|
| Tool(工具) | 可以让 AI 调用执行的功能 | ”查询天气”、“发送邮件”、“创建文件” |
| Resource(资源) | AI 可以读取的数据 | ”歌曲列表”、“传感器数据”、“配置文件” |
| Prompt(提示) | 预设提示模板 | ”代码审查模板”、“翻译模板” |
三、三种传输协议
MCP 支持三种传输方式:
| 传输 | 全称 | 部署位置 | 能访问本地? |
|---|---|---|---|
| STDIO | 标准输入/输出 | 本地 | ✅ 能 |
| SSE | Server-Sent Events | 远程 HTTP | ❌ 不能 |
| streamableHttp | HTTP 流式 | 远程 HTTP | ❌ 不能 |
3.1 STDIO(本地)
- 通过进程的标准输入/输出通信
- 跑在你电脑上,能访问文件 / 数据库 / shell
- 适合:文件系统操作、本地 git 操作、本地数据库
3.2 SSE(远程)
- 通过 HTTP Server-Sent Events
- 跑在远程服务器
- 适合:公开 API 包装、共享工具
3.3 streamableHttp(远程,新)
- 更灵活的 HTTP 流,支持双向 / 二进制
- 适合复杂远程交互、专业开发场景
四、装第一个 MCP Server
最常用的几个官方 MCP:
| MCP | 用途 |
|---|---|
@modelcontextprotocol/server-filesystem | 文件操作 |
@modelcontextprotocol/server-github | GitHub API |
@modelcontextprotocol/server-postgres | Postgres 查询 |
@modelcontextprotocol/server-fetch | HTTP 请求 |
@modelcontextprotocol/server-memory | 长期记忆 |
4.1 在 Claude Desktop 装 filesystem MCP
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{ "mcpServers": { "filesystem": { "command": "npx", "args": [ "-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/directory" ] } }}重启 Claude Desktop。在对话里输入 “帮我列出 /path 下的所有文件”——AI 会调用 filesystem MCP。
4.2 在 Cursor 装
Settings → MCP → Add new MCP Server,填同样的配置。
五、多 MCP 的管理:MCPHub
装多了 MCP 之后,每个客户端都要重复配置 + 切换主题 + 维护 token,非常烦。MCPHub 解决这个问题——一个中心化的 MCP 网关,所有 MCP 注册一次,所有客户端共用。
5.1 它能干什么
- 集中管理:所有 MCP 在 Hub 注册一次
- 多客户端共享:Hub 给所有客户端提供统一入口
- 权限控制:按 token 分组限制
- 日志统计:每个 MCP 的调用情况
- 远程 MCP 本地化:Hub 跑远程 MCP,本地客户端通过 stdio 连 Hub
5.2 部署
Docker Compose:
services: mcphub: image: mcphub/mcphub:latest container_name: mcphub restart: always ports: - "127.0.0.1:3000:3000" volumes: - /opt/mcphub/data:/data environment: - TZ=Asia/Shanghai打开 http://127.0.0.1:3000,UI 里添加 MCP:
- 从 npm:填包名 + 参数
- 远程 SSE:填 URL
- 本地命令:填 command + args
5.3 客户端接入
Claude Desktop 配置改成连 MCPHub:
{ "mcpServers": { "mcphub": { "command": "npx", "args": ["-y", "mcphub-client", "http://127.0.0.1:3000"] } }}所有原本要单独配的 MCP 都通过 Hub 暴露出来。
六、自己写一个 MCP Server
用 Python 写一个”查询今日天气”的 MCP。
6.1 装 SDK
pip install mcp6.2 写 server.py
from mcp.server.fastmcp import FastMCPimport httpx
mcp = FastMCP("weather")
@mcp.tool()async def get_weather(city: str) -> str: """查询指定城市今日天气。
Args: city: 城市名(中文或英文) """ # 示意:替换成真实天气 API async with httpx.AsyncClient() as client: r = await client.get( f"https://wttr.in/{city}", params={"format": "3"}, timeout=10, ) return r.text
@mcp.resource("weather://cities")def list_cities() -> str: """支持查询的城市列表。""" return "Beijing, Shanghai, Shenzhen, Tokyo, New York, London"
@mcp.prompt()def weather_check(city: str) -> str: """生成查天气的标准 prompt。""" return f"请帮我查 {city} 今天的天气,并建议穿衣。"
if __name__ == "__main__": mcp.run(transport="stdio")6.3 在 Claude Desktop 注册
{ "mcpServers": { "weather": { "command": "python", "args": ["/absolute/path/to/server.py"] } }}重启 Claude,问”今天北京天气怎么样”——它会调你的 get_weather 工具。
七、写远程 MCP(SSE / streamableHttp)
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather")
# 工具定义同上
if __name__ == "__main__": # 注意:transport 改成 sse mcp.run(transport="sse", host="0.0.0.0", port=8080)部署到 VPS 之后,客户端连这个 URL:
{ "mcpServers": { "weather-remote": { "url": "https://mcp.your-domain.com/sse" } }}⚠️ 远程 MCP 必须加认证(API key / OAuth),否则等于把工具公开给所有人。
八、Tavily / Playwright 等好用的 MCP
我自己常用的 MCP 推荐:
| MCP | 用途 |
|---|---|
| tavily | AI 友好的搜索 API |
| playwright | 浏览器自动化 + 截图 |
| chrome-devtools | Chrome 调试协议 |
| github | issue / PR / 仓库操作 |
| postgres | 数据库查询 |
| filesystem | 本地文件读写 |
| memory | AI 长期记忆 |
| fetch | 网页抓取 |
| augment-context-engine | 代码库语义检索 |
每个的配置方式都差不多,找官方 README 即可。
九、踩坑清单
| 现象 | 原因 | 解决 |
|---|---|---|
| Claude Desktop 看不到工具 | 配置文件 JSON 语法错 | 用 JSON 校验工具检查 |
| MCP 启动失败 | npx 包不存在 / 网络问题 | 手动 npx -y xxx 跑一次看错误 |
| 工具调用一次就报错 | API key 没传 | 检查 env 字段是否传了 |
| 远程 MCP 访问 401 | 没配认证 | 加 Bearer token |
| 上下文中工具太多 AI 选错 | 工具命名重复 / description 不清 | 改 tool description 更具体 |
| Windows 上 npx 找不到 | Node 路径问题 | 用绝对路径或装 Volta |
十、几条实用经验
- 本地 MCP 优先 STDIO,远程优先 streamableHttp(SSE 是过渡方案)。
- MCPHub 是省心利器:多客户端共享 MCP 池,token 管理一次配。
- 写自己的 MCP 用 FastMCP:30 行代码就能搞定一个工具。
- 工具 description 要写好:AI 是看 description 决定调不调用的,写得越具体调用越准。
- 不要装太多 MCP:每个工具都进 system prompt,太多反而干扰模型判断。10-15 个工具是个上限。
- 远程 MCP 一定加认证:暴露在公网就是被滥用。
- MCP server 跑在 Docker 里:隔离 + 易部署,别裸跑在宿主机。
MCP 这个生态目前还在快速演化,但核心思想很稳——让 AI 用工具像人插 USB 一样自然。把它的角色和协议理清楚,之后任何新 MCP 都是几分钟接入的事。