MCPクライアントを構築する

ADK-Rustアプリケーションは、サーバーに接続し、その公開カタログを読み取り、選択した機能をエージェントまたはワークフローで利用可能にすると、MCPクライアントになります。

インストール

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

リモートのストリーム可能な HTTP の場合:

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

ローカル stdio 接続

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

本番環境では絶対バイナリパスを使用してください。デプロイ構成で latest のようなパッケージタグを使用することは避けてください。これらを使用すると、ビルドとインシデントからの復旧が再現不可能になります。

ツールの検出とフィルタリング

McpToolset は、公開された各 MCP ツールを ADK-Rust Tool に変換します。サーバーの入力スキーマと出力スキーマは変更されません。選択されたモデルプロバイダーは、リクエストを構築する際にスキーマのコピーを正規化します。

アダプターは MCP ツールアノテーションも保持します。readOnlyHint は ADK ツールを読み取り専用かつ並行実行安全として示します。idempotentHint は再接続後の安全な再実行を許可しますが、それだけでツールが自動並列ディスパッチの対象になるわけではありません。ヒントがない場合は、どちらの動作も無効になります。

重要: MCP アノテーションは、サーバーが公開するヒントです。自動再実行およびディスパッチメタデータは、アプリケーションの信頼境界内にあるサーバーに対してのみ使用してください。

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

フィルタリングはモデルから見える範囲を制御します。ツール実行時の認可に代わるものではありません。

リソース、プロンプト、補完

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

リソーステンプレートの補完には complete_resource_argument を使用します。一覧操作を実装していないサーバーが MCP MethodNotFound で応答した場合は空のリストを返します。それ以外のプロトコルおよびトランスポートの障害は、引き続きエラーとして扱われます。

リソースサブスクリプション

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は、制限付き接続更新後にアクティブなサブスクリプションを復元します。
McpServerManagerは、管理対象プロセスの再起動をまたいでもサブスクリプションを保持します。
ハンドラーのエラーとパニックは、MCP接続を終了せずにログに記録されます。
Streamable HTTPの場合は、connect_with_elicitationを呼び出す前に
McpHttpClientBuilder::with_resource_notification_handlerで同じハンドラーを設定してください。

情報要求

情報要求を使用すると、サーバーはツール呼び出しの処理中に情報を要求できます。
アプリケーションは、要求をどのように提示するか、また受け入れるか、拒否するか、キャンセルするかを決定します。

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

ADK-Rustは、フォームおよびURL情報要求を通知します。ハンドラーの失敗またはパニックは拒否として扱われ、MCPセッションが維持されます。アプリケーションは、受け入れた値を引き続き検証し、同意ポリシーを適用する必要があります。

完全なクライアントとサーバーの組み合わせについては、examples/mcp_elicitationを参照してください。

ネゴシエーションされたタスク

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

タスクモードは、ネゴシエーションされた次の2つの事実に基づいて選択されます。

  1. サーバーがtasks.requests.tools.callを通知していること、および
  2. ツールがタスクのサポートを必須または任意として宣言していること。

ADK-Rustは、tools/callでタスクメタデータを送信し、作成されたタスクを受信し、tasks/getをポーリングし、tasks/resultを読み取り、ローカルの制限を超えた場合にtasks/cancelを呼び出します。通常のADKツール呼び出しには、プロトコルに依存しないタスク再開用の入力チャネルがまだ用意されていないため、input_requiredは型付きエラーとして返されます。

リモート 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?;

ビルダーは、ベアラートークン、カスタムAPIキーのヘッダー、および固定されたOAuth 2.0クライアント資格情報をサポートします。認証フローを選択する前に、セキュリティと認可を参照してください。