pulseengine_mcp_server/
common_backend.rs1use crate::{BackendError, McpBackend};
7use async_trait::async_trait;
8use pulseengine_mcp_protocol::*;
9
10#[derive(Debug, thiserror::Error)]
12pub enum CommonMcpError {
13 #[error("Invalid parameters: {0}")]
14 InvalidParams(String),
15
16 #[error("Internal error: {0}")]
17 Internal(String),
18
19 #[error("Backend error: {0}")]
20 Backend(#[from] BackendError),
21
22 #[error("Setup error: {0}")]
23 Setup(String),
24}
25
26impl From<CommonMcpError> for pulseengine_mcp_protocol::Error {
27 fn from(err: CommonMcpError) -> Self {
28 match err {
29 CommonMcpError::InvalidParams(msg) => {
30 pulseengine_mcp_protocol::Error::invalid_params(msg)
31 }
32 CommonMcpError::Internal(msg) => pulseengine_mcp_protocol::Error::internal_error(msg),
33 CommonMcpError::Backend(backend_err) => {
34 pulseengine_mcp_protocol::Error::internal_error(backend_err.to_string())
35 }
36 CommonMcpError::Setup(msg) => pulseengine_mcp_protocol::Error::internal_error(msg),
37 }
38 }
39}
40
41#[derive(Clone)]
43pub struct CommonBackendImpl<T>
44where
45 T: Clone,
46{
47 #[allow(dead_code)]
48 inner: T,
49 server_info: ServerInfo,
50}
51
52impl<T> CommonBackendImpl<T>
53where
54 T: Clone,
55{
56 pub fn new(inner: T, server_info: ServerInfo) -> Self {
57 Self { inner, server_info }
58 }
59}
60
61#[async_trait]
62impl<T> McpBackend for CommonBackendImpl<T>
63where
64 T: Send + Sync + Clone + Default + 'static,
65{
66 type Error = CommonMcpError;
67 type Config = T;
68
69 async fn initialize(config: Self::Config) -> std::result::Result<Self, Self::Error> {
70 let server_info = ServerInfo {
71 protocol_version: ProtocolVersion::default(),
72 capabilities: ServerCapabilities {
73 tools: Some(ToolsCapability {
74 list_changed: Some(false),
75 }),
76 resources: Some(ResourcesCapability {
77 subscribe: Some(false),
78 list_changed: Some(false),
79 }),
80 prompts: Some(PromptsCapability {
81 list_changed: Some(false),
82 }),
83 logging: Some(LoggingCapability {
84 level: Some("info".to_string()),
85 }),
86 sampling: None,
87 ..Default::default()
88 },
89 server_info: Implementation {
90 name: "MCP Server".to_string(),
91 version: "1.0.0".to_string(),
92 },
93 instructions: Some("Generated MCP Server".to_string()),
94 };
95
96 Ok(Self::new(config, server_info))
97 }
98
99 fn get_server_info(&self) -> ServerInfo {
100 self.server_info.clone()
101 }
102
103 async fn health_check(&self) -> std::result::Result<(), Self::Error> {
104 Ok(())
105 }
106
107 async fn list_tools(
108 &self,
109 _request: PaginatedRequestParam,
110 ) -> std::result::Result<ListToolsResult, Self::Error> {
111 Ok(ListToolsResult {
113 tools: vec![],
114 next_cursor: None,
115 })
116 }
117
118 async fn call_tool(
119 &self,
120 request: CallToolRequestParam,
121 ) -> std::result::Result<CallToolResult, Self::Error> {
122 Err(CommonMcpError::InvalidParams(format!(
123 "Unknown tool: {}",
124 request.name
125 )))
126 }
127
128 async fn list_resources(
129 &self,
130 _request: PaginatedRequestParam,
131 ) -> std::result::Result<ListResourcesResult, Self::Error> {
132 Ok(ListResourcesResult {
133 resources: vec![],
134 next_cursor: None,
135 })
136 }
137
138 async fn read_resource(
139 &self,
140 request: ReadResourceRequestParam,
141 ) -> std::result::Result<ReadResourceResult, Self::Error> {
142 Err(CommonMcpError::InvalidParams(format!(
143 "Unknown resource: {}",
144 request.uri
145 )))
146 }
147
148 async fn list_prompts(
149 &self,
150 _request: PaginatedRequestParam,
151 ) -> std::result::Result<ListPromptsResult, Self::Error> {
152 Ok(ListPromptsResult {
153 prompts: vec![],
154 next_cursor: None,
155 })
156 }
157
158 async fn get_prompt(
159 &self,
160 request: GetPromptRequestParam,
161 ) -> std::result::Result<GetPromptResult, Self::Error> {
162 Err(CommonMcpError::InvalidParams(format!(
163 "Unknown prompt: {}",
164 request.name
165 )))
166 }
167}
168
169pub trait HasServerInfo {
171 fn server_info() -> ServerInfo;
172}
173
174pub trait McpToolsProvider {
176 fn get_available_tools(&self) -> Vec<Tool>;
177 fn call_tool_impl(
178 &self,
179 request: CallToolRequestParam,
180 ) -> impl std::future::Future<
181 Output = std::result::Result<CallToolResult, pulseengine_mcp_protocol::Error>,
182 > + Send;
183}
184
185pub trait McpResourcesProvider {
187 fn get_available_resources(&self) -> Vec<Resource>;
188 fn read_resource_impl(
189 &self,
190 request: ReadResourceRequestParam,
191 ) -> impl std::future::Future<
192 Output = std::result::Result<ReadResourceResult, pulseengine_mcp_protocol::Error>,
193 > + Send;
194}
195
196pub trait McpPromptsProvider {
198 fn get_available_prompts(&self) -> Vec<Prompt>;
199 fn get_prompt_impl(
200 &self,
201 request: GetPromptRequestParam,
202 ) -> impl std::future::Future<
203 Output = std::result::Result<GetPromptResult, pulseengine_mcp_protocol::Error>,
204 > + Send;
205}