模型上下文协议 (MCP)

文档地图: 概述与架构 · 客户端 · 动态管理器 · 服务器编写 · 安全 · 测试

MCP 为 AI 应用程序提供了一种标准方式来发现和使用由另一个进程或服务拥有的功能。服务器可以发布:

  • 工具,用于执行操作;
  • 资源,用于返回可读上下文;
  • 提示,用于提供可重用的消息模板;以及
  • 补全建议,帮助客户端填写提示或资源参数。

ADK-Rust 通常是 MCP 客户端McpToolset 将发现的 MCP 工具转换为正常的 ADK-Rust Tool 值,以便 LlmAgent 可以选择并调用它们。该框架还公开了资源、提示、补全、订阅、启发和协商的任务生命周期。对于 MCP 服务器编写和高级协议工作,ADK-Rust 重新导出了它使用的确切 rmcp SDK 版本。

ADK-Rust 2 目前使用 rmcp 2.2,这是与 MCP 2025-11-25 规范对齐的官方 Rust SDK。

架构

Rendering architecture…

有两个独立的层:

  1. McpToolset 拥有一个已初始化的 MCP 客户端连接。它发现服务器的功能并将其适配到 ADK-Rust。
  2. McpServerManager 拥有一个不断变化的本地 stdio 服务器注册表。它启动、监控、重启、更新、启用、禁用、持久化和聚合这些连接。

管理器不授予工具批准。它在读取兼容配置时保留 autoApprove,但应用程序必须应用其正常的 ADK-Rust 授权和批准策略。

安装

本地 stdio MCP 支持是可选的:

[dependencies]
adk-tool = { version = "2.0.0", features = ["mcp"] }

连接到远程服务时添加 Streamable HTTP:

adk-tool = { version = "2.0.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 密钥。

远程 Streamable 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 启发。处理程序错误或 panic 会转换为拒绝,以便 MCP 连接保持可用。在接受有影响的请求之前,请在应用程序中验证返回的值并应用同意规则。

有关完整的服务器和交互式客户端,请参阅 examples/mcp_elicitation

长期运行的 MCP 任务

MCP 2025-11-25 可以将工具调用移动到协议任务中。ADK-Rust 仅在服务器协商了 tasks.requests.tools.call 且工具声明了必需或可选任务支持时才使用任务流。

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:

  1. 发送带有官方任务元数据的 tools/call
  2. 接收创建的任务;
  3. 使用服务器建议的间隔轮询 tasks/get
  4. 通过 tasks/result 读取最终有效载荷;以及
  5. 当达到其本地超时或轮询限制时调用 tasks/cancel

input_required 作为类型化错误返回,因为普通的 ADK 工具调用尚未具有协议中立的恢复通道来提供缺失的输入。在拥有工作流中明确设计该交互。

功能图

MCP 能力ADK-Rust 2 界面备注
工具发现和调用McpToolset, Toolset原始模式;多模态和结构化结果得以保留
工具过滤with_filter, with_tools在暴露给模型之前进行过滤
资源和模板列表/读取方法为旧服务器处理方法未找到的情况
提示列表/获取方法类型化参数映射
完成提示/资源完成方法返回官方 CompletionInfo
资源订阅订阅/取消订阅方法通知需要适当的客户端处理程序
启发ElicitationHandler形式和 URL 模式
任务McpTaskConfig协商的 tool-call 任务生命周期
本地 stdioTokioChildProcess直接或管理器拥有
可流式传输的 HTTPMcpHttpClientBuilder超时、请求头、认证注入、会话恢复
动态本地注册表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 发现和用户授权流程。

声明这些限制是为了使部署决策保持明确。

参考资料

模型上下文协议 (MCP) - ADK-Rust 文档 | ADK-Rust