أدوات MCP
بروتوكول سياق النموذج (MCP) هو معيار مفتوح يمكّن LLMs من التواصل مع التطبيقات الخارجية ومصادر البيانات والأدوات. يوفر adk-rust دعمًا كاملاً لـ MCP من خلال McpToolset، مما يتيح لك الاتصال بأي خادم متوافق مع MCP وكشف أدواته لوكلائك.
نظرة عامة
يتبع MCP بنية العميل والخادم:
- تكشف MCP Servers عن الأدوات والموارد والمطالبات
- تتصل MCP Clients (مثل ADK agents) بالخوادم وتستخدم قدراتها
فوائد تكامل MCP:
- اتصال عالمي - اتصل بأي خادم متوافق مع MCP
- اكتشاف تلقائي - يتم اكتشاف الأدوات ديناميكيًا من الخادم
- محايد للغة - استخدم الأدوات المكتوبة بأي لغة
- نظام بيئي متنامي - الوصول إلى الآلاف من MCP servers الموجودة
المتطلبات الأساسية
تُوزع MCP servers عادةً كحزم npm. ستحتاج إلى:
- تثبيت Node.js و npm
- مفتاح LLM API (Gemini، OpenAI، إلخ)
بدء سريع
اتصل بـ MCP server واستخدم أدواته:
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
إنشاء مجموعة أدوات
use adk_tool::McpToolset;
// إنشاء أساسي
let toolset = McpToolset::new(client);
// باسم مخصص
let toolset = McpToolset::new(client)
.with_name("filesystem-tools");
تصفية الأدوات
تصفية الأدوات التي سيتم عرضها:
// التصفية بواسطة دالة المسند
let toolset = McpToolset::new(client)
.with_filter(|name| {
matches!(name, "read_file" | "write_file" | "list_directory")
});
// التصفية بالأسماء الدقيقة (طريقة ملائمة)
let toolset = McpToolset::new(client)
.with_tools(&["echo", "add", "get_time"]);
التنظيف باستخدام رمز الإلغاء
احصل دائمًا على رمز إلغاء لإيقاف تشغيل خادم MCP بشكل نظيف:
let toolset = McpToolset::new(client);
let cancel_token = toolset.cancellation_token().await;
// ... استخدم مجموعة الأدوات ...
// قبل الخروج، أوقف تشغيل خادم MCP
cancel_token.cancel();
يمنع هذا أخطاء EPIPE ويضمن إنهاء نظيفًا للعملية.
الاتصال بخوادم MCP
الخوادم المحلية (Stdio)
الاتصال بخادم MCP محلي عبر الإدخال/الإخراج القياسي:
use rmcp::{ServiceExt, transport::TokioChildProcess};
use tokio::process::Command;
// خادم حزمة NPM
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?;
// خادم ثنائي محلي
let mut cmd = Command::new("./my-mcp-server");
cmd.arg("--config").arg("config.json");
let client = ().serve(TokioChildProcess::new(cmd)?).await?;
الخوادم البعيدة (SSE)
الاتصال بخادم MCP بعيد عبر أحداث مرسلة من الخادم (Server-Sent Events):
use rmcp::{ServiceExt, transport::SseClient};
let client = ().serve(
SseClient::new("http://localhost:8080/sse")?
).await?;
اكتشاف الأدوات
تكتشف McpToolset الأدوات تلقائيًا من الخادم المتصل:
use adk_core::{ReadonlyContext, Toolset};
// الحصول على الأدوات المكتشفة
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 استلمت وسيطات غير صحيحة
أفضل الممارسات
- تصفية Tools - اعرض فقط Tools التي يحتاجها Agent لتقليل الالتباس
- استخدام رموز الإلغاء - قم دائمًا باستدعاء
cancel()قبل الخروج للتنظيف - معالجة الأخطاء - قد تفشل خوادم MCP؛ طبق معالجة الأخطاء المناسبة
- استخدام الخوادم المحلية - للتطوير، نقل stdio أبسط من النقل عن بعد
- التحقق من حالة الخادم - تحقق من تشغيل خادم MCP قبل إنشاء toolset
مثال كامل
إليك مثال عملي كامل مع تنظيف مناسب:
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 مخصص
يمكنك إنشاء خادم MCP خاص بك في Rust باستخدام rmcp SDK:
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 للاطلاع على تفاصيل تنفيذ الخادم الكاملة.
ذات صلة
- أدوات الوظائف - إنشاء أدوات مخصصة في Rust
- الأدوات المضمنة - أدوات جاهزة مضمنة مع ADK
- LlmAgent - إضافة أدوات إلى الوكلاء
- rmcp SDK - SDK الرسمي لـ Rust MCP
- مواصفات MCP - توثيق البروتوكول
السابق: ← أدوات واجهة المستخدم | التالي: الجلسات →