大模型能写代码、能聊天,但一到"查公司内部数据库""读项目私有文档"就卡壳——它根本看不到你的数据。MCP(Model Context Protocol)就是解决这个断层的协议:你写一个 MCP Server,把数据暴露成 工具、资源、提示词 三类能力,AI 客户端(Cursor、Claude Desktop 等)就能像调用本地函数一样直接操作你的数据。
下面从协议概念到可运行的代码,完整走一遍。
MCP 的三个核心概念
MCP 把"大模型能做什么"拆成三个明确的原语:
| 原语 | 作用 | 例子 |
|---|---|---|
| Tool | 模型可以主动调用的函数 | query_orders(customer_id) 查订单 |
| Resource | 模型可以按 URI 读取的数据源 | file:///reports/2024-q3.md 读季度报告 |
| Prompt | 预置的提示模板,带可变参数 | analyze_dataset(name, format) 生成分析指令 |
Tool 是"模型主动发起动作",Resource 是"模型按需读取内容",Prompt 是"给模型一个现成的思考框架"。三者组合起来,就能覆盖绝大多数数据交互场景。
搭一个能跑的 Python MCP Server
用官方 mcp SDK,几十行代码就能搭一个暴露 Tool + Resource 的 Server。下面这个例子模拟了一个"内部订单系统"——模型可以查订单、读客户画像。
先装依赖:
pip install mcp
然后创建 order_server.py:
import json
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("order-server")
# ---------- 模拟数据 ----------
ORDERS = {
"C001": [{"id": "O1001", "amount": 5280, "status": "shipped"},
{"id": "O1002", "amount": 320, "status": "pending"}],
"C002": [{"id": "O2001", "amount": 1500, "status": "delivered"}],
}
CUSTOMER_PROFILES = {
"C001": {"name": "星河科技", "tier": "gold", "region": "华东"},
"C002": {"name": "云帆物流", "tier": "silver", "region": "华南"},
}
# ---------- Tool:模型主动调用 ----------
@mcp.tool()
def query_orders(customer_id: str) -> str:
"""查询指定客户的全部订单,返回 JSON 字符串。"""
orders = ORDERS.get(customer_id, [])
if not orders:
return json.dumps({"error": f"客户 {customer_id} 无订单记录"}, ensure_ascii=False)
return json.dumps({"customer_id": customer_id, "orders": orders}, ensure_ascii=False)
# ---------- Resource:模型按 URI 读取 ----------
@mcp.resource("customer://profile/{customer_id}")
def customer_profile(customer_id: str) -> str:
"""读取客户画像,URI 格式 customer://profile/C001。"""
profile = CUSTOMER_PROFILES.get(customer_id)
if not profile:
return f"未找到客户 {customer_id} 的画像"
return json.dumps(profile, ensure_ascii=False)
# ---------- Prompt:预置分析模板 ----------
@mcp.prompt()
def analyze_customer(customer_id: str) -> str:
"""生成客户分析提示词,引导模型综合订单和画像做判断。"""
return (
f"请分析客户 {customer_id}:\n"
f"1. 先用 query_orders 工具查订单\n"
f"2. 再用 customer://profile/{customer_id} 读画像\n"
f"3. 综合订单金额、状态和客户等级,给出是否优先服务的建议"
)
if __name__ == "__main__":
mcp.run()
运行:
python order_server.py
Server 默认通过 stdio 传输启动,等待客户端连接。
在 Cursor 里接上这个 Server
Cursor 支持 MCP 配置。打开 ~/.cursor/mcp.json(项目级则放在 .cursor/mcp.json),写入:
{
"mcpServers": {
"order-server": {
"command": "python",
"args": ["order_server.py"],
"cwd": "/path/to/your/project"
}
}
}
重启 Cursor 后,在 Composer 或 Chat 中输入:
"帮我看看客户 C001 的订单情况,并判断是否需要优先服务"
模型会自动:
1. 调用 query_orders("C001") 拿到订单数据;
2. 读取 customer://profile/C001 获得客户画像;
3. 综合两者给出建议——整个过程你不需要手动复制粘贴数据。
Claude Desktop 配置类似,文件路径是 ~/.claude/claude_desktop_config.json,格式一致。
Tool vs Resource:什么时候用哪个
新手常犯的错误是把所有东西都写成 Tool。区分原则很简单:
- Resource:数据是"被读取"的,模型不会改变它。适合文档、配置、静态画像、日志文件。URI 语义清晰,客户端可以提前列举可用资源。
- Tool:数据是"被计算或被操作"的,模型主动发起。适合查询数据库、调用 API、执行脚本、写入记录。
一个判断方式:如果动作是"给我看看 X",用 Resource;如果是"帮我算一下 X"或"帮我执行 X",用 Tool。
生产环境的几个注意事项
-
传输方式:示例用了 stdio(子进程通信),适合本地工具。如果 Server 需要远程部署,改用 SSE 传输:
mcp.run(transport="sse"),客户端配置加url字段指向 HTTP 地址。 -
权限边界:Tool 能执行动作就意味着能造成副作用。生产 Server 一定要:
- 限制可操作的数据范围(只暴露必要的表 / API);
- 对写操作加确认步骤或只暴露读操作;
-
记录每次 Tool 调用的参数和返回值,便于审计。
-
错误处理:Tool 返回的字符串会被模型直接看到。把错误信息用自然语言描述清楚,比返回一个裸 HTTP 状态码更有效——模型能根据描述自行调整策略。
-
性能:Resource 列举(
list_resources)会被客户端频繁调用。如果资源数量大,考虑分页或按目录层级组织,避免一次返回几千条 URI。 -
Prompt 的定位:Prompt 不是给人类用的快捷指令,而是给模型的"任务模板"。好的 Prompt 模板会明确告诉模型应该调用哪些 Tool / Resource、按什么顺序推理。这能显著减少模型"不知道该用什么工具"的犹豫。
快速上手清单
- [ ]
pip install mcp,用FastMCP创建 Server 实例 - [ ] 用
@mcp.tool()暴露可调用的函数,参数和返回值都用字符串 - [ ] 用
@mcp.resource()暴露可读取的数据,URI 模板用{param}声明变量 - [ ] 用
@mcp.prompt()提供预置推理模板,引导模型组合 Tool 和 Resource - [ ] 在 Cursor / Claude Desktop 的 MCP 配置文件中注册 Server
- [ ] 先只暴露读操作,验证流程跑通后再考虑是否加写操作
- [ ] 加日志记录每次调用,生产环境必须有审计链路
MCP 的价值不在协议本身有多复杂——它恰恰很简单。价值在于:你终于可以用 Python 写一个几十行的小服务,就把大模型和公司内部数据之间的墙拆掉,而且客户端不需要任何定制代码,只要支持 MCP 协议就能直接用。