MCP 起源于 2024 年 11 月 25 日 Anthropic 发布的文章:
Introducing the Model Context Protocol
[1]
。
MCP (Model Context Protocol,模型上下文协议)定义了应用程序和 AI 模型之间交换上下文信息的方式。这使得开发者能够
以一致的方式将各种数据源、工具和功能连接到 AI 模型
(一个中间协议层),就像 USB-C 让不同设备能够通过相同的接口连接一样。MCP 的目标是创建一个通用标准,使 AI 应用程序的开发和集成变得更加简单和统一。
为了克服手工 prompt 的局限性,许多 LLM 平台(如 OpenAI、Google)引入了
function call
功能。这一机制允许模型在需要时调用预定义的函数来获取数据或执行操作,显著提升了自动化水平。
但是 function call 也有其局限性(我对于 function call vs MCP 的理解不一定成熟,欢迎大家补充),我认为重点在于
function call 平台依赖性强
,不同 LLM 平台的 function call API 实现差异较大。例如,OpenAI 的函数调用方式与 Google 的不兼容,开发者在切换模型时需要重写代码,增加了适配成本。除此之外,还有安全性,交互性等问题。
数据与工具本身是客观存在的
,只不过我们希望将数据连接到模型的这个环节可以更智能更统一。Anthropic 基于这样的痛点设计了 MCP,充当 AI 模型的"万能转接头",让 LLM 能轻松得获取数据或者调用工具。更具体的说 MCP 的优势在于:
... # 省略了无关的代码 asyncdefstart(self):# 初始化所有的 mcp serverfor server inself.servers:await server.initialize()# 获取所有的 tools 命名为 all_tools all_tools = []for server inself
.servers: tools = await server.list_tools() all_tools.extend(tools)# 将所有的 tools 的功能描述格式化成字符串供 LLM 使用# tool.format_for_llm() 我放到了这段代码最后,方便阅读。 tools_description = "\n".join( [tool.format_for_llm() for tool in all_tools] )# 这里就不简化了,以供参考,实际上就是基于 prompt 和当前所有工具的信息# 询问 LLM(Claude) 应该使用哪些工具。 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." ) messages = [{"role": "system", "content": system_message}]whileTrue:# Final... 假设这里已经处理了用户消息输入. messages.append({"role": "user", "content": user_input})# 将 system_message 和用户消息输入一起发送给 LLM llm_response = self.llm_client.get_response(messages) ... # 后面和确定使用哪些工具无关classTool:"""Represents a tool with its properties and formatting."""def__init__( self, name: str, description: str, input_schema: dict[str, Any] ) -> None:self.name: str = nameself.description: str = descriptionself.input_schema: dict[str, Any] = input_schema# 把工具的名字 / 工具的用途(description)和工具所需要的参数(args_desc)转化为文本defformat_for_llm(self) -> str:"""Format tool information for LLM. Returns: A formatted string describing the tool. """ args_desc = []if"properties"inself.input_schema:for param_name, param_info inself.input_schema["properties"].items(): arg_desc = (f"- {param_name}: {param_info.get('description', 'No description')}" )if param_name inself.input_schema.get("required", []): arg_desc += " (required)" args_desc.append(arg_desc)returnf"""
Tool: {self.name} Description: {self.description} Arguments: {chr(10).join(args_desc)} """