mcp_ectors/examples/
hello_world.rs

1use actix::ResponseFuture;
2use serde_json::Value;
3
4use crate::router::{router::CapabilitiesBuilder, Router};
5use mcp_spec::{handler::ResourceError, prompt::Prompt, protocol::{CallToolResult, GetPromptResult, ReadResourceResult, ServerCapabilities}, Content, Resource, Tool, ToolError};
6
7/// **A simple Hello World router**
8#[derive(Clone)]
9pub struct HelloWorldRouter;
10
11impl HelloWorldRouter {
12    pub fn new() -> Self {
13        Self {}
14    }
15}
16
17
18impl Router for HelloWorldRouter {
19    fn name(&self) -> String {
20        "hello_world".to_string()
21    }
22
23    fn instructions(&self) -> String {
24        "This server responds with a greeting, 'Hello {name}', where 'name' is the parameter passed.".to_string()
25    }
26
27    fn capabilities(&self) -> ServerCapabilities {
28        CapabilitiesBuilder::new()
29            .with_tools(true)
30            .with_prompts(false)
31            .with_resources(false, false)
32            .build()
33    }
34
35    fn list_tools(&self) -> Vec<Tool> {
36        vec![
37            Tool::new(
38                "greet".to_string(),
39                "Responds with a greeting 'Hello {name}'".to_string(),
40                serde_json::json!({
41                    "type": "object",
42                    "properties": {
43                        "name": { "type": "string" }
44                    },
45                    "required": ["name"]
46                }),
47            ),
48        ]
49    }
50
51    fn call_tool(
52        &self,
53        tool_name: &str,
54        arguments: Value,
55    ) -> ResponseFuture<Result<CallToolResult, ToolError>> {
56        let tool_name = tool_name.to_string();
57
58        Box::pin(async move {
59            match tool_name.as_str() {
60                "greet" => {
61                    // Expect the "name" parameter in the arguments
62                    if let Some(name) = arguments.get("name").and_then(|v| v.as_str()) {
63                        let greeting = format!("Hello {}", name);
64                        let result = CallToolResult{ content: vec![Content::text(greeting)], is_error: Some(false) };
65                        Ok(result)
66                    } else {
67                        Err(ToolError::InvalidParameters("Missing or invalid 'name' parameter.".to_string()))
68                    }
69                }
70                _ => Err(ToolError::NotFound(format!("Tool {} not found", tool_name))),
71            }
72        })
73    }
74
75    fn list_resources(&self) -> Vec<Resource> {
76        vec![]
77    }
78
79    fn read_resource(
80        &self,
81        _uri: &str,
82    ) -> ResponseFuture<Result<ReadResourceResult, ResourceError>> {
83        Box::pin(async { Err(ResourceError::NotFound("Resource not found".to_string())) })
84    }
85    
86    fn list_prompts(&self) -> Vec<Prompt> {
87        vec![]
88    }
89    
90    fn get_prompt(&self, _prompt_name: &str) -> ResponseFuture<Result<GetPromptResult, ResourceError>> {
91
92        let result = GetPromptResult{ description: None, messages: vec![] };
93        Box::pin(async move {
94            Ok(result)
95        })
96    }
97}
98