1. 为什么我要自己搭一个 MCP 服务
MCP(Model Context Protocol)说白了就是给 AI 工具装“外挂”的一套协议。你平时用 Cline、Cherry Studio 这类客户端,它们能读文件、能跑命令,但如果你想让它查公司内部接口、读本地 Excel、调一个自己写的 Python 函数,就得有个 MCP 服务在中间当桥。FastMCP 是 Python 生态里上手最快的一个库,几行代码就能把普通函数注册成 AI 可调用的工具,还自带 SSE 传输,部署成 Web 服务后远程也能连。
这篇面向的是已经听过 MCP、想动手写第一个服务的人。我会用一个“查天气”的例子,从建环境、写 server.py、启动 SSE、到用 Cline 配置 TaoToken 统一 Key 通道完成一次真实工具调用,全程可复制。你不需要懂 FastAPI 底层,只要会写 Python 函数就行。踩过的坑我也会标出来,比如 SSE 端口、transport 参数、客户端配置路径这些容易卡住的地方。
2. TaoToken 前置:统一 Key 与 API 通道
自己搭 MCP 服务只是第一步,真正让 AI 客户端稳定调用模型和工具,Key 管理是个麻烦事。我一开始每个客户端配一套 Key,Cline 一套、Cherry Studio 一套、脚本里又一套,改起来到处找。后来用 TaoToken 把 Key 和 API 通道统一了,客户端只认一个地址,换模型、加额度都在后台改,本地配置不用动。
TaoToken 在这里的角色是“统一入口”:你的 MCP 服务负责业务逻辑(查天气、读文件),模型调用走 TaoToken 的 API 通道。这样 MCP 服务本身不用关心模型是哪家,客户端配置也简单。官网入口在 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 基址是 https://taotoken.net/api ,注意这个不带 UTM 参数,配置里直接填。
你需要先拿到一个 Key。进控制台创建:https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite ,然后在 API Keys 页面生成:https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite 。Key 生成后复制保存,后面 Cline 配置要用。如果你只是想先验证模型通不通,可以打开模型对话页试一句:https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=models&utm_campaign=rewrite 。
注意:Key 只显示一次,丢了就重新生成。不要把它写进会提交到 Git 的文件里,用环境变量或本地配置文件。
3. 可复制配置:server.py 骨架与依赖
3.1 建环境与装依赖
我用 conda 建一个干净的 Python 3.10 环境,避免和系统包打架。命令如下:
conda create -n fastmcp-demo python=3.10 -y conda activate fastmcp-demo pip install mcp fastapi uvicorn requests pandas openpyxl这里mcp是官方库,FastMCP 在mcp.server.fastmcp里;fastapi和uvicorn是 SSE 传输依赖的 Web 层;requests用来调外部接口;pandas+openpyxl用来读 Excel 城市编码表。装完可以pip list | grep mcp确认版本。
3.2 最小可运行 server.py
先写一个不依赖外部接口的版本,确认 MCP 本身能跑通。新建server.py:
from mcp.server.fastmcp import FastMCP import os mcp = FastMCP("demo-server") @mcp.tool() def list_desktop_files() -> list: """获取当前用户桌面上的所有文件列表""" desktop_path = os.path.expanduser("~/Desktop") return os.listdir(desktop_path) @mcp.tool() def say_hello(name: str) -> str: """生成个性化问候语""" return f"你好 {name}!欢迎使用 MCP 服务。" @mcp.resource("config://app_settings") def get_app_config() -> dict: return {"theme": "dark", "language": "zh-CN"} @mcp.prompt() def code_review_prompt(code: str) -> str: return f"请审查以下代码并指出问题:\n\n{code}" if __name__ == "__main__": mcp.run(transport="sse")几个关键点:FastMCP("demo-server")里的名字会显示在客户端;@mcp.tool()装饰的函数就是 AI 能调用的工具,函数签名和 docstring 会被解析成参数说明;@mcp.resource提供只读资源;@mcp.prompt是可复用提示模板。transport="sse"表示走 HTTP 事件流,适合远程;如果只在 IDE 本地集成,可以改成stdio。
3.3 启动 SSE 服务
直接运行:
python server.py默认会监听http://127.0.0.1:8000,SSE 端点在/sse。如果你想改端口,可以在FastMCP初始化时传参,或者用 uvicorn 手动挂载。启动成功后终端会打印类似Uvicorn running on http://127.0.0.1:8000的日志。
注意:SSE 模式下服务是常驻的,别用
python server.py &后就不管了,调试时建议开一个独立终端看日志。
4. 验证请求:从 mcp dev 到 Cline 调用
4.1 用 mcp dev 本地自测
官方提供了一个调试工具,不用写客户端就能看工具列表:
mcp dev server.py它会启动一个本地调试页,默认在http://127.0.0.1:6274。打开后点 Connect,再点 Tools,就能看到list_desktop_files和say_hello。点某个工具填参数执行,右侧会返回结果。这一步能确认工具注册没问题,再往下接客户端。
4.2 Cline 配置 TaoToken 通道
Cline 是 VS Code 里的 AI 编码插件,支持 MCP 服务。配置分两块:模型通道和 MCP 服务。
模型通道填 TaoToken 的 API 基址和 Key。在 Cline 设置里选 OpenAI Compatible,Base URL 填https://taotoken.net/api,API Key 填你在控制台生成的那个。模型名按你实际用的填。这样 Cline 的对话和工具调用都走统一通道。
MCP 服务配置在 Cline 的 MCP Servers 设置里,添加一个 SSE 类型:
{ "mcpServers": { "demo-server": { "url": "http://127.0.0.1:8000/sse" } } }保存后 Cline 会尝试连接,连上后工具列表里会出现list_desktop_files和say_hello。你在对话里说“帮我看看桌面有哪些文件”,Cline 就会调用这个工具并把结果返回。
4.3 加一个真实业务工具:查天气
光有 demo 不够,加一个调外部接口的工具。这里用高德开放平台的天气接口,需要先申请 Key,并下载城市编码表AMap_adcode_citycode.xlsx放到和server.py同目录。核心代码如下:
import pandas as pd import requests AMAP_KEY = "你的高德Key" def get_area_code(city: str) -> str: df = pd.read_excel("AMap_adcode_citycode.xlsx", header=None) for values in df.iloc[:, :].values: if city in values: return values[1] return "无" @mcp.tool() def get_weather(city: str) -> str: """查询指定城市的实时天气""" adcode = get_area_code(city) if adcode == "无": return f"未找到城市 {city} 的编码" url = f"https://restapi.amap.com/v3/weather/weatherInfo?city={adcode}&key={AMAP_KEY}" resp = requests.get(url, timeout=10) return resp.text重启python server.py,在 Cline 里说“查一下杭州天气”,它会调用get_weather并返回 JSON。实测下来,从注册工具到客户端拿到结果,整条链路是通的。
5. 本篇常见错排查
SSE 连不上,客户端报 connection refused:先确认python server.py还在前台跑着,端口没被占。用curl http://127.0.0.1:8000/sse看有没有事件流返回。如果换了端口,客户端 URL 也要同步改。
工具列表为空:检查@mcp.tool()是否加在函数上,函数是否有类型注解和 docstring。FastMCP 靠这些生成 schema,缺了可能不注册。另外mcp dev里能看到但客户端看不到,多半是客户端缓存,重启 Cline 或重新加载窗口。
transport 选错:本地 IDE 集成用stdio,远程或 Web 客户端用sse。如果你用stdio却配了 URL,或者用sse却配了 command,都会失败。两者配置格式不一样,别混。
读 Excel 报 FileNotFoundError:AMap_adcode_citycode.xlsx要和运行目录一致。用os.path.dirname(__file__)拼绝对路径更稳,别依赖当前工作目录。
高德接口返回 INVALID_USER_KEY:Key 没生效或没开通 Web 服务。去高德控制台确认 Key 类型是 Web 服务,并且绑定了正确权限。请求里的city参数必须是 adcode,不是城市名,所以编码表那步不能省。
Cline 调用工具但模型没反应:先确认 TaoToken 通道的模型能正常对话,再确认 MCP 服务在 Cline 里显示已连接。两边都通但工具不触发,试试在对话里明确说“使用 get_weather 工具查询”,有些模型需要更直接的指令。
6. 把通道固定下来,继续加工具
服务跑通之后,真正省事的是把 Key 和 API 通道固定成一套。我现在的做法是:MCP 服务只写业务逻辑,模型调用统一走 TaoToken,客户端配置里只填一个 Base URL 和一个 Key。这样加新工具时不用碰客户端,改完server.py重启就行。如果你要长期跑编码类任务或 Agent,可以看下 Coding Plan:https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite ,接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite ,Claude Code 相关配置参考 https://taotoken.net/claude-code-anthropic?utm_source=taotoken_aicg_blog_end&utm_content=claude-code-anthropic&utm_campaign=rewrite 。下一步你可以把get_weather换成公司内部接口,或者加一个读数据库的工具,套路是一样的:写函数、加装饰器、重启、在客户端验证。