模型上下文协议(MCP)
MCP 为 AI 应用提供了一种标准方式,用于发现和使用由其他进程或服务拥有的能力。服务器可以发布:
- 执行操作的 工具;
- 返回可读上下文的 资源;
- 提供可复用消息模板的 提示;以及
- 帮助客户端填写提示或资源参数的 补全建议。
ADK-Rust 通常是 MCP 客户端。McpToolset 会将发现的 MCP 工具转换为普通的 ADK-Rust Tool 值,使 LlmAgent 能够选择并调用它们。该框架还提供资源、提示、补全、订阅、引导请求以及协商后的任务生命周期。对于 MCP 服务器编写和高级协议工作,ADK-Rust 会重新导出其使用的确切 rmcp SDK 版本。
ADK-Rust 2 使用 rmcp 3.1,即官方 Rust SDK。客户端会公布 MCP 2025-11-25,并通过其旧版握手连接到 2026-07-28 服务器。examples/mcp_protocol_revisions 演示了两个修订版本,以及针对捆绑服务器的 SEP-2663 任务扩展。
架构
这里有两个独立的层:
McpToolset负责一个已初始化的 MCP 客户端连接。它发现服务器的能力,并将其适配到 ADK-Rust。McpServerManager负责本地 stdio 服务器的动态注册表。它启动、监控、重启、更新、启用、禁用、持久化并聚合这些连接。
管理器不会授予工具批准权限。读取兼容配置时,它会保留 autoApprove,但应用程序必须应用其常规的
ADK-Rust 授权和批准策略。
安装
本地 stdio MCP 支持需要选择启用:
[dependencies]
adk-tool = { version = "2.1.0", features = ["mcp"] }
连接远程服务时添加 Streamable HTTP:
adk-tool = { version = "2.1.0", features = ["mcp", "http-transport"] }
旧版采样回调需要单独启用 mcp-sampling 特性。MCP
项目已通过 SEP-2577 弃用采样、根目录和日志记录;仅在维护兼容部署时使用这些
APIs。
连接一个本地服务器
use adk_tool::{
McpToolset,
mcp::rmcp::{ServiceExt, transport::TokioChildProcess},
};
use std::sync::Arc;
use tokio::process::Command;
let command = Command::new("./target/release/company-mcp");
let client = ().serve(TokioChildProcess::new(command)?).await?;
let toolset = McpToolset::new(client)
.with_name("company_tools")
.with_tools(&["find_customer", "read_order", "request_refund"]);
let agent = LlmAgentBuilder::new("support")
.model(model)
.toolset(Arc::new(toolset.clone()))
.build()?;
// Keep the token when the application owns the process lifecycle.
let shutdown = toolset.cancellation_token().await;
// ... run the agent ...
shutdown.cancel();
McpToolset 会保持服务器的输入和输出模式不变。每个模型适配器在构建模型请求时,
都会针对其提供商规范化一份副本。
这样,同一个 MCP 服务器就能与 Gemini、OpenAI、Anthropic 以及其他
提供商协同工作,而不会破坏源模式。
将协议用于工具之外
use serde_json::json;
let resources = toolset.list_resources().await?;
let templates = toolset.list_resource_templates().await?;
let contents = toolset.read_resource("company://policy/refunds").await?;
let prompts = toolset.list_prompts().await?;
let prompt = toolset
.get_prompt(
"investigate_order",
Some(serde_json::Map::from_iter([
("order_id".to_string(), json!("ORD-1042")),
])),
)
.await?;
let suggestions = toolset
.complete_prompt_argument("investigate_order", "order_id", "ORD-", None)
.await?;
toolset.subscribe_resource("company://inventory/sku-42").await?;
// ... receive notifications in a custom ClientHandler ...
toolset.unsubscribe_resource("company://inventory/sku-42").await?;
当较旧的服务器未实现资源或提示列表功能时,便捷方法会返回空列表。 对已声明资源或提示执行操作时,如果远程调用失败,则会返回错误。
动态管理服务器
当应用程序需要管理一组本地 MCP 子进程,而不是一个静态连接时,请使用 McpServerManager。
use adk_tool::mcp::manager::{McpServerConfig, McpServerManager};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
let manager = Arc::new(McpServerManager::from_json_file("mcp.json")?
.with_name("product_mcp_servers")
.with_health_check_interval(Duration::from_secs(15))
.with_grace_period(Duration::from_secs(2)));
let outcomes = manager.start_all().await;
for (server_id, outcome) in outcomes {
if let Err(error) = outcome {
eprintln!("{server_id} did not start: {error}");
}
}
manager.start_monitoring();
let agent = LlmAgentBuilder::new("operator")
.model(model)
.toolset(manager.clone())
.build()?;
运行时注册表支持:
manager.add_server("billing".into(), billing_config).await?;
manager.start_server("billing").await?;
manager.update_server("billing", replacement_config).await?;
manager.disable_server("billing").await?;
manager.enable_server("billing").await?;
manager.save_json_file("mcp.json").await?;
manager.remove_server("billing").await?;
manager.shutdown().await?;
当两个服务器发布同名工具时,聚合工具集会将两个名称都添加前缀 {server_id}__{tool_name}。
唯一名称保持不变。
健康监视器检测到已关闭的 MCP 连接。配置的
RestartPolicy 通过指数退避控制有界重试。这是连接监控,而不是应用层健康检查:需要验证服务器后端数据库或外部 API 时,请使用领域工具或单独的服务探针。
运行确定性示例:
cargo run --manifest-path examples/mcp_manager/Cargo.toml
它会启动一个真实的 Rust MCP 子服务器,并测试发现、工具调用、 运行时添加/启用/更新/禁用/移除、配置持久化和关闭流程。它不会下载软件包,也不需要 API 密钥。
远程可流式 HTTP
use adk_tool::{McpAuth, McpHttpClientBuilder};
use std::time::Duration;
let toolset = McpHttpClientBuilder::new("https://mcp.example.com/mcp")
.with_auth(McpAuth::bearer(std::env::var("MCP_TOKEN")?))
.header("X-Tenant-ID", "tenant-42")
.timeout(Duration::from_secs(30))
.reinit_on_expired_session(true)
.connect()
.await?;
构建器会应用请求超时、自定义标头、Bearer 令牌、自定义 API-key 标头,以及在 HTTP 会话过期时进行有界恢复。
OAuth2Config 实现固定的 OAuth 2.0 客户端凭据令牌请求。
它适用于具有已知令牌端点的服务器。但它不是完整的
MCP 授权流程:不会执行受保护资源元数据发现、
授权服务器发现、浏览器授权、PKCE 或资源指示器协商。部署需要该流程时,请使用 rmcp 的授权 APIs,或使用外部
身份组件。
引导式信息收集
MCP 服务器可能需要工具参数中未包含的信息。在 这种情况下,它可以向客户端发送引导式信息收集请求。应用程序决定如何向用户显示该请求,以及是否接受、拒绝或 取消该请求。
let toolset = McpToolset::with_elicitation_handler(
transport,
Arc::new(MyElicitationHandler),
).await?;
ADK-Rust 同时支持表单和 URL 引导式收集。处理程序错误或崩溃会被转换为拒绝,以便 MCP 连接保持可用。在接受具有后果的请求之前,请在应用程序中验证返回值并应用用户同意规则。
有关完整的服务器和交互式客户端,请参阅 examples/mcp_elicitation。
长时间运行的 MCP 任务
MCP 2025-11-25 可以将工具调用转为协议任务。只有当服务器协商了 tasks.requests.tools.call,并且工具声明支持必需或可选任务时,ADK-Rust 才会使用任务流程。
use adk_tool::McpTaskConfig;
use std::time::Duration;
let toolset = McpToolset::new(client).with_task_support(
McpTaskConfig::enabled()
.poll_interval(Duration::from_secs(1))
.timeout(Duration::from_secs(120))
.max_attempts(120),
);
在任务模式下,ADK-Rust:
- 使用官方任务元数据发送
tools/call; - 接收创建的任务;
- 按照服务器建议的间隔轮询
tasks/get; - 通过
tasks/result读取最终载荷;以及 - 在达到本地超时或轮询次数限制时调用
tasks/cancel。
input_required 会作为类型化错误返回,因为普通的 ADK 工具调用目前还没有用于提供缺失输入的协议中立恢复通道。请在所属工作流中明确设计该交互。
能力映射
| MCP 能力 | ADK-Rust 2 表面 | 注释 |
|---|---|---|
| 工具发现与调用 | McpToolset, Toolset | 保留原始模式、多模态结果和结构化结果 |
| 工具筛选 | with_filter, with_tools | 在向模型公开之前进行筛选 |
| 资源和模板 | 列出/读取方法 | 为旧版服务器处理方法未找到错误 |
| 提示 | 列出/获取方法 | 类型化参数映射 |
| 补全 | 提示/资源补全方法 | 返回官方 CompletionInfo |
| 资源订阅 | 订阅/取消订阅方法 | 通知需要适当的客户端处理程序 |
| 启发 | ElicitationHandler | 表单和 URL 模式 |
| 任务 | McpTaskConfig | 协商式工具调用任务生命周期 |
| 本地标准输入输出 | TokioChildProcess | 直接拥有或由管理器拥有 |
| 可流式传输的 HTTP | McpHttpClientBuilder | 超时、标头、身份验证注入、会话恢复 |
| 动态本地注册表 | McpServerManager | 添加/更新/启用/禁用/移除/保存/监控/重启 |
| 服务器编写与扩展 | adk_tool::mcp::rmcp | 用于高级用途的精确 SDK 再导出 |
| 采样、根目录、日志记录 | 兼容性功能 / rmcp | 上游已通过 SEP-2577 弃用 |
选择边界
当能力属于同一进程和发布版本时,使用 Rust FunctionTool。当另一个程序、团队、语言、安全边界或部署拥有该能力,并且应发布自己的契约时,使用 MCP。
对于生产部署:
- 暴露最小的实用工具集;
- 分离只读操作和有重大影响的操作;
- 不要将机密放入命令行参数和已提交的
mcp.json文件中; - 对远程 HTTP 服务器进行身份验证,并严格限定凭据的使用范围;
- 将工具描述和服务器返回的内容视为不受信任的输入;
- 在工具执行周围保留 ADK-Rust 授权和审批;
- 限制连接、工具和任务的超时时间;以及
- 记录工具调用、审批、错误和服务器生命周期变更。
当前限制
McpServerManager管理本地 stdio 子进程。远程 HTTP 服务使用McpHttpClientBuilder和由应用管理的配置。- 管理器健康检查会检测已关闭的 MCP 连接;但不会调用业务级健康工具。
- 注册表变更会在子进程完成其 MCP 握手期间进行序列化。
autoApprove是配置兼容性机制,而不是授权强制机制。- 内置的 OAuth 辅助工具用于客户端凭据,并不包含完整的 MCP OAuth 发现和用户授权流程。
明确说明这些限制,是为了确保部署决策保持清晰。