从零构建MCP Server:Model Context Protocol开发完全指南(TaoToken统一Key接入版)
1. 为什么我要自己写一个 MCP ServerMCP Server 是什么简单说它是一个遵循 Model Context Protocol 的小进程把「查数据库」「读文件」「调内部接口」这些能力包装成模型能看懂的工具清单让 Claude、Cursor、Cline 这类客户端在对话里直接调用。它适合谁适合手里有一堆内部系统、又不想为每个 AI 客户端重复写插件的前后端和算法同学。我最早接触 MCP 是因为一个很具体的痛点团队内部有个订单查询服务每次排查问题都要手动拼 SQL、复制结果、再贴给模型分析。模型本身很聪明但它看不到我们的库只能靠我喂数据。后来我把这个查询逻辑写成一个 MCP Server模型就能自己决定「先查订单状态再查物流」整个排查链路从十分钟压到一分钟。但真正动手时卡点往往不在协议本身而在模型调用这一环。MCP Server 里如果要用到大模型做意图识别、字段抽取或者结果润色就得配一套 API Key 和 Base URL。每个客户端、每个环境都配一遍密钥散落各处换台机器就报 401。这篇就按「从零搭建 统一 Key 接入」的思路走一遍环境准备、协议握手、工具注册、本地验证全部给到可复制的片段你跟着敲就能跑通第一个 MCP Server。核心检索词先摆在这MCP Server 开发指南、Model Context Protocol 教程、MCP 工具注册与调试。下面所有步骤都围绕这三件事展开不绕弯子。2. TaoToken 统一 Key 的前置准备在写代码之前先把模型调用这条链路理顺。MCP Server 本身不强制你调用大模型但只要你的工具涉及「理解自然语言参数」「生成摘要」「做分类」就需要一个稳定的模型入口。我试过在每个 Server 里硬编码不同厂商的 Key结果是配置漂移、密钥泄露风险、换模型要改代码。统一走一个兼容 OpenAI 协议的入口会省很多事。TaoToken 在这里扮演的就是这个统一入口一个 Key、一个 Base URL兼容主流 SDK 的调用方式。官网地址是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 根地址是 https://taotoken.net/api 注意这个 API 地址不带 UTM 参数配置时直接写死即可。你需要准备三样东西我把它叫做「三件套」后面每个客户端配置都会用到配置项取值说明Base URLhttps://taotoken.net/api兼容 OpenAI 协议的根地址API Key在控制台创建形如 sk-xxx只显示一次Model ID按需选择例如 claude 系列或 gpt 系列的模型标识创建 Key 的入口在控制台路径是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 进去之后新建一个 Key复制保存。如果你只是想先验证模型通不通可以用模型对话页面快速试一句 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。长期跑编码类 Agent 的话Coding Plan 会更划算入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。注意API Key 不要写进代码仓库也不要放进 MCP Server 的工具描述里。统一用环境变量注入后面配置片段里我会用${TAOTOKEN_API_KEY}这种占位写法。环境层面Python 侧建议 3.10 以上Node 侧建议 18 以上。MCP 官方提供了 Python 和 TypeScript 两套 SDK这篇以 Python 为主线因为它的mcp库把 stdio 传输封装得很干净适合第一次跑通。装依赖之前先建虚拟环境避免污染全局mkdir mcp-demo-server cd mcp-demo-server python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install mcp[cli] openai这里多装了一个openai库因为后面演示的工具里会调用模型做字段抽取用兼容协议直接请求 TaoToken 的 API 根地址就行。装完可以用pip show mcp确认版本SDK 迭代较快遇到 API 变化先看更新日志。3. 可复制的 Server 配置与工具注册这一节是重头戏我会给出完整的server.py包含协议握手、工具注册、模型调用三部分。先讲结构再贴代码最后给客户端的 JSON 配置片段。MCP Server 的核心就三块创建 Server 实例、声明工具列表、处理工具调用。协议握手由 SDK 在stdio_server上下文里自动完成你不需要手写 JSON-RPC 报文。工具注册靠装饰器app.list_tools()和app.call_tool()前者告诉客户端「我有哪些工具」后者负责「真正执行」。先看模型调用的封装。把 TaoToken 的三件套读进环境变量用 OpenAI SDK 指向兼容地址import os from openai import OpenAI client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) def extract_city(text: str) - str: resp client.chat.completions.create( modelos.environ.get(TAOTOKEN_MODEL, claude-3-5-sonnet), messages[ {role: system, content: 从用户输入中抽取城市名只返回城市名本身。}, {role: user, content: text}, ], temperature0, ) return resp.choices[0].message.content.strip()注意base_url结尾不要多加/v1SDK 会自己拼路径。Model ID 用环境变量兜底方便在不同环境切换。接下来是完整的 Server 代码我把它命名为server.py#!/usr/bin/env python3 import asyncio import os from typing import Any from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent from openai import OpenAI app Server(demo-server) client OpenAI( base_urlhttps://taotoken.net/api, api_keyos.environ[TAOTOKEN_API_KEY], ) WEATHER { Beijing: {temp: 22, condition: 晴}, Shanghai: {temp: 28, condition: 多云}, Guangzhou: {temp: 30, condition: 雷阵雨}, } app.list_tools() async def list_tools() - list[Tool]: return [ Tool( nameget_weather, description查询指定城市的当前天气城市名可用自然语言描述, inputSchema{ type: object, properties: { query: {type: string, description: 例如北京今天天气}, unit: {type: string, enum: [celsius, fahrenheit]}, }, required: [query], }, ) ] app.call_tool() async def call_tool(name: str, arguments: dict[str, Any]) - list[TextContent]: if name ! get_weather: raise ValueError(f未知工具: {name}) query arguments.get(query, ) unit arguments.get(unit, celsius) city extract_city(query) info WEATHER.get(city, {temp: 20, condition: 未知}) temp info[temp] if unit fahrenheit: temp temp * 9 / 5 32 unit_symbol ℉ if unit fahrenheit else ℃ text f{city}当前天气{info[condition]}温度{temp:.1f}{unit_symbol} return [TextContent(typetext, texttext)] async def main(): async with stdio_server() as (read_stream, write_stream): await app.run(read_stream, write_stream, app.create_initialization_options()) if __name__ __main__: asyncio.run(main())这段代码里extract_city就是模型调用的落点用户说「北京今天天气」模型抽出「Beijing」再查本地字典。真实项目里把字典换成数据库或外部 API 即可。客户端配置以 Claude Desktop 为例配置文件路径 macOS 是~/Library/Application Support/Claude/claude_desktop_config.jsonWindows 是%APPDATA%\Claude\claude_desktop_config.json。写入以下 JSON{ mcpServers: { demo: { command: /绝对路径/venv/bin/python, args: [/绝对路径/server.py], env: { TAOTOKEN_API_KEY: sk-你的Key, TAOTOKEN_MODEL: claude-3-5-sonnet } } } }如果你用的是 Cline 或 CC Switch 这类支持 MCP 的客户端配置结构类似同样要写全 Base URL、Key、Model ID 三件套。Cline 的 MCP 配置在设置面板里字段名可能是baseUrl和apiKey本质一样。Codex 侧如果走auth.json把 Key 写进对应字段Base URL 指向https://taotoken.net/api即可。提示command一定要写虚拟环境里的 python 绝对路径不要写系统python否则依赖找不到握手阶段就会失败。4. 本地验证请求与成功结果配置写完先别急着接客户端用官方 CLI 在本地验证一遍能省掉大量「到底是 Server 问题还是客户端问题」的排查时间。第一步直接跑 Server 看有没有语法错误python server.py如果它安静地阻塞住说明 stdio 传输已就绪没有报错就是好消息。按 CtrlC 退出。第二步用mcp dev启动可视化调试界面mcp dev server.py它会输出一个本地地址通常是http://localhost:5173浏览器打开后能看到工具列表。点get_weather在参数框里填{query: 上海天气}点调用。正常的话右侧会返回类似{ content: [ {type: text, text: Shanghai当前天气多云温度28.0℃} ] }看到这个结果说明三件事都通了协议握手成功、工具注册被识别、模型调用链路正常因为城市名是模型抽出来的。如果返回的是「未知」城市多半是模型没抽对检查TAOTOKEN_MODEL是否填了有效值。第三步接进 Claude Desktop 做端到端验证。重启客户端后在对话里输入「帮我查一下广州的天气用华氏度」。模型应该会自动调用get_weather参数里带上unit: fahrenheit返回类似「Guangzhou当前天气雷阵雨温度86.0℉」。这一步能跑通你的第一个 MCP Server 就算正式上线了。验证模型本身通不通也可以单独发一条请求不经过 MCPcurl https://taotoken.net/api/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d {model:claude-3-5-sonnet,messages:[{role:user,content:ping}]}返回里有choices字段就说明 Key 和地址都没问题。这一步和 MCP 解耦方便定位问题出在哪一层。5. 本篇常见报错与排查这一节按真实遇到的报错来写每条都给定位思路。401 Unauthorized。最常见两种原因Key 没注入或者 Base URL 写错。先确认环境变量在 Server 进程里可见mcp dev启动时不会自动读你 shell 的.env要么在配置的env字段里显式写要么用export后再启动。Base URL 必须是https://taotoken.net/api多写/v1或漏写https都会 401 或 404。local proxy failed / connection refused。这类报错通常出现在客户端启动 Server 时command路径不对或者虚拟环境没激活导致依赖缺失。把command换成绝对路径先用python server.py手动确认能跑再回填配置。reading choices of undefined。这是模型返回体结构不符合预期多半是 Model ID 填错或者请求打到了非兼容端点。检查model字段是否是有效标识base_url是否指向https://taotoken.net/api。用上面那条 curl 单独验证一次能快速区分是 SDK 问题还是配置问题。OAuth 相关报错。部分客户端默认走 OAuth 流程如果你用的是 API Key 模式需要在客户端设置里显式切换到 Key 认证别让它去走浏览器授权。Codex 的auth.json里如果残留了旧的 OAuth token清掉再写 Key。工具列表为空。Server 起来了但客户端看不到工具通常是app.list_tools()装饰器没生效或者inputSchema不是合法 JSON Schema。用mcp dev看一眼如果那边也空就是代码问题如果那边有、客户端没有就是客户端缓存重启即可。握手超时。stdio 传输下Server 启动太慢比如在 import 阶段做了网络请求会导致握手超时。把耗时初始化挪到main()里或者改成懒加载。排查顺序建议固定成先 curl 验证模型 → 再python server.py验证进程 → 再mcp dev验证工具 → 最后接客户端。逐层收敛比一上来就怀疑客户端高效得多。6. 继续往下走从跑通到可用跑通第一个 Server 只是起点。接下来你大概率会碰到这几件事我按优先级排一下。把 stdio 换成 SSE让多个客户端能同时连。改动很小主函数换成uvicorn.run(sse_server(app), host0.0.0.0, port8000)客户端连http://your-host:8000/sse。但要注意鉴权SSE 暴露在网络上别裸奔。给工具加输入校验。模型传参不可信query字段要限长度unit要枚举校验涉及文件路径的要限制目录范围。错误不要直接抛异常让进程崩捕获后返回TextContent里的错误文案模型会据此调整重试。把模型调用抽成独立模块。现在extract_city和 Server 逻辑混在一起工具一多就乱。建议单独建llm.py统一读三件套方便换模型、加重试、做超时控制。TaoToken 的接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 参数细节以那边为准。密钥管理别偷懒。本地开发用环境变量部署到服务器用密钥管理服务永远不要把 Key 提交进 Git。如果团队多人协作给每人发独立 Key方便审计和吊销。API Keys 管理入口在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。最后一句实操建议先把你手头最烦的那个「手动复制粘贴」流程写成工具哪怕只有一个跑通端到端比看十篇教程都管用。MCP 的价值不在协议本身而在它让你能把重复劳动一次性交给模型。

相关新闻

2026年茶饮品牌视觉体系:画星人教育作为插画人才供给纽带的合作价值

2026年茶饮品牌视觉体系:画星人教育作为插画人才供给纽带的合作价值

摘要新茶饮行业进入存量竞争阶段,行业竞争维度由单一产品力拓展至产品研发、品牌审美体系、视觉内容生产、IP 运营、用户体验等综合层面。同时,国家持续出台文化创意与版权扶持政策,鼓励美术、插画、文创视觉领域精品创作与人才培育&#xff…

2026/10/11 11:55:19 阅读更多 →
C# WinForms可空日期控件扩展:从继承到数据绑定全实现

C# WinForms可空日期控件扩展:从继承到数据绑定全实现

简介:面向C# WinForms开发者的一套自定义日期控件扩展项目,针对标准DateTimePicker无法直接留空的问题,通过继承控件并补充逻辑实现可空日期值,同时采用下拉式树形层级视图,使用户能按年、月、日逐级展开选择&#xff…

2026/10/11 11:55:19 阅读更多 →
HTTP/2 原理与实战:解决队头阻塞、多路复用及配置指南

HTTP/2 原理与实战:解决队头阻塞、多路复用及配置指南

1. 从一个慢页面的琐碎等待说起 做 Web 开发的人大概都遇到过这种场景:页面里只有十几个资源文件,但打开速度就是慢得离谱——首屏要等两三秒,图片一张张蹦出来,控制台里全是 pending 状态的请求。早期我们总习惯把锅甩给服务器带…

2026/10/11 11:55:19 阅读更多 →

最新新闻

深度学习交通流量预测与可视化:从LSTM时序模型到FastAPI+ECharts部署

深度学习交通流量预测与可视化:从LSTM时序模型到FastAPI+ECharts部署

简介:基于深度学习的交通流量预测可视化网站完整源码包,面向计算机、数学、电子信息等专业学生的课程设计、期末大作业与毕业设计场景,也适合深度学习入门者作为项目实战参考。包体共2007个文件,压缩包大小约102.37MB,…

2026/10/11 12:55:40 阅读更多 →
Tracely完全入门:为什么AI智能体需要Trace原生CI/CD(完整概念指南)

Tracely完全入门:为什么AI智能体需要Trace原生CI/CD(完整概念指南)

【免费下载链接】Tracely-ai Trace-native CI/CD for AI agents — production failures become regression tests that block the PR. Auto-detect, cluster, freeze into hermetic cases, replay in CI for $0. 项目地址: https://gitcode.com/gh_mirrors/tra/Tra…

2026/10/11 12:55:40 阅读更多 →
Java七大排序算法详解:从冒泡到归并,手写排序不再难

Java七大排序算法详解:从冒泡到归并,手写排序不再难

很多初学 Java 的人学到排序这一章,都会遇到一个奇怪的现象:看代码能看懂,关掉书自己写就卡住;笔试能用库函数,面试一让手写就紧张。原因很简单,排序不是背代码,而是理解每一轮循环在干什么。七…

2026/10/11 12:55:40 阅读更多 →
排序算法全解析:从七大经典到非比较排序的Java实现与面试要点

排序算法全解析:从七大经典到非比较排序的Java实现与面试要点

每次面试问到排序算法,我都会先反问自己一句:我要的是稳定排序、原地排序,还是单纯的排序结果?这个问题看起来简单,却直接决定了算法选型的方向。排序算法是数据结构课程里最基础也最容易被低估的一块内容,…

2026/10/11 12:55:40 阅读更多 →
QualityMatters 源码集分离秘诀:main/debug/release 三套代码如何优雅共存

QualityMatters 源码集分离秘诀:main/debug/release 三套代码如何优雅共存

【免费下载链接】qualitymatters Android Development Culture 项目地址: https://gitcode.com/gh_mirrors/qu/qualitymatters 点击查看 免费下载 QualityMatters 是一个践行《Android Development Culture》的开源示例 App,它最大的特色之一就是用 Gra…

2026/10/11 12:55:40 阅读更多 →
基于Java与SpringBoot的个性化电影推荐系统实战与避坑指南

基于Java与SpringBoot的个性化电影推荐系统实战与避坑指南

简介:这套基于SpringBoot与Vue的个性化电影推荐系统,是为计算机专业毕业设计、课程项目量身打造的可运行完整源码包。项目采用B/S架构,后端以JavaSpringBoot为核心,结合MyBatisPlus与MySQL 5.7存储数据,前端使用Vue实现…

2026/10/11 12:54:40 阅读更多 →

日新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/11 0:00:27 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/11 0:00:27 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/11 10:45:37 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 21:32:20 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/10 10:38:42 阅读更多 →