初识MCP
什么是MCP?
在了解mcp的过程中,我最迷惑的就是
到底什么是MCP?他作用于哪里?MCP是怎么和大模型沟通的?
直到我翻了MCP的python sdk之后才发现:
MCP和模型本身根本没有关系。
或者说:MCP和大模型完全是解耦的
MCP其实是后端协议
当你意识到这一点的时候,可能你就明白MCP是什么了,他完全是结构化的后端的内容。
简单来说
MCP定义了:
执行 模型发起的Tools call 的 MCP Client 和 远程服务 MCP Server 的接口。
实际应用中的MCP
这里举一个简单的例子,也不包含代码了。目的是让你能够清楚的认识MCP到底作用在哪。
比如说你想写一个加法AGENT,你提供给他自然语言,他返回给你加法的计算结果。
负责 计算加法的MCP Server
# server.py
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo")
# 官方文档中有
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
然后这样你就在Server端定义好这个Tool了
负责 链接用户、LLM和Tool的Client
为什么不说是MCP Client呢?因为MCP SDK只帮你实现了Tool和Tool Server的链接部分,其他的都要你自己手写。
当你手写完了用户输入、提示工程以实现模型工具调用、发起LLM推理请求、返回结果JSON解析,直到这一步:你有了模型要调用的 ToolName:str
和 ToolArguments:dict[str, any]
。
有了tool name和tool args,我怎么call 我的tool呢?
与MCP Server链接的核心是session, session可以这样使用:
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
server_params = StdioServerParameters(
command=command,
args=self.config["args"],
env={**os.environ, **self.config["env"]}
if self.config.get("env")
else None,
)
stdio_transport = await self.exit_stack.enter_async_context(
stdio_client(server_params)
)
read, write = stdio_transport
session = await self.exit_stack.enter_async_context(
ClientSession(read, write)
)
await session.initialize()
# 当然一般的操作是把session存在类中,这里只是展示如何call tool。
result = await self.session.call_tool(tool_name, arguments)
然后他返回的是一个 CallToolResult
类:
class CallToolResult(Result):
"""The server's response to a tool call."""
content: list[TextContent | ImageContent | EmbeddedResource]
isError: bool = False
所以,所谓的MCP tools call,在开发的时候就是这样实现的。
MCP和市面上的Restful API有什么区别?
MCP的session除了call_tool这个函数外,他还定义了很多接口,每个接口的结构都明确定义了,比如说:
获取MCP Server资源的接口
MCP 定义了三个资源大类:Tool, Resource, Prompt 三种.
- list_tools: 用来获取该session对应server的可用tools
class ClientSession():
async def list_tools(self) -> types.ListToolsResult:
ListToolsResult
的类定义:
class ListToolsResult(PaginatedResult):
"""The server's response to a tools/list request from the client."""
tools: list[Tool]
- list_resources 用来获取可用资源(Resources是MCP定义的和Tools并列的类或者说资源)
class ClientSession():
async def list_resources(self) -> types.ListResourcesResult:
ListResourcesResult
的类定义:
class ListResourcesResult(PaginatedResult):
"""The server's response to a resources/list request from the client."""
resources: list[Resource]
- list_prompts 用来获取可用提示词Prompts:
class ClientSession():
async def list_prompts(self) -> types.ListPromptsResult:
ListPromptsResult
的类定义:
class ListPromptsResult(PaginatedResult):
"""The server's response to a prompts/list request from the client."""
prompts: list[Prompt]
所以其实就是不断的类定义。
总结
到这里我们大概就了解MCP的python SDK在做什么了。
提供符合LLM期望(?)的后端框架
符合LLM期望指的是,LLM的可用资源他定义为了Tool, Resource, Prompt 三种。围绕着这三种资源,MCP的Client框架提供了:
- 获取服务器的可用资源(session的List 系列函数)
- 调用Tool,读取Resource,获取Prompt的发起Tool请求(session的call_tool()、read_resource()、get_prompt())等。
LLM的Client的交互
很多人关心的可能是Client到底如何和LLM进行交互,实现Tools call的方法可以又很多方法。
推理的时候限制解码、模型微调、提示工程
等等。其实大家都很期望在Agent领域能有一个统一的方案能够实现这个功能。但是目前来看只有实现了刚刚提到的三个能力的大模型供应商才能达到sota。开源社区目前真的很难实现“统一的LLM和Client”交互。
更何况
MCP根本不关系这个东西。
MCP从头到尾就和LLM Client交互没有任何关系,MCP想做的是LLM常用资源的接口统一化。这个是开源社区能做到的,上限很高,更重要的是下线非常低,你有一个服务器就能搭建MCP Server,去做服务(虽然还没有研究鉴权是怎么实现的)。这是一个非常有利于开源社区发展的。
但是。为什么MCP发布这么久了,我连文档和讨论都搜不到呢?
MCP就是封装了一遍Restful API?
保留意见。研究不够深入。
BTW 官方repo里chat agent的LLM Client交互是如此实现的
system_message = (
"You are a helpful assistant with access to these tools:\n\n"
f"{tools_description}\n"
"Choose the appropriate tool based on the user's question. "
"If no tool is needed, reply directly.\n\n"
"IMPORTANT: When you need to use a tool, you must ONLY respond with "
"the exact JSON object format below, nothing else:\n"
"{\n"
' "tool": "tool-name",\n'
' "arguments": {\n'
' "argument-name": "value"\n'
" }\n"
"}\n\n"
"After receiving a tool's response:\n"
"1. Transform the raw data into a natural, conversational response\n"
"2. Keep responses concise but informative\n"
"3. Focus on the most relevant information\n"
"4. Use appropriate context from the user's question\n"
"5. Avoid simply repeating the raw data\n\n"
"Please use only the tools that are explicitly defined above."
)
IMPORTANT: When you need to use a tool, you must ONLY respond with the exact JSON object format below, nothing else:
...
OK Sure.