ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

简单容易理解的MCP server实现:用FastMCP打通stdio与SSE接入TaoToken

简单容易理解的MCP server实现:用FastMCP打通stdio与SSE接入TaoToken 1. 从 function_call 到 MCP server为什么你需要一个可共享的工具服务如果你写过 function_call大概率遇到过这种尴尬同一个「查天气」函数在 A 项目里写一遍换到 B 项目又得复制粘贴一遍参数格式、描述文案还容易写歪。MCPModel Context Protocol就是来解决这个问题的——它把「工具」从某个具体应用里抽出来变成一个独立的 server任何支持 MCP 的 LLM 客户端都能连上来调用。MCP server 能做什么简单说它把可执行函数Tool、只读数据Resource、提示模板Prompt以标准协议暴露出去客户端通过 JSON-RPC 传参、拿结果。适合谁想快速给自己的 Agent、IDE 插件、聊天前端接上「外部能力」的开发者。这篇我用 FastMCP 从零写一个能跑的工具服务覆盖 stdio 和 SSE 两种传输方式并演示怎么通过统一 Key/API 通道接入 TaoToken30 分钟内你能跑通第一个 MCP server。先明确两种传输的差别这决定了你后面怎么启动、怎么连传输方式通信载体典型场景启动方式stdio标准输入输出本地工具、IDE 内嵌客户端拉起进程SSEHTTP 长连接远程调用、多客户端独立进程常驻stdio 适合「客户端自己把 server 进程拉起来」你不需要提前运行脚本SSE 适合「server 常驻多个客户端通过 URL 连过来」。理解了这一点后面的配置就不会迷糊。2. 前置准备装 FastMCP 与拿到 TaoToken 统一 Key动手前把环境铺好。FastMCP 是 MCP 官方 Python SDK 里封装好的一层装饰器写法几乎和 function_call 一样直观。# 建议 Python 3.10 python -m venv mcp-demo source mcp-demo/bin/activate # Windows 用 mcp-demo\Scripts\activate pip install mcp[cli] fastmcp装完验证一下python -c from mcp.server.fastmcp import FastMCP; print(ok)输出ok就说明 SDK 就位。接下来是 Key。TaoToken 提供统一的 API 通道模型对话、编码、Agent 调用都走同一个入口省得你为每个模型单独配一套鉴权。你可以先到官网了解整体能力官网入口https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content然后进控制台创建 Key这一步别跳过后面 config.toml 要用控制台https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content创建完在 API Keys 页面复制出来形如sk-xxxx。如果你打算长期跑编码类 Agent可以顺带看下 Coding Plan 的额度策略Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_contentAPI 的基础地址统一是https://taotoken.net/api注意这个不带 UTM 参数配置里直接写它就行。3. 可复制配置stdio 与 SSE 两套 server 骨架先写 stdio 版本这是最容易跑通的。新建math_server.pyfrom mcp.server.fastmcp import FastMCP MCP_SERVER_NAME math-mcp-server mcp FastMCP(MCP_SERVER_NAME) mcp.tool() def multiply(a: int, b: int) - int: 计算两个数字相乘 :param a: 第一个数字 :param b: 第二个数字 :return: 相乘结果 print(fa:{a}, b:{b}) return a * b 10 mcp.tool(namemi, description计算两个数字的密集) def mi(a: int, b: int) - int: print(fa:{a}, b:{b}) return a * b 1 if __name__ __main__: mcp.run(transportstdio)注意两点装饰器里name和description可以显式指定不写就默认取函数名和 docstringdocstring 里的参数说明会被解析成 JSON SchemaLLM 靠它决定怎么传参。所以描述写清楚比什么都重要。再写 SSE 版本search_server.py结构几乎一样只改最后一行from mcp.server.fastmcp import FastMCP MCP_SERVER_NAME search-mcp-server mcp FastMCP(MCP_SERVER_NAME) mcp.tool(namesearch_tool, description搜索互联网上的内容) def search_tool(query: str) - str: 搜索互联网上的内容 :param query: 需要搜索的内容或者关键词 :return: 返回搜索结果 print(fquery:{query}) return f搜索:{query}, 结果:太多了。。。 mcp.tool() def get_weather(address: str) - str: 获取一个地方的天气信息 :param address: 地名 :return: 返回查询的天气信息 print(f地名:{address}) return f{address}天气晴空万里。 if __name__ __main__: mcp.run(transportsse)FastMCP 内部已经封装了 FastAPI 和 uvicornSSE 模式下直接运行脚本就会起一个 HTTP 服务默认监听本地端口不需要你额外写 web 框架。接下来是客户端侧的config.toml以支持 MCP 的客户端为例[mcp_servers.math] command python args [/abs/path/to/math_server.py] transport stdio [mcp_servers.search] url http://127.0.0.1:8000/sse transport sse [llm] base_url https://taotoken.net/api api_key sk-你的TaoToken密钥 model claude-sonnetstdio 那段用command args客户端会自己拉起进程SSE 那段用url前提是你已经手动把search_server.py跑起来了。base_url指向 TaoToken 的 API 入口模型调用和工具调用走同一条通道Key 只维护一份。4. 验证请求本地启动与成功结果长什么样先验证 stdio。stdio 模式不需要你手动运行脚本但为了确认逻辑没问题可以用 MCP 自带的 CLI 调试mcp dev math_server.py这会打开一个调试界面列出你注册的所有 tool 及其参数 schema。点multiply传a3, b4应该返回223*410。终端里会打印a:3, b:4说明函数真的被调用了不是 mock。再验证 SSE。手动启动python search_server.py看到 uvicorn 启动日志、监听127.0.0.1:8000就对了。另开一个终端用 curl 探一下 SSE 端点curl -N http://127.0.0.1:8000/sse-N关闭缓冲你会看到服务端持续推送event:和data:行这就是 SSE 长连接在工作的样子。保持连接别断客户端就是靠它接收工具调用请求的。最后做一次端到端在客户端里问「北京天气怎么样」LLM 会先通过 TaoToken 通道拿到工具列表识别出get_weather然后发起 JSON-RPC 调用server 返回「北京天气晴空万里。」模型再把这句话组织成自然语言回给你。整个过程你能在 server 终端看到地名:北京的打印这就是调用成功的铁证。想直接和模型对话验证工具是否被正确识别可以用模型对话入口试模型对话https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content5. 本篇常见错排查从 Key 到传输的坑报错一ModuleNotFoundError: No module named mcp多半是虚拟环境没激活或者 pip 装到了全局。确认which python指向 venv 里的解释器再重装一次。报错二SSE 连不上Connection refused检查search_server.py是否真的在跑端口有没有被占。默认端口冲突时可以在FastMCP初始化时指定或改启动参数。另外确认 config.toml 里的 url 路径是/sse少写这段会 404。报错三工具列表为空LLM 说「没有可用工具」九成是 docstring 缺失或格式不对。FastMCP 靠 docstring 生成 schema函数没有说明、参数没有:param注释schema 就是空的模型自然看不见。把描述补全再重启。报错四401 / 鉴权失败Key 复制时带了空格或者用了过期的 Key。到 API Keys 页面重新生成一个注意base_url写https://taotoken.net/api别多加斜杠或路径。报错五stdio 模式下客户端卡住不返回通常是 server 往 stdout 打了非协议内容。stdio 的 stdout 是协议通道任何print都会污染它。调试信息请打到 stderr或者干脆用日志文件。上面示例里的print在调试时方便正式用建议换成logging输出到 stderr。报错六改了代码但行为没变stdio 模式下客户端会缓存进程改完脚本要重启客户端SSE 模式要手动 kill 旧进程再重启。这个坑我踩过不止一次改半天发现跑的还是旧代码。6. 把工具接进你的 Agent下一步怎么走server 跑通只是起点。真正让它产生价值是把它接进你日常用的编码或 Agent 工作流。如果你在做长期编码类任务建议把工具服务和模型调用统一到一套 Key 管理下省去到处配鉴权的麻烦Coding Planhttps://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content需要新建或轮换 Key 时API Keyshttps://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content接入细节和参数说明看文档接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content如果你用的是 Claude Code 这类工具Anthropic 兼容通道的配置方式单独整理过ClaudeCodeAnthropichttps://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content一个实用建议先把工具数量控制在 3 个以内每个都写清楚 docstring跑通端到端再加。工具一多模型选错函数的概率会上升描述文案的清晰度比数量重要得多。等你把 stdio 和 SSE 都摸熟了下一步可以试试给同一个 server 同时暴露 Resource让模型既能调函数又能读上下文那才是 MCP 完整的样子。
返回列表