use std::sync::Arc;
use rmcp::{
ErrorData as McpError, ServerHandler,
model::{
CallToolRequestParams, CallToolResult, Implementation, ListToolsResult,
PaginatedRequestParams, ServerCapabilities, ServerInfo,
},
service::{RequestContext, RoleServer},
};
use crate::{
config::HubConfig,
runtime::{SessionRuntime, SessionRuntimeBuildError},
};
#[derive(Clone)]
pub(crate) struct HubServer {
runtime: Arc<SessionRuntime>,
}
impl HubServer {
pub(crate) async fn from_config(config: HubConfig) -> Result<Self, SessionRuntimeBuildError> {
Ok(Self {
runtime: Arc::new(SessionRuntime::build(&config).await?),
})
}
pub(crate) async fn shutdown(&self) {
self.runtime.shutdown().await;
}
}
impl ServerHandler for HubServer {
fn get_info(&self) -> ServerInfo {
ServerInfo::new(ServerCapabilities::builder().enable_tools().build())
.with_server_info(Implementation::new("mcp-hub", env!("CARGO_PKG_VERSION")))
.with_instructions("Tool-only MCP aggregation hub. This server exposes tools only.")
}
async fn list_tools(
&self,
_request: Option<PaginatedRequestParams>,
_context: RequestContext<RoleServer>,
) -> Result<ListToolsResult, McpError> {
Ok(ListToolsResult {
tools: self.runtime.list_tools().await,
next_cursor: None,
meta: None,
})
}
async fn call_tool(
&self,
request: CallToolRequestParams,
_context: RequestContext<RoleServer>,
) -> Result<CallToolResult, McpError> {
self.runtime
.call_tool(&request)
.await
.map_err(|error| error.into_mcp_error())
}
}