4.8 MCP 工具集成
MCP(Model Context Protocol,模型上下文协议)是一个开放协议,允许 AI Agent 通过标准化的 JSON-RPC 2.0 接口调用外部工具、访问资源和获取提示词。RAF 通过 `rust-agent-mcp` crate 提供了完整的 MCP 客户端实现,使 Agent 可以无缝集成任何兼容 MCP 的工具服务器。
架构概览
graph TB
subgraph "RAF Agent"
AGENT["ChatClientAgent"]
FICC["FunctionInvokingChatClient"]
end
subgraph "MCP 适配层"
MCPT["McpTool<br/>(ITool 适配器)"]
MCPS["McpServerClient<br/>(连接管理+工具发现)"]
MCPCTX["McpContextProvider<br/>(动态工具注入)"]
end
subgraph "MCP 协议客户端"
CLIENT["McpClient<br/>(connect, tools/list, tools/call)"]
end
subgraph "传输层"
STDIO["StdioTransport<br/>(子进程 stdin/stdout)"]
SSE["SseTransport<br/>(HTTP SSE)"]
end
subgraph "外部"
MCPSRV["MCP Server<br/>(工具服务器)"]
end
AGENT --> FICC
FICC --> MCPT
FICC --> MCPCTX
MCPT --> MCPS
MCPCTX --> MCPS
MCPS --> CLIENT
CLIENT --> STDIO
CLIENT --> SSE
STDIO --> MCPSRV
SSE --> MCPSRV
核心组件
McpClient — MCP 协议客户端
`McpClient` 是 MCP 协议的核心实现,负责:
- **连接管理**:建立连接并完成 MCP `initialize`/`initialized` 握手 - **工具操作**:`tools/list`(列出工具)、`tools/call`(调用工具) - **资源操作**:`resources/list`(列出资源)、`resources/read`(读取资源) - **提示词操作**:`prompts/list`(列出提示词)、`prompts/get`(获取提示词)
use rust_agent_mcp::{McpClient, McpConnectionOptions};
use std::collections::HashMap;
// 通过 stdio 子进程连接 MCP 服务器
let config = McpConnectionOptions::stdio("mcp-filesystem-server", vec!["/work".into()]);
let client = McpClient::connect(config).await?;
// 列出可用工具
if let Some(tools) = client.list_tools(None).await? {
for tool in &tools.tools {
println!("Tool: {} — {}", tool.name, tool.description);
}
}
// 调用工具
let mut args = HashMap::new();
args.insert("path".into(), serde_json::json!("/work/readme.md"));
let result = client.call("read_file", args).await?;
println!("Result: {:?}", result.content);
McpTool — ITool 适配器
`McpTool` 将 MCP 工具适配为 RAF 的 `ITool` trait,使 MCP 工具可以被 `ToolRegistry` 注册、被 `FunctionInvokingChatClient` 调用,与其他内置工具无差别使用。
use rust_agent_mcp::McpTool;
use std::sync::Arc;
// 从 McpClient 创建 McpTool
let client = Arc::new(McpClient::connect(config).await?);
let tools = client.list_tools(None).await?.unwrap();
for tool_info in &tools.tools {
let mcp_tool = McpTool::new(Arc::clone(&client), tool_info);
registry.register(mcp_tool);
}
**工作原理:** - `name()` → 返回 MCP 服务器的工具名称 - `description()` → 返回 MCP 服务器的工具描述 - `parameters()` → 返回 MCP 服务器的 `inputSchema`(JSON Schema) - `execute(arguments)` → 调用 `McpClient::call()`,将结果包装为 `ToolResult`
McpServerClient — 连接管理与工具发现
`McpServerClient` 封装 `McpClient` 并提供便捷的工具发现接口:
use rust_agent_mcp::{McpServerClient, McpConnectionOptions};
// 连接并发现所有工具
let config = McpConnectionOptions::stdio("my-mcp-server", vec![]);
let server = McpServerClient::connect(config).await?;
let tools = server.discover_tools().await?;
println!("Discovered {} tools from {}", tools.len(), server.server_name().unwrap_or("unknown"));
McpContextProvider — 动态工具注入
`McpContextProvider` 实现 `IContextProvider`,在 Agent 每次调用时自动发现并注入 MCP 工具。工具列表会被缓存,避免重复发现。
use rust_agent_mcp::{McpContextProvider, McpServerClient, McpConnectionOptions};
let config = McpConnectionOptions::stdio("filesystem", vec!["/work"]);
let server = McpServerClient::connect(config).await?;
let agent = AgentBuilder::new("assistant")
.chat_client(client)
.instructions("You are a helpful coding assistant.")
// 通过 ContextProvider 动态注入 MCP 工具
.add_context_provider(McpContextProvider::new(server))
.build()?;
传输层
MCP 支持两种传输方式,通过 `McpConnectionOptions` 选择。
Stdio 传输(子进程)
最常用的方式,通过启动子进程并与其 stdin/stdout 通信:
// Go/Python/Node.js 实现的 MCP 服务器
let config = McpConnectionOptions::stdio(
"python", // 可执行文件
vec!["-m", "mcp_server"].into(), // 参数
);
子进程的 stderr 会自动转发到 tracing 日志(`target: "mcp_server_stderr"`)。连接关闭时会 kill 子进程。
SSE 传输(HTTP)
适合远程 MCP 服务器,通过 HTTP POST 发送请求,SSE 流接收响应:
let config = McpConnectionOptions::sse(
"https://mcp.example.com/sse", // SSE 端点
"https://mcp.example.com/messages", // POST 端点
);
Agent Builder 集成
RAF 为 `AgentBuilder` 提供了 `AgentBuilderMcpExt` 扩展 trait,提供流畅的 MCP 集成 API:
use rust_agent_decl::AgentBuilderMcpExt;
use rust_agent_mcp::McpConnectionOptions;
// 方式一:连接 MCP 服务器并注册所有工具
let agent = AgentBuilder::new("assistant")
.chat_client(client)
.with_mcp_server(McpConnectionOptions::stdio("mcp-server", vec![]))
.await?
.build()?;
// 方式二:注册单个 MCP 工具
let server = McpServerClient::connect(config).await?;
let agent = AgentBuilder::new("assistant")
.chat_client(client)
.with_mcp_tool(&server, "specific_tool_name")
.await?
.build()?;
// 方式三:使用 ContextProvider 动态注入
let agent = AgentBuilder::new("assistant")
.chat_client(client)
.with_mcp_server_provider(McpContextProvider::new(server))
.build()?;
声明式配置
在 MAF 兼容的 YAML/JSON 声明文件中,可以声明 MCP 工具:
kind: prompt
name: mcp-agent
model:
id: agnes-2.0-flash
connection:
kind: key
api_key: $AGNES_API_KEY
endpoint: https://apihub.agnes-ai.com/v1
instructions: You can use MCP tools to interact with external services.
tools:
- kind: mcp
name: filesystem_read
server_url: "stdio://filesystem-server"
tool_name: read_file
- kind: mcp
name: github_search
server_url: "stdio://github-mcp-server"
tool_name: search_repositories
通过 `DeclAgentBuilder` 解析(推荐):
use rust_agent_decl::DeclAgentBuilder;
use rust_agent_mcp::{McpServerClient, McpConnectionOptions};
// MCP 服务器需在 ToolResolver 中注册 — 当前通过 with_tool 或扩展 ToolResolver 预注册
let agent = DeclAgentBuilder::from_file("agent.yaml")
.build()
.await?;
若需手动注册 MCP 服务器,仍可使用 `ToolResolver`:
use rust_agent_decl::resolver::tool_resolver::ToolResolver;
use rust_agent_mcp::{McpServerClient, McpConnectionOptions};
let mut resolver = ToolResolver::new();
resolver.register_mcp_server(
"stdio://filesystem-server",
McpServerClient::connect(McpConnectionOptions::stdio("mcp-server", vec![])).await?,
);
let tools = resolver.resolve_all(&agent_def.tools).await?;
工作流中的 MCP 调用
kind: workflow
name: mcp-workflow
trigger:
kind: manual
actions:
- kind: invoke_mcp_tool
serverUrl: "stdio://filesystem-server"
toolName: search_files
arguments:
pattern: "*.rs"
path: "/project"
output:
result: search_results
多个 MCP 服务器
RAF 支持同时连接多个 MCP 服务器:
let filesystem = McpServerClient::connect(
McpConnectionOptions::stdio("filesystem-server", vec!["/work"])
).await?;
let github = McpServerClient::connect(
McpConnectionOptions::stdio("github-mcp-server", vec![])
).await?;
let agent = AgentBuilder::new("multi-server")
.chat_client(client)
.add_context_provider(
McpContextProvider::new(filesystem)
.add_server(github)
)
.build()?;
错误处理
MCP 工具执行失败时返回 `ToolResult::error()`:
// MCP 工具返回 is_error: true 时
// → ToolResult { ok: false, error: "MCP tool 'read_file' returned error: ..." }
// MCP 连接失败时
// → AgentError::ToolError("MCP tool 'read_file' call failed: Transport error: ...")
// 工具未找到时(声明式解析)
// → DeclError::Missing("MCP server '...' does not expose a tool named '...'")
关键要点
1. **McpClient** 是 MCP 协议的核心实现,支持 stdio 和 SSE 两种传输方式 2. **McpTool** 将任意 MCP 工具适配为 RAF 的 `ITool`,与内置工具无差别 3. **McpContextProvider** 通过 `IContextProvider` 机制动态注入 MCP 工具 4. **McpServerClient** 提供连接管理和便捷的工具发现 API 5. **AgentBuilderMcpExt** 提供流畅的 `with_mcp_server` / `with_mcp_tool` 构建 API 6. **声明式配置** 在 YAML/JSON 中声明 MCP 工具,通过 `ToolResolver` 解析 7. **多服务器支持** 同时连接多个 MCP 服务器,工具自动去重
下一步
- 阅读 [McpContextProvider 动态工具注入](../05-context-providers/overview.md) 了解 ContextProvider 机制 - 阅读 [第 10 章声明式配置](../10-macros-declarative/agent-schema.md) 了解 Workflow 中的 `invoke_mcp_tool` 动作 - 阅读 [AgentBuilder 构建器](../03-agent-engine/agent-builder.md) 了解 Agent 构建的更多方式