用 Python MCP Server 把大模型接上你的真实数据

2026-05-26 32 预计阅读时间:1 分钟
来源:realpython.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:9 分钟

大模型能写代码、能聊天,但一到"查公司内部数据库""读项目私有文档"就卡壳——它根本看不到你的数据。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。

生产环境的几个注意事项

  1. 传输方式:示例用了 stdio(子进程通信),适合本地工具。如果 Server 需要远程部署,改用 SSE 传输:mcp.run(transport="sse"),客户端配置加 url 字段指向 HTTP 地址。

  2. 权限边界:Tool 能执行动作就意味着能造成副作用。生产 Server 一定要:

  3. 限制可操作的数据范围(只暴露必要的表 / API);
  4. 对写操作加确认步骤或只暴露读操作;
  5. 记录每次 Tool 调用的参数和返回值,便于审计。

  6. 错误处理:Tool 返回的字符串会被模型直接看到。把错误信息用自然语言描述清楚,比返回一个裸 HTTP 状态码更有效——模型能根据描述自行调整策略。

  7. 性能:Resource 列举(list_resources)会被客户端频繁调用。如果资源数量大,考虑分页或按目录层级组织,避免一次返回几千条 URI。

  8. 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 协议就能直接用。


相关推荐