use rmcp::handler::server::router::tool::ToolRouter; use rmcp::handler::server::wrapper::Parameters; use std::sync::Arc; use rmcp::model::{ CallToolResult, ListResourceTemplatesResult, PaginatedRequestParams, ReadResourceRequestParams, ReadResourceResponse, ServerConfig, SubscriptionFilter, }; use rmcp::service::{RequestContext, SubscriptionContext}; use rmcp::transport::stdio; use rmcp::{tool, tool_handler, tool_router, ServerHandler, ServiceExt}; use rmcp::{ErrorData, RoleServer}; use super::service::KcpServiceHandle; use super::watch::{self, WatchHub}; use super::{spec, tools}; #[derive(Clone)] pub struct ReadonlyServer { tool_router: ToolRouter, service: KcpServiceHandle, watches: Arc, } impl ReadonlyServer { pub fn new(service: KcpServiceHandle) -> Self { Self { tool_router: Self::tool_router(), service, watches: Arc::default(), } } } #[tool_router] impl ReadonlyServer { #[tool(description = spec::LIST_KCPS, output_schema = spec::kcp_report(), annotations(read_only_hint = true))] pub async fn list_kcps( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::list_kcps(&self.service, request).await } #[tool(description = spec::LIST_WORKSPACES, output_schema = spec::workspaces(), annotations(read_only_hint = true))] pub async fn list_workspaces( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::list_workspaces(&self.service, request).await } #[tool(description = spec::GET_API_RESOURCES, output_schema = spec::api_resources(), annotations(read_only_hint = true))] pub async fn get_api_resources( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::get_api_resources(&self.service, request).await } #[tool(description = spec::LIST_OBJECTS, output_schema = spec::kube_list(), annotations(read_only_hint = true))] pub async fn list_objects( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::list_objects(&self.service, request).await } #[tool(description = spec::GET_OBJECT, output_schema = spec::kube_object(), annotations(read_only_hint = true))] pub async fn get_object( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::get_object(&self.service, request).await } #[tool(description = spec::GET_LOGS, annotations(read_only_hint = true))] pub async fn get_logs( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::get_logs(&self.service, request).await } #[tool(description = spec::GET_EVENTS, output_schema = spec::event_list(), annotations(read_only_hint = true))] pub async fn get_events( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::get_events(&self.service, request).await } #[tool(description = spec::READONLY_CREDENTIALS, output_schema = spec::credential(), annotations(read_only_hint = true))] pub async fn readonly_credentials( &self, Parameters(request): Parameters, ) -> CallToolResult { tools::readonly_credentials(&self.service, request).await } } #[tool_handler(router = self.tool_router)] impl ServerHandler for ReadonlyServer { fn get_info(&self) -> ServerConfig { watch::server_info() } async fn list_resource_templates( &self, _request: Option, _context: RequestContext, ) -> Result { Ok(watch::resource_templates()) } async fn read_resource( &self, request: ReadResourceRequestParams, _context: RequestContext, ) -> Result { watch::read_resource(&self.watches, &self.service, &request.uri).await } fn accepted_subscription_filter( &self, requested: &SubscriptionFilter, ) -> Option { watch::accepted_subscriptions(requested) } async fn listen(&self, context: SubscriptionContext) -> Result<(), ErrorData> { watch::listen(&self.watches, &self.service, context).await } } pub async fn serve_stdio(service: KcpServiceHandle) -> Result<(), Box> { let service = ReadonlyServer::new(service).serve(stdio()).await?; service.waiting().await?; Ok(()) }