1# AGENTS.md
2
3This file provides guidance to AI coding agents when working with code in this repository.
4
5## Common Commands
6
7```bash
8# Build the project
9cargo build
10
11# Build in release mode
12cargo build --release
13
14# Run the project (requires a config file)
15cargo run -- --config sample_config.json
16
17# Run tests
18cargo test
19
20# Run a specific test
21cargo test <test_name>
22
23# Check for compilation errors without building
24cargo check
25
26# Format code
27cargo fmt
28
29# Run clippy linter
30cargo clippy
31```
32
33## Architecture Overview
34
35**lsp2mcp** is a bridge that translates arbitrary LSP (Language Server Protocol) servers into MCP (Model Context Protocol) servers, enabling AI coding agents to receive real-time diagnostics and ground truth about the code they write.
36
37### Three-Layer Architecture
38
39The application operates with three concurrent layers:
40
411. **MCP Server Layer** (`MCPServer` struct)
42 - Exposes tools to AI agents via MCP protocol
43 - Runs on stdio transport (reads from stdin, writes to stdout)
44 - Currently implements a `read` tool that returns file content + LSP diagnostics
45
462. **LSP Client Layer** (`async_lsp::MainLoop`)
47 - Acts as an LSP client to communicate with external LSP servers
48 - Spawns the LSP server process as a subprocess (stdin/stdout pipes)
49 - Handles LSP notifications (Progress, PublishDiagnostics, ShowMessage)
50 - Router-based event handling with `LSPClientState`
51
523. **LSP Server Process** (spawned subprocess)
53 - External process (e.g., rust-analyzer, typescript-language-server)
54 - Configured via JSON config file (`sample_config.json`)
55 - Killed automatically when parent process exits (`kill_on_drop: true`)
56
57### Execution Flow
58
59```
60AI Agent (MCP Client)
61 ↓ stdio
62MCPServer::read() tool
63 ↓ LSPServerSocket::document_diagnostic()
64async_lsp MainLoop (LSP Client)
65 ↓ subprocess stdin/stdout pipes
66LSP Server Process (e.g., rust-analyzer)
67```
68
69### Critical Concurrency Detail
70
71The application uses `futures::join!()` to run two async tasks concurrently:
72- `mainloop_fut`: The LSP client mainloop reading/writing from LSP server subprocess
73- `server.waiting()`: The MCP server awaiting requests from AI agents
74
75Both must run simultaneously because MCP tool calls need to send LSP requests and await responses.
76
77### Configuration
78
79The config file (`sample_config.json`) specifies:
80- `lsp_server_command`: Command and args to spawn the LSP server subprocess
81- `project_root`: Workspace root directory (passed to LSP server initialization and used for resolving relative file paths)
82
83File paths in tool arguments are relative to `project_root` and are canonicalized before use.
84
85### Key Framework Usage Patterns
86
87**rmcp (MCP server framework):**
88- Use `#[tool_router]` macro on impl blocks to register tools
89- Use `#[tool(description = "...")]` macro on methods to expose them as MCP tools
90- Tool arguments must be deserializable (`serde::Deserialize`) and have JSON schema (`schemars::JsonSchema`)
91- Extract parameters with `Parameters<T>` wrapper
92- Return `Result<CallToolResult, MCPError>`
93
94**async-lsp (LSP client framework):**
95- Use `Router::new()` with a state type (`LSPClientState`)
96- Chain `.notification::<NotificationType>(handler)` to handle LSP notifications
97- Handlers return `ControlFlow::Continue(())` or `ControlFlow::Break(result)`
98- The `MainLoop::new_client()` creates both the mainloop runner and the `ServerSocket` client handle
99- `ServerSocket` is cloneable and can be shared across async contexts (used in `MCPServer`)
100
101### Current Limitations and TODOs
102
103- Only the `read` tool is implemented; other tools like `edit`, `complete`, `definition`, etc. are not yet implemented
104- Diagnostics are fetched on-demand via `document_diagnostic` (pull-based), not via `PublishDiagnostics` notifications (push-based)
105- Commented-out `did_open` code suggests file opening/tracking may be needed for some LSP servers
106- Unused variables and dead code indicate work-in-progress state (see compiler warnings)
107
108### Adding New MCP Tools
109
110To add a new tool that leverages LSP capabilities:
111
1121. Add a method to the `#[tool_router] impl MCPServer` block
1132. Define argument and output structs with `serde::Deserialize` + `schemars::JsonSchema`
1143. Use `self.lsp_server.clone().<lsp_method>()` to call LSP methods
1154. Construct and return `CallToolResult` with diagnostics/results in `structured_content`
116
117Example LSP methods available via `LSPServerSocket`:
118- `document_diagnostic()` - Get diagnostics for a file
119- `completion()` - Get code completions
120- `goto_definition()` - Find symbol definitions
121- `hover()` - Get hover information
122- `did_open()`, `did_change()`, `did_close()` - Notify file changes