
1. 为什么你的 AI 助手总是“差一口气”你有没有遇到过这种场景你让 AI 助手帮你查一下本地数据库里上个月的销售数据它很礼貌地回复“我无法直接访问你的数据库”。你让它帮你操作一下 GitHub 仓库它说“我没有这个权限”。你让它读一下你电脑里的某个配置文件它直接开始编造内容。这不是 AI 不够聪明而是它和外部世界之间缺了一根“数据线”。模型本身只活在上下文窗口里它能推理、能生成但碰不到你的文件系统、数据库、API、消息队列。Function Calling 解决了一部分问题但每个模型厂商的格式不一样每个工具都要单独写适配层接三个工具就要维护三套代码。Agent 框架看起来能编排但权限边界模糊跑着跑着就卡在鉴权上。MCPModel Context Protocol就是冲着这个“最后一公里”来的。Anthropic 主导设计底层用 JSON-RPC 2.0 做通信鉴权走 OAuth 2.0把工具注册、调用、权限控制收敛成一套统一协议。你可以把它理解成 AI 工具界的 Type-C 接口不管对面是数据库、文件系统还是第三方 API只要按 MCP 规范暴露能力任何支持 MCP 的客户端都能即插即用。这篇文章面向想快速跑通 MCP 最小闭环的开发者。我会用一个可复制的服务端骨架加客户端调用示例带你在本地验证连通性。全程不需要复杂的环境配置一杯奶茶的时间足够。2. 动手前先把 TaoToken 的 Key 和接入点准备好MCP 服务端本身不依赖特定模型但你要验证“AI 调用工具”这个完整链路就需要一个能发起工具调用的模型入口。我实测下来用 TaoToken 的 API 接入点来跑客户端侧的工具调用比较顺手因为它兼容 Anthropic 的接口格式MCP 相关的工具声明可以直接透传。你需要先拿到一个 API Key。打开 https://taotoken.net/api-keys 登录后创建一个新 Key复制保存。注意这个 Key 只在创建时完整显示一次丢了就重新生成。接入点在 https://taotoken.net/api 不需要额外加路径参数。如果你用的是 Anthropic 官方 SDK把 base_url 指向这个地址即可。模型名称按你实际需要的选验证 MCP 工具调用建议用支持 tool use 的模型。注意API Key 不要硬编码在代码里提交到仓库。本地测试可以用环境变量生产环境走密钥管理服务。如果你还没决定用哪个模型来跑客户端可以先到 https://taotoken.net/models 看一下当前可用的模型列表和各自的工具调用支持情况。选一个支持 function calling / tool use 的就行。3. 可复制的 MCP 服务端骨架与客户端调用3.1 服务端用 Python 暴露一个数据库查询工具MCP 服务端的核心是注册“资源”和“工具”然后通过 JSON-RPC 2.0 响应客户端的 list_tools 和 call_tool 请求。下面是一个最小可运行骨架暴露一个查询 SQLite 的工具。# mcp_server_demo.py import json import sqlite3 from mcp.server import Server from mcp.types import Tool, TextContent app Server(demo-db-server) # 初始化一个内存数据库做演示 conn sqlite3.connect(:memory:) conn.execute(CREATE TABLE sales (product TEXT, amount INTEGER)) conn.execute(INSERT INTO sales VALUES (珍珠奶茶, 1520)) conn.execute(INSERT INTO sales VALUES (芝士奶盖, 980)) conn.commit() app.list_tools() async def list_tools(): return [ Tool( namequery_sales, description查询销售数据输入 SQL 语句, inputSchema{ type: object, properties: { sql: {type: string, description: SELECT 语句} }, required: [sql] } ) ] app.call_tool() async def call_tool(name: str, arguments: dict): if name ! query_sales: raise ValueError(f未知工具: {name}) sql arguments.get(sql, ) if not sql.strip().upper().startswith(SELECT): return [TextContent(typetext, text只允许 SELECT 查询)] try: cur conn.execute(sql) rows cur.fetchall() cols [d[0] for d in cur.description] result [dict(zip(cols, row)) for row in rows] return [TextContent(typetext, textjson.dumps(result, ensure_asciiFalse))] except Exception as e: return [TextContent(typetext, textf查询出错: {e})] if __name__ __main__: import mcp.server.stdio mcp.server.stdio.run(app)这段代码的关键点list_tools 返回工具描述和 JSON Schemacall_tool 根据工具名分发执行。通信层用 stdio客户端通过标准输入输出和服务端交互。你不需要自己写 JSON-RPC 的解析mcp 库已经封装好了。3.2 客户端用 Anthropic SDK 发起工具调用客户端侧要做的三件事连接 MCP 服务端、获取工具列表、把工具声明传给模型并处理 tool_use 响应。# mcp_client_demo.py import asyncio import json import os from anthropic import Anthropic from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): server_params StdioServerParameters( commandpython, args[mcp_server_demo.py] ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools_resp await session.list_tools() # 把 MCP 工具转成 Anthropic 的 tool 格式 anthropic_tools [] for t in tools_resp.tools: anthropic_tools.append({ name: t.name, description: t.description, input_schema: t.inputSchema }) client Anthropic( api_keyos.environ[TAOTOKEN_API_KEY], base_urlhttps://taotoken.net/api ) resp client.messages.create( modelclaude-sonnet-4-20250514, max_tokens1024, toolsanthropic_tools, messages[{ role: user, content: 帮我查一下所有产品的销售数据 }] ) # 处理 tool_use for block in resp.content: if block.type tool_use: result await session.call_tool( block.name, block.input ) print(工具返回:, result.content[0].text) asyncio.run(main())这里 base_url 指向 https://taotoken.net/api API Key 从环境变量读取。模型返回 tool_use 块后客户端通过 MCP session 调用对应工具拿到结果再回传。整个链路就是 JSON-RPC 请求-响应OAuth 鉴权在传输层由 API Key 承载。3.3 关键参数对照配置项服务端客户端通信方式stdio / SSEstdio_client / sse_client工具声明list_tools 返回 Tool 对象转成模型 tool 格式调用入口call_tool 按 name 分发session.call_tool鉴权本地无需远程走 OAuthAPI Key 放 header接入点无https://taotoken.net/api4. 本地验证连通性的具体动作跑通上面两个文件后你需要确认三件事服务端能列出工具、客户端能拿到工具列表、模型能正确触发 tool_use。第一步单独启动服务端用 echo 发一个 JSON-RPC 请求测试echo {jsonrpc:2.0,id:1,method:tools/list,params:{}} | python mcp_server_demo.py如果返回包含 query_sales 的 JSON说明服务端注册正常。第二步运行客户端脚本观察输出。正常情况你会看到工具返回的销售数据 JSON。如果模型没有触发 tool_use检查 tools 参数是否传对以及模型是否支持工具调用。第三步故意传一个非 SELECT 语句验证服务端的错误处理result await session.call_tool(query_sales, {sql: DROP TABLE sales}) print(result.content[0].text) # 应输出只允许 SELECT 查询这一步能确认权限边界在服务端生效而不是靠模型自觉。5. 本篇常见错排查报错一ModuleNotFoundError: No module named mcpmcp 库还在快速迭代安装时指定版本pip install mcp1.2.0如果用的是旧版 Python建议升到 3.10 以上因为 mcp 用到了较新的 asyncio 特性。报错二客户端连接后 list_tools 返回空检查服务端是否在 initialize 之后才注册工具。有些示例把注册放在模块顶层但 stdio 启动时序可能导致客户端拿到空列表。把注册逻辑放在 list_tools 装饰器内部或者确保服务端启动完成后再连接。报错三模型返回 tool_use 但 call_tool 报“未知工具”工具名大小写不一致。MCP 工具名区分大小写服务端注册的是 query_sales客户端传的也必须是 query_sales。另外检查 input_schema 的 required 字段是否和实际传参匹配。报错四API 返回 401 或鉴权失败确认 API Key 是从 https://taotoken.net/api-keys 生成的且没有多余空格。base_url 必须是 https://taotoken.net/api 不要加 /v1 或其他路径。如果用的是环境变量打印出来确认读取正确。报错五stdio 通信卡死服务端往 stdout 打印了非 JSON-RPC 内容比如调试日志。MCP 的 stdio 通道只能传协议消息所有日志走 stderr。检查你的 print 语句改成 sys.stderr.write。6. 把 MCP 接进你的日常编码流跑通最小闭环之后下一步是把它接进真实工作流。如果你主要用 Claude Code 或类似工具做长期编码可以把 MCP 服务端配置到 Coding Plan 里让编辑器直接调用本地工具。具体配置方式参考 https://taotoken.net/coding-plan 里面有针对 MCP 服务端的接入说明。如果你只是想快速验证某个模型对 MCP 工具调用的支持程度可以直接在模型对话页面测试把工具声明粘贴进去看模型是否能正确生成 tool_use 结构。入口在 https://taotoken.net/models 。接入文档在 https://taotoken.net/doc 里面有完整的 JSON-RPC 方法列表和 OAuth 鉴权流程。遇到协议层面的问题先查文档里的错误码对照表。MCP 的价值不在于协议本身多复杂而在于它把“AI 调用外部能力”这件事标准化了。你写一次服务端所有支持 MCP 的客户端都能用。今天花一杯奶茶时间跑通的这个骨架换成文件系统、GitHub、数据库都只是替换 call_tool 里的实现。真正省下来的是以后每接一个新工具那三到五天的适配时间。