
1. 为什么你的 Python 工具写完了AI 却还是“看不见”很多人第一次接触 MCP Server 时都会经历一个心理落差代码写完了python server.py也能跑起来终端里安安静静没有报错可一打开 Cursor 或 Claude Desktop问它“帮我查一下上海天气”它还是自顾自地编一段回答完全不碰你写的函数。问题不在你的 Python 代码而在于客户端根本不知道这个 Server 存在。MCPModel Context Protocol的本质是给 AI 客户端和本地工具之间定一套“发现—描述—调用”的协议。你的 Server 只是把工具“挂”了出来但 Cursor 和 Claude Desktop 需要被明确告知去哪里启动它、用什么命令启动、启动后能拿到哪些工具。我试过把整个链路拆开看它其实是这样的用户提问 → Claude Desktop / Cursor → MCP Client → MCP Server → Python Tool → 数据库/API/文件 → 返回结果 → AI 组织自然语言真正执行 Python 代码的是 MCP ServerAI 只负责“决定什么时候调用哪个工具”。所以接入的核心动作只有两个把 Server 注册进客户端配置以及验证 AI 确实触发了你的函数。这篇就围绕 FastMCP 写的 Python 工具把 Cursor 和 Claude Desktop 两条接入路径都走一遍每一步都给可复制的配置和验证方法。适合谁看已经用 FastMCP 写过至少一个app.tool()的 Python 开发者想让 Cursor 里的 AI 真正调用本地脚本的人以及准备把内部系统封装成 MCP 工具、但卡在“接不上客户端”这一步的工程同学。需要提前说明一点MCP Server 跑在本地客户端通过标准输入输出或本地命令与它通信不涉及任何网络穿透类操作。你只需要保证 Python 环境可用、脚本路径正确即可。2. 用 FastMCP 把 Python 工具封装成 MCP Server 的完整写法在接入客户端之前先把 Server 本身写扎实。FastMCP 的好处是把协议细节都藏起来了你只需要关心“工具函数长什么样”。但要让 AI 正确选择工具函数命名、类型标注、docstring 这三样一个都不能省。先装依赖。FastMCP 现在有独立包也可以直接用官方mcp包里的 FastMCPpip install fastmcp # 或者 pip install mcp下面是一个可以直接跑的server.py我放了两个工具一个做加法一个查天气先用假数据方便验证调用链路from mcp.server.fastmcp import FastMCP app FastMCP(DemoTools) app.tool() def add(a: int, b: int) - int: 计算两个整数之和用于数学运算类请求。 return a b app.tool() def get_weather(city: str) - str: 查询指定城市的当前天气输入为城市中文名。 fake {上海: 晴30℃, 北京: 多云26℃} return fake.get(city, f{city} 暂无数据) if __name__ __main__: app.run()启动它python server.py如果终端没有报错、进程保持运行说明 Server 已经就绪。这里有个容易被忽略的点app.tool()装饰器是工具被发现的唯一入口。如果你写了函数却忘了加装饰器AI 那边永远看不到它后面配置再正确也没用。工具暴露给 AI 的其实是这样一段结构化描述{ name: get_weather, description: 查询指定城市的当前天气输入为城市中文名。, inputSchema: { city: string } }AI 就是靠name和description判断“什么时候该调用它”。所以def test():这种命名和空 docstring 是灾难模型根本不知道它能干什么。反过来get_weather加上一句清晰描述命中率会高很多。再补一个稍微贴近真实业务的工具把数据库查询封装成固定用途函数而不是让模型直接执行任意 SQLapp.tool() def query_customer(customer_id: int) - dict: 根据客户 ID 查询客户基本信息返回姓名与等级。 # 实际项目里替换为你的 DB 查询 return {id: customer_id, name: 张三, level: VIP}这种写法的好处是权限边界清晰模型只能调用你允许的固定查询不能拼 SQL。企业项目里这一点比“功能强大”更重要。Server 写完后建议先在命令行确认它能正常启动、不依赖任何客户端。因为后面 90% 的接入失败根源都在“Server 本身没跑起来”或“路径写错”。3. Cursor 与 Claude Desktop 的 MCP 配置片段可直接复制这一节是重点两个客户端的配置文件格式不同但核心三要素一致启动命令、脚本路径、Server 名称。任何一处写错客户端都会静默失败或报 “No MCP Server”。3.1 Claude Desktop 配置Claude Desktop 通过一个 JSON 配置文件注册本地 MCP Server。不同系统路径不同macOS~/Library/Application Support/Claude/claude_desktop_config.jsonWindows%APPDATA%\Claude\claude_desktop_config.json打开没有就新建后写入{ mcpServers: { demo-tools: { command: python, args: [ D:/mcp/demo/server.py ] } } }三个字段的含义字段作用常见错误demo-toolsServer 名称客户端内显示用重名会互相覆盖command启动命令写成python3但系统只有pythonargs脚本绝对路径用相对路径导致找不到文件保存后完全退出并重启 Claude Desktop不是关窗口是退出进程。重启时它会自动拉起这个 Server并发现add、get_weather、query_customer三个工具。如果 Python 不在系统 PATH 里command要写绝对路径比如 Windows 下C:/Python311/python.exe。这是新手最常踩的坑之一。3.2 Cursor 配置Cursor 的 MCP 配置入口在设置里不同版本位置略有差异通常在Settings → MCP或Features → MCP Servers选择 “Add Server”。它同样支持 JSON 配置格式与 Claude Desktop 接近{ mcpServers: { demo-tools: { command: python, args: [ D:/mcp/demo/server.py ] } } }如果你用的是较新版本Cursor 也支持在项目根目录放.cursor/mcp.json这样配置可以跟着项目走团队协作时更方便。写入后重启 Cursor在 MCP 面板里应该能看到demo-tools处于已连接状态展开后列出三个工具。这里要强调一个完整配置的“三件套”概念无论 Claude Desktop 还是 Cursor一个可用的 MCP 接入都必须同时具备Base URL本地场景即启动命令、Key本地场景通常不需要远程 Server 才涉及、Model ID客户端里选用的模型。本地 stdio 模式下Key 一般留空但如果你接的是远程 MCP 服务就需要在配置里补上鉴权信息。很多教程只贴一半配置导致读者接不上问题就出在这。配置完成后两个客户端的行为是一致的启动时自动拉起 Server读取工具列表之后在对话中按需调用。你不需要手动“连接”客户端会管理生命周期。4. 验证 AI 真的调用了你的 Python 函数配置写完不代表成功必须做一次可观测的调用验证。否则你无法区分“AI 调用了工具”和“AI 自己编了答案”。最直接的验证方式是在工具函数里加一行打印让调用留下痕迹app.tool() def add(a: int, b: int) - int: 计算两个整数之和用于数学运算类请求。 print(f[TOOL CALLED] add({a}, {b})) return a b然后在 Claude Desktop 或 Cursor 里输入帮我计算 12345 加 67890如果接入成功你会看到两件事同时发生客户端返回80235同时运行 Server 的终端里打印出[TOOL CALLED] add(12345, 67890)。这行打印就是“AI 真正触发了 Python 函数”的铁证。再验证天气工具上海今天多少度预期终端打印[TOOL CALLED] get_weather(上海)客户端回答里出现“晴30℃”。如果 AI 回答的是“我无法获取实时天气”说明工具没被发现如果它编了一个温度说明它没调用工具而是自己生成。这里有个细节值得注意AI 内部流程是“理解需求 → 发现可用工具 → 选择get_weather→ 传入city上海→ 拿到返回值 → 组织自然语言”。整个过程用户无感知但后台函数确实执行了。这也是 MCP 相比“让模型直接写代码”的核心价值——执行发生在你可控的 Python 环境里而不是模型的黑盒里。验证通过后你可以把假数据换成真实 API 或数据库查询链路不用改。工具层、业务层、数据访问层分离后续维护会轻松很多。5. 接入失败排查401、local proxy failed、reading choices、OAuth 对照表接入阶段最常见的不是代码错而是配置和环境的错。下面按真实报错逐条对照。报错一No MCP Server或工具列表为空这是最高频的问题。原因通常是三类Python 路径错误、脚本路径错误、环境变量未生效。排查顺序是先在命令行手动执行python D:/mcp/demo/server.py确认能启动再把配置里的command换成 Python 绝对路径最后确认 JSON 没有多余逗号。JSON 语法错误会导致整个配置被忽略且客户端往往不报明确错误。报错二401 Unauthorized本地 stdio 模式一般不会出现 401。如果你接的是远程 MCP 服务401 说明鉴权信息缺失或过期。检查配置里是否带了正确的 Key以及 Key 是否已失效。远程场景下 Base URL、Key、Model ID 三件套缺一不可。报错三local proxy failed这个报错通常出现在客户端尝试通过本地代理连接 Server 时。检查是否有其他进程占用了同一端口或配置里误加了代理相关字段。本地 stdio 模式不需要任何代理设置把多余字段删掉即可。报错四reading choices相关错误这类错误多出现在模型返回结构解析阶段常见于客户端版本与模型接口不匹配。先升级 Cursor / Claude Desktop 到最新版再确认所选模型 ID 正确。如果配置里 Model ID 写错客户端可能拿到非预期响应。报错五OAuth 相关报错部分远程 MCP 服务要求 OAuth 授权。如果报 OAuth 失败检查回调地址是否与注册时一致以及授权是否已过期。本地工具不需要 OAuth遇到这个报错说明你接的是远程服务按服务方文档重新授权即可。报错六AI 始终不调用工具配置没问题、工具也发现了但 AI 就是不用。这几乎总是描述问题。把def test():改成def get_weather(city: str):并补上 docstring。函数名要能自解释参数类型要标注描述要说清“什么时候用”。模型选择工具靠的就是这些元信息。排查时建议养成一个习惯每改一次配置就重启客户端并观察 Server 终端输出。有打印就说明链路通了没打印就往配置和路径上找。这套方法能覆盖绝大多数接入问题。6. 把工具接上之后下一步怎么走走到这里你的 FastMCP Server 应该已经能在 Cursor 和 Claude Desktop 里被真实调用了。回头看真正卡住大多数人的从来不是 Python 代码而是“客户端不知道 Server 在哪”这一层配置。把配置写对、把验证做扎实AI 就从“会聊天”变成了“能干活”。如果你还想继续扩展几个方向比较实用把数据库查询、文件操作、内部 API 都封装成固定用途的工具让模型在权限边界内调用给工具加统一的异常处理和超时避免一个慢查询拖垮整个对话敏感信息走环境变量不要写进代码或配置。需要提醒的是MCP 工具应该封装成明确的业务动作而不是把生产库的任意 SQL 执行权交给模型。工具层做窄、做清晰权限和审计才好落地。接入过程中如果卡在配置或鉴权上可以直接对照官方文档排查也可以到控制台里管理你的 Key 和接入信息。把本地工具接上 AI 客户端只是第一步后面把更多业务能力以 MCP 工具的形式暴露出来AI Agent 能承担的事情会越来越多。