The tool_registry module can register Model Context Protocol (MCP) servers,
start and stop them, refresh health status, and list tools exposed by running
servers. Tool queries are only allowed when a server is in the running
lifecycle state.
use std::sync::Arc;
use corbusier::context::{CorrelationId, RequestContext, SessionId, UserId};
use corbusier::tenant::TenantId;
use corbusier::tool_registry::{
adapters::{InMemoryMcpServerHost, memory::InMemoryMcpServerRegistry},
domain::{McpServerName, McpToolDefinition, McpTransport},
services::{McpServerLifecycleService, RegisterMcpServerRequest},
};
use mockable::DefaultClock;
use serde_json::json;
async fn manage_mcp_servers() -> Result<(), Box<dyn std::error::Error>> {
let host = Arc::new(InMemoryMcpServerHost::new());
host.set_tool_catalog(
McpServerName::new("workspace_tools")?,
vec![McpToolDefinition::new(
"search_code",
"Searches the workspace source tree",
json!({"type": "object", "properties": {"query": {"type": "string"}}}),
)?],
)?;
let service = McpServerLifecycleService::new(
Arc::new(InMemoryMcpServerRegistry::new()),
host,
Arc::new(DefaultClock),
);
let ctx = RequestContext::new(
TenantId::new(),
CorrelationId::new(),
UserId::new(),
SessionId::new(),
);
let request = RegisterMcpServerRequest::new(
"workspace_tools",
McpTransport::stdio("mcp-server")?,
);
let registered = service.register(&ctx, request).await?;
let started = service.start(&ctx, registered.id()).await?;
assert_eq!(started.server.lifecycle_state().as_str(), "running");
let servers = service.list_all(&ctx).await?;
assert_eq!(servers.len(), 1);
let tools = service.list_tools(&ctx, started.server.id()).await?;
assert_eq!(tools.len(), 1);
let stopped = service.stop(&ctx, started.server.id()).await?;
assert_eq!(stopped.lifecycle_state().as_str(), "stopped");
let after_stop = service.list_tools(&ctx, stopped.id()).await;
assert!(after_stop.is_err());
Ok(())
}