#![allow(clippy::manual_async_fn)]
use serde_json::Value;
use std::future::Future;
use turbomcp_core::{McpError, McpHandler, McpResult, RequestContext};
use turbomcp_types::{
Prompt, PromptResult, Resource, ResourceResult, ServerInfo, Tool, ToolResult,
};
#[derive(Clone)]
struct MockHandler;
impl McpHandler for MockHandler {
fn server_info(&self) -> ServerInfo {
ServerInfo::new("mock-server", "1.0.0")
}
fn list_tools(&self) -> Vec<Tool> {
vec![Tool::new("ping", "Ping pong")]
}
fn list_resources(&self) -> Vec<Resource> {
vec![]
}
fn list_prompts(&self) -> Vec<Prompt> {
vec![]
}
fn call_tool<'a>(
&'a self,
name: &'a str,
_args: Value,
_ctx: &'a RequestContext,
) -> impl Future<Output = McpResult<ToolResult>> + Send + 'a {
let name = name.to_string();
async move {
match name.as_str() {
"ping" => Ok(ToolResult::text("pong")),
_ => Err(McpError::tool_not_found(&name)),
}
}
}
fn read_resource<'a>(
&'a self,
uri: &'a str,
_ctx: &'a RequestContext,
) -> impl Future<Output = McpResult<ResourceResult>> + Send + 'a {
async move { Err(McpError::resource_not_found(uri)) }
}
fn get_prompt<'a>(
&'a self,
name: &'a str,
_args: Option<Value>,
_ctx: &'a RequestContext,
) -> impl Future<Output = McpResult<PromptResult>> + Send + 'a {
async move { Err(McpError::prompt_not_found(name)) }
}
}
#[tokio::test]
async fn test_handler_dispatch() {
let handler = MockHandler;
let ctx = RequestContext::default();
let info = handler.server_info();
assert_eq!(info.name, "mock-server");
let tools = handler.list_tools();
assert_eq!(tools.len(), 1);
assert_eq!(tools[0].name, "ping");
let result = handler.call_tool("ping", Value::Null, &ctx).await.unwrap();
assert!(!result.is_error());
let err = handler
.call_tool("unknown", Value::Null, &ctx)
.await
.unwrap_err();
assert_eq!(err.jsonrpc_code(), -32001); }