A fast Elm Language Server written in Rust, designed for Claude Code integration via MCP.
In Claude Code, run:
/plugin install elm-lsp-rust@CharlonTank/elm-lsp-plugin
Then restart Claude Code.
┌─────────────────────────────────────────────────────────────────┐
│ elm-lsp-plugin │
│ (Marketplace Repository) │
│ https://github.com/CharlonTank/elm-lsp-plugin │
│ │
│ .claude-plugin/marketplace.json │
│ └── plugins: [ │
│ { name: "elm-lsp-rust", │
│ source: "CharlonTank/elm-lsp-rust" } │
│ ] │
└─────────────────────────────────────────────────────────────────┘
│
│ references
▼
┌─────────────────────────────────────────────────────────────────┐
│ elm-lsp-rust │
│ (This Repository - Plugin) │
│ https://github.com/CharlonTank/elm-lsp-rust │
│ │
│ .claude-plugin/plugin.json ─► Plugin metadata │
│ src/ ─► Rust LSP server │
│ mcp-wrapper/ ─► MCP server (bridges MCP↔LSP) │
│ scripts/setup.sh ─► Builds Rust binary on install │
└─────────────────────────────────────────────────────────────────┘
When you install via the marketplace:
- Claude Code fetches plugin metadata from
elm-lsp-plugin/marketplace.json - The marketplace points to this repository (
elm-lsp-rust) - Claude Code clones this repo and runs
scripts/setup.shto build the Rust binary - The MCP wrapper (
mcp-wrapper/index.mjs) becomes available aselm-lsp-rustMCP server
| Feature | Description |
|---|---|
| Go to Definition | Jump to symbol definitions |
| Find References | All usages across workspace |
| Rename | Safe rename across all files (functions, types, variants, fields) |
| Document Symbols | List all symbols in a file |
| Diagnostics | Compiler errors via elm make / lamdera make |
| Formatting | Via elm-format |
| Code Actions | Quick fixes and refactorings |
| Move Function | Move function to another module with import updates |
| File Rename/Move | Rename or move Elm files with module/import updates |
| Add Variant | Add variant to custom type with auto case branch updates |
| Remove Variant | Smart union type variant removal |
| Remove Field | Remove field from type alias with usage updates |
| ERD Generation | Generate Mermaid diagrams from types |
Add Variant: Adds a variant and automatically inserts branches in all case expressions:
-- elm_add_variant with custom branch code for each case expression
type Route = HomeRoute | AboutRoute | NewRoute
-- All case expressions get new branches with your specified code
Remove Variant: Intelligently removes variants:
- Replaces constructor usages with
Debug.todo - Auto-removes pattern match branches
- Errors if removing the only variant
Remove Field: Removes fields from type aliases:
- Updates record literals, patterns, and field accesses
- Replaces field access with
Debug.todo
| Tool | Description |
|---|---|
elm_definition |
Go to definition |
elm_references |
Find all references |
elm_symbols |
List file symbols |
elm_diagnostics |
Get compiler errors |
elm_code_actions |
Get available actions |
elm_apply_code_action |
Apply a code action |
elm_format |
Format file |
elm_rename_variant |
Rename a variant |
elm_rename_type |
Rename a type |
elm_rename_function |
Rename a function |
elm_rename_field |
Rename a record field |
elm_move_function |
Move function to module |
elm_rename_file |
Rename an Elm file |
elm_move_file |
Move an Elm file |
elm_notify_file_changed |
Notify LSP of external file changes |
elm_prepare_add_variant |
Check what adding a variant would affect |
elm_add_variant |
Add variant with auto case branch updates |
elm_prepare_remove_variant |
Check what removing a variant would affect |
elm_remove_variant |
Remove variant with auto pattern removal |
elm_prepare_remove_field |
Check what removing a field would affect |
elm_remove_field |
Remove field from type alias |
elm_generate_erd |
Generate Mermaid ERD from type |
cd elm-lsp-rust
cargo build --release
# Binary at: target/release/elm_lsp
Run one MCP server yourself and point multiple Claude Code sessions to it.
cd /path/to/elm-lsp-rust
cargo build --release
cd mcp-wrapper && npm install
cd /path/to/elm-project
node /path/to/elm-lsp-rust/mcp-wrapper/index.mjs --http --host 127.0.0.1 --port 3333
Claude Code config example (in ~/.claude.json or project .mcp.json):
{
"mcpServers": {
"elm-lsp-rust": {
"type": "http",
"url": "http://127.0.0.1:3333/mcp"
}
}
}
Notes:
- Start the server from your Elm project root so
elm.jsonis present. - This shares one LSP per workspace; use the same repo across sessions.
- Disable the stdio server entry to avoid duplicates.
elm-lsp-rust/
├── .claude-plugin/
│ └── plugin.json # Plugin metadata for marketplace
├── src/
│ ├── main.rs # Entry point
│ ├── server.rs # LSP protocol (tower-lsp)
│ ├── workspace.rs # Indexing, symbols, refactoring
│ ├── document.rs # Single file representation
│ ├── parser.rs # Tree-sitter parsing
│ └── diagnostics.rs # Elm compiler integration
├── mcp-wrapper/ # MCP server (Node.js)
│ └── index.mjs # Translates MCP <-> LSP
├── scripts/
│ └── setup.sh # Build script run on plugin install
├── skills/ # Claude Code skills
└── tests/ # Test suite (228 tests)
- Workspace Indexing: Indexes all
.elmfiles at startup for immediate cross-file operations - Tree-sitter Parsing: Fast, incremental, error-tolerant parsing
- Compiler Diagnostics: Uses
elm make --report=jsonfor 100% accurate errors - Evergreen Exclusion: Skips
src/Evergreen/migration files in refactoring
# Run all tests (228 tests total)
node tests/run_tests.mjs && node tests/test_meetdown_comprehensive.mjs
Tests cover: definition, references, symbols, rename (functions, types, variants, fields), diagnostics, code actions, move function, file rename/move, add/remove variant, add/remove field, and ERD generation.
- elm-lsp-plugin - Marketplace that distributes this plugin
- elm-language-server - Original TypeScript LSP
- tree-sitter-elm - Elm grammar
- tower-lsp - Rust LSP framework
Report bugs at: https://github.com/CharlonTank/elm-lsp-rust/issues