尧图精选

什么是MCP(Model Context Protocol)?从对话、意图识别到服务调用与上下文管理

🕒 发布时间:2026/10/2 17:00:37 📁 来源:尧图网络
1. 从一次真实对话看 MCP 到底在做什么你对着 AI 编程助手敲下一句「帮我查一下订单 12345 明天能不能发货」它没有直接胡编一个答案而是先判断你想干什么再去调一个真实的服务最后把结果揉进回复里。这一整套动作背后就是 MCPModel Context Protocol在起作用。MCP 是一套让模型和外部工具、数据源、服务之间用统一方式说话的协议你可以把它理解成 AI 世界的 USB-C 接口以前每个工具都要写一套私有对接代码现在只要工具实现了 MCP任何支持 MCP 的客户端都能直接插上用。它解决的问题很具体。没有 MCP 的时候你想让模型查数据库得自己写函数、定义参数、处理返回、再塞回对话历史换一个模型或换一个客户端这套代码基本重写。MCP 把这些约定标准化了工具怎么声明自己、参数长什么样、调用结果怎么回传、上下文怎么在多轮之间保持全都有固定格式。对初次接触的开发者来说最值得先搞清楚的不是协议规范文档而是一条完整链路——用户输入如何被解析成意图、意图如何映射到服务调用、上下文如何跨轮次管理。把这条链路跑通一次比读十页概念都有用。这篇文章就按这条链路走。我会用一个最小可运行的 MCP 服务端配置配合一次端到端调用验证让你在自己的 AI 工具里跑通闭环。适合谁适合已经会用某个 AI 编程工具、但还没接过后端服务的开发者适合想把内部 API 暴露给模型调用、又不想为每个客户端写适配层的人。读完之后你应该能自己加一个工具、看懂调用日志、并在出错时知道去哪查。先说清楚一个容易混淆的点MCP 不是模型本身也不是某个具体产品。它是一个协议层模型通过客户端比如各种 AI 编程工具连接到 MCP 服务端服务端再连到你真正的业务系统。所以你会看到三个角色客户端、服务端、以及服务端背后的真实服务。意图识别发生在模型侧服务调用发生在服务端侧上下文管理则横跨两者。理解这个分工后面配置的时候就不会迷路。2. TaoToken 前置准备与 MCP 服务端接入配置在跑通链路之前得先有一个能调用模型的入口。我这边用的是 TaoToken它提供兼容常见接口规范的模型调用能力配置方式和主流客户端一致省去自己搭转发层的麻烦。官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址后面不加任何查询参数。你需要准备三样东西我把它叫做「三件套」Base URL、API Key、Model ID。Base URL 就是上面那个 API 地址API Key 在控制台的 API Keys 页面生成地址是 https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite Model ID 则取决于你想用哪个模型可以在模型对话页面先试一下地址是 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel_chatutm_campaignrewrite 。这三个值后面会反复用到建议先记在一个临时文件里。接下来是 MCP 服务端的配置。不同客户端的配置文件位置不一样但结构大同小异。以常见的 JSON 配置为例一个最小 MCP 服务端声明大概长这样{ mcpServers: { order-service: { command: python, args: [-m, mcp_server_order], env: { ORDER_API_BASE: https://your-internal-api.example.com, ORDER_API_TOKEN: your-service-token } } } }这段配置的意思是客户端启动时会用python -m mcp_server_order拉起一个本地 MCP 服务端进程并通过环境变量把业务 API 的地址和令牌传进去。服务端启动后会通过标准输入输出和客户端通信声明自己提供哪些工具。注意command和args必须是你本机真实可执行的命令路径写错是最常见的启动失败原因。如果你用的是 TOML 格式的配置部分客户端偏好这种等价写法是[mcp_servers.order-service] command python args [-m, mcp_server_order] [mcp_servers.order-service.env] ORDER_API_BASE https://your-internal-api.example.com ORDER_API_TOKEN your-service-token两种格式选你客户端支持的那种就行内容完全对应。配置写完后客户端一般会在启动时读取所以改完要重启客户端。这里有个坑有些客户端只在首次启动时读配置之后改了不生效必须完全退出再打开不是关窗口那种退出。服务端本身要做什么它需要实现 MCP 规定的几个方法最核心的是列出工具告诉客户端我有哪些能力和执行工具接收参数、调用真实服务、返回结果。用 Python 的话官方 SDK 已经把协议细节封装好了你只需要写业务逻辑。下面是一个极简服务端骨架展示工具声明和调用的对应关系from mcp.server import Server from mcp.server.stdio import stdio_server from mcp.types import Tool, TextContent app Server(order-service) app.list_tools() async def list_tools(): return [ Tool( namecheck_order_status, description查询订单发货状态参数为订单号, inputSchema{ type: object, properties: { order_id: {type: string, description: 订单编号} }, required: [order_id] } ) ] app.call_tool() async def call_tool(name: str, arguments: dict): if name check_order_status: order_id arguments[order_id] # 这里调用你真实的业务 API result await query_order_api(order_id) return [TextContent(typetext, textresult)] raise ValueError(f未知工具: {name}) async def main(): async with stdio_server() as (read, write): await app.run(read, write, app.create_initialization_options()) if __name__ __main__: import asyncio asyncio.run(main())list_tools返回的工具描述就是模型做意图识别时看到的「菜单」。模型会根据description和inputSchema判断用户这句话该不该调这个工具、参数怎么填。所以描述写得越清楚意图识别越准。我试过把描述从「查询订单」改成「查询订单发货状态参数为订单号」模型误调用的概率明显下降。这一步是很多人忽略的优化点。3. 可复制配置把意图识别、服务调用、上下文管理串起来配置好服务端只是第一步真正让链路跑起来还需要在客户端侧确认模型能拿到工具列表、能发起调用、能把结果带回对话。这一节我把三个环节的配置和代码都摊开你可以直接复制改。意图识别环节模型依赖的是工具描述和当前对话上下文。客户端在每次请求时会把可用工具列表和对话历史一起发给模型。模型返回的要么是普通文本要么是一个工具调用请求包含工具名和参数。这个判断过程就是意图识别。你不需要自己写分类器但要保证工具描述准确、参数 schema 严格。比如订单号如果限定为数字就在inputSchema里写pattern: ^[0-9]$模型填错时客户端会拦截。服务调用环节客户端收到模型的工具调用请求后会转发给对应的 MCP 服务端。服务端执行call_tool调用真实 API把结果按 MCP 格式返回。这里的关键是错误处理如果业务 API 超时或返回异常服务端要返回结构化的错误信息而不是直接崩溃。崩溃会导致整个 MCP 连接断开后续所有调用都失败。我踩过的坑就是没做超时捕获一个慢查询把整个会话卡死。上下文管理环节分两层。第一层是对话历史客户端负责把多轮消息按顺序保存并发送第二层是服务端自己的状态比如用户 ID、当前订单号可以存在服务端内存或外部存储里。MCP 协议本身不强制你怎么存但推荐把跨轮次需要的信息通过工具返回值带回对话让模型自己记住这样更透明。比如查询订单后把订单号放进返回文本里下一轮用户说「那它什么时候到」模型能从历史里找到订单号。下面是一个完整的客户端调用验证脚本用 Python 直接调 TaoToken 的接口模拟一次带工具调用的对话。把YOUR_API_KEY换成你在控制台生成的 Keyimport requests import json API_BASE https://taotoken.net/api API_KEY YOUR_API_KEY MODEL_ID your-model-id headers { Authorization: fBearer {API_KEY}, Content-Type: application/json } tools [ { type: function, function: { name: check_order_status, description: 查询订单发货状态参数为订单号, parameters: { type: object, properties: { order_id: {type: string, description: 订单编号} }, required: [order_id] } } } ] messages [ {role: user, content: 帮我查一下订单 12345 明天能发货吗} ] payload { model: MODEL_ID, messages: messages, tools: tools, tool_choice: auto } resp requests.post(f{API_BASE}/v1/chat/completions, headersheaders, jsonpayload) data resp.json() print(json.dumps(data, ensure_asciiFalse, indent2))这段代码跑通后你会看到模型返回的tool_calls字段里面包含它识别出的工具名和参数。这就是意图识别到服务调用的交接点。拿到tool_calls后你的客户端应该去调用对应的 MCP 服务端把结果作为role: tool的消息追加到messages再发一次请求模型就会基于真实结果生成自然语言回复。这一来一回就是完整闭环。如果你用的是 Claude Code 这类工具配置方式略有不同通常在 settings 里指定 MCP 服务端启动命令工具列表会自动加载。Cline 的 MCP 配置则在插件设置里格式和上面的 JSON 一致。Codex 的 auth.json 里配置的是模型凭证MCP 服务端单独在配置文件里声明。不管哪种客户端三件套Base URL、Key、Model ID加上 MCP 服务端声明是绕不开的最小集合。4. 端到端验证一次请求从输入到服务返回配置写完最激动人心的就是看它真的跑起来。这一节我带你走一遍完整验证每一步都有预期结果对不上就往下看排障部分。第一步确认 MCP 服务端能独立启动。在终端直接运行你配置里的命令比如python -m mcp_server_order。如果服务端正常它会挂起等待标准输入不报错。如果立刻退出并打印异常说明依赖没装或代码有问题。这一步排掉后面省一半时间。第二步确认客户端能加载工具列表。重启客户端后在对话界面输入「你有哪些工具」或者查看客户端的 MCP 状态面板。正常情况下能看到check_order_status这个工具。看不到就检查配置文件路径和格式JSON 多一个逗号都会导致解析失败。第三步发一条会触发工具调用的消息。就用「帮我查一下订单 12345 明天能发货吗」。观察客户端日志应该能看到类似这样的流程模型返回 tool_call客户端调用 MCP 服务端服务端返回订单状态客户端把结果回传模型模型生成最终回复。最终回复里应该包含真实的订单状态而不是模型编的。第四步验证上下文跨轮次。紧接着发「那它预计什么时候到」。如果上下文管理正常模型应该记得上一轮的订单号直接查询物流预计送达时间而不是反问你订单号是多少。这一步能过说明对话历史和服务端状态都串起来了。预期输出大概是这样{ role: assistant, content: 您的订单 12345 已发货物流单号 123456789预计明天下午送达。 }注意这个结果是基于你真实业务 API 返回的数据生成的。如果 API 返回的是「未发货」模型就应该说未发货。如果模型说的和 API 返回不一致说明工具结果没正确回传检查role: tool消息的tool_call_id是否和请求里的 id 匹配。这个 id 对不上模型会忽略工具结果转而自己编。验证通过后你可以试着加第二个工具比如天气查询然后发「北京天气怎么样」。观察模型是否能在两个工具之间正确选择。这一步是检验意图识别鲁棒性的好方法。如果它把天气查询路由到了订单工具回去优化工具描述把两者的关键词区分开。整个验证过程不需要写复杂代码核心就是观察日志和结果。我建议你开着客户端的日志窗口操作每一步的请求和响应都能看到出问题时定位非常快。很多人卡住是因为不看日志凭感觉猜效率低很多。5. 常见报错排查401、local proxy failed、reading choices、OAuth链路跑不通时报错信息往往很吓人但归类后其实就那几种。这一节我按真实遇到的报错逐个拆给你对照排查的方法。401 Unauthorized 是最常见的。原因通常是 API Key 没填、填错、或者过期。检查三件套里的 Key 是否和控制台生成的一致注意不要有多余空格。如果用的是环境变量确认变量名和代码里读的一致。还有一种情况是 Base URL 写错比如把/api漏了或者多加了斜杠导致请求打到了错误端点也会返回 401 或 404。TaoToken 的 API 地址是 https://taotoken.net/api 后面接/v1/chat/completions这类路径不要自己拼错。local proxy failed 通常出现在客户端配置了本地代理但代理没启动或者端口被占用。如果你没有用代理检查客户端设置里是否残留了代理配置清掉即可。这个报错和网络环境有关但解决思路是确认客户端到底在往哪个地址发请求。看日志里的实际请求 URL往往一眼就能看出问题。reading choices 报错一般发生在解析模型响应时。模型返回的 JSON 结构和你代码里取字段的路径不一致比如你取data[choices][0]但实际返回里choices为空或结构不同。先打印完整响应体确认结构再取字段。还有一种可能是模型返回了工具调用choices[0].message里没有content而有tool_calls你的代码如果硬取content就会报错。处理方式是先判断有没有tool_calls有就先走工具调用分支。OAuth 相关报错多出现在需要授权的 MCP 服务端。有些服务端要求先完成 OAuth 流程才能调用工具配置里需要填 client_id、client_secret 等。如果你用的是不需要授权的内部服务确认服务端没有强制开启 OAuth。报错信息里通常会带授权地址按提示完成一次授权即可。注意授权回调地址要和配置里一致否则会卡在回调环节。除了这四类还有一类是工具调用参数校验失败。模型填的参数不符合inputSchema客户端会拒绝发送。排查方法是看日志里模型生成的参数和 schema 对比。常见的是把数字填成字符串、漏了必填字段。优化工具描述里的参数说明能显著降低这类错误。最后提醒一个容易忽略的点MCP 服务端的标准输出被协议占用如果你在服务端代码里用print调试会污染通信数据导致客户端解析失败。调试信息一律走标准错误或者写日志文件。这个坑很隐蔽报错信息往往和真实原因无关。6. 把 MCP 用起来从最小闭环到长期编码工作流跑通最小闭环之后你可能会想把它用到日常开发里。MCP 的价值在长期编码和 Agent 场景里才真正放大。比如你可以把代码仓库的检索、CI 状态查询、issue 管理都做成 MCP 工具让 AI 助手在写代码时直接调用真实数据而不是靠猜。这种工作流适合用 Coding Plan 来承载地址是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 它面向的就是需要长期、稳定调用模型能力的编码场景。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各客户端的详细配置说明遇到不确定的字段可以去查。如果你用的是 Claude Code 相关的接入参考 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_codeutm_campaignrewrite 里面有针对性的配置示例。我的建议是先把一个工具跑稳再逐步加。每加一个工具都重新验证意图识别是否准确、上下文是否连贯。工具不是越多越好描述清晰、职责单一的工具模型用起来更可靠。等你有了三五个稳定工具再考虑把它们组合成更复杂的 Agent 流程。到那时MCP 的上下文管理和服务调用机制会成为你整个工作流的骨架。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →