MCP模型上下文协议以及交互流程
1. MCP 是什么
全称:Model Context Protocol
定位:让大语言模型(LLM)能在“上下文”之外,按统一格式访问外部数据、调用插件、持久化状态。
动机:以前每家框架(LangChain、LlamaIndex 等)都有自己的“工具调用/记忆”规范,很难互通;MCP 就是做一个“HTTP/JSON-RPC”风格的公共协议。
2. 结构 & 概念
MCP 定义了几类对象/消息:
名称 | 作用 |
---|---|
resources | 模型可直接访问的数据(文件、数据库、API、消息流) |
prompts | 可复用的 prompt 模板,外部系统可以动态注入 |
tools | 可调用的外部函数或 API,带参数 schema |
sessions | 一次上下文交互(可包含用户消息、模型回复、工具调用) |
capabilities | 服务端声明自己支持哪些功能(资源、工具、订阅、推送等) |
协议本质是 JSON-RPC 2.0 风格(双向流),模型和外部“上下文服务器”之间通过 WebSocket 或 HTTP(SSE/gRPC)传递消息。
3. 消息交互流程
角色与数据流(逐步)
用户 → MCP客户端
用户的输入(语音、文字等)先进到你自己写的“前端/适配层”,这个层里包含 MCP 客户端。
MCP 客户端在收到用户输入前,已经向 MCP 服务器拿过一遍
tools/resources/prompts
列表,存着最新的能力元数据。
MCP客户端 → LLM
MCP 客户端把用户输入 + 工具/资源描述(以及任何 session 上下文)拼成一份上下文,一起发给 LLM。
对于支持 function-calling 的模型,这一步就是把
functions
参数传进去;对于不支持的模型,就把工具描述写在 system prompt 里。
LLM 推理
如果它觉得自己能直接回答,就直接返回自然语言。
如果它觉得需要外部数据/工具,就按你提供的工具描述生成一条 工具调用请求(
tool_call
或 JSON)。
LLM → MCP客户端
这个“工具调用消息”不会直接给用户,模型返回给 MCP 客户端。
MCP客户端 → MCP服务器
MCP 客户端检查工具名和参数是否合法,然后调用 MCP 服务器的
tools/call
或resources/read
等 API。
MCP服务器 执行
调后端 API、查数据库、读文件,返回 JSON 结果。
MCP客户端 → LLM(tool_result)
MCP 客户端把结果包成 “tool_result” 消息再发回给 LLM,让模型继续推理生成自然语言。
LLM → MCP客户端 → 用户
LLM 生成最终的对话文本。
MCP 客户端把这个文本转发回给用户界面/设备。
sequenceDiagramparticipant User as 用户participant MCPClient as MCP客户端(含前端)participant LLM as AI(LLM)participant MCPServer as MCP服务器User->>MCPClient: 用户输入MCPClient->>LLM: 用户输入 + 工具/资源描述LLM-->>MCPClient: ①直接回答 或 ②tool_call JSONalt 直接回答MCPClient->>User: 转发 LLM 的自然语言回答else tool_callMCPClient->>MCPServer: 调用工具/资源MCPServer-->>MCPClient: 工具结果MCPClient->>LLM: tool_resultLLM-->>MCPClient: 最终自然语言回答MCPClient->>User: 转发回答end
关键点(回答你的问题)
最后一句话(自然语言回答)总是由 LLM 生成的,因为只有模型能把外部数据变成人能读懂的话。
真正“发回用户”的动作通常由 MCP 客户端来做,因为客户端是“会话的中间人”,它既能调模型、又能调 MCP 服务器、又能跟你的前端交互。
也就是说:
生成者:LLM
发送者:MCP 客户端(它把 LLM 的回答发给用户)
5. 协议格式(简例)
列出工具
{"jsonrpc": "2.0","id": "1","method": "tools/list"
}
响应
{"jsonrpc": "2.0","id": "1","result": {"tools": [{"name": "search_contacts","description": "Search contacts by name","input_schema": {"type": "object","properties": {"query": {"type": "string"}},"required": ["query"]}}]}
}
调用工具
{"jsonrpc": "2.0","id": "2","method": "tools/call","params": {"name": "search_contacts","arguments": {"query": "Alice"}}
}
6. 应用场景
统一模型插件生态(比如 OpenAI Assistant、Claude Workbench、LangChain agent 都能用同一协议)。
本地/企业内部数据(CRM、ERP、数据库、知识库)接入模型。
安全地持久化模型“记忆”。
7.MCP 的标准工作方式
角色 | 作用 |
---|---|
AI(LLM) | 只做推理:理解用户话 → 生成自然语言或工具调用请求(JSON)。它本身不知道“天气 API 在哪”。 |
MCP 客户端 | 嵌在 AI 运行环境里的适配层。负责:- 向 MCP Server 拉取工具列表、资源列表- 把 LLM 生成的“工具调用 JSON”包装成协议请求发出去- 把响应结果再送回给 LLM。 |
MCP 服务器 | 工具/资源的实际托管地,负责执行真正的 API/数据库操作,并按 MCP 协议返回结果。 |
时序(以查天气为例)
sequenceDiagram
participant User as 用户
participant AI as LLM
participant MCPClient as MCP客户端
participant MCPServer as MCP服务器User->>AI: “帮我查一下北京的天气”
Note right of AI: LLM推理<br>发现自己不能回答
AI->>MCPClient: 生成工具调用JSON {name:"get_weather",args:{"city":"北京"}}
MCPClient->>MCPServer: tools/call(get_weather,{"city":"北京"})
MCPServer-->>MCPClient: {"result":"晴 28℃"}
MCPClient-->>AI: 返回工具结果
AI->>User: “北京今天晴,28℃”
LLM 的“工具调用消息”是什么样子
在 MCP/Assistants 框架里,模型输出的其实是一个 结构化消息,类似这样:
{"type": "tool_call","name": "get_weather","arguments": {"city": "北京"}
}
这个消息不会直接给用户,而是交给 MCP 客户端去执行。
然后客户端执行工具 → 把结果打包成一条 “tool_result” 消息送回模型;模型再在上下文里用这个结果生成给用户的自然语言回复。
MCP调用流程可以简化为一句话:
LLM 只“决定要不要用哪个工具 + 怎么调用”,真正执行工具和返回结果都是 MCP 客户端+服务器干的
流程是这样的 llm可以请求的除了工具 还可以请求资源、提示词等其他东西
所以标准交互模式:
LLM → MCP客户端:
list_tools
/list_resources
/list_prompts
…MCP客户端 → MCP服务器:按 JSON-RPC 发请求
MCP服务器 → MCP客户端:返回可用项列表
LLM 决定用哪个 → 发起具体调用
MCP服务器执行 → 把结果返回给 LLM
总的来说,MCP 给模型开放了“资源/提示词/工具/上下文”等一整套统一接口,模型并不需要知道背后是数据库、API 还是文件,只管按 MCP 协议去“列/读/调”。用户只看见 MCP 客户端,模型负责生成回答或工具调用,客户端负责把所有东西串起来并最终把模型回答送回用户。