From a05ef90350576423f9192a2de1808a7c0278ef86 Mon Sep 17 00:00:00 2001 From: Phillip Davis Date: Wed, 8 Oct 2025 08:10:56 -0400 Subject: [PATCH] LSP and MCP ends share global Arc --- src/lsp/client.rs | 26 +++++++++++------- src/main.rs | 3 ++- src/mcp/server.rs | 23 ++++++---------- src/mcp/tools/read.rs | 63 +++++++++++++++++++++---------------------- 4 files changed, 57 insertions(+), 58 deletions(-) diff --git a/src/lsp/client.rs b/src/lsp/client.rs index 7acc31a01a9cc0c3a87e69de3a0ae58087a79d3d..e71cb2a2e4df49447de82150f987e97a38e88b53 100644 --- a/src/lsp/client.rs +++ b/src/lsp/client.rs @@ -1,5 +1,6 @@ use std::ops::ControlFlow; use std::path::PathBuf; +use std::sync::Arc; use async_lsp::lsp_types::notification::{Progress, PublishDiagnostics, ShowMessage}; use async_lsp::lsp_types::{ @@ -12,7 +13,10 @@ use async_process::{Child, Command as ProcessCommand, Stdio}; use futures::channel::oneshot; use tower::ServiceBuilder; +use crate::config::Config; + pub struct LSPClientState { + pub config: Arc, pub indexed_tx: Option>, } @@ -28,22 +32,24 @@ pub struct LSPClient { impl LSPClient { pub async fn setup( - lsp_command: &str, - lsp_args: &[String], - project_root: &PathBuf, + config: Arc, ) -> anyhow::Result { - let child = ProcessCommand::new(lsp_command) - .args(lsp_args) - .current_dir(project_root) + let child = ProcessCommand::new(&config.lsp_server_command.command) + .args(&config.lsp_server_command.args) + .current_dir(&config.project_root) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::inherit()) .kill_on_drop(true) .spawn() - .expect(format!("Failed to start lsp: {} {:?}", lsp_command, lsp_args).as_ref()); + .expect(format!("Failed to start lsp: {} {:?}", &config.lsp_server_command.command, &config.lsp_server_command.args).as_ref()); - let (mainloop, mut server) = async_lsp::MainLoop::new_client(|_server| { - let mut router = Router::new(LSPClientState { indexed_tx: None }); + let config_clone = config.clone(); + let (mainloop, mut server) = async_lsp::MainLoop::new_client(move |_server| { + let mut router = Router::new(LSPClientState { + config: config_clone, + indexed_tx: None + }); router .notification::(|_this, _params| ControlFlow::Continue(())) @@ -54,7 +60,7 @@ impl LSPClient { ServiceBuilder::new().service(router) }); - let project_root_canonicalized = tokio::fs::canonicalize(project_root) + let project_root_canonicalized = tokio::fs::canonicalize(&config.project_root) .await .expect("Failed to canonicalize project root"); diff --git a/src/main.rs b/src/main.rs index b0e6b5f1a3f9ba7e75cb9d32787ea09093705835..3b3cd6ce42f303652390fb1d489f905bf24a2ebf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,6 +2,7 @@ mod config; mod lsp; mod mcp; +use std::sync::Arc; use clap::Parser; use config::{CommandLineArgs, Config}; @@ -16,7 +17,7 @@ async fn main() -> anyhow::Result<()> { .init(); let args = CommandLineArgs::parse(); - let config = Config::load(&args.config).await?; + let config = Arc::new(Config::load(&args.config).await?); let (mcp_server, lsp_client) = mcp::setup(config).await?; mcp_server.run(lsp_client).await?; diff --git a/src/mcp/server.rs b/src/mcp/server.rs index c2275f3afd65ab6b3c68e9777c87bfd635aa4dbe..e8820579df0aa3649ab813c62d1131386e0d0667 100644 --- a/src/mcp/server.rs +++ b/src/mcp/server.rs @@ -1,4 +1,5 @@ use std::path::PathBuf; +use std::sync::Arc; use rmcp::ErrorData as MCPError; use rmcp::ServerHandler as MCPServerHandler; @@ -16,31 +17,23 @@ pub use crate::mcp::tools::read::*; pub struct MCPServer { pub(crate) tool_router: ToolRouter, - pub(crate) project_root: PathBuf, + pub(crate) config: Arc, pub(crate) lsp_server: LSPServerSocket, } -pub async fn setup(config: Config) -> anyhow::Result<(MCPServer, LSPClient)> { - let project_root = tokio::fs::canonicalize(&config.project_root) - .await - .expect("Failed to canonicalize project root"); +pub async fn setup(config: Arc) -> anyhow::Result<(MCPServer, LSPClient)> { + let lsp_client = LSPClient::setup(config.clone()) + .await?; - let lsp_client = LSPClient::setup( - &config.lsp_server_command.command, - &config.lsp_server_command.args, - &project_root, - ) - .await?; - - let server = MCPServer::new(project_root, lsp_client.server.clone()); + let server = MCPServer::new(config, lsp_client.server.clone()); Ok((server, lsp_client)) } impl MCPServer { - pub fn new(project_root: PathBuf, lsp_server: LSPServerSocket) -> Self { + pub fn new(config: Arc, lsp_server: LSPServerSocket) -> Self { Self { - project_root, + config, lsp_server, tool_router: Self::tool_router(), } diff --git a/src/mcp/tools/read.rs b/src/mcp/tools/read.rs index 84b08a8fa4804b4feab06817ad78b4508f9cac9c..534eccee818babb378b533c18cf6f25d02bcc8d0 100644 --- a/src/mcp/tools/read.rs +++ b/src/mcp/tools/read.rs @@ -27,36 +27,35 @@ pub async fn call( server: &MCPServer, Parameters(args): Parameters, ) -> Result { - let file_path = server.project_root.join(&args.path); - let file_path = tokio::fs::canonicalize(file_path).await.unwrap(); - let content = tokio::fs::read_to_string(&file_path) - .await - .map_err(|e| MCPError::invalid_request(format!("Failed to read file: {e}"), None))?; - - let mut lsp_server = server.lsp_server.clone(); - - let diagnostic_report = lsp_server - .document_diagnostic(DocumentDiagnosticParams { - text_document: TextDocumentIdentifier::new(Url::from_file_path(file_path).unwrap()), - identifier: None, - previous_result_id: None, - work_done_progress_params: WorkDoneProgressParams { - work_done_token: None, - }, - partial_result_params: PartialResultParams { - partial_result_token: None, - }, - }) - .await - .unwrap(); - - Ok(CallToolResult { - content: vec![], - structured_content: Some(serde_json::json!(ReadToolOutput { - content: Some(content), - diagnostics: diagnostic_report - })), - is_error: None, - meta: None, - }) + Err(MCPError::internal_error("Not yet implemented", None)) + // let content = tokio::fs::read_to_string(&file_path) + // .await + // .map_err(|e| MCPError::invalid_request(format!("Failed to read file: {e}"), None))?; + + // let mut lsp_server = server.lsp_server.clone(); + + // let diagnostic_report = lsp_server + // .document_diagnostic(DocumentDiagnosticParams { + // text_document: TextDocumentIdentifier::new(Url::from_file_path(file_path).unwrap()), + // identifier: None, + // previous_result_id: None, + // work_done_progress_params: WorkDoneProgressParams { + // work_done_token: None, + // }, + // partial_result_params: PartialResultParams { + // partial_result_token: None, + // }, + // }) + // .await + // .unwrap(); + + // Ok(CallToolResult { + // content: vec![], + // structured_content: Some(serde_json::json!(ReadToolOutput { + // content: Some(content), + // diagnostics: diagnostic_report + // })), + // is_error: None, + // meta: None, + // }) }