1use std::path::PathBuf;
2use std::sync::Arc;
3
4use rmcp::ErrorData as MCPError;
5use rmcp::ServerHandler as MCPServerHandler;
6use rmcp::handler::server::tool::ToolRouter;
7use rmcp::handler::server::wrapper::Parameters;
8use rmcp::model::CallToolResult;
9use rmcp::model::{Implementation, ProtocolVersion, ServerCapabilities, ServerInfo};
10use rmcp::{tool_handler, tool_router};
11
12use crate::buf_pool::BufPool;
13use crate::config::Config;
14use crate::lsp::{LSPClient, LSPServer};
15pub use crate::mcp::tools::read::*;
16
17pub struct MCPServer {
18 pub(crate) tool_router: ToolRouter<Self>,
19 pub(crate) config: Arc<Config>,
20 pub(crate) lsp_server: LSPServer,
21 pub(crate) buf_pool: BufPool<Vec<u8>>,
22}
23
24pub async fn setup(config: Arc<Config>) -> anyhow::Result<(MCPServer, LSPClient)> {
25 let (lsp_client, lsp_server) = LSPClient::setup(config.clone()).await?;
26
27 let server = MCPServer::new(config, lsp_server);
28
29 Ok((server, lsp_client))
30}
31
32impl MCPServer {
33 pub fn new(config: Arc<Config>, lsp_server: LSPServer) -> Self {
34 Self {
35 config,
36 lsp_server,
37 tool_router: Self::tool_router(),
38 buf_pool: BufPool::with_capacity(8),
39 }
40 }
41
42 pub async fn run(self, lsp_client: LSPClient) -> anyhow::Result<()> {
43 let mainloop_fut = tokio::spawn(async move {
44 lsp_client
45 .run_main_loop()
46 .await
47 .expect("Error while running main LSP loop");
48 });
49
50 let server = rmcp::ServiceExt::serve(self, rmcp::transport::stdio())
51 .await
52 .expect("Failed to start serving MCP");
53
54 let (mainloop_result, server_result) = tokio::join!(mainloop_fut, server.waiting());
55
56 mainloop_result?;
57 server_result?;
58
59 Ok(())
60 }
61}
62
63#[tool_router]
64impl MCPServer {
65 #[rmcp::tool(
66 description = "Like the 'view' tool, except it returns LSP diagnostics too. Always use this instead of 'view'"
67 )]
68 pub async fn read(
69 &self,
70 Parameters(args): Parameters<ReadToolArgs>,
71 ) -> Result<CallToolResult, MCPError> {
72 crate::mcp::tools::read::call(self, Parameters(args)).await
73 }
74}
75
76#[tool_handler]
77impl MCPServerHandler for MCPServer {
78 fn get_info(&self) -> ServerInfo {
79 ServerInfo {
80 protocol_version: ProtocolVersion::V_2024_11_05,
81 capabilities: ServerCapabilities::builder().enable_tools().build(),
82 server_info: Implementation::from_build_env(),
83 instructions: Some("This server turns standard coding agent tools like `read` and `edit` into LSP clients.".into())
84 }
85 }
86}