mcp_commune/
server.rs

1//! Server module for the Commune project.
2//!
3//! This module provides the implementation of the Commune server, including
4//! the server builder, the main server struct, and the handler for WebSocket connections.
5
6use crate::{error::Error, peer::Peer};
7use async_trait::async_trait;
8use mcp_sdk_rs::{
9    error::Error as McpError,
10    server::{Server as McpServer, ServerHandler},
11    transport::websocket::WebSocketTransport,
12    types::*,
13};
14use serde::{Deserialize, Serialize};
15use serde_json::{json, Value};
16use std::sync::Arc;
17use tokio::net::TcpListener;
18use tokio_tungstenite::accept_async;
19
20/// Builder for creating a Commune server with customizable components.
21#[derive(Default)]
22pub struct ServerBuilder {
23    peers: Vec<Peer>,
24    prompts: Vec<Prompt>,
25    resources: Vec<Resource>,
26    tools: Vec<Tool>,
27}
28
29impl ServerBuilder {
30    /// Creates a new ServerBuilder with default values.
31    pub fn new() -> ServerBuilder {
32        ServerBuilder {
33            ..Default::default()
34        }
35    }
36
37    /// Adds multiple peers to the server.
38    pub fn with_peers(mut self, peers: Vec<Peer>) -> ServerBuilder {
39        self.peers = peers;
40        self
41    }
42
43    /// Adds a single peer to the server.
44    pub fn with_peer(mut self, peer: Peer) -> ServerBuilder {
45        self.peers.push(peer);
46        self
47    }
48
49    /// Adds a single prompt to the server.
50    pub fn with_prompt(mut self, prompt: Prompt) -> ServerBuilder {
51        self.prompts.push(prompt);
52        self
53    }
54
55    /// Adds multiple prompts to the server.
56    pub fn with_prompts(mut self, prompts: Vec<Prompt>) -> ServerBuilder {
57        self.prompts = prompts;
58        self
59    }
60
61    /// Adds a single resource to the server.
62    pub fn with_resource(mut self, resource: Resource) -> ServerBuilder {
63        self.resources.push(resource);
64        self
65    }
66
67    /// Adds multiple resources to the server.
68    pub fn with_resources(mut self, resources: Vec<Resource>) -> ServerBuilder {
69        self.resources = resources;
70        self
71    }
72
73    /// Adds a single tool to the server.
74    pub fn with_tool(mut self, tool: Tool) -> ServerBuilder {
75        self.tools.push(tool);
76        self
77    }
78
79    /// Adds multiple tools to the server.
80    pub fn with_tools(mut self, tools: Vec<Tool>) -> ServerBuilder {
81        self.tools = tools;
82        self
83    }
84
85    /// Builds the server with the configured components.
86    ///
87    /// # Returns
88    /// A `Result` containing either the built `Server` or an `Error`.
89    pub async fn build(self) -> Result<Server, Error> {
90        let mut caps = ServerCapabilities::default();
91        // Set up server capabilities based on the presence of different components
92        if !self.peers.is_empty() {
93            caps.experimental = Some(json!({"peers": {}}));
94        }
95        if !self.prompts.is_empty() {
96            caps.prompts = Some(json!({}));
97        }
98        if !self.resources.is_empty() {
99            caps.resources = Some(json!({}));
100        }
101        if !self.tools.is_empty() {
102            caps.tools = Some(json!({}));
103        }
104        Ok(Server {
105            peers: self.peers,
106            capabilities: caps,
107            prompts: self.prompts,
108            resources: self.resources,
109            tools: self.tools,
110        })
111    }
112}
113
114/// The main Server struct representing a Commune server instance.
115pub struct Server {
116    pub capabilities: ServerCapabilities,
117    pub peers: Vec<Peer>,
118    pub prompts: Vec<Prompt>,
119    pub resources: Vec<Resource>,
120    pub tools: Vec<Tool>,
121}
122
123impl Server {
124    /// Starts the server and listens for incoming WebSocket connections.
125    ///
126    /// # Arguments
127    /// * `addr` - A string slice that holds the address to bind the server to.
128    ///
129    /// # Returns
130    /// A `Result` indicating success or containing an `Error`.
131    pub async fn start(&self, addr: &str) -> Result<(), Error> {
132        let listener = TcpListener::bind(addr).await.map_err(|_| Error::Internal)?;
133        println!("WebSocket server listening on ws://{}", addr);
134
135        while let Ok((stream, addr)) = listener.accept().await {
136            println!("New connection from: {}", addr);
137            let ws_stream = accept_async(stream)
138                .await
139                .map_err(|e| {
140                    println!("Error during WebSocket handshake: {}", e);
141                    e
142                })
143                .unwrap();
144
145            let transport = WebSocketTransport::from_stream(ws_stream);
146            let handler = CommuneHandler {
147                peers: self.peers.clone(),
148                prompts: self.prompts.clone(),
149                tools: self.tools.clone(),
150                resources: self.resources.clone(),
151            };
152            let server = McpServer::new(Arc::new(transport), Arc::new(handler));
153
154            tokio::spawn(async move {
155                println!("Starting server for connection from {}", addr);
156                if let Err(e) = server.start().await {
157                    eprintln!("Error in WebSocket connection from {}: {}", addr, e);
158                }
159                println!("Connection from {} closed", addr);
160            });
161        }
162        Ok(())
163    }
164}
165
166/// Handler for Commune server requests.
167struct CommuneHandler {
168    peers: Vec<Peer>,
169    prompts: Vec<Prompt>,
170    tools: Vec<Tool>,
171    resources: Vec<Resource>,
172}
173
174#[async_trait]
175impl ServerHandler for CommuneHandler {
176    /// Initializes the connection with a client.
177    ///
178    /// # Arguments
179    /// * `implementation` - The client implementation details.
180    /// * `_capabilities` - The client's capabilities (currently unused).
181    ///
182    /// # Returns
183    /// A `Result` containing either the `ServerCapabilities` or an `McpError`.
184    async fn initialize(
185        &self,
186        implementation: Implementation,
187        _capabilities: ClientCapabilities,
188    ) -> Result<ServerCapabilities, McpError> {
189        println!(
190            "Client connected: {} v{}",
191            implementation.name, implementation.version
192        );
193        Ok(ServerCapabilities::default())
194    }
195
196    /// Handles incoming method calls from clients.
197    ///
198    /// # Arguments
199    /// * `method` - A string slice containing the method name.
200    /// * `_params` - An optional `Value` containing the method parameters.
201    ///
202    /// # Returns
203    /// A `Result` containing either the method result as a `Value` or an `McpError`.
204    async fn handle_method(&self, method: &str, _params: Option<Value>) -> Result<Value, McpError> {
205        match method {
206            "peers/list" => Ok(serde_json::to_value(ListPeersResult {
207                peers: self.peers.clone(),
208                next_cursor: None,
209            })?),
210            "prompts/list" => Ok(serde_json::to_value(ListPromptsResult {
211                prompts: self.prompts.clone(),
212                next_cursor: None,
213            })?),
214            "tools/list" => Ok(serde_json::to_value(ListToolsResult {
215                tools: self.tools.clone(),
216                next_cursor: None,
217            })?),
218            "resources/list" => Ok(serde_json::to_value(ListResourcesResult {
219                resources: self.resources.clone(),
220                next_cursor: None,
221            })?),
222            _ => Err(McpError::Other("unknown method".to_string())),
223        }
224    }
225
226    /// Handles the shutdown request from a client.
227    ///
228    /// # Returns
229    /// A `Result` indicating success or containing an `McpError`.
230    async fn shutdown(&self) -> Result<(), McpError> {
231        println!("Server shutting down");
232        Ok(())
233    }
234}
235
236/// Request structure for the /peers/list method.
237#[derive(Clone, Serialize, Deserialize)]
238pub struct ListPeersRequest {
239    #[serde(skip_serializing_if = "Option::is_none")]
240    pub cursor: Option<Cursor>,
241}
242
243/// Response structure for the /peers/list method.
244#[derive(Clone, Serialize, Deserialize)]
245pub struct ListPeersResult {
246    pub peers: Vec<Peer>,
247    #[serde(skip_serializing_if = "Option::is_none")]
248    pub next_cursor: Option<Cursor>,
249}