1use std::fmt;
8use std::pin::Pin;
9use std::sync::Arc;
10
11use rmcp::model::{
12 CallToolRequestParams, CallToolResponse, Implementation, ListToolsResult, PaginatedRequestParams,
13 ServerCapabilities, ServerConfig, Tool,
14};
15use rmcp::service::RequestContext;
16use rmcp::{ErrorData, RoleServer, ServerHandler};
17
18const NAME: &str = "dbmcp";
20
21const VERSION: &str = env!("CARGO_PKG_VERSION");
23
24const TITLE: &str = "Database MCP Server";
26
27const HOMEPAGE: &str = env!("CARGO_PKG_HOMEPAGE");
29
30#[derive(Clone)]
38pub struct Server {
39 handler: Arc<dyn DynHandler>,
40 shutdown: Arc<dyn Shutdown>,
41}
42
43type HandlerFuture<'a, T> = Pin<Box<dyn Future<Output = Result<T, ErrorData>> + Send + 'a>>;
45
46trait DynHandler: Send + Sync {
52 fn get_info(&self) -> ServerConfig;
53
54 fn call_tool(
55 &self,
56 request: CallToolRequestParams,
57 context: RequestContext<RoleServer>,
58 ) -> HandlerFuture<'_, CallToolResponse>;
59
60 fn list_tools(
61 &self,
62 request: Option<PaginatedRequestParams>,
63 context: RequestContext<RoleServer>,
64 ) -> HandlerFuture<'_, ListToolsResult>;
65
66 fn get_tool(&self, name: &str) -> Option<Tool>;
67}
68
69impl<H: ServerHandler> DynHandler for H {
70 fn get_info(&self) -> ServerConfig {
71 ServerHandler::get_info(self)
72 }
73
74 fn call_tool(
75 &self,
76 request: CallToolRequestParams,
77 context: RequestContext<RoleServer>,
78 ) -> HandlerFuture<'_, CallToolResponse> {
79 Box::pin(ServerHandler::call_tool(self, request, context))
80 }
81
82 fn list_tools(
83 &self,
84 request: Option<PaginatedRequestParams>,
85 context: RequestContext<RoleServer>,
86 ) -> HandlerFuture<'_, ListToolsResult> {
87 Box::pin(ServerHandler::list_tools(self, request, context))
88 }
89
90 fn get_tool(&self, name: &str) -> Option<Tool> {
91 ServerHandler::get_tool(self, name)
92 }
93}
94
95pub type ShutdownFuture<'a> = Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
97
98pub trait Shutdown: Send + Sync {
103 fn shutdown(&self) -> ShutdownFuture<'_>;
105}
106
107impl fmt::Debug for Server {
108 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109 f.debug_struct("Server").finish_non_exhaustive()
110 }
111}
112
113impl Server {
114 pub fn new<S>(handler: S) -> Self
120 where
121 S: ServerHandler + Shutdown,
122 {
123 let handler = Arc::new(handler);
124 Self {
125 handler: handler.clone(),
126 shutdown: handler,
127 }
128 }
129
130 pub async fn shutdown(&self) {
132 self.shutdown.shutdown().await;
133 }
134}
135
136impl ServerHandler for Server {
137 fn get_info(&self) -> ServerConfig {
138 self.handler.get_info()
139 }
140
141 async fn call_tool(
142 &self,
143 request: CallToolRequestParams,
144 context: RequestContext<RoleServer>,
145 ) -> Result<CallToolResponse, ErrorData> {
146 self.handler.call_tool(request, context).await
147 }
148
149 async fn list_tools(
150 &self,
151 request: Option<PaginatedRequestParams>,
152 context: RequestContext<RoleServer>,
153 ) -> Result<ListToolsResult, ErrorData> {
154 self.handler.list_tools(request, context).await
155 }
156
157 fn get_tool(&self, name: &str) -> Option<Tool> {
158 self.handler.get_tool(name)
159 }
160}
161
162#[must_use]
168pub fn server_info() -> ServerConfig {
169 let capabilities = ServerCapabilities::builder().enable_tools().build();
170
171 let server_info = Implementation::new(NAME, VERSION)
172 .with_title(TITLE)
173 .with_website_url(HOMEPAGE);
174
175 ServerConfig::new(capabilities).with_server_info(server_info)
176}