Model Context Protocol (MCP) server lifecycle management

Updated Jul 14, 2026

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