从零开始搭建AI智能体 10:MCP原理及简单实现
MCP概念
模型上下文协议 (MCP, Model Context Protocol),是一种开放协议,能够将外部系统能力标准化为“工具(Tool)”,用于让大模型(LLM)能够统一调用不同数据源或服务。
MCP架构
MCP Server
MCP Server是“工具提供方”,它通过对外部系统(如 GitHub)进行封装,能够向外提供统一的 Tool 接口。
MCP Client
MCP Client是“能力接入层”,它通过连接多个MCP Server,可以获取工具列表,并将工具转化为Langchain Tool。
Agent
Agent是“能力使用方”,无需关心工具来源,只需在初始化阶段获取工具列表即可。而工具列表中的tools则可来自于MCP,也可以是本地编写的普通Tool。
简单实现
尝试通过MCP实现智能体与GitHub的交互。
MCP Server配置
MCPServer的获取和运行主要有四种方法:
-
远程托管服务:直接用服务商提供的云端 MCP 服务,无需本地运行,零部署,最省事。
-
包管理器一键安装:用npm/pip/go直接安装并启动,适合通用工具。
-
Docker 容器运行:环境隔离,稳定
-
源码克隆 + 编译:适用于二次开发
为了方便,采用远程托管服务,创建mcp_config.json配置mcp服务器:
{
"servers": {
"github": {
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"enabled": true,
"description": "GitHub MCP Server for repository operations"
}
}
}
其中@modelcontextprotocol/server-github是官方 GitHub MCP 服务包,其中封装了 GitHub API,提供:
- 读取仓库
- 搜索代码
- 创建 issue
- 查看 PR
- 评论、合并等操作
MCP Client管理器
LangChain 代理可以使用langchain-mcp-adapters库来使用在 MCP 服务器上定义的工具。
class MCPClientManager:
async def initialize(self):
self.client = MultiServerMCPClient(self._servers_config)
self.tools = await self.client.get_tools()
- MultiServerMCPClient (connections):初始化客户端与多个服务器之间的连接,connections是一个字典,其中包含服务器的配置,也就是前面创建的mcp_config.json。
- await self.client.get_tools():将mcp 服务器提供的工具转化为langchain tool供agent使用。
工具自动加载流程
async def get_all_tools():
manager = await get_mcp_manager()
tools = []
tools += await manager.get_tools()
print(f"load {len(tools)} mcp tools")
tools += load_all_tools_from_package("agent.skills")
return tools
代码中,首先获取mcp工具,先获取mcp客户端示例,然后调用提供的对外接口(get_tools())获取连接的mcp服务器中的工具。然后调用load_all_tools_from_package()方法(省略),获取指定package中的所有带有@tool的工具方法。
注入Agent
@classmethod
async def create(cls):
llm = ChatOpenAI(
model=LLM_MODEL,
api_key=LLM_API_KEY,
base_url=LLM_BASE_URL,
temperature=0.2,
)
tools = await get_all_tools()
graph = create_agent(
model=llm,
tools=tools,
system_prompt=load_system_prompt(),
checkpointer=InMemorySaver(),
)
return cls(llm, graph)
由于 MCP Server 的工具列表获取是异步操作,而 Python 构造方法__init__(self)不支持异步执行,因此 Agent 不能在构造函数中完成初始化。需定义一个异步类方法实现初始化逻辑,在该方法内调用工具获取接口,拉取并加载全部可用工具。
调用
response = await agent.graph.ainvoke({
"messages": [...]
})
更多推荐
所有评论(0)