ARTICLE DETAIL

资讯详情

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

MCP 协议实战(上):什么是 MCP,怎么跑起来

MCP 协议实战(上):什么是 MCP,怎么跑起来 1. 从一次“工具调用失败”说起MCP 到底解决什么问题如果你正在做 AI Agent 或者智能客服大概率遇到过这种场景模型能理解用户意图也能生成看起来很专业的回答但一到“真正去查数据、调接口”这一步就掉链子。比如用户问“帮我查一下北京今天的天气”模型会回你一句“好的我帮您查询”然后……就没有然后了。它没有工具可用只能靠训练数据里的旧信息编一个答案。传统做法是用 Function Call把工具定义写进每次请求的 prompt 里模型返回一个函数名和参数你的业务代码再去执行。这个方案能用但问题也很明显——工具定义和业务代码强耦合换一个模型就要重写一遍适配层工具多了以后 prompt 会膨胀得厉害维护成本直线上升。MCPModel Context Protocol就是冲着这个痛点来的。你可以把它理解成大模型和外部工具之间的“通用 USB 接口”工具提供方只需要写一个 MCP Server所有支持 MCP 的 Host比如 Claude Desktop、Cursor、各类 Agent 平台都能直接发现并调用它不用为每个模型单独适配。通信层统一走 JSON-RPC 2.0工具发现走tools/list工具执行走tools/call整个链路是标准化的。这篇是实战上篇目标很明确带你在本地 30 分钟内跑通第一个 MCP 服务。我会从 Python 环境准备讲起给出可复制的config.toml和settings.json配置片段演示一次完整的 JSON-RPC 调用与结果验证最后把常见的报错逐个排查一遍。适合谁看有 Python 基础、想搞明白 MCP 通信骨架、准备给自己的 Agent 接工具的开发者。下篇会讲怎么把这个本地 Server 接到真实模型上做 Function Call 触发。2. 前置准备Python 环境与 TaoToken 接入信息动手之前先把环境理清楚。MCP 的 Python SDK 对版本有要求建议 Python 3.10 及以上3.11 体验最稳。我试过在 3.9 上跑asyncio相关的类型标注会报错别在这上面浪费时间。# 建议用虚拟环境隔离避免污染全局包 python -m venv mcp-env source mcp-env/bin/activate # Windows 用 mcp-env\Scripts\activate # 升级 pip 并安装 MCP SDK pip install --upgrade pip pip install mcp[cli]装完之后验证一下python -c import mcp; print(mcp.__version__)能打印出版本号就说明 SDK 就位了。mcp[cli]这个 extras 很关键它会额外装上mcp命令行工具后面本地调试和mcp dev都靠它。接下来是模型侧的准备。本地 Server 跑通后你需要一个能发起 Function Call 的模型端点来验证完整链路。我用的是 TaoToken 的 API 服务它兼容 OpenAI 风格的接口接入成本低。先去控制台创建一个 API Key控制台入口https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewriteAPI Key 管理https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite创建好 Key 之后先存到环境变量里别硬编码进代码export TAOTOKEN_API_KEYsk-你的keyAPI 的基础地址是https://taotoken.net/api注意这个地址后面不加任何查询参数直接作为base_url使用即可。如果你对某个模型的调用方式不确定可以先去模型对话页面手动试一条消息确认 Key 和模型名都对得上模型对话体验https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite这一步别跳过。很多人后面调不通根源就是 Key 没生效或者模型名写错先在这里排除掉能省下大量排查时间。3. 可复制配置config.toml 与 settings.json 片段MCP 的配置分两块一块是 Server 自己的运行参数config.toml一块是 Host 侧声明要连接哪些 Serversettings.json。很多人第一次跑不通就是没搞清楚这两个文件各管什么。先看config.toml。这是给 MCP Server 用的放在项目根目录# config.toml [server] name weather-server version 0.1.0 transport stdio # 本地调试用 stdio部署到远端再换 http [server.capabilities] tools true # 声明本 Server 提供工具能力 resources false # 暂不提供资源读取 prompts false # 暂不提供提示模板 [logging] level INFO # 调试阶段可以改成 DEBUG看完整 JSON-RPC 报文transport stdio是本地跑的关键Server 通过标准输入输出和 Host 通信不需要开端口最省事。capabilities里把tools打开Host 才会去调tools/list发现你的工具。再看settings.json。这是 Host 侧的配置告诉它去哪里找你的 Server、怎么启动{ mcpServers: { weather: { command: python, args: [/absolute/path/to/weather_server.py], env: { TAOTOKEN_API_KEY: sk-你的key, PYTHONUNBUFFERED: 1 } } } }几个容易踩的坑提前说清楚。第一args里的路径必须是绝对路径相对路径在 Host 启动子进程时经常解析失败。第二PYTHONUNBUFFERED1建议加上否则 stdout 有缓冲JSON-RPC 的响应可能延迟到你怀疑人生。第三env里传的 Key 是给 Server 内部调用模型或外部 API 用的和 Host 自己的 Key 是两回事别混。如果你用的是 Claude Desktop 这类客户端settings.json的位置通常在用户配置目录下如果是自己写的 Host就按你的加载逻辑放。配置改完记得重启 Host热加载不一定生效。4. 完整调用演示从 tools/list 到 tools/call配置就位现在写 Server 本体。核心就三件事创建 Server 实例、注册工具、启动 stdio 循环。下面这段可以直接复制运行# weather_server.py import asyncio import json from mcp.server import Server, NotificationOptions from mcp.server.models import InitializationCapabilities from mcp.server.stdio import stdio_server # 1. 创建 Server 实例名字要和 config.toml 里一致 server Server(weather-server) # 2. 注册工具清单告诉 Host 我能干什么 server.list_tools() async def list_tools(): return [ { name: get_weather, description: 查询指定城市的实时天气, inputSchema: { type: object, properties: { city: { type: string, description: 城市名称例如 北京、上海 } }, required: [city] } } ] # 3. 实现工具逻辑Host 调 tools/call 时真正执行的部分 server.call_tool() async def call_tool(name: str, arguments: dict): if name get_weather: city arguments.get(city, ) # 真实项目里这里换成你的天气 API 调用 mock_data { 北京: 晴25°C湿度 40%, 上海: 多云28°C湿度 65%, 深圳: 阵雨30°C湿度 80% } result mock_data.get(city, f暂不支持查询 {city}) return {content: [{type: text, text: result}]} raise ValueError(f未知工具: {name}) # 4. 启动 stdio 服务循环 async def main(): async with stdio_server() as (read_stream, write_stream): await server.run( read_stream, write_stream, InitializationCapabilities(samplingNone, experimentalNone, rootsNone), NotificationOptions() ) if __name__ __main__: asyncio.run(main())代码分四段对应 MCP 通信的四个阶段。Server(weather-server)是初始化握手时对外暴露的身份list_tools()响应tools/list请求返回工具清单call_tool()响应tools/call请求执行实际逻辑stdio_server()负责把 JSON-RPC 报文从 stdin 读进来、把结果写到 stdout。启动它python weather_server.py进程会挂起等待输入这是正常的说明 stdio 循环起来了。现在手动发一条 JSON-RPC 请求验证。MCP 的报文格式是标准的 JSON-RPC 2.0初始化请求长这样{jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:test-client,version:1.0}}}把这一行贴进终端回车你会看到 Server 返回一条包含serverInfo和capabilities的响应。接着发工具发现请求{jsonrpc:2.0,id:2,method:tools/list,params:{}}响应里应该能看到get_weather的完整定义。最后发调用请求{jsonrpc:2.0,id:3,method:tools/call,params:{name:get_weather,arguments:{city:北京}}}预期返回{jsonrpc:2.0,id:3,result:{content:[{type:text,text:晴25°C湿度 40%}]}}看到这条恭喜你的第一个 MCP 服务完整跑通了。从initialize握手到tools/list发现再到tools/call执行整条 JSON-RPC 链路验证完毕。如果想让 Host 自动完成这套流程用mcp dev weather_server.py启动调试器它会帮你把交互界面搭好。5. 本篇常见报错排查跑不通的时候别慌MCP 的报错信息其实挺明确按下面这张表对号入座基本能解决。报错现象根本原因解决方式ModuleNotFoundError: No module named mcp虚拟环境没激活或装到了全局确认which python指向 venv重装pip install mcp[cli]Host 启动后无响应args路径是相对路径改成绝对路径pwd确认tools/list返回空数组没加server.list_tools()装饰器检查装饰器是否漏写函数名不重要但装饰器必须在调用后卡住不返回stdout 缓冲未关闭环境变量加PYTHONUNBUFFERED1Invalid JSON-RPC手动测试时多打了换行或空格一行一条报文末尾回车即可别加多余字符KeyError: cityinputSchema里 required 和实际参数不匹配核对arguments的 key 和 schema 定义模型不触发工具调用Host 没把工具清单传给模型确认capabilities.toolstrue且 Host 支持 MCP重点说两个高频坑。第一个是路径问题占了新手报错的一半以上。Host 启动 Server 是 fork 子进程工作目录和你终端里不一样相对路径必挂。第二个是缓冲问题Python 默认对 stdout 做行缓冲非交互场景下可能攒够一块才输出Host 等不到响应就超时了。PYTHONUNBUFFERED1是标准解法。还有一个隐蔽的坑inputSchema里required字段如果写了[city]但call_tool里用arguments[city]直接取模型偶尔不传就会抛KeyError。稳妥写法是arguments.get(city, )再自己判断空值返回友好提示。工具的参数校验尽量在 Server 侧做全别指望模型每次都传对。如果排查完还是不通建议把config.toml里的日志级别调到DEBUG完整报文会打出来对着 JSON-RPC 规范逐字段看问题基本无所遁形。6. 下一步把本地 Server 接到真实模型本地链路验证完接下来就是让它真正被模型用起来。这一步的核心是把 MCP Server 注册到支持 MCP 的 Host 或 Agent 平台让模型在 Function Call 触发时能自动发现并调用你的工具。如果你打算长期做编码类 Agent 或者需要频繁调试工具调用可以考虑用 Coding Plan 来管理模型额度和调用配额接入方式和普通 API 一致Coding Plan 入口https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite接入文档里有完整的 MCP 对接说明和示例包括 Host 侧配置、工具注册、调用链路验证建议对照着过一遍接入文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite如果你用的是 Claude Code 这类工具它本身对 MCP 的支持比较完整配置方式略有不同可以参考专门的接入说明Claude Code 接入https://taotoken.net/claudecode-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecode-anthropicutm_campaignrewrite下篇我会讲怎么把今天这个天气 Server 接到真实模型上走一遍完整的 Function Call 触发链路包括模型如何从工具清单里选工具、参数怎么传、多轮调用怎么处理。今天先把本地这 30 分钟跑通把 JSON-RPC 的骨架吃透后面接什么都快。
返回列表