Ferramentas MCP
Model Context Protocol (MCP) é um padrão aberto que permite que LLMs se comuniquem com aplicações externas, fontes de dados e Tools. adk-rust oferece suporte MCP completo através do McpToolset, permitindo que você se conecte a qualquer servidor compatível com MCP e exponha suas Tools aos seus Agents.
Visão Geral
MCP segue uma arquitetura cliente-servidor:
- Servidores MCP expõem Tools, recursos e prompts
- Clientes MCP (como Agents adk) conectam-se a servidores e usam suas capacidades
Benefícios da integração MCP:
- Conectividade universal - Conecte-se a qualquer servidor compatível com MCP
- Descoberta automática - As Tools são descobertas dinamicamente a partir do servidor
- Independente de linguagem - Use Tools escritas em qualquer linguagem
- Ecossistema em crescimento - Acesse milhares de servidores MCP existentes
Pré-requisitos
Servidores MCP são tipicamente distribuídos como pacotes npm. Você precisará de:
- Node.js e npm instalados
- Uma chave de API de LLM (GeminiModel, OpenAIClient, etc.)
Início Rápido
Conecte-se a um servidor MCP e use suas 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"]); // Apenas exponha estas 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("Você tem Tools MCP. Use 'echo' para repetir mensagens, 'add' para somar números.");
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(())
}
// Contexto mínimo para descoberta de Tools
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"))
}
}
Run with:
GOOGLE_API_KEY=your_key cargo run --bin basic
API McpToolset
Criando um Toolset
use adk_tool::McpToolset;
// Basic creation
let toolset = McpToolset::new(client);
// With custom name
let toolset = McpToolset::new(client)
.with_name("filesystem-tools");
Filtragem de Ferramentas
Filtra quais ferramentas expor:
// 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"]);
Limpeza com Cancellation Token
Sempre obtenha um cancellation token para desligar o servidor MCP de forma limpa:
let toolset = McpToolset::new(client);
let cancel_token = toolset.cancellation_token().await;
// ... use the toolset ...
// Before exiting, shutdown the MCP server
cancel_token.cancel();
Isso previne erros EPIPE e garante uma terminação limpa do processo.
Conectando-se a Servidores MCP
Servidores Locais (Stdio)
Conecte-se a um servidor MCP local via entrada/saída padrão:
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?;
Servidores Remotos (SSE)
Conecte-se a um servidor MCP remoto via Server-Sent Events:
use rmcp::{ServiceExt, transport::SseClient};
let client = ().serve(
SseClient::new("http://localhost:8080/sse")?
).await?;
Descoberta de Ferramentas
O McpToolset descobre automaticamente ferramentas do servidor conectado:
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());
}
Cada ferramenta descoberta:
- Tem seu nome e descrição do servidor MCP
- Inclui esquemas de parâmetros para precisão de LLM
- Executa via protocolo MCP quando chamada
Adicionando Ferramentas ao Agent
Existem dois padrões para adicionar ferramentas MCP a um agent:
Padrão 1: Adicionar como Toolset
let toolset = McpToolset::new(client);
let agent = LlmAgentBuilder::new("agent")
.model(model)
.toolset(Arc::new(toolset))
.build()?;
Padrão 2: Adicionar Ferramentas Individuais
Isso lhe dá mais controle sobre quais ferramentas são adicionadas:
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()?;
Servidores MCP Populares
Aqui estão alguns servidores MCP comumente usados que você pode integrar:
Everything Server (Teste)
npx -y @modelcontextprotocol/server-everything
Ferramentas: echo, add, longRunningOperation, sampleLLM, getAlerts, printEnv
Servidor Filesystem
npx -y @modelcontextprotocol/server-filesystem /path/to/directory
Ferramentas: read_file, write_file, list_directory, search_files
Servidor GitHub
npx -y @modelcontextprotocol/server-github
Ferramentas: search_repositories, get_file_contents, create_issue
Servidor Slack
npx -y @modelcontextprotocol/server-slack
Ferramentas: send_message, list_channels, search_messages
Servidor Memory
npx -y @modelcontextprotocol/server-memory
Ferramentas: store, retrieve, search
Encontre mais servidores no MCP Server Registry.
Tratamento de Erros
Lida com erros de conexão e execução do 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);
}
}
Erros comuns:
- Falha na conexão - Servidor não está em execução ou endereço errado
- Falha na execução da Tool - Servidor MCP retornou um erro
- Parâmetros inválidos - A Tool recebeu argumentos incorretos
Melhores Práticas
- Filtrar Tools - Exponha apenas as Tools que o Agent precisa para reduzir a confusão
- Usar tokens de cancelamento - Sempre chame
cancel()antes de sair para realizar a limpeza - Lidar com erros - Servidores MCP podem falhar; implemente tratamento de erros apropriado
- Usar servidores locais - Para desenvolvimento, o transporte stdio é mais simples do que o remoto
- Verificar status do servidor - Verifique se o servidor MCP está em execução antes de criar o toolset
Exemplo Completo
Aqui está um exemplo completo e funcional com a limpeza adequada:
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!("Iniciando servidor MCP...");
let mut cmd = Command::new("npx");
cmd.arg("-y").arg("@modelcontextprotocol/server-everything");
let client = ().serve(TokioChildProcess::new(cmd)?).await?;
println!("Servidor MCP conectado!");
// Criar toolset filtrado
let toolset = McpToolset::new(client)
.with_name("everything-tools")
.with_filter(|name| matches!(name, "echo" | "add" | "printEnv"));
// Obter token de cancelamento para limpeza
let cancel_token = toolset.cancellation_token().await;
// Descobrir tools
let ctx = Arc::new(SimpleContext) as Arc<dyn ReadonlyContext>;
let tools = toolset.tools(ctx).await?;
println!("{} tools descobertas:", tools.len());
for tool in &tools {
println!(" - {}: {}", tool.name(), tool.description());
}
// Construir Agent com tools
let mut builder = LlmAgentBuilder::new("mcp_demo")
.model(model)
.instruction(
"Você tem acesso às tools do MCP:\n\
- echo: Repete uma mensagem de volta\n\
- add: Adiciona dois números (a + b)\n\
- printEnv: Imprime variáveis de ambiente"
);
for tool in tools {
builder = builder.tool(tool);
}
let agent = builder.build()?;
// Executar console interativo
let result = adk_cli::console::run_console(
Arc::new(agent),
"mcp_demo".to_string(),
"user".to_string(),
).await;
// Limpeza
println!("\nDesligando o servidor MCP...");
cancel_token.cancel();
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
result?;
Ok(())
}
Avançado: Servidor MCP Personalizado
Você pode criar seu próprio servidor MCP em Rust usando o SDK rmcp:
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())]))
}
}
Consulte a documentação do rmcp para obter detalhes completos da implementação do servidor.
Relacionado
- Function Tools - Criando ferramentas personalizadas em Rust
- Built-in Tools - Ferramentas pré-construídas incluídas com o ADK
- LlmAgent - Adicionando ferramentas a agentes
- rmcp SDK - SDK oficial do Rust MCP
- MCP Specification - Documentação do protocolo
Anterior: ← UI Tools | Próximo: Sessions →