Crear un cliente MCP

Una aplicación ADK-Rust es un cliente MCP cuando se conecta a un servidor, lee su catálogo publicado y pone capacidades seleccionadas a disposición de un agente o flujo de trabajo.

Instalar

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

Para HTTP remoto:

adk-tool = { version = "2.1.0", features = ["mcp", "http-transport"] }

Conexión stdio local

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 shutdown = toolset.cancellation_token().await;

let agent = LlmAgentBuilder::new("support")
    .model(model)
    .toolset(Arc::new(toolset))
    .build()?;

// Run the agent, then close the client-owned MCP session.
shutdown.cancel();

Usa una ruta binaria absoluta en producción. Evita etiquetas de paquetes como latest en la configuración de despliegue, ya que hacen que las compilaciones y la recuperación ante incidentes no sean reproducibles.

Descubrimiento y filtrado de herramientas

McpToolset convierte cada herramienta MCP publicada en una ADK-Rust Tool. Conserva sin cambios los esquemas de entrada y salida del servidor. El proveedor de modelo seleccionado normaliza una copia del esquema cuando crea su solicitud.

El adaptador también conserva las anotaciones de herramientas MCP. Un readOnlyHint marca la herramienta ADK como de solo lectura y segura para la concurrencia; un idempotentHint permite repetirla de forma segura después de volver a conectarse, pero no hace que la herramienta sea apta por sí misma para el envío paralelo automático. La ausencia de indicaciones mantiene ambos comportamientos deshabilitados.

Importante: Las anotaciones MCP son indicaciones publicadas por el servidor. Usa los metadatos de repetición y envío automáticos únicamente con servidores dentro del límite de confianza de la aplicación.

let reviewed = McpToolset::new(client).with_filter(|name| {
    matches!(name, "read_order" | "read_policy" | "request_replacement")
});

El filtrado controla la visibilidad para el modelo. No sustituye la autorización en el momento de ejecutar la herramienta.

Recursos, indicaciones y finalización

use serde_json::json;

let resources = toolset.list_resources().await?;
let templates = toolset.list_resource_templates().await?;
let policy = 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?;

La finalización de plantillas de recursos usa complete_resource_argument. Un servidor que no implementa operaciones de listado devuelve una lista vacía cuando responde con MCP MethodNotFound; los demás errores de protocolo y transporte siguen siendo errores.

Suscripciones a recursos

use adk_tool::{AutoDeclineElicitationHandler, McpToolset, ResourceNotificationHandler};
use std::sync::Arc;

struct ResourceUpdates;

#[async_trait::async_trait]
impl ResourceNotificationHandler for ResourceUpdates {
    async fn handle_resource_updated(
        &self,
        uri: &str,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        println!("Resource changed: {uri}");
        Ok(())
    }

    async fn handle_resource_list_changed(
        &self,
    ) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        println!("The resource catalog changed");
        Ok(())
    }
}

let toolset = McpToolset::with_handlers(
    transport,
    Arc::new(AutoDeclineElicitationHandler),
    Arc::new(ResourceUpdates),
).await?;

toolset.subscribe_resource("company://inventory/sku-42").await?;
toolset.unsubscribe_resource("company://inventory/sku-42").await?;

McpToolset restaura las suscripciones activas después de actualizar la conexión dentro de los límites establecidos. McpServerManager también conserva las suscripciones durante los reinicios gestionados del proceso. Los errores y pánicos de los controladores se registran sin terminar la conexión MCP. Para HTTP transmisible, configura el mismo controlador con McpHttpClientBuilder::with_resource_notification_handler antes de llamar a connect_with_elicitation.

Solicitud de información

La solicitud de información permite que un servidor solicite datos mientras gestiona una llamada a una herramienta. La aplicación decide cómo presentar la solicitud y si la acepta, la rechaza o la cancela.

let toolset = McpToolset::with_elicitation_handler(
    transport,
    Arc::new(MyElicitationHandler),
).await?;

ADK-Rust anuncia la solicitud de información mediante formularios y URL. Un fallo o pánico del controlador se convierte en un rechazo, preservando la sesión MCP. La aplicación aún debe validar los valores aceptados y aplicar la política de consentimiento.

Consulta examples/mcp_elicitation para ver un par completo de cliente y servidor.

Tareas negociadas

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),
);

El modo de tarea se selecciona a partir de dos hechos negociados:

  1. el servidor anuncia tasks.requests.tools.call; y
  2. la herramienta declara que la compatibilidad con tareas es obligatoria u opcional.

ADK-Rust envía metadatos de tarea con tools/call, recibe la tarea creada, consulta periódicamente tasks/get, lee tasks/result y llama a tasks/cancel cuando se superan los límites locales. input_required se devuelve como un error tipado porque una llamada ordinaria a la herramienta ADK todavía no proporciona un canal neutral respecto al protocolo para reanudar tareas.

HTTP transmisible remoto

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?;

El creador admite tokens de portador, un encabezado de clave API personalizado y credenciales de cliente fijas de OAuth 2.0. Consulta Seguridad y autorización antes de elegir un flujo de autenticación.