Add MCP Server support to LSP4IJ
Context: existing MCP servers for LSP and DAP
Several projects already expose LSP and DAP features as MCP tools, which is a great idea: it allows AI assistants to leverage language intelligence (diagnostics, completions, hover, rename, code actions...) or debugging capabilities (breakpoints, call stack, variable inspection...) directly from their MCP client.
Existing LSP MCP projects:
- lsp-mcp — spawns a language server as a subprocess and acts as an LSP client to expose features as MCP tools
- Language-Server-MCP-Bridge — a universal VSCode extension that bridges LSP capabilities to MCP tools, but runs externally to the IDE
- cclsp
Existing DAP MCP projects:
- Similar approaches exist for DAP, spawning a debug adapter externally and acting as a DAP client
The problem with these approaches
All these projects share the same fundamental architecture: they spawn the language or debug server as an external subprocess and implement their own LSP/DAP client to communicate with it. This leads to several significant issues:
- Double process: the language server is started twice — once by the IDE, once by the MCP bridge — consuming extra memory and CPU
- No shared state: the MCP bridge has its own LSP/DAP client instance, completely disconnected from what the IDE sees. Diagnostics, caches, indexes, and document state can diverge
- No project context: the bridge starts the language server naively, without the configuration, workspace setup, or initialization options that the IDE provides
- No support for custom LSP requests/notifications: each language server can define proprietary extensions (e.g.
rust-analyzer/expandMacro, qute/dataModel). A generic bridge doesn't know about them and can't expose them as MCP tools
- No support for LSP commands: language servers expose custom commands (e.g. via
workspace/executeCommand). Again, a generic bridge has to hardcode them
- Duplicated configuration management:
didChangeConfiguration must be handled by the bridge separately, leading to potential config drift between the IDE and the AI
- Cold server: the language server started by the bridge has no warmup — no indexed workspace, no cached symbols — leading to slower and less accurate results compared to the already-running IDE server
The LSP4IJ approach: deep IDE integration
LSP4IJ takes a fundamentally different approach. Instead of being yet another external LSP/DAP client, the MCP server lives inside the IDE and delegates everything to LSP4IJ, which already manages the full lifecycle of language and debug servers.
The architecture is:
LLM → MCP Server → LSP4IJ (LSP/DAP client) → Language / Debug Server
Instead of:
LLM → MCP Server (LSP/DAP client) → Language / Debug Server
This means:
- Single process: the MCP server reuses the language server already started and warmed up by LSP4IJ. No extra memory, no cold start
- Shared state: the AI sees exactly what the IDE sees — same diagnostics, same index, same document state, in real time
- Full project context: LSP4IJ already handles workspace initialization,
didChangeConfiguration, and all the configuration defined in the JetBrains settings (including the JSON editor for user-defined language servers). The MCP server inherits all of this for free
- Custom LSP requests and notifications: since LSP4IJ manages the LSP client, plugins that extend it can expose their proprietary LSP extensions as MCP tools without the MCP server needing to know anything about them
- LSP commands: same —
workspace/executeCommand and server-specific commands are handled by LSP4IJ and can be exposed transparently
- No LSP/DAP knowledge required in the MCP server: the MCP server is completely agnostic of the underlying protocol. It doesn't speak LSP or DAP — it just calls LSP4IJ APIs
Standard MCP tools provided by LSP4IJ
LSP4IJ will provide a set of standard MCP tools out of the box:
- List all configured language servers and their status
- Find language servers matching a given file or project
- Start / stop a language server
- Get server capabilities
- Execute a language server command
- Standard LSP features: diagnostics, hover, completion, references, rename, code actions, inlay hints, etc.
- Create user-defined language servers when none match the project files
Extension point for custom MCP tools
A key feature of this integration is an extension point that allows any plugin using LSP4IJ to register its own MCP tools. This means a plugin can expose its proprietary LSP extensions or DAP capabilities as first-class MCP tools, without modifying LSP4IJ itself.
Example: the Qute plugin (part of the Quarkus Tools for IntelliJ) manages its own language server via LSP4IJ. It can register a qute/dataModel MCP tool that exposes the Qute data model — a custom LSP request that only the Qute language server understands, and that no generic bridge could ever expose correctly.
Future work: DAP support
The same architecture applies naturally to DAP. LSP4IJ already manages debug adapters, so the MCP server could expose DAP capabilities as tools:
- Start / stop a debug session
- Set breakpoints
- Read call stack and variable state at a breakpoint
- Observe and analyze the runtime state of a running debug session
This would allow an AI assistant to act as an intelligent debug observer: it can read the exact state of a debug session running in JetBrains — variables, stack frames, exceptions — and help diagnose bugs without the user having to describe what they see.
Related
Add MCP Server support to LSP4IJ
Context: existing MCP servers for LSP and DAP
Several projects already expose LSP and DAP features as MCP tools, which is a great idea: it allows AI assistants to leverage language intelligence (diagnostics, completions, hover, rename, code actions...) or debugging capabilities (breakpoints, call stack, variable inspection...) directly from their MCP client.
Existing LSP MCP projects:
Existing DAP MCP projects:
The problem with these approaches
All these projects share the same fundamental architecture: they spawn the language or debug server as an external subprocess and implement their own LSP/DAP client to communicate with it. This leads to several significant issues:
rust-analyzer/expandMacro,qute/dataModel). A generic bridge doesn't know about them and can't expose them as MCP toolsworkspace/executeCommand). Again, a generic bridge has to hardcode themdidChangeConfigurationmust be handled by the bridge separately, leading to potential config drift between the IDE and the AIThe LSP4IJ approach: deep IDE integration
LSP4IJ takes a fundamentally different approach. Instead of being yet another external LSP/DAP client, the MCP server lives inside the IDE and delegates everything to LSP4IJ, which already manages the full lifecycle of language and debug servers.
The architecture is:
Instead of:
This means:
didChangeConfiguration, and all the configuration defined in the JetBrains settings (including the JSON editor for user-defined language servers). The MCP server inherits all of this for freeworkspace/executeCommandand server-specific commands are handled by LSP4IJ and can be exposed transparentlyStandard MCP tools provided by LSP4IJ
LSP4IJ will provide a set of standard MCP tools out of the box:
Extension point for custom MCP tools
A key feature of this integration is an extension point that allows any plugin using LSP4IJ to register its own MCP tools. This means a plugin can expose its proprietary LSP extensions or DAP capabilities as first-class MCP tools, without modifying LSP4IJ itself.
Example: the Qute plugin (part of the Quarkus Tools for IntelliJ) manages its own language server via LSP4IJ. It can register a
qute/dataModelMCP tool that exposes the Qute data model — a custom LSP request that only the Qute language server understands, and that no generic bridge could ever expose correctly.Future work: DAP support
The same architecture applies naturally to DAP. LSP4IJ already manages debug adapters, so the MCP server could expose DAP capabilities as tools:
This would allow an AI assistant to act as an intelligent debug observer: it can read the exact state of a debug session running in JetBrains — variables, stack frames, exceptions — and help diagnose bugs without the user having to describe what they see.
Related