如何为你的 API 构建 MCP 服务器
将任何 REST API 转换为 MCP 服务器,让 AI 工具直接调用。涵盖端点映射、认证、错误处理和部署。
William Wang — TokRepo & GEOScore AI 创始人,专注 AI 开发者工具和搜索可见性。
一句话答案
把 REST API 包装成 MCP Server 的核心原则:无参数的 GET 变成 Resource,带查询参数的 GET 和所有 POST/PUT/DELETE 变成 Tool。用 FastMCP(Python)或 @modelcontextprotocol/sdk(TypeScript),Auth headers 通过环境变量注入,30 分钟就能把任何 REST API 暴露给 Claude Code。
学习如何将任何 REST API 包装为 MCP 服务器,让 Claude Code、Cursor 等 AI 工具通过自然语言与之交互。
前置条件
- 一个你想暴露给 AI 工具的 REST API
- Python 3.10+ 或 Node.js 16+
- Claude Code 或 Cursor 用于测试
REST → MCP 映射
| REST 概念 | MCP 等价物 | 何时使用 |
|---|---|---|
| GET(无参数) | Resource | 只读数据 |
| GET(有查询参数) | Tool | LLM 决定查询什么 |
| POST/PUT/DELETE | Tool | 有副作用的操作 |
| Auth headers | 环境变量 | 启动时注入 |
核心原则:无参数的 GET 变成 Resource,其他一切变成 Tool。
步骤 1 — 规划端点映射
GET /projects → Resource: projects://list
POST /projects → Tool: create_project
GET /projects/{id}/tasks → Tool: list_tasks(有查询参数)
POST /projects/{id}/tasks → Tool: create_task
步骤 2 — 构建服务器
import os
from typing import Any
import httpx
from mcp.server.fastmcp import FastMCP
API_BASE_URL = os.environ.get("API_BASE_URL", "https://api.example.com/v1")
API_KEY = os.environ.get("API_KEY", "")
mcp = FastMCP("project-api")
async def api_request(method: str, path: str, **kwargs) -> dict[str, Any]:
headers = {"Authorization": f"Bearer {API_KEY}"}
async with httpx.AsyncClient() as client:
r = await client.request(method, f"{API_BASE_URL}{path}", headers=headers, timeout=30.0, **kwargs)
r.raise_for_status()
return r.json()
@mcp.resource("projects://list")
async def list_projects() -> str:
data = await api_request("GET", "/projects")
return "\n".join(f"- [{p['id']}] {p['name']}" for p in data.get("projects", []))
@mcp.tool()
async def create_project(name: str, description: str = "") -> str:
"""创建新项目。"""
data = await api_request("POST", "/projects", json={"name": name, "description": description})
return f"已创建项目 '{data['name']}'(ID: {data['id']})"
if __name__ == "__main__":
mcp.run(transport="stdio")
步骤 3 — 安全认证
绝不硬编码 API Key,使用环境变量:
{
"mcpServers": {
"project-api": {
"command": "uv",
"args": ["--directory", "/path/to/server", "run", "server.py"],
"env": {
"API_BASE_URL": "https://api.example.com/v1",
"API_KEY": "sk-your-key"
}
}
}
}
步骤 4 — 错误处理
@mcp.tool()
async def safe_call(endpoint: str) -> str:
try:
return str(await api_request("GET", endpoint))
except httpx.HTTPStatusError as e:
if e.response.status_code == 404: return f"未找到: {endpoint}"
if e.response.status_code == 429: return "请求过于频繁,稍后再试。"
return f"API 错误 {e.response.status_code}"
except httpx.TimeoutException:
return "请求超时。"
步骤 5 — 大型 API 拆分
50+ 端点的 API 应拆分为多个服务器:
api-users-mcp/ → 用户管理
api-projects-mcp/ → 项目管理
api-billing-mcp/ → 账单支付
每个服务器保持工具数在 30 个以内。Cursor 有 40 工具上限。
FAQ
Q: 如何将 REST API 转为 MCP? A: 无参 GET → Resource,其他 → Tool。用环境变量做认证。
Q: 一个大服务器还是多个小服务器? A: 多个聚焦的小服务器(每个 30 个以内工具)效果更好。
下一步
常见问题
REST API 的 GET 应该变成 Resource 还是 Tool?+
无参数的 GET(例如 /projects 列表)变成 Resource,LLM 可以像读文件一样访问。带查询参数的 GET(例如 /projects/{id}/tasks?status=open)变成 Tool,因为 LLM 需要决定传什么参数。这是 MCP 设计的核心规则。
如何处理 API 认证?+
通过环境变量注入,不要硬编码。常见做法:API_BASE_URL 和 API_KEY 放在启动时的 env,MCP Server 内部用 httpx 客户端把 Authorization header 自动加到每个请求。Claude Code 的 .mcp.json 可以配置 env 字段传递这些变量。
MCP Server 的错误处理和 REST 有什么不同?+
MCP Server 要把 HTTP 错误翻译成 LLM 能理解的文本。4xx 返回清晰的错误消息(例如 project 123 不存在请检查 ID),5xx 返回可重试提示。不要把 raw JSON 错误原样抛给 LLM,它会反复重试无效请求。
一个 API 该拆成几个 MCP Server?+
按业务域拆分,不按微服务拆。例如项目管理 API 即使后端有 10 个微服务,也只做 1 个 MCP Server,内部封装端点路由。给 LLM 的是一套连贯的工具,而不是 10 个相关但分散的 Server。
MCP Server 做好后如何部署?+
本地开发直接用 stdio 模式,Claude Code 配置 command 启动进程。生产环境可以打包成 Docker 镜像或 PyPI/npm 包发布,让用户 pip install 或 npx 运行。远程 MCP Server 目前还在实验阶段,大部分场景 stdio 本地模式就够。