Skip to content

第 17 章 · MCP 协议集成

本章目标:理解 MCP(Model Context Protocol)要解决什么问题,学会用 MCPTools 通过 stdio/SSE/Streamable HTTP 连接 MCP 服务器,把外部工具能力即插即用地挂给 Agent,并守住安全边界。

17.1 MCP 是什么

每个框架都有自己的工具格式,每接一个新系统(GitHub、数据库、文件系统……)都要重写一遍封装。**MCP(Model Context Protocol)**是 Anthropic 发起的开放协议:工具提供方实现一次 MCP Server,任何支持 MCP 的客户端(Agent 框架、IDE、聊天应用)都能直接发现并调用它的全部工具。

类比理解:

  • 没有 MCP:每对"Agent × 外部系统"都要写定制集成,N×M 的接入成本;
  • 有 MCP:Server 只写一次(N+M),客户端按标准发现与调用。

Agno 内置了完整的 MCP 客户端能力(from agno.tools.mcp import MCPTools),支持三种传输方式。

17.2 Stdio 连接本地 Server

stdio 是默认传输:Agno 把 MCP Server 作为子进程启动,通过标准输入输出通信,最适合本机工具(文件、Git、本地命令)。以官方 filesystem server 为例:

python
# mcp_fs.py
import asyncio
import os
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.tools.mcp import MCPTools

async def run():
    # 以子进程方式启动 npx @modelcontextprotocol/server-filesystem,
    # 并限定它只能访问 ./docs 目录
    mcp_tools = MCPTools(command="npx -y @modelcontextprotocol/server-filesystem ./docs")
    await mcp_tools.connect()          # 连接并拉取该 server 提供的工具清单
    try:
        agent = Agent(
            model=OpenAIChat(
                id="deepseek-chat",
                api_key=os.getenv("DEEPSEEK_API_KEY"),
                base_url="https://api.deepseek.com/v1",
            ),
            tools=[mcp_tools],         # 像普通工具一样传入即可
            markdown=True,
        )
        await agent.aprint_response("列出 docs 目录下有哪些 Markdown 文件,并总结第一个文件的目录结构")
    finally:
        await mcp_tools.close()        # 务必关闭连接、回收子进程

asyncio.run(run())

依赖准备:

bash
pip install "agno[mcp]"      # 安装 MCP 客户端依赖
npx --version                # 需要Node.js 环境运行 npx 启动的 server

17.3 三种 Transport 的选择

Transport连接对象适用场景
stdio本地子进程本机文件/命令行/Git 等私有工具
SSEHTTP(S) 服务端推送远程托管的旧版 MCP 服务
Streamable HTTP普通 HTTP 请求当前推荐的远程连接方式,易扩展、好部署

远程连接时改传 URL 类参数而不是 command,例如 SSE 用 MCPTools(url="https://example.com/sse") 形式;具体参数以所用 server 的文档为准。

python
import asyncio
from agno.tools.mcp import MCPTools

async def remote_tools():
    # 远程 server:SSE 传输,凭证走环境变量而非硬编码
    sse_tools = MCPTools(url="https://mcp.example.com/sse")
    await sse_tools.connect()
    try:
        yield sse_tools        # 在 FastAPI 请求生命周期内复用连接
    finally:
        await sse_tools.close()

多 Server 组合

早期版本用 MultiMCPTools 同时连多个 server,但它已被标记废弃——现在推荐创建多个 MCPTools 实例放进同一个 tools=[...] 列表,职责更清晰。

17.4 与自定义工具混用

MCP 工具和你手写的 @tool 函数可以自由组合,模型看到的是一个统一的工具池:

python
agent = Agent(
    model=model,
    tools=[
        mcp_tools,                       # 来自 MCP server 的外部工具
        get_current_user,                # 自己写的内部函数工具
        DuckDuckGoTools(),               # Agno 内置工具包
    ],
)

这种组合正是 MCP 的价值:通用能力交给生态的 server,业务逻辑自己写,互不干扰。

17.5 安全边界

MCP 大幅降低接入成本的同时也放大了供应链风险,务必守住四条边界:

  1. 最小授权:filesystem server 只开放必要目录;数据库 server 用只读账号;
  2. 来源可信:只启用经过审计的 server 包,npx -y 会自动下载执行任意代码,生产环境应固定版本号;
  3. 敏感操作加确认:给危险的 MCP 工具叠加第 16 章的确认机制或 guardrail;
  4. 出口管控:远程 server 的 URL 与凭证走环境变量/密钥管理,不要硬编码。
python
from agno.guardrails import PIIDetectionGuardrail

# 把第 16 章的防线叠加到 MCP 工具上
safe_agent = Agent(
    model=model,
    tools=[mcp_tools],                      # 外部 server 的工具池
    pre_hooks=[PIIDetectionGuardrail()],    # 敏感信息不进模型,也不进外部工具
    instructions=["调用文件工具前先向用户确认目标路径。"],
)

本章小结

  • MCP 是"工具提供方实现一次、所有客户端通用"的开放协议,把 N×M 集成降为 N+M;
  • MCPTools(command=...) + connect()/close() 接入 stdio 本地 server;远程用 SSE 或 Streamable HTTP;
  • 多 server 场景用多个 MCPTools 实例并列(MultiMCPTools 已废弃);
  • MCP 工具可与自定义工具、内置 Toolkit 自由混合传给 tools=[...]
  • 安全是 MCP 落地的第一优先级:最小授权、可信来源、危险操作确认。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. MCP 协议解决的核心问题是?

2. 在 Agno 中通过 stdio 连接本地 MCP server 的正确做法是?

3. 需要同时连接多个 MCP server 时,官方现在的建议是?

4. 关于 MCP 安全实践,下列说法错误的是?

🛠️ 动手实践

  1. 用 stdio 方式连接 filesystem server,让 Agent 统计某个目录下各类型文件的数量。
  2. 再连接一个 Git MCP server(uvx mcp-server-git),让 Agent 总结当前仓库最近 5 条提交。
  3. 把 MCP 工具和一个自定义 @tool 组合使用,完成"读取本地 README 并把摘要发布到内部 API"的任务。

单个 Agent 能力已足够丰富,接下来让多个 Agent 协同作战:第 18 章:Agent Team 入门