MCP टूल्स

Model Context Protocol (MCP) एक ओपन स्टैंडर्ड है जो LLMs को बाहरी एप्लिकेशन्स, डेटा स्रोतों और tools के साथ संचार करने में सक्षम बनाता है। ADK-Rust McpToolset के माध्यम से पूर्ण MCP समर्थन प्रदान करता है, जिससे आप किसी भी MCP-अनुरूप server से जुड़ सकते हैं और इसके tools को अपने agents के लिए उजागर कर सकते हैं।

अवलोकन

MCP क्लाइंट-server आर्किटेक्चर का पालन करता है:

  • MCP Servers tools, resources, और prompts को उजागर करते हैं
  • MCP Clients (जैसे ADK agents) servers से जुड़ते हैं और उनकी क्षमताओं का उपयोग करते हैं

MCP एकीकरण के लाभ:

  • सार्वभौमिक कनेक्टिविटी - किसी भी MCP-अनुरूप server से जुड़ें
  • स्वचालित खोज - Tools server से गतिशील रूप से खोजे जाते हैं
  • भाषा-अज्ञेयवादी - किसी भी भाषा में लिखे गए tools का उपयोग करें
  • बढ़ता हुआ इकोसिस्टम - हजारों मौजूदा MCP servers तक पहुँच प्राप्त करें

पूर्व-आवश्यकताएँ

MCP servers आमतौर पर npm packages के रूप में वितरित किए जाते हैं। आपको इनकी आवश्यकता होगी:

  • Node.js और npm स्थापित
  • एक LLM API key (Gemini, OpenAI, आदि)

त्वरित शुरुआत

एक MCP server से कनेक्ट करें और उसके tools का उपयोग करें:

use adk_agent::LlmAgentBuilder;
use adk_core::{Content, Part, ReadonlyContext, Toolset};
use adk_model::GeminiModel;
use adk_tool::McpToolset;
use rmcp::{ServiceExt, transport::TokioChildProcess};
use tokio::process::Command;
use std::sync::Arc;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();
    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.0-flash")?);

    // 1. Start MCP server and connect
    let mut cmd = Command::new("npx");
    cmd.arg("-y").arg("@modelcontextprotocol/server-everything");

    let client = ().serve(TokioChildProcess::new(cmd)?).await?;

    // 2. Create toolset from the client
    let toolset = McpToolset::new(client)
        .with_tools(&["echo", "add"]);  // Only expose these tools

    // 3. Get cancellation token for cleanup
    let cancel_token = toolset.cancellation_token().await;

    // 4. Discover tools and add to agent
    let ctx: Arc<dyn ReadonlyContext> = Arc::new(SimpleContext);
    let tools = toolset.tools(ctx).await?;

    let mut builder = LlmAgentBuilder::new("mcp_agent")
        .model(model)
        .instruction("You have MCP tools. Use 'echo' to repeat messages, 'add' to sum numbers.");

    for tool in tools {
        builder = builder.tool(tool);
    }

    let agent = builder.build()?;

    // 5. Run interactive console
    adk_cli::console::run_console(
        Arc::new(agent),
        "mcp_demo".to_string(),
        "user".to_string(),
    ).await?;

    // 6. Cleanup: shutdown MCP server
    cancel_token.cancel();

    Ok(())
}

// Minimal context for tool discovery
struct SimpleContext;

#[async_trait::async_trait]
impl ReadonlyContext for SimpleContext {
    fn invocation_id(&self) -> &str { "init" }
    fn agent_name(&self) -> &str { "init" }
    fn user_id(&self) -> &str { "user" }
    fn app_name(&self) -> &str { "mcp" }
    fn session_id(&self) -> &str { "init" }
    fn branch(&self) -> &str { "main" }
    fn user_content(&self) -> &Content {
        static CONTENT: std::sync::OnceLock<Content> = std::sync::OnceLock::new();
        CONTENT.get_or_init(|| Content::new("user").with_text("init"))
    }
}

इसके साथ चलाएँ:

GOOGLE_API_KEY=your_key cargo run --bin basic

McpToolset API

एक टूलसेट बनाना

use adk_tool::McpToolset;

// Basic creation
let toolset = McpToolset::new(client);

// With custom name
let toolset = McpToolset::new(client)
    .with_name("filesystem-tools");

टूल फ़िल्टरिंग

कौन से टूल प्रदर्शित करने हैं, उन्हें फ़िल्टर करें:

// Filter by predicate function
let toolset = McpToolset::new(client)
    .with_filter(|name| {
        matches!(name, "read_file" | "write_file" | "list_directory")
    });

// Filter by exact names (convenience method)
let toolset = McpToolset::new(client)
    .with_tools(&["echo", "add", "get_time"]);

कैंसलेशन टोकन के साथ सफाई

MCP सर्वर को ठीक से बंद करने के लिए हमेशा एक कैंसलेशन टोकन प्राप्त करें:

let toolset = McpToolset::new(client);
let cancel_token = toolset.cancellation_token().await;

// ... use the toolset ...

// Before exiting, shutdown the MCP server
cancel_token.cancel();

यह EPIPE त्रुटियों को रोकता है और स्वच्छ प्रक्रिया समाप्ति सुनिश्चित करता है।

MCP सर्वर से कनेक्ट करना

स्थानीय सर्वर (Stdio)

मानक इनपुट/आउटपुट के माध्यम से एक स्थानीय MCP सर्वर से कनेक्ट करें:

use rmcp::{ServiceExt, transport::TokioChildProcess};
use tokio::process::Command;

// NPM package server
let mut cmd = Command::new("npx");
cmd.arg("-y")
    .arg("@modelcontextprotocol/server-filesystem")
    .arg("/path/to/allowed/directory");
let client = ().serve(TokioChildProcess::new(cmd)?).await?;

// Local binary server
let mut cmd = Command::new("./my-mcp-server");
cmd.arg("--config").arg("config.json");
let client = ().serve(TokioChildProcess::new(cmd)?).await?;

रिमोट सर्वर (SSE)

सर्वर-सेंट इवेंट्स के माध्यम से एक रिमोट MCP सर्वर से कनेक्ट करें:

use rmcp::{ServiceExt, transport::SseClient};

let client = ().serve(
    SseClient::new("http://localhost:8080/sse")?
).await?;

टूल डिस्कवरी

McpToolset स्वचालित रूप से कनेक्टेड सर्वर से टूल का पता लगाता है:

use adk_core::{ReadonlyContext, Toolset};

// Get discovered tools
let tools = toolset.tools(ctx).await?;

println!("Discovered {} tools:", tools.len());
for tool in &tools {
    println!("  - {}: {}", tool.name(), tool.description());
}

प्रत्येक खोजा गया टूल:

  • MCP सर्वर से इसका नाम और विवरण होता है
  • LLM सटीकता के लिए पैरामीटर स्कीमा शामिल करता है
  • बुलाए जाने पर MCP प्रोटोकॉल के माध्यम से निष्पादित होता है

एजेंट में टूल जोड़ना

किसी एजेंट में MCP टूल जोड़ने के लिए दो पैटर्न हैं:

पैटर्न 1: टूलसेट के रूप में जोड़ें

let toolset = McpToolset::new(client);

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

पैटर्न 2: व्यक्तिगत टूल जोड़ें

यह आपको इस बात पर अधिक नियंत्रण देता है कि कौन से टूल जोड़े गए हैं:

let toolset = McpToolset::new(client)
    .with_tools(&["echo", "add"]);

let tools = toolset.tools(ctx).await?;

let mut builder = LlmAgentBuilder::new("agent")
    .model(model);

for tool in tools {
    builder = builder.tool(tool);
}

let agent = builder.build()?;

लोकप्रिय MCP सर्वर

यहां कुछ सामान्य रूप से उपयोग किए जाने वाले MCP सर्वर दिए गए हैं जिन्हें आप एकीकृत कर सकते हैं:

एवरीथिंग सर्वर (परीक्षण)

npx -y @modelcontextprotocol/server-everything

टूल: echo, add, longRunningOperation, sampleLLM, getAlerts, printEnv

फाइलसिस्टम सर्वर

npx -y @modelcontextprotocol/server-filesystem /path/to/directory

टूल: read_file, write_file, list_directory, search_files

GitHub सर्वर

npx -y @modelcontextprotocol/server-github

टूल: search_repositories, get_file_contents, create_issue

Slack सर्वर

npx -y @modelcontextprotocol/server-slack

टूल: send_message, list_channels, search_messages

मेमोरी सर्वर

npx -y @modelcontextprotocol/server-memory

टूल: store, retrieve, search

MCP सर्वर रजिस्ट्री पर और सर्वर खोजें।

त्रुटि प्रबंधन

MCP कनेक्शन और निष्पादन त्रुटियों को संभालें:

use adk_core::AdkError;

match toolset.tools(ctx).await {
    Ok(tools) => {
        println!("Discovered {} tools", tools.len());
    }
    Err(AdkError::Tool(msg)) => {
        eprintln!("MCP error: {}", msg);
    }
    Err(e) => {
        eprintln!("Other error: {}", e);
    }
}

सामान्य त्रुटियाँ:

  • कनेक्शन विफल - सर्वर नहीं चल रहा है या गलत पता
  • Tool निष्पादन विफल - MCP सर्वर ने एक त्रुटि लौटा दी
  • अमान्य पैरामीटर - Tool को गलत आर्गुमेंट प्राप्त हुए

सर्वोत्तम अभ्यास

  1. Tool को फ़िल्टर करें - भ्रम को कम करने के लिए केवल उन tools को उजागर करें जिनकी Agent को आवश्यकता है
  2. कैंसिलेशन टोकन का उपयोग करें - cleanup के लिए बाहर निकलने से पहले हमेशा cancel() को कॉल करें
  3. त्रुटियों को संभालें - MCP सर्वर विफल हो सकते हैं; उचित त्रुटि प्रबंधन लागू करें
  4. स्थानीय सर्वर का उपयोग करें - विकास के लिए, stdio ट्रांसपोर्ट रिमोट की तुलना में सरल है
  5. सर्वर स्थिति जांचें - Toolset बनाने से पहले MCP सर्वर के चलने की पुष्टि करें

पूर्ण उदाहरण

यहाँ उचित cleanup के साथ एक पूर्ण कार्यशील उदाहरण दिया गया है:

use adk_agent::LlmAgentBuilder;
use adk_core::{Content, Part, ReadonlyContext, Toolset};
use adk_model::GeminiModel;
use adk_tool::McpToolset;
use rmcp::{ServiceExt, transport::TokioChildProcess};
use std::sync::Arc;
use tokio::process::Command;

struct SimpleContext;

#[async_trait::async_trait]
impl ReadonlyContext for SimpleContext {
    fn invocation_id(&self) -> &str { "init" }
    fn agent_name(&self) -> &str { "init" }
    fn user_id(&self) -> &str { "user" }
    fn app_name(&self) -> &str { "mcp" }
    fn session_id(&self) -> &str { "init" }
    fn branch(&self) -> &str { "main" }
    fn user_content(&self) -> &Content {
        static CONTENT: std::sync::OnceLock<Content> = std::sync::OnceLock::new();
        CONTENT.get_or_init(|| Content::new("user").with_text("init"))
    }
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenvy::dotenv().ok();

    let api_key = std::env::var("GOOGLE_API_KEY")?;
    let model = Arc::new(GeminiModel::new(&api_key, "gemini-2.0-flash")?);

    println!("Starting MCP server...");
    let mut cmd = Command::new("npx");
    cmd.arg("-y").arg("@modelcontextprotocol/server-everything");

    let client = ().serve(TokioChildProcess::new(cmd)?).await?;
    println!("MCP server connected!");

    // Create filtered toolset
    let toolset = McpToolset::new(client)
        .with_name("everything-tools")
        .with_filter(|name| matches!(name, "echo" | "add" | "printEnv"));

    // Get cancellation token for cleanup
    let cancel_token = toolset.cancellation_token().await;

    // Discover tools
    let ctx = Arc::new(SimpleContext) as Arc<dyn ReadonlyContext>;
    let tools = toolset.tools(ctx).await?;

    println!("Discovered {} tools:", tools.len());
    for tool in &tools {
        println!("  - {}: {}", tool.name(), tool.description());
    }

    // Build agent with tools
    let mut builder = LlmAgentBuilder::new("mcp_demo")
        .model(model)
        .instruction(
            "You have access to MCP tools:\n\
             - echo: Repeat a message back\n\
             - add: Add two numbers (a + b)\n\
             - printEnv: Print environment variables"
        );

    for tool in tools {
        builder = builder.tool(tool);
    }

    let agent = builder.build()?;

    // Run interactive console
    let result = adk_cli::console::run_console(
        Arc::new(agent),
        "mcp_demo".to_string(),
        "user".to_string(),
    ).await;

    // Cleanup
    println!("\nShutting down MCP server...");
    cancel_token.cancel();
    tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;

    result?;
    Ok(())
}

उन्नत: अनुकूलित MCP सर्वर

आप rmcp SDK का उपयोग करके Rust में अपना स्वयं का MCP सर्वर बना सकते हैं:

use rmcp::{tool, tool_router, handler::server::tool::ToolRouter, model::*};

#[derive(Clone)]
pub struct MyServer {
    tool_router: ToolRouter<Self>,
}

#[tool_router]
impl MyServer {
    fn new() -> Self {
        Self { tool_router: Self::tool_router() }
    }

    #[tool(description = "Add two numbers")]
    async fn add(&self, a: i32, b: i32) -> Result<CallToolResult, ErrorData> {
        Ok(CallToolResult::success(vec![Content::text((a + b).to_string())]))
    }

    #[tool(description = "Multiply two numbers")]
    async fn multiply(&self, a: i32, b: i32) -> Result<CallToolResult, ErrorData> {
        Ok(CallToolResult::success(vec![Content::text((a * b).to_string())]))
    }
}

संपूर्ण सर्वर कार्यान्वयन विवरण के लिए rmcp दस्तावेज़ देखें।

संबंधित

  • Function Tools - Rust में कस्टम टूल बनाना
  • Built-in Tools - ADK के साथ शामिल पूर्व-निर्मित टूल
  • LlmAgent - एजेंटों में टूल जोड़ना
  • rmcp SDK - आधिकारिक Rust MCP SDK
  • MCP Specification - प्रोटोकॉल दस्तावेज़

पिछला: ← UI Tools | अगला: Sessions →