新版本Cursor中配置自定义MCP服务器教程:TaoToken统一Key接入与MCP工具开发实战源码
1. 新版 Cursor 的 MCP 配置到底变了什么如果你最近升级了 Cursor打开设置想加一个自定义 MCP 服务器可能会发现老教程里的路径和字段对不上了。新版本把 MCP 配置从原来的界面式操作改成了以mcp.json为核心的 JSON 文件配置方式字段结构、生效逻辑、调试入口都有调整。这篇就围绕「新版本 Cursor 中配置自定义 MCP 服务器」这件事从配置文件定位、参数填写、连通性验证到最小可运行的工具源码走一遍完整闭环。先说清楚 MCP 是什么。Model Context Protocol 是一套让 AI 编辑器连接外部工具和服务的协议通信走标准输入输出stdio消息格式是 JSON-RPC 2.0。你可以把它理解成给 Cursor 装「插件插座」Cursor 负责发请求你的 MCP 服务器负责执行具体动作比如读 git diff、查数据库、调内部接口然后把结果按协议格式吐回去。它适合谁适合那些不满足于编辑器内置能力、想把公司内部工具或私有服务接进 AI 工作流的开发者。新版配置的核心变化有三点。第一配置入口统一到用户级mcp.json不再依赖图形界面逐项点选。第二服务器定义里command、args、cwd、env这几个字段的语义更严格路径写错会直接导致服务器起不来。第三工具列表和调用结果都要求严格的 JSON-RPC 结构initialize没走完就调tools/list会直接报错。我试过在 Windows 和 macOS 上各配一遍最容易踩的坑不是协议本身而是路径分隔符和 Python 解释器指向。下面按顺序把每一步拆开你可以直接跟着做。2. TaoToken 统一 Key 接入 MCP 的前置准备在写 MCP 服务器之前得先解决「模型从哪来」的问题。很多自定义 MCP 工具本身不生成内容而是把提示词或数据整理好再交给模型处理。这时候如果每个工具都单独配一套 Key维护成本会很高。用 TaoToken 的统一 API 通道可以把模型调用收敛到一个 Base URL 和一把 Key 上MCP 服务器里只读环境变量就行。TaoToken 在这里扮演的是统一接入层你拿到一个 API 地址和 KeyMCP 工具内部通过它去请求模型不用在代码里硬编码多家厂商的地址。官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 注意 API 地址后面不加 UTM 参数。具体要准备三样东西第一API Key。去控制台创建地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 创建完复制出来后面写进env字段。Key 的管理页面在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以随时吊销重发。第二Base URL。统一用https://taotoken.net/apiMCP 服务器里拼请求路径时基于它。第三Model ID。这个要和你实际调用的模型对上写进配置或代码里。如果你不确定用哪个可以先去模型对话页面试一下地址是 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 确认模型能正常返回再写进 MCP 工具。如果你打算长期做编码类 Agent或者要跑多个 MCP 工具共享额度可以看下 Coding Plan地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 遇到字段不清楚可以对照查。这里强调一个原则MCP 服务器里不要明文写 Key统一走env注入。这样配置文件可以进版本库Key 留在本地环境变量或 Cursor 的env块里泄露风险小很多。3. 可复制的 mcp.json 配置与最小工具源码这一节是全文的核心给你一份能直接抄的配置片段加一份最小可运行的 MCP 服务器源码。先看配置文件。新版 Cursor 的 MCP 配置在用户设置目录下。Windows 一般是%APPDATA%\.Cursor\mcp.jsonmacOS 在~/.cursor/mcp.json。如果文件不存在就新建一个。结构如下{ mcpServers: { taotoken-demo-mcp: { command: python, args: [server.py], cwd: D:/mcp-demo/taotoken-demo-mcp, env: { TAOTOKEN_API_KEY: sk-你的Key, TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_MODEL_ID: 你的模型ID } } } }字段逐个说。taotoken-demo-mcp是服务器名随便起但后面在 Cursor 里看到的工具会挂在这个名字下。command是启动命令Python 就写pythonNode 就写node。args是参数数组指向你的入口脚本。cwd是工作目录必须写绝对路径Windows 上用正斜杠D:/...比反斜杠稳避免转义问题。env里放三个变量Key、Base URL、Model ID这就是前面说的三件套缺一个工具内部就调不通模型。注意cwd和args的关系args里的server.py是相对cwd的所以脚本要放在cwd指向的目录里。路径里尽量别带中文和空格否则某些环境下启动会失败。接下来是最小工具源码。新建server.py内容如下#!/usr/bin/env python3 import json import sys import os API_KEY os.environ.get(TAOTOKEN_API_KEY, ) BASE_URL os.environ.get(TAOTOKEN_BASE_URL, https://taotoken.net/api) MODEL_ID os.environ.get(TAOTOKEN_MODEL_ID, ) request_id 0 initialized False def send(resultNone, errorNone): resp {jsonrpc: 2.0, id: request_id} if error: resp[error] error else: resp[result] result print(json.dumps(resp), flushTrue) def handle_initialize(params): global initialized initialized True send({ protocolVersion: 2024-11-05, capabilities: {tools: {}}, serverInfo: {name: taotoken-demo-mcp, version: 1.0.0} }) def handle_tools_list(params): if not initialized: send(error{code: -32002, message: Server not initialized}) return send({ tools: [ { name: echo_env, description: Return current TaoToken config for connectivity check, inputSchema: { type: object, properties: {} } } ] }) def handle_tools_call(params): if not initialized: send(error{code: -32002, message: Server not initialized}) return name params.get(name) if name echo_env: masked API_KEY[:6] *** if API_KEY else (empty) send({ content: [ { type: text, text: fbase_url{BASE_URL}\nmodel_id{MODEL_ID}\napi_key{masked} } ] }) else: send(error{code: -32601, message: fTool not found: {name}}) def handle_request(req): global request_id request_id req.get(id, 0) method req.get(method) params req.get(params, {}) if method initialize: handle_initialize(params) elif method tools/list: handle_tools_list(params) elif method tools/call: handle_tools_call(params) else: send(error{code: -32601, message: fMethod not found: {method}}) def main(): print(taotoken-demo-mcp started, filesys.stderr) for line in sys.stdin: line line.strip() if not line: continue try: handle_request(json.loads(line)) except json.JSONDecodeError as e: print(finvalid json: {e}, filesys.stderr) except Exception as e: print(ferror: {e}, filesys.stderr) if __name__ __main__: main()这份源码只做一件事把env里的三个变量回显出来用来验证配置是否被正确注入。它实现了initialize、tools/list、tools/call三个必需方法协议版本写2024-11-05和 Cursor 新版对齐。echo_env工具把 Key 做了掩码只显示前六位避免日志泄露。把server.py放进D:/mcp-demo/taotoken-demo-mcp确认mcp.json的cwd指向同一目录然后重启 Cursor。重启是必须的新版不会热加载 MCP 配置。4. 验证请求与成功结果重启 Cursor 后打开设置里的 MCP 面板应该能看到taotoken-demo-mcp这个服务器状态是绿色或已连接。如果显示 0 个工具先别急按下一节的排查走。验证分两步。第一步确认工具被识别。在 MCP 面板里展开服务器应该看到echo_env。第二步在 Cursor 的 AI 聊天里直接调用它输入类似「调用 echo_env 工具把当前配置打印出来」。正常情况下AI 会发起tools/call服务器返回一段文本内容形如base_urlhttps://taotoken.net/api model_idyour-model-id api_keysk-abc***看到这段就说明整条链路通了Cursor 启动进程、注入env、走完initialize、列出工具、调用工具、拿到结果。如果api_key显示(empty)说明env没注入成功回去检查mcp.json的env块拼写。想更直接地验证协议层可以手动喂一条 JSON-RPC 消息。在终端里跑cd D:/mcp-demo/taotoken-demo-mcp echo {jsonrpc:2.0,id:1,method:initialize,params:{}} | python server.py你应该看到一行 JSON 返回包含protocolVersion和serverInfo。再喂一条tools/listecho {jsonrpc:2.0,id:2,method:tools/list,params:{}} | python server.py注意这里每次都是新进程initialized是 False所以第二条会返回Server not initialized。这是正常的因为 stdio 模式下 Cursor 会保持同一个进程连续发消息。要模拟连续调用可以写个脚本一次喂两行printf %s\n%s\n {jsonrpc:2.0,id:1,method:initialize,params:{}} {jsonrpc:2.0,id:2,method:tools/list,params:{}} | python server.py这样就能看到先初始化、再列出工具的完整返回。这一步能过说明你的 JSON-RPC 实现没问题剩下的就是 Cursor 侧的配置对齐。成功结果的标准很简单聊天里能拿到echo_env的返回且base_url和model_id和你写的一致。到这一步一个可运行的 MCP 调用闭环就完成了。5. 本篇常见报错排查配置 MCP 最容易卡在几个固定报错上逐个对照。报错一Server not initializedcode -32002。这是tools/list或tools/call在initialize之前被调用。原因通常是 Cursor 发了消息但你的服务器没正确响应initialize或者响应格式不对。检查handle_initialize里send的result是否包含protocolVersion、capabilities、serverInfo三个字段缺一个 Cursor 可能认为初始化失败。另外确认request_id是从请求里取的不是写死的。报错二local proxy failed或进程起不来。这类多半是command或cwd的问题。先确认python在系统 PATH 里终端能直接跑python --version。如果用的是虚拟环境command要写虚拟环境里的解释器绝对路径比如D:/venv/Scripts/python.exe。cwd必须是绝对路径且目录存在路径带空格要小心。Windows 上如果python指向 Microsoft Store 的占位程序也会起不来换成真实安装路径。报错三401或鉴权失败。如果工具内部要调模型返回 401 说明 Key 不对或没注入。先在终端echo $TAOTOKEN_API_KEYWindows 用echo %TAOTOKEN_API_KEY%确认环境变量再确认mcp.json的env块里 Key 没有多余空格。Key 失效就去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 重新生成。报错四reading choices相关解析错误。这通常出现在工具内部调模型后解析响应时说明返回结构和你代码里取字段的路径不一致。先打印原始响应体确认返回的是标准结构再调整取值逻辑。别直接假设字段一定存在加个判空。报错五OAuth 或授权跳转异常。如果你接的是需要 OAuth 的远程 MCP 服务回调地址和客户端配置要对齐。本地 stdio 模式一般不涉及 OAuth遇到这类报错先确认你用的是不是远程模式以及授权信息是否过期。报错六工具列表为空。服务器连上了但工具是 0 个检查tools/list返回的tools数组是否为空以及每个工具是否有name、description、inputSchema。inputSchema必须是合法 JSON Schematype写objectproperties即使为空也要给。排查通用手法看 Cursor 的输出面板MCP 相关日志会打在那里同时在服务器脚本里往stderr打日志stdout只留给 JSON-RPC混用会导致解析失败。这一点很关键print调试信息一定要带filesys.stderr。6. 把 MCP 工具接进日常编码流跑通最小闭环之后就可以往真实场景扩了。比如把echo_env换成读 git diff 的工具或者接内部接口查询。核心结构不变initialize声明能力tools/list暴露工具tools/call执行逻辑模型调用统一走 TaoToken 的 Base URL 和 Key。如果你要接 Claude Code 这类编码 Agent配置思路类似Base URL 和 Key 还是那套Model ID 按实际填。文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Claude Code 相关说明可以对照看。想先验证模型通不通去 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 试一条请求最快。最后给个实用建议MCP 服务器脚本单独建目录用版本控制管理mcp.json里的 Key 走env不落盘。每次改完配置记得重启 Cursor改完源码也要重启因为 stdio 进程是启动时拉起的。调试阶段把日志打到stderr稳定后再精简。这样一套下来你的自定义 MCP 工具就能稳定挂在 Cursor 里随用随调。