use crate::{BackendError, McpBackend};
use async_trait::async_trait;
use pulseengine_mcp_protocol::*;
#[derive(Debug, thiserror::Error)]
pub enum CommonMcpError {
#[error("Invalid parameters: {0}")]
InvalidParams(String),
#[error("Internal error: {0}")]
Internal(String),
#[error("Backend error: {0}")]
Backend(#[from] BackendError),
#[error("Setup error: {0}")]
Setup(String),
}
impl From<CommonMcpError> for pulseengine_mcp_protocol::Error {
fn from(err: CommonMcpError) -> Self {
match err {
CommonMcpError::InvalidParams(msg) => {
pulseengine_mcp_protocol::Error::invalid_params(msg)
}
CommonMcpError::Internal(msg) => pulseengine_mcp_protocol::Error::internal_error(msg),
CommonMcpError::Backend(backend_err) => {
pulseengine_mcp_protocol::Error::internal_error(backend_err.to_string())
}
CommonMcpError::Setup(msg) => pulseengine_mcp_protocol::Error::internal_error(msg),
}
}
}
#[derive(Clone)]
pub struct CommonBackendImpl<T>
where
T: Clone,
{
#[allow(dead_code)]
inner: T,
server_info: ServerInfo,
}
impl<T> CommonBackendImpl<T>
where
T: Clone,
{
pub fn new(inner: T, server_info: ServerInfo) -> Self {
Self { inner, server_info }
}
}
#[async_trait]
impl<T> McpBackend for CommonBackendImpl<T>
where
T: Send + Sync + Clone + Default + 'static,
{
type Error = CommonMcpError;
type Config = T;
async fn initialize(config: Self::Config) -> std::result::Result<Self, Self::Error> {
let server_info = ServerInfo {
protocol_version: ProtocolVersion::default(),
capabilities: ServerCapabilities {
tools: Some(ToolsCapability {
list_changed: Some(false),
}),
resources: Some(ResourcesCapability {
subscribe: Some(false),
list_changed: Some(false),
}),
prompts: Some(PromptsCapability {
list_changed: Some(false),
}),
logging: Some(LoggingCapability {
level: Some("info".to_string()),
}),
sampling: None,
..Default::default()
},
server_info: Implementation::new("MCP Server", "1.0.0"),
instructions: Some("Generated MCP Server".to_string()),
};
Ok(Self::new(config, server_info))
}
fn get_server_info(&self) -> ServerInfo {
self.server_info.clone()
}
async fn health_check(&self) -> std::result::Result<(), Self::Error> {
Ok(())
}
async fn list_tools(
&self,
_request: PaginatedRequestParam,
) -> std::result::Result<ListToolsResult, Self::Error> {
Ok(ListToolsResult {
tools: vec![],
next_cursor: None,
})
}
async fn call_tool(
&self,
request: CallToolRequestParam,
) -> std::result::Result<CallToolResult, Self::Error> {
Err(CommonMcpError::InvalidParams(format!(
"Unknown tool: {}",
request.name
)))
}
async fn list_resources(
&self,
_request: PaginatedRequestParam,
) -> std::result::Result<ListResourcesResult, Self::Error> {
Ok(ListResourcesResult {
resources: vec![],
next_cursor: None,
})
}
async fn read_resource(
&self,
request: ReadResourceRequestParam,
) -> std::result::Result<ReadResourceResult, Self::Error> {
Err(CommonMcpError::InvalidParams(format!(
"Unknown resource: {}",
request.uri
)))
}
async fn list_prompts(
&self,
_request: PaginatedRequestParam,
) -> std::result::Result<ListPromptsResult, Self::Error> {
Ok(ListPromptsResult {
prompts: vec![],
next_cursor: None,
})
}
async fn get_prompt(
&self,
request: GetPromptRequestParam,
) -> std::result::Result<GetPromptResult, Self::Error> {
Err(CommonMcpError::InvalidParams(format!(
"Unknown prompt: {}",
request.name
)))
}
}
pub trait HasServerInfo {
fn server_info() -> ServerInfo;
}
pub trait McpToolsProvider {
fn get_available_tools(&self) -> Vec<Tool>;
fn call_tool_impl(
&self,
request: CallToolRequestParam,
) -> impl std::future::Future<
Output = std::result::Result<CallToolResult, pulseengine_mcp_protocol::Error>,
> + Send;
}
pub trait McpResourcesProvider {
fn get_available_resources(&self) -> Vec<Resource>;
fn read_resource_impl(
&self,
request: ReadResourceRequestParam,
) -> impl std::future::Future<
Output = std::result::Result<ReadResourceResult, pulseengine_mcp_protocol::Error>,
> + Send;
}
pub trait McpPromptsProvider {
fn get_available_prompts(&self) -> Vec<Prompt>;
fn get_prompt_impl(
&self,
request: GetPromptRequestParam,
) -> impl std::future::Future<
Output = std::result::Result<GetPromptResult, pulseengine_mcp_protocol::Error>,
> + Send;
}