1pub mod bridge;
31pub mod config;
32pub mod error;
33pub mod lsp;
34pub mod mcp;
35
36use std::path::PathBuf;
37use std::sync::Arc;
38
39use bridge::Translator;
40pub use config::ServerConfig;
41pub use error::Error;
42use lsp::{LspServer, ServerInitConfig};
43use rmcp::ServiceExt;
44use tokio::sync::Mutex;
45
46pub async fn serve(config: ServerConfig) -> Result<(), Error> {
57 tracing::info!("Starting MCPLS server...");
58
59 let mut translator = Translator::new();
60 let workspace_roots = if config.workspace.roots.is_empty() {
61 vec![PathBuf::from(".")]
62 } else {
63 config.workspace.roots.clone()
64 };
65
66 translator.set_workspace_roots(workspace_roots.clone());
67
68 for lsp_config in config.lsp_servers {
69 tracing::info!(
70 "Spawning LSP server for language '{}': {} {:?}",
71 lsp_config.language_id,
72 lsp_config.command,
73 lsp_config.args
74 );
75
76 let server_init_config = ServerInitConfig {
77 server_config: lsp_config.clone(),
78 workspace_roots: workspace_roots.clone(),
79 initialization_options: lsp_config.initialization_options.clone(),
80 };
81
82 let server = LspServer::spawn(server_init_config).await?;
83 let client = server.client().clone();
84
85 translator.register_client(lsp_config.language_id.clone(), client);
86 }
87
88 let translator = Arc::new(Mutex::new(translator));
89
90 tracing::info!("Starting MCP server with rmcp...");
91 let mcp_server = mcp::McplsServer::new(translator);
92
93 tracing::info!("MCPLS server initialized successfully");
94 tracing::info!("Listening for MCP requests on stdio...");
95
96 let service = mcp_server
97 .serve(rmcp::transport::stdio())
98 .await
99 .map_err(|e| Error::McpServer(format!("Failed to start MCP server: {e}")))?;
100
101 service
102 .waiting()
103 .await
104 .map_err(|e| Error::McpServer(format!("MCP server error: {e}")))?;
105
106 tracing::info!("MCPLS server shutting down");
107 Ok(())
108}