mcp-lsp-v1
An MCP stdio server that wraps language servers to expose read-oriented code-intelligence tools (hover, definition, references, diagnostics, etc.) for coding agents, supporting TypeScript/JavaScript and Python.
README
MCP LSP — Code Intelligence Server
<div align="center">
</div>
A Model Context Protocol (MCP) stdio server that wraps language servers to expose a safe, read-oriented code-intelligence tool surface for coding agents. Supports TypeScript, JavaScript, Python, Go, and Rust — 59 tools across navigation, diagnostics, refactoring, deep understanding, hierarchy, lifecycle, and operations.
Table of Contents
- Quick Start
- Prerequisites
- Installation
- Configuration
- Architecture
- API Reference
- Error Handling
- Safety Model
- Development
- Testing
- Supported Languages
- Troubleshooting
- Changelog
- License
Quick Start
# Prerequisites: install language servers
npm install -g typescript-language-server pyright
# Go and Rust: install gopls and rust-analyzer via your package manager
# Clone and install
git clone https://github.com/beruang/lsp-mcp.git
cd lsp-mcp
pnpm install
# Build
pnpm run build
# Point at a workspace and start
WORKSPACE_PATH=/path/to/your/project node dist/index.js
Connect any MCP client to the server's stdio transport.
Prerequisites
| Dependency | Version | Purpose |
|---|---|---|
| Node.js | >= 20 | Runtime |
| pnpm | — | Package management |
typescript-language-server |
— | TypeScript/JavaScript LSP backend |
pyright-langserver |
— | Python LSP backend |
gopls |
— | Go LSP backend |
rust-analyzer |
— | Rust LSP backend |
Language servers must be on $PATH. The server checks availability via lsp_list_supported_languages.
Installation
pnpm install
Dependencies: @modelcontextprotocol/sdk, vscode-jsonrpc, vscode-languageserver-types, zod, diff.
Configuration
Environment Variables
| Variable | Required | Default | Description |
|---|---|---|---|
WORKSPACE_PATH |
No | process.cwd() |
Absolute path to the workspace root |
Runtime Config (V4)
| Variable | Default | Description |
|---|---|---|
LSP_MAX_REFERENCES |
200 | Max references returned |
LSP_MAX_WORKSPACE_SYMBOLS |
100 | Max workspace symbols |
LSP_MAX_DIAGNOSTICS |
500 | Max diagnostics |
LSP_MAX_COMPLETION_ITEMS |
50 | Max completion items |
LSP_MAX_CHANGED_FILES |
100 | Max files in rename preview |
LSP_MAX_EDITS |
1000 | Max edits in workspace edit |
LSP_MAX_CONTEXT_CHARACTERS |
20000 | Max context characters |
LSP_TIMEOUT_HOVER_MS |
3000 | Hover timeout |
LSP_TIMEOUT_DEFINITION_MS |
5000 | Definition timeout |
LSP_TIMEOUT_REFERENCES_MS |
10000 | References timeout |
LSP_REQUEST_LOG_MAX_ENTRIES |
500 | Request log ring buffer size |
LSP_RAW_REQUEST_ENABLED |
false | Enable debug raw request tool |
LSP_VERBOSE_LOGGING |
false | Verbose logging |
Use lsp_get_config to inspect effective configuration and lsp_update_runtime_config to adjust limits, timeouts, cache TTLs, and debug flags at runtime (in-memory only).
Architecture
src/
├── index.ts # Entry point — MCP server bootstrap
├── config/
│ ├── languageServers.ts # Language server registry
│ ├── defaults.ts # Default runtime config values
│ ├── envConfig.ts # Environment variable parsing
│ └── runtimeConfig.ts # In-memory config merge + validation
├── lsp/
│ ├── LspClient.ts # LSP connection: spawn, initialize, request, shutdown
│ ├── LspClientManager.ts # Per-language client pool + state queries
│ ├── LspState.ts # 8-state machine with validated transitions
│ ├── capabilities.ts # Server capabilities extraction
│ ├── diagnosticsCache.ts # publishDiagnostics notification cache
│ ├── documentStore.ts # didOpen/didChange state tracking
│ └── normalize.ts # LSP → normalized shape converters
├── mcp/
│ ├── registerTools.ts # All 59 MCP tool registrations
│ ├── toolErrors.ts # Structured error envelope
│ └── schemas.ts # Zod schemas
├── navigation/ # V3: declaration, typeDef, implementation, signatureHelp, completion
├── hierarchy/ # V3: call hierarchy + type hierarchy (prepare, incoming/outgoing, super/subtypes)
├── workspaceEdit/ # V2: parse, validate, preview workspace edits
├── codeActions/ # V2: code action cache + normalization
├── diagnostics/ # V2: snapshot store, compare, wait-for-diagnostics
├── context/ # V3: enclosing symbol, symbol context, file outline
├── analysis/ # V3: change impact, fix candidates, explain diagnostics
├── formatting/ # V2: format + range format preview
├── refactor/ # V2: prepare rename, organize imports
├── composite/ # V1: diagnostics summary, inspect symbol
├── diff/ # V1: applyTextEdits, workspaceEditToDiff
├── semantic/ # V3: fixDiagnosticCandidates, explainDiagnostics, analyzeChangeImpact
├── documents/ # V4: open, close, sync, save, list documents
├── ops/ # V4: server status, restart, shutdown, readiness, liveness, workspace status
├── observability/ # V4: request tracker, request log
├── cache/ # V4: cache status + selective clearing
├── debug/ # V4: raw request (disabled by default, method denylist)
├── safety/
│ ├── paths.ts # Workspace containment check
│ └── limits.ts # Truncation caps and timeouts
└── utils/
├── asyncTimeout.ts # Promise race with timeout
├── uri.ts # URI ↔ path conversion
├── symbols.ts # Symbol kind normalization
├── ids.ts # ID generation
├── text.ts # Text utilities
└── time.ts # Time utilities
API Reference
Every tool returns either a success payload or a structured error:
{
"error": {
"code": "path_outside_workspace",
"message": "Human-readable description",
"details": {}
}
}
Navigation & Discovery
| Tool | LSP Method | Description |
|---|---|---|
lsp_hover |
textDocument/hover |
Type information and documentation at cursor |
lsp_definition |
textDocument/definition |
Go-to-definition locations |
lsp_references |
textDocument/references |
Find all references to a symbol |
lsp_document_symbols |
textDocument/documentSymbol |
Symbol outline for a file |
lsp_workspace_symbols |
workspace/symbol |
Workspace-wide symbol search |
lsp_declaration |
textDocument/declaration |
Go-to-declaration |
lsp_type_definition |
textDocument/typeDefinition |
Go-to-type-definition |
lsp_implementation |
textDocument/implementation |
Find implementations |
Diagnostics
| Tool | Description |
|---|---|
lsp_diagnostics |
Cached diagnostics for a file or workspace-wide |
lsp_diagnostics_summary |
Grouped diagnostics with root-cause heuristic |
lsp_wait_for_diagnostics |
Wait for fresh diagnostics after a change |
lsp_snapshot_diagnostics |
Save a named diagnostic snapshot for comparison |
lsp_compare_diagnostics |
Diff two diagnostic snapshots |
lsp_explain_diagnostics |
Cluster diagnostics and identify root causes |
lsp_fix_diagnostic_candidates |
Multi-source fix suggestions (hover + code actions + definition) |
Refactoring & Editing
| Tool | LSP Method | Description |
|---|---|---|
lsp_rename_preview |
textDocument/rename |
Preview rename via WorkspaceEdit + unified diff |
lsp_prepare_rename |
textDocument/prepareRename |
Check if rename is valid at a position |
lsp_code_actions_preview |
textDocument/codeAction |
Preview code actions with diffs |
lsp_resolve_code_action |
codeAction/resolve |
Resolve a cached code action |
lsp_format_preview |
textDocument/formatting |
Preview formatting with diff |
lsp_range_format_preview |
textDocument/rangeFormatting |
Preview range formatting with diff |
lsp_organize_imports_preview |
textDocument/organizeImports |
Preview import organization with diff |
lsp_workspace_edit_preview |
— | Preview any WorkspaceEdit + unified diff |
lsp_validate_workspace_edit |
— | Validate WorkspaceEdit safety |
Deep Understanding
| Tool | LSP Method | Description |
|---|---|---|
lsp_signature_help |
textDocument/signatureHelp |
Function signature at call site |
lsp_completion |
textDocument/completion |
Code completion suggestions |
lsp_inspect_symbol |
composite | Aggregate: hover + definition + refs + risk hints |
lsp_symbol_context |
composite | Surrounding symbols at a position |
lsp_enclosing_symbol |
composite | Innermost enclosing symbol |
lsp_file_outline |
composite | File-level symbol outline |
Hierarchy & Impact
| Tool | LSP Method | Description |
|---|---|---|
lsp_prepare_call_hierarchy |
textDocument/prepareCallHierarchy |
Prepare call hierarchy for a symbol |
lsp_incoming_calls |
callHierarchy/incomingCalls |
Who calls this symbol |
lsp_outgoing_calls |
callHierarchy/outgoingCalls |
What this symbol calls |
lsp_prepare_type_hierarchy |
textDocument/prepareTypeHierarchy |
Prepare type hierarchy |
lsp_supertypes |
typeHierarchy/supertypes |
Super-types of a symbol |
lsp_subtypes |
typeHierarchy/subtypes |
Sub-types of a symbol |
lsp_analyze_change_impact |
composite | Cross-file impact analysis for a proposed change |
Server Lifecycle
| Tool | Description |
|---|---|
lsp_server_status |
Runtime status for all configured language servers |
lsp_restart_server |
Restart a language server (reopens docs, clears diagnostics) |
lsp_shutdown_server |
Graceful shutdown with timeout |
lsp_list_supported_languages |
Configured languages, extensions, commands, binary availability |
lsp_get_capabilities |
Normalized LSP capabilities per language |
Document Lifecycle
| Tool | LSP Method | Description |
|---|---|---|
lsp_open_document |
textDocument/didOpen |
Register a document with the LSP server |
lsp_close_document |
textDocument/didClose |
Unregister a document |
lsp_sync_document |
textDocument/didChange |
Notify LSP of content changes |
lsp_save_document |
textDocument/didSave |
Notify LSP of a save |
lsp_list_open_documents |
— | All currently tracked open documents |
Health
| Tool | Description |
|---|---|
lsp_health_check |
Server health and per-language LSP capabilities |
lsp_readiness |
Workspace + language server availability check |
lsp_liveness |
Fast liveness check + optional memory stats |
Observability & Cache
| Tool | Description |
|---|---|
lsp_request_log |
LSP request history with filtering |
lsp_clear_request_log |
Clear request log entries |
lsp_cache_status |
Entry counts for all internal caches |
lsp_clear_caches |
Selective or full cache clearing |
Configuration
| Tool | Description |
|---|---|
lsp_get_config |
Effective config (defaults → env → runtime overrides) |
lsp_update_runtime_config |
In-memory config updates (limits, timeouts, caches, debug) |
Debug
| Tool | Description |
|---|---|
lsp_raw_request |
Raw LSP request with method denylist (disabled by default) |
Multi-Workspace
| Tool | Description |
|---|---|
lsp_list_workspaces |
Known workspaces (foundation) |
lsp_workspace_status |
Status for a specific workspace (foundation) |
Error Handling
Every tool returns errors in a uniform envelope:
{
"error": {
"code": "path_outside_workspace",
"message": "Path is outside workspace: /etc/passwd",
"details": {}
}
}
Error Codes
| Code | Trigger |
|---|---|
path_outside_workspace |
filePath does not resolve inside WORKSPACE_PATH |
unsupported_language |
File extension has no registered LSP server |
file_not_found |
File does not exist on disk |
lsp_server_unavailable |
Language server binary not on $PATH |
lsp_server_not_initialized |
Server not initialized |
lsp_request_failed |
LSP request returned an error |
lsp_request_timeout |
LSP request exceeded its deadline |
lsp_capability_unsupported |
Server does not support the capability |
declaration_not_supported |
Server lacks declaration provider |
type_definition_not_supported |
Server lacks type definition provider |
implementation_not_supported |
Server lacks implementation provider |
signature_help_not_supported |
Server lacks signature help provider |
completion_not_supported |
Server lacks completion provider |
call_hierarchy_not_supported |
Server lacks call hierarchy provider |
call_hierarchy_item_not_found |
Hierarchy item ID not found |
call_hierarchy_item_expired |
Hierarchy item TTL expired |
type_hierarchy_not_supported |
Server lacks type hierarchy provider |
type_hierarchy_item_not_found |
Type hierarchy item ID not found |
type_hierarchy_item_expired |
Type hierarchy item TTL expired |
change_impact_analysis_incomplete |
Change impact partial results |
diagnostic_not_found |
Diagnostic index not found |
invalid_config_key |
Unknown config key in update |
invalid_config_value |
Invalid config value (e.g., negative limit) |
immutable_config_key |
Attempt to change workspacePath at runtime |
server_not_found |
Language not configured |
restart_rate_limited |
Too many restarts in window |
raw_request_disabled |
Debug tool is disabled |
method_denied |
LSP method blocked by denylist |
document_not_found |
Document not in open documents store |
Safety Model
The server is designed for read-oriented coding agents:
| Guard | Mechanism |
|---|---|
| Workspace containment | Every file path validated against WORKSPACE_PATH |
| No file writes | All tools are read-only; lsp_rename_preview returns a diff but never applies edits |
| Result caps | All list results are truncated with configurable limits |
| Timeouts | Every LSP request has a per-method deadline |
| Structured errors | All errors use the uniform { error: { code, message, details } } envelope |
| Request log privacy | Logs method, duration, status — never full file contents (unless verbose logging explicitly enabled) |
| Method denylist | lsp_raw_request blocks workspace/applyEdit, workspace/executeCommand, and other dangerous methods |
| Restart rate limiting | Max 3 restarts per 60s per language |
| State machine validation | Invalid LSP state transitions are logged and rejected |
Development
pnpm run typecheck # TypeScript type-check
pnpm run lint # ESLint (zero warnings)
pnpm run lint:fix # ESLint auto-fix
pnpm run dev # Run with tsx (no build)
pnpm run build # Build to dist/
pnpm run start # Start built artifact
Pre-commit Hook
husky + lint-staged:
eslint --fix --max-warnings 0pnpm run typecheckpnpm run verify:decoupling
Conventions
- Module system: ESM (
"type": "module",NodeNext) - TypeScript: strict, target ES2022
- Testing:
node --test+tsx - Linting: ESLint with
@typescript-eslint, zero-warnings policy
Testing
pnpm test # All unit tests
npm run test:safety # Safety tests
npm run test:integration # Integration tests (requires language servers)
Coverage
- 106+ tests across unit, integration, and safety suites
- 5 languages: TypeScript, JavaScript, Python, Go, Rust
- V1-V3 regression: all passing with every V4 change
Supported Languages
| Language | Extensions | Language Server | Language ID |
|---|---|---|---|
| TypeScript | .ts, .tsx |
typescript-language-server --stdio |
typescript |
| JavaScript | .js, .jsx |
typescript-language-server --stdio |
typescript |
| Python | .py |
pyright-langserver --stdio |
python |
| Go | .go |
gopls |
go |
| Rust | .rs |
rust-analyzer |
rust |
Adding a language:
- Entry in
src/config/languageServers.ts - Binary on
$PATH - Optional
waitConfiginsrc/lsp/diagnosticsCache.ts
Troubleshooting
lsp_server_unavailable
which typescript-language-server pyright-langserver gopls rust-analyzer
npm install -g typescript-language-server pyright
Use lsp_list_supported_languages to check binary availability at runtime.
path_outside_workspace
Set WORKSPACE_PATH to the project root. Symlinks are resolved before containment check.
No diagnostics
Diagnostics are cached from publishDiagnostics notifications. For cold cache, use lsp_diagnostics with workspaceWide: true to trigger a warm-up pass, or lsp_wait_for_diagnostics.
Stale diagnostics after external edit
Use lsp_sync_document to notify the LSP of changes, then lsp_wait_for_diagnostics. For bulk recovery, lsp_restart_server with reopenDocuments: true.
Changelog
| Version | Focus | Key Additions |
|---|---|---|
| V4 | Production operations | Server lifecycle, document lifecycle, observability, cache, config, health, debug, multi-workspace (21 tools) |
| V3 | Deep understanding | Hierarchy (call + type), declaration, type definition, implementation, signature help, completion, impact analysis (17 tools) |
| V2 | Safe refactoring | Preview-first editing — rename, code actions, formatting, organize imports, diagnostics snapshots (11 tools) |
| V1 | Semantic navigation | Hover, definition, references, symbols, diagnostics, rename preview, inspect (10 tools) |
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.