agent-lsp
Summary: agent-lsp is an MCP server that orchestrates real language servers (gopls, rust-analyzer, pyright, tsserver, clangd, …) to give AI agents semantic code intelligence, safe editing, and speculative what-if analysis across 30+ languages.
Navigation: jump to definition, declaration, type definition, and all implementations of an interface; resolve symbols by dot-notation name without knowing file/position (
go_to_symbol,get_workspace_symbols).References & impact analysis: find all references, file-scoped document highlights, call hierarchy (callers/callees), type hierarchy (supertypes/subtypes), and blast-radius analysis (
get_change_impact) that partitions callers into test vs non-test with optional transitive depth.Cross-repo intelligence: add/remove/list workspace folders and find a library symbol's usages across multiple consumer repositories in one call.
Safe refactoring:
prepare_renamesafety gate,rename_symbol(dry-run preview,exclude_globsfor vendored/generated code),apply_editin WorkspaceEdit or fuzzy text-match mode, code actions, andexecute_commandfor server-side actions.Speculative execution: create in-memory simulation sessions, apply single edits (
simulate_edit,simulate_edit_atomic) or chained edits (simulate_chain), evaluate diagnostic deltas with confidence (evaluate_session), then commit (diff or apply) or discard — nothing touches disk until verified.Diagnostics & verification: errors/warnings for one file or all open files, quick-fix code actions, formatting for a document or range, and language-dispatched
run_build/run_testswith LSP-normalized failure locations.Code understanding: hover type/doc info, authoritative docs from local toolchains (
go doc,pydoc,cargo doc) including un-indexed dependencies, enclosing symbol source extraction, document/workspace symbol outlines, completions, signature help, semantic tokens, and inlay hints.Test correlation: static lookup of which test files exercise a given source file.
Session & server management:
start_lsp/restart_lsp_serverper workspace root or language, capability probing (get_server_capabilities), server detection and config suggestion (detect_lsp_servers), open/close documents, watched-file notifications, and log-level control.Output efficiency: responses encoded in GCF (graph/tabular compact format) for 30–84% token savings versus JSON, with persistent warm indexes across sessions.
Supports Bun runtime as an alternative to Node.js for running the MCP server, offering compatibility with JavaScript/TypeScript language server tooling.
Provides C++ language support through clangd language server integration, enabling code analysis, navigation, and refactoring capabilities for C++ projects.
Provides Clojure language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Clojure projects.
Provides Dart language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Dart projects.
Provides Docker container deployment options for the MCP server with stdio and HTTP modes, supporting multiple language server configurations in isolated environments.
Provides Elixir language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Elixir projects.
Hosts the project repository and provides installation scripts via GitHub raw URLs for platform-agnostic deployment of the MCP server.
Provides package installation through Homebrew tap for macOS/Linux users, offering a native package management experience for the MCP server.
Provides JavaScript language support through TypeScript language server integration, enabling code analysis, navigation, and refactoring capabilities for JavaScript projects.
Provides Kotlin language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Kotlin projects.
Provides LLVM-based tooling for C/C++ language support through clangd integration, enabling advanced code analysis and refactoring capabilities.
Provides Lua language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Lua projects.
Provides MongoDB query language support through language server integration, enabling code analysis and validation capabilities for MongoDB projects.
Provides Node.js runtime support for language servers and npm package installation for the MCP server and language server dependencies.
Provides npm package installation for the MCP server globally and for language server dependencies like TypeScript language server and pyright.
Provides PHP language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for PHP projects.
Provides Prisma schema language support through language server integration, enabling code analysis and validation capabilities for Prisma projects.
Provides Python language support through pyright language server integration, enabling code analysis, navigation, and refactoring capabilities for Python projects.
Provides Ruby language support through solargraph language server integration, enabling code analysis, navigation, and refactoring capabilities for Ruby projects.
Provides Rust language support through rust-analyzer language server integration, enabling code analysis, navigation, and refactoring capabilities for Rust projects.
Provides Scala language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Scala projects.
Provides Swift language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Swift projects.
Provides Terraform HCL language support through language server integration, enabling code analysis and validation capabilities for Terraform projects.
Provides TypeScript language support through typescript-language-server integration, enabling code analysis, navigation, and refactoring capabilities for TypeScript projects.
Provides Zig language support through language server integration, enabling code analysis, navigation, and refactoring capabilities for Zig projects.
English · 简体中文 · Русский · हिन्दी · العربية
Code intelligence infrastructure for AI agents. 66 tools, 32 CI-verified languages, 24 agent workflows. Single Go binary.
curl -fsSL https://raw.githubusercontent.com/blackwell-systems/agent-lsp/main/install.sh | sh && agent-lsp initWhat is it?
agent-lsp is an MCP server that orchestrates existing LSP servers (gopls, rust-analyzer, jdtls, etc.) into agent-native workflows.
Not an LSP server — it's an orchestration layer that manages language servers and exposes batch operations, speculative editing, and multi-step workflows via MCP tools.
Architecture:
Language servers (gopls, rust-analyzer, etc.) → provide code intelligence
agent-lsp (MCP server) → orchestrates workflows, maintains warm runtime
AI agents → consume via MCP protocol
Related MCP server: uacos
Why agent-lsp?
Persistent warm runtime
Language servers stay indexed across agent sessions. First session: indexes workspace (~10s for typical projects). Subsequent sessions: instant. No cold-start penalty on each request.
Batch operationsblast_radius → one call returns all exports + all callers (test vs non-test partitioned). Without orchestration: 20+ sequential LSP calls.
Speculative editingsimulate_edit → preview changes in memory, check diagnostic delta, apply or discard. Test edits before touching disk. safe_apply_edit writes only an edit it could verify: if the preview timed out or the server was still indexing, nothing is written.
Workflow orchestration
24 skills that chain LSP operations into complete pipelines:
/lsp-refactor→ impact analysis → preview → apply → verify build → run tests/lsp-safe-edit→ preview → diagnostic diff → apply if safe/lsp-verify→ LSP diagnostics → build → test suite
Multi-language, single session
One agent-lsp process routes .go to gopls, .ts to tsserver, .py to pyright. No reconfiguration between projects. Session persists across files and repositories. Workspace-wide queries (find_symbol, get_server_capabilities) ask every running language server, not just the default one. start_lsp can also connect to a language server that is already running (e.g. gopls -listen) and reuse its warm index.
Token-optimized output: Tool responses encoded in GCF instead of JSON. 30-84% fewer tokens depending on tool (up to 92.7% with session dedup). 100% LLM comprehension on every frontier model, 91.2% on complex code graphs where JSON averages 54.1%. See below for measured savings per tool.
How the pieces fit together: LSP (Language Server Protocol) is how editors get code intelligence: completions, diagnostics, go-to-definition. MCP (Model Context Protocol) is the standard way AI tools like Claude Code discover and call external tools. agent-lsp bridges the two: language server intelligence, accessible to AI agents.
Use it when
Building agentic code generation systems
Automating refactors across large codebases
CI tooling that needs programmatic code intelligence
Any workflow where sequential LSP calls are too slow or complex
What agents say
We asked AI agents to evaluate agent-lsp across 10 coding tasks (find callers, rename safely, preview edits, detect dead code) and write an honest assessment. Four different models, four independent evaluations, same conclusion:
Claude (Opus 4.6): "I would recommend agent-lsp for any workflow involving refactoring, impact analysis, or safe editing. The standout tools are
blast_radius(blast radius in one call, with test/non-test partitioning that would take 5-10 grep commands to replicate),go_to_implementation(type-checked interface satisfaction that grep simply cannot do), and the simulation session workflow (speculative type-checking without touching disk, which has no grep/read equivalent at all)."
Cursor (auto): "I would recommend agent-lsp for heavy refactors and code navigation because the rename, references, implementations, call hierarchy, and simulation tools remove a lot of brittle grep/manual-edit work and make changes safer."
GPT-5.5 (via Codex): "I would recommend agent-lsp for symbol-aware work: references, implementations, rename previews, diagnostics, and large-file structure are materially faster and less error-prone than grep/read loops."
Gemini 2.5 Pro (via Gemini CLI): "I would highly recommend agent-lsp because it provides a level of semantic awareness that standard text-searching tools simply cannot match. The ability to perform high-confidence renames, find interface implementations, and preview the diagnostic impact of edits without writing to disk significantly reduces the risk of introducing regressions."
Tested, not assumed
Every other MCP-LSP implementation lists supported languages in a config file. None of them run the actual language server in CI to verify it works.
agent-lsp CI runs 32 real language servers against real fixture codebases on every push, and all 32 pass end to end: Go, Python, TypeScript, Rust, Java, C, C++, C#, Ruby, PHP, Kotlin, Swift, Scala, Zig, Lua, Elixir, Gleam, Clojure, Dart, Terraform, Nix, Prisma, SQL, MongoDB, MQL, and more. When we say "works with gopls," that's a verified, automated claim, not a hope.
Speculative execution
Simulate changes in memory before writing to disk. No other MCP-LSP implementation has this.
preview_edit previews the diagnostic impact of any edit. You see exactly what breaks before the file is touched. simulate_chain evaluates a sequence of dependent edits (rename a function, update all callers, change the return type) and reports which step first introduces an error.
8 speculative execution tools. See docs/guide/speculative-execution.md for the full workflow.
Interactive refactoring
Some refactorings need answers before the language server can compute them: which struct tags to add and how to name them, which interface to implement, where a declaration should move. gopls v0.24 asks these questions through a new LSP extension (golang/go#76331), which editors show as dialogs. agent-lsp is a client for it built for agents: refactor returns the questions as a typed form (choices, defaults, a searchable list for the interface), the agent answers, and the server computes the edit. agent-lsp captures that edit before it is written, so dry_run previews it.
refactor(file, line, column) → available refactorings
refactor(..., action: "Add struct tags") → questions: tags (default "json"), naming style (camelCase, snake_case, ...)
refactor(..., answers: {addTags: "json", transform: "snakecase"}) → appliedSee refactor in the tool reference.
Token savings
Structured LSP responses use 5-34x fewer tokens than grep/read on the same tasks. On HashiCorp Consul (319K lines), a blast-radius analysis uses 17.7MB via grep vs 841KB via LSP, reducing 5,534 tool calls to 119. Savings scale with codebase size. See docs/guide/token-savings.md for the full experiment across five codebases.
Token-optimized output (GCF)
Tool responses are encoded in GCF (Graph Compact Format) instead of JSON. GCF eliminates field-name repetition, identifier repetition, and per-record structural overhead.
Profile | Tools | Savings vs JSON |
Tabular | Other structured results (find_references, diagnostics, detect_changes, ...) | 30-51% |
Graph | list_symbols, find_symbol, blast_radius, find_callers, explore_symbol, type_hierarchy, get_cross_repo_references | 79-84% |
Graph + session dedup | Same, via gcf-proxy | 92.7% (5th call) |
Workspace edits (rename and refactor previews) are always JSON, so they round-trip into apply_edit byte-exact. Grouped/nested responses (callers under a symbol, diagnostics with related info) tabularize too, for ~14% over JSON on that shape (details).
GCF is enabled by default. To revert to JSON:
export AGENT_LSP_OUTPUT_FORMAT=jsonBenchmark: go run scripts/gcf-benchmark.go. See docs/guide/gcf-integration.md for architecture details.
GCF: gcformat.com · Spec · Go · Python · TypeScript · Playground
Why orchestration matters
AI agents make incorrect code changes because they can't see the full picture: who calls this function, what breaks if I rename it, does the build still pass. Language servers have the answers, but raw LSP tools require 20+ sequential calls and complex orchestration logic.
agent-lsp solves this by encoding correct multi-step operations into single calls and skills. blast_radius does what would take an agent 20+ calls in one. /lsp-refactor chains impact → preview → apply → verify → test without per-prompt orchestration.
Persistent daemon mode
Python and TypeScript projects need minutes of background indexing before find_references works. agent-lsp automatically spawns a persistent daemon broker that survives between sessions, so the workspace stays indexed. First session: daemon starts and indexes (~10s for FastAPI). Subsequent sessions: instant connection to the warm daemon. Auto-exits after 30 minutes of inactivity. Go, Rust, and other fast-indexing languages bypass this entirely (zero overhead).
Phase enforcement
Skills tell agents the correct order of operations. Phase enforcement makes the runtime block violations instead of trusting the agent to follow instructions.
When an agent activates a skill, every tool call is checked against the current phase's permissions. Calling apply_edit during blast-radius analysis doesn't silently proceed; it returns an error with specific recovery guidance, followed by a JSON copy of the same fields:
Phase violation: apply_edit is forbidden in the "blast_radius" phase
Recovery: apply_edit becomes available in the "apply" phase. Next phase is "speculative_preview". Allowed tools: [open_document get_diagnostics preview_edit simulate_chain]Phases advance automatically as the agent calls tools from later phases.
No other MCP tool provider enforces workflow ordering at runtime. See docs/guide/phase-enforcement.md.
Concurrency analysis
The inspector includes 4 concurrency checks that work across 25 languages in 4 concurrency families (goroutine, thread, async, actor):
Unrecovered concurrent entry: goroutines/threads/tasks without recovery
Unchecked shared state: bare type assertions on sync.Map, ConcurrentHashMap
Channel never closed: channels/queues created but never closed (goroutine leaks)
Shared field without sync: fields accessed from concurrent contexts without synchronization
blast_radius annotates symbols with sync_guarded: true when the parent type has a mutex. find_callers with cross_concurrent: true traces call chains through goroutine/thread boundaries. The /lsp-concurrency-audit skill produces a field-level safety report for any type.
Auto-diagnostics
Symbol edit tools (replace_symbol_body, insert_after_symbol, insert_before_symbol, safe_delete_symbol) automatically return errors_after and warnings_after counts. Agents know immediately whether an edit broke something without a separate get_diagnostics call.
safe_apply_edit combines preview + apply in one call: previews speculatively, applies to disk only if net_delta == 0 (no new errors). It also refuses edits it could not verify (a timed-out preview or a server still indexing) and writes only the content it previewed: if the file changed in between, nothing is written. One tool call instead of three.
Works with
AI Tool | Transport | Setup |
stdio |
| |
stdio |
| |
stdio |
| |
stdio |
| |
Codex and the ChatGPT desktop app | stdio |
|
stdio | ||
stdio |
| |
stdio |
| |
Any MCP client | Streamable HTTP |
|
See docs/getting-started/mcp-clients.md for copy-paste configs.
Skills
Raw tools get ignored. Skills get used. Each skill encodes the correct tool sequence so workflows actually happen without per-prompt orchestration instructions. Skills are available as AgentSkills slash commands and as MCP prompts via prompts/list / prompts/get for any MCP client.
See docs/guide/skills.md for full descriptions and usage guidance.
Before you change anything
Skill | Purpose |
| Blast-radius analysis before touching a symbol or file |
| Find all concrete implementations of an interface |
| Detect zero-reference exports before cleanup |
Editing safely
Skill | Purpose |
| Speculative preview before disk write; before/after diagnostic diff; surfaces code actions on errors |
| Test changes in-memory without touching the file |
| Edit a named symbol without knowing its file or position |
| Safe editing of exported symbols, finds all callers first |
|
|
Getting started
Skill | Purpose |
| Structural architecture overview: languages, package map, entry points, dependency graph, and hotspots |
| First-session project onboarding: detect languages, map packages, find entry points and hotspots, check diagnostics |
Understanding unfamiliar code
Skill | Purpose |
| "Tell me about this symbol": hover + implementations + call hierarchy + references in one pass |
| Deep-dive Code Map for a symbol or file: type info, call hierarchy, references, source |
| Three-tier documentation: hover → offline toolchain → source |
| Find all usages of a library symbol across consumer repos |
| File-scoped symbol list, usage search, and type info |
After editing
Skill | Purpose |
| Diagnostics + build + tests after every edit |
| Apply quick-fix code actions for all diagnostics in a file |
| Find and run only tests that cover an edited file |
| Format a file or selection via the language server formatter |
Generating code
Skill | Purpose |
| Trigger server-side code generation (interface stubs, test skeletons, mocks) |
| Extract a code block into a named function via code actions |
Full workflow
Skill | Purpose |
| End-to-end refactor: blast-radius → preview → apply → verify → test |
| Full code quality audit (12 checks): dead symbols, test coverage, error handling, doc drift, concurrency safety |
| Field-level concurrency safety audit for a type: traces concurrent access, flags unsynced fields |
Docker
Stdio mode (MCP client spawns the container directly):
# Go
docker run --rm -i -v /your/project:/workspace ghcr.io/blackwell-systems/agent-lsp:go go:gopls
# TypeScript
docker run --rm -i -v /your/project:/workspace ghcr.io/blackwell-systems/agent-lsp:typescript typescript:typescript-language-server,--stdio
# Python
docker run --rm -i -v /your/project:/workspace ghcr.io/blackwell-systems/agent-lsp:python python:pyright-langserver,--stdioHTTP mode (persistent service, remote clients connect over Streamable HTTP):
docker run --rm \
-p 8080:8080 \
-v /your/project:/workspace \
-e AGENT_LSP_TOKEN=your-secret-token \
ghcr.io/blackwell-systems/agent-lsp:go \
--http --port 8080 --listen-addr 0.0.0.0 go:goplsThe server binds 127.0.0.1 by default, so pass --listen-addr 0.0.0.0 inside a container for the port mapping to reach it. Images run as a non-root user (uid 65532) by default. Set AGENT_LSP_TOKEN via environment variable, never --token on the command line. Images are also mirrored to Docker Hub (blackwellsystems/agent-lsp). See DOCKER.md for the full tag list, HTTP mode setup, and security hardening options.
Setup
Step 1: Install agent-lsp
curl -fsSL https://raw.githubusercontent.com/blackwell-systems/agent-lsp/main/install.sh | shmacOS / Linux
brew install blackwell-systems/tap/agent-lspWindows
# PowerShell (no admin required)
iwr -useb https://raw.githubusercontent.com/blackwell-systems/agent-lsp/main/install.ps1 | iex
# Scoop
scoop bucket add blackwell-systems https://github.com/blackwell-systems/agent-lsp
scoop install blackwell-systems/agent-lsp
# Winget
winget install BlackwellSystems.agent-lspAll platforms
# pip
pip install agent-lsp
# npm
npm install -g @blackwell-systems/agent-lsp
# Go install
go install github.com/blackwell-systems/agent-lsp/cmd/agent-lsp@latestStep 2: Install language servers
Install the servers for your stack. Common ones:
Language | Server | Install |
TypeScript / JavaScript |
|
|
Python |
|
|
Go |
|
|
Rust |
|
|
C / C++ |
|
|
Ruby |
|
|
TypeScript 7 ships without tsserver, which typescript-language-server needs, so install TypeScript 6 (typescript@6) until that changes. A project with TypeScript 6 in its own node_modules works either way.
Full list of supported languages and their CI status in docs/reference/language-support.md.
Step 3: Verify setup
agent-lsp doctorProbes each configured language server and reports capabilities. Fix any failures before proceeding. See language support for install commands and server-specific notes.
Step 4: Configure your AI tool
agent-lsp initDetects language servers on your PATH, asks which AI tool you use, writes the correct MCP config, and installs skill awareness rules for your AI provider (CLAUDE.md for Claude Code, .cursor/rules/ for Cursor, .clinerules for Cline, .windsurfrules for Windsurf, GEMINI.md for Gemini CLI, AGENTS.md for Pi and Codex). For CI or scripted use: agent-lsp init --non-interactive.
For Claude Code, choose the project target (1, writes .mcp.json in the current directory) or the user scope (2, all projects: registers the server with claude mcp add --scope user when the claude CLI is installed, otherwise adds it to ~/.claude.json). init only sets the agent-lsp entry; every other server and setting in an existing config file is kept.
For Codex and the ChatGPT desktop app, which share one MCP configuration, choose the user target (11: registers the server with codex mcp add when the codex CLI is installed, otherwise adds an [mcp_servers.agent-lsp] table to $CODEX_HOME/config.toml, default ~/.codex/config.toml) or the project target (12: .codex/config.toml in the current directory, read for trusted projects). The TOML file is edited in place, so your other settings and comments are kept.
For Pi, choose the project (9) or global (10) target. Pi has no built-in MCP support; init writes the shared standard MCP files that the pi-mcp-adapter package reads — project .mcp.json (same file Claude Code uses, so one config serves both) or global ~/.config/mcp/mcp.json. Skill awareness rules go into AGENTS.md (project) or ~/.pi/agent/AGENTS.md (global). Install the adapter once with pi install npm:pi-mcp-adapter.
One-command complete setup
Add --with-skills to also install the embedded skill files (no repo clone needed):
agent-lsp init --with-skillsSkills are written to the destination matching the chosen target: only the Pi project target (9) uses the tool-agnostic .agents/skills/ directory (versionable with the repo); the Pi global target (10) uses ~/.pi/agent/skills/; the Claude Code targets (1/2) use ~/.claude/skills/; Cursor (4) uses ~/.cursor/skills/; Gemini CLI (7) uses ~/.config/gemini-cli/skills/; and the Codex user target (11) uses $CODEX_HOME/skills/. Providers without a verified skills directory are skipped with a pointer to skills/install.sh --dest. Re-running overwrites the managed skill files, keeping them in sync with the installed binary. agent-lsp uninstall removes them.
The generated config looks like:
{
"mcpServers": {
"agent-lsp": {
"type": "stdio",
"command": "agent-lsp",
"args": [
"go:gopls",
"typescript:typescript-language-server,--stdio",
"python:pyright-langserver,--stdio"
]
}
}
}Each arg is language:server-binary (comma-separate server args).
Step 5: Install skills
git clone https://github.com/blackwell-systems/agent-lsp.git /tmp/agent-lsp-skills
cd /tmp/agent-lsp-skills/skills && ./install.sh --copyOr skip the clone entirely: agent-lsp init --with-skills installs the same embedded skills to the destination matching your chosen target.
Skills are prompt files copied into your AI tool's configuration. --copy means the clone can be safely deleted afterward. The script defaults to ~/.claude/skills/; pass --dest for other agents, e.g. --dest ~/.pi/agent/skills for Pi. It also appends a managed skills table to existing instruction files (~/.claude/CLAUDE.md, project AGENTS.md, ~/.pi/agent/AGENTS.md, GEMINI.md).
Skills are also available as MCP prompts: any MCP client can discover them via prompts/list and retrieve full workflow instructions via prompts/get, with no manual installation required. The install.sh path is for AgentSkills-compatible clients (Claude Code slash commands, Pi /skill:name commands).
Step 6: Allow tool permissions (Claude Code)
For Claude Code, add mcp__agent-lsp__* to your permissions allow list so all 66 tools are available without per-tool approval prompts:
// ~/.claude/settings.json
{
"permissions": {
"allow": ["mcp__agent-lsp__*"]
}
}Without this, Claude Code will prompt for permission on each tool call. Other MCP clients handle permissions differently; check your client's documentation.
Skills are multi-tool workflows that encode reliable procedures: blast-radius check before edit, speculative preview before write, test run after change. See docs/guide/skills.md for the full list.
Step 7: Start working
Your AI agent calls tools automatically. The first call initializes the workspace:
start_lsp(root_dir="/your/project")This is what the agent does, not something you type. Then use any of the 66 tools. The session stays warm; no restart needed when switching files.
What's unique about agent-lsp
Capability | Details |
Tools | 66 |
Languages (CI-verified) | 32, end-to-end integration tests on every push |
Agent workflows (skills) | 24, named multi-step procedures, discoverable via MCP |
Speculative execution | 8 tools, simulate changes before writing to disk |
Interactive refactoring | ✓, answers the language server's refactoring questions (gopls v0.24+) |
Phase enforcement | 4 skills, runtime blocks out-of-order tool calls with recovery guidance |
Connection model | persistent, warm index across files and projects |
Call hierarchy | ✓, single tool, direction param |
Type hierarchy | ✓, CI-verified |
Cross-repo references | ✓, multi-root workspace |
Multi-server queries | ✓, |
Auto-watch | ✓, always-on, debounced file watching |
Streamable HTTP transport | ✓, bearer token auth, non-root Docker |
Distribution | single Go binary, 10 install channels |
Use Cases
Multi-project sessions: point your AI at
~/code/, work across any project without reconfiguringPolyglot development: Go backend + TypeScript frontend + Python scripts in one session
Large monorepos: one server handles all languages, routes by file extension
Code migration: refactor across repos with full cross-repo reference tracking
CI pipelines: validate against real language server behavior
Niche language stacks: Gleam, Elixir, Prisma, Zig, Clojure, Nix, Dart, Scala, MongoDB, all CI-verified
Multi-Language Support
32 languages CI-verified end to end against real language servers on every CI run. A language that fails to start or answer fails CI rather than being skipped. No other MCP-LSP implementation tests a single language in CI.
Go, Python, TypeScript, Rust, Java, C, C++, C#, Ruby, PHP, Kotlin, Swift, Scala, Zig, Lua, Elixir, Gleam, Clojure, Dart, Terraform, Nix, Prisma, SQL, MongoDB, JavaScript, YAML, JSON, Dockerfile, CSS, HTML, MQL, Luau.
See docs/reference/language-support.md for the full coverage matrix.
Tools
66 tools covering navigation, analysis, refactoring, symbol editing, composite exploration, safe editing, speculative execution, and session lifecycle. All CI-verified.
See docs/reference/tools.md for the full reference with parameters and examples.
Further reading
Documentation
Tools reference: full tool reference with parameters and examples
Skills reference: skill reference, workflows, use cases, and composition
Language support: language coverage matrix
Architecture: system design and internals
Speculative execution: simulate-before-apply workflows
LSP conformance: LSP 3.17 spec coverage
Docker: Docker tags, compose, and volume caching
Contributing
CI notes: CI quirks and test harness details
Distribution: install channels and release pipeline
Development
git clone https://github.com/blackwell-systems/agent-lsp.git
cd agent-lsp && go build ./...
go test ./... # unit tests
go test ./... -tags integration # integration tests (requires language servers)Library Usage
The pkg/lsp, pkg/session, and pkg/types packages expose a stable Go API for using agent-lsp's LSP client directly without running the MCP server.
import "github.com/blackwell-systems/agent-lsp/pkg/lsp"
client := lsp.NewLSPClient("gopls", []string{})
client.Initialize(ctx, "/path/to/workspace")
defer client.Shutdown(ctx)
locs, err := client.GetDefinition(ctx, fileURI, lsp.Position{Line: 10, Character: 4})See docs/architecture/architecture.md for the full package API.
License
MIT
Available Tools
50 toolsadd_workspace_folderA
Add a directory to the LSP workspace, enabling cross-repo references, definitions, and diagnostics. Useful when working across a library and its consumers — after adding the consumer repo, get_references on a library function returns call sites in both repos. Requires start_lsp to have been called first. Language servers that support multi-root workspaces (gopls, rust-analyzer, typescript-language-server) will re-index the new folder automatically.
Inputs: path (required).
apply_editA
Apply an edit to a file. Two modes: (1) WorkspaceEdit mode — pass workspace_edit with positional changes returned by rename_symbol or format_document; (2) Text-match mode — pass file_path + old_text + new_text to find and replace text without needing line/column positions. Text-match tries exact match first, then whitespace-normalised line match (handles indentation differences). Use text-match when AI-generated positions would be imprecise.
Inputs: new_text, old_text, file_path, workspace_edit.
call_hierarchyB
Show call hierarchy for a symbol at a position. Returns callers (incoming), callees (outgoing), or both depending on the direction parameter. Direction defaults to "both". Use this to understand code flow -- which functions call this function and which functions it calls.
Inputs: line (required), column (required), file_path (required), direction, +1 more.
close_documentB
Close a file in the LSP server. Use this tool when you're done with a file to free up resources and reduce memory usage. It's good practice to close files that are no longer being actively analyzed, especially in long-running sessions or when working with large codebases.
Inputs: file_path (required).
commit_sessionA
Commit a simulation session. With apply=true, writes changes to disk and notifies LSP servers. With apply=false, returns a unified diff patch. Use after evaluate_session confirms the changes are safe.
Inputs: session_id (required), apply, target.
create_simulation_sessionA
Create a new speculative code session for simulating edits without committing to disk. Returns a session ID. Baseline diagnostics are captured lazily on first edit per file. Use this to explore what-if scenarios before applying changes.
Inputs: language (required), workspace_root (required).
destroy_sessionA
Destroy a simulation session and release all resources. Call this after commit or discard to clean up. Sessions in terminal states (committed, discarded, destroyed) cannot be reused.
Inputs: session_id (required).
detect_lsp_serversA
Scan a workspace directory for source languages and check PATH for the corresponding LSP server binaries. Returns detected workspace languages (ranked by prevalence), installed servers with their paths, and a suggested_config array ready to paste into the agent-lsp MCP server args. Use this to set up agent-lsp for a new project or verify your configuration.
Inputs: workspace_dir (required).
did_change_watched_filesA
Notify the language server that files have changed on disk outside the editor (workspace/didChangeWatchedFiles). Use this after writing files directly to disk so the server refreshes its caches. Change types: 1=created, 2=changed, 3=deleted. File URIs must use the file:/// scheme.
Inputs: changes (required).
discard_sessionA
Discard a simulation session and revert all in-memory changes by restoring baseline content. Use when simulation results show the changes would introduce errors.
Inputs: session_id (required).
evaluate_sessionA
Evaluate a simulation session by comparing current diagnostics against baselines. Returns errors introduced, errors resolved, net delta, and confidence (high for file scope, eventual for workspace). Use after simulate_edit to assess impact before committing.
Inputs: session_id (required), scope, timeout_ms.
execute_commandA
Execute a workspace command via LSP. Commands are server-defined identifiers returned by code actions (in the command field of a CodeAction). Use this after get_code_actions to trigger a server-side operation such as applying a refactoring, generating code, or running a server-specific action. Returns the server-defined result or null.
Inputs: command (required), arguments.
format_documentA
Get formatting edits for an entire document via LSP. Returns TextEdit[] describing the changes needed to format the file according to the language server's style rules. The edits are returned for inspection — they are NOT applied automatically. Use this to see what formatting changes a formatter would make.
Inputs: file_path (required), tab_size, language_id, insert_spaces.
format_rangeA
Get formatting edits for a specific range within a document via LSP (textDocument/rangeFormatting). Returns TextEdit[] for the selected lines/characters only. Use this when you want to format a function, block, or selection rather than the entire file. The edits are NOT applied automatically.
Inputs: end_line (required), file_path (required), end_column (required), start_line (required), +4 more.
get_change_impactA
Enumerate all exported symbols in the specified files, resolve their references across the workspace, and partition callers into test vs non-test. Returns affected_symbols (name, file, line), test_callers (with enclosing test function names), and non_test_callers. Use before editing a file to understand blast radius. Set include_transitive=true to surface second-order callers (callers of callers).
Inputs: changed_files (required), include_transitive.
get_code_actionsA
Get code actions for a specific range in a file. Use this tool to obtain available refactorings, quick fixes, and other code modifications that can be applied to a selected code range. Examples include adding imports, fixing errors, or implementing interfaces.
Inputs: end_line (required), file_path (required), end_column (required), start_line (required), +2 more.
get_completionsB
Get completion suggestions at a specific location in a file. Use this tool to retrieve code completion options based on the current context, including variable names, function calls, object properties, and more. Helpful for code assistance and auto-completion at a particular location. Use this when determining which functions you have available in a given package, for example when changing libraries.
Inputs: line (required), column (required), file_path (required), language_id.
get_cross_repo_referencesA
Find all references to a library symbol across one or more consumer repositories. Adds each consumer_root as a workspace folder, waits for indexing, then calls get_references and partitions results by repo. Returns library_references (within the primary repo), consumer_references (map of root → locations), and warnings (roots that could not be indexed). Use before changing a shared library API to find all downstream callers.
Inputs: line (required), column (required), symbol_file (required), consumer_roots (required), +1 more.
get_diagnosticsA
Get diagnostic messages (errors, warnings) for files. Use this tool to identify problems in code files such as syntax errors, type mismatches, or other issues detected by the language server. When used without a file_path, returns diagnostics for all open files.
Inputs: file_path.
get_document_highlightsA
Find all occurrences of the symbol at a position within the same file via LSP (textDocument/documentHighlight). Returns ranges and kinds: 1=Text, 2=Read, 3=Write. File-scoped and instant — does not trigger a workspace-wide reference search. Use this to find all local usages of a variable, parameter, or field without the overhead of get_references.
Inputs: line (required), column (required), file_path (required), language_id.
get_document_symbolsA
Get all symbols defined in a document via LSP (functions, classes, variables, methods, etc.). Returns a hierarchical DocumentSymbol tree or flat SymbolInformation list depending on server support. Use this to get a structural overview of a file. Pass format: "outline" for compact markdown output (name [Kind] :line) optimized for LLM consumption — ~5x fewer tokens than JSON for the same structural information.
Inputs: file_path (required), format, language_id.
get_info_on_locationC
Get information on a specific location in a file via LSP hover. Use this tool to retrieve detailed type information, documentation, and other contextual details about symbols in your code. Particularly useful for understanding variable types, function signatures, and module documentation at a specific location in the code. Use this whenever you need to get a better idea on what a particular function is doing in that context.
Inputs: line (required), column (required), file_path (required), language_id, +1 more.
get_inlay_hintsA
Get inlay hints for a range within a document via LSP (textDocument/inlayHint). Inlay hints are inline annotations that IDEs display in source code — typically inferred type names (e.g. : string) and parameter name labels (e.g. count:). Useful in languages with type inference (TypeScript, Rust, Go) to see what the compiler knows without reading every type annotation. Returns an array of InlayHint objects, each with a position, label, and optional kind (1=Type, 2=Parameter). Returns an empty array if the language server does not support inlay hints.
Inputs: end_line (required), file_path (required), end_column (required), start_line (required), +2 more.
get_referencesA
Find all references to a symbol at a specific location in a file via LSP. Returns every location in the codebase where the symbol is used. Use this to determine if a symbol is dead (zero references), to understand call sites before refactoring, or to trace data flow. Results include file path and line/column for each reference.
Inputs: line (required), column (required), file_path (required), language_id, +2 more.
get_semantic_tokensA
Get semantic tokens for a range in a file. Returns each token's type (function, variable, keyword, parameter, type, etc.) and modifiers (readonly, static, deprecated, etc.) with 1-based line/character positions. Use this to understand the syntactic role of code elements — distinct from hover which gives documentation. Only available when the language server supports textDocument/semanticTokens.
Inputs: end_line (required), file_path (required), end_column (required), start_line (required), +2 more.
get_server_capabilitiesA
Return the language server's capability map and classify every agent-lsp tool as supported or unsupported based on what the server advertised during initialization. Use this to determine which tools will return results before calling them — saves round trips on servers that don't support certain LSP features (e.g. not all servers support type_hierarchy or inlay_hints). Requires start_lsp to have been called first.
get_signature_helpA
Get function signature help at a specific location in a file via LSP. Returns available overloads and highlights the active parameter. Use this when the cursor is inside a function call's argument list to understand what parameters the function expects.
Inputs: line (required), column (required), file_path (required), language_id.
get_symbol_documentationA
Fetch authoritative documentation for a named symbol from local toolchain sources (go doc, pydoc, cargo doc) without requiring an LSP hover response. Works on transitive dependencies not indexed by the language server. Returns the full doc text, extracted signature, and source tag. Falls back gracefully when the toolchain command fails or the language is unsupported.
Inputs: symbol (required), language_id (required), format, file_path.
get_symbol_sourceA
Return the source code of the innermost symbol (function, method, class, struct, etc.) whose range contains the given cursor position. Calls textDocument/documentSymbol, walks the symbol tree to find the smallest enclosing symbol, then slices the file at that symbol's range. Returns symbol_name, symbol_kind, start_line (1-based), end_line (1-based), and source text. Use line+character or position_pattern (@@-syntax) to specify the cursor. character defaults to 1.
Inputs: file_path (required), line, character, language_id, +1 more.
get_tests_for_fileA
Given a source file path, return the test files that exercise it. Static lookup — no test execution. Go: test.go in same directory. Python: test.py / *_test.py in same dir and tests/ sibling. TypeScript/JS: *.test.ts, *.spec.ts etc. Rust: returns source file itself (tests inline). Does not require start_lsp.
Inputs: file_path (required).
get_workspace_symbolsA
Search for symbols across the entire workspace via LSP. Returns all matching symbols with name, kind, and location. detail_level controls enrichment: omit or use "basic" for names/locations only; use "hover" to also return hover info (type signature + docs) for a paginated window of results. limit (default 3) and offset (default 0) control which symbols get enriched — use offset to step through results without re-running the search.
Inputs: limit, query, offset, detail_level.
go_to_declarationA
Jump to the declaration of a symbol at a specific location in a file via LSP. Completes the 'go to X' family alongside go_to_definition, go_to_type_definition, and go_to_implementation. Most useful for languages with separate declaration and definition (e.g., C/C++ header files). Returns the file path and position where the symbol is declared.
Inputs: line (required), column (required), file_path (required), language_id.
go_to_definitionC
Jump to the definition of a symbol at a specific location in a file via LSP. Returns the file path and position where the symbol is defined. Useful for navigating to type declarations, function implementations, or variable assignments across the codebase.
Inputs: line (required), column (required), file_path (required), language_id, +1 more.
go_to_implementationA
Find all implementations of an interface or abstract method at a specific location in a file via LSP. Returns the file paths and positions of all concrete implementations. Use this to navigate from an interface declaration or abstract method to the concrete classes that implement it.
Inputs: line (required), column (required), file_path (required), language_id.
go_to_symbolA
Navigate to a symbol definition by dot-notation name (e.g. "LSPClient.GetReferences", "http.Handler") without needing file_path or line/column. Uses workspace symbol search to locate the definition. Useful when you know the symbol name but not its location.
Inputs: symbol_path (required), language, workspace_root.
go_to_type_definitionA
Jump to the definition of the type of a symbol at a specific location in a file via LSP. Unlike go_to_definition (which goes to where the symbol itself is defined), this navigates to the type declaration. Useful for interface types, type aliases, and class definitions when working with instances or variables.
Inputs: line (required), column (required), file_path (required), language_id.
list_workspace_foldersA
List all currently active workspace folders. Use this to see which roots the language server is indexing.
open_documentA
Open a file in the LSP server for analysis. Use this tool before performing operations like getting diagnostics, hover information, or completions for a file. The file remains open for continued analysis until explicitly closed. The language_id parameter tells the server which language service to use (e.g., 'typescript', 'javascript', 'haskell'). The LSP server starts automatically on MCP launch.
Inputs: file_path (required), text, language_id.
prepare_renameA
Validate that a rename is possible at the given position before committing to rename_symbol. Returns the range that would be renamed and a placeholder name suggestion, or a message indicating rename is not supported at this position. Use this before rename_symbol to avoid attempting invalid renames. Returns null if the server does not support prepareRename.
Inputs: line (required), column (required), file_path (required), language_id.
remove_workspace_folderA
Remove a directory from the LSP workspace. The language server will stop indexing that folder.
Inputs: path (required).
rename_symbolA
Get a WorkspaceEdit for renaming a symbol across the entire workspace via LSP. Returns the edit object — NOT applied automatically. Use dry_run=true to preview what would change (returns workspace_edit + note). Use position_pattern with @@ marker for reliable position targeting instead of line/column. Inspect the returned WorkspaceEdit then call apply_edit to commit. Optional exclude_globs (array of glob patterns, e.g. ["vendor/", "/*_gen.go"]) skips matching files from the rename — useful for generated code, vendored files, and test fixtures.
Inputs: new_name (required), file_path (required), line, column, +4 more.
restart_lsp_serverA
Restart the LSP server process. Use this if the LSP server becomes unresponsive or after making significant changes to the project structure. Optionally provide a new root_dir to restart with a different workspace root.
Inputs: root_dir.
run_buildA
Compile the project at workspace_dir using the detected workspace language. Language-specific dispatch (no arbitrary shell execution): go build ./..., cargo build, tsc --noEmit, mypy . (Python typecheck proxy). Optional path param narrows scope. Returns: { success: bool, errors: [{file, line, column, message}], raw: string }. Does not require start_lsp.
Inputs: workspace_dir (required), path, language.
run_testsA
Run the test suite for the detected workspace language. Language-specific dispatch: go test -json ./..., cargo test --message-format=json, pytest --tb=json, npm test. Optional path param narrows scope. Test failure locations are LSP-normalized — paste directly into go_to_definition. Returns: { passed: bool, failures: [{file, line, test_name, message, location}], raw: string }. Does not require start_lsp.
Inputs: workspace_dir (required), path, language.
set_log_levelA
Set the server logging level. Use this tool to control the verbosity of logs generated by the LSP MCP server. Available levels from least to most verbose: emergency, alert, critical, error, warning, notice, info, debug. Increasing verbosity can help troubleshoot issues but may generate large amounts of output.
Inputs: level (required).
simulate_chainA
Apply a sequence of edits and evaluate after each step. Returns per-step diagnostics and identifies the safe-to-apply-through step (last step with net delta == 0). Use this to find the safest partial application of a multi-step change. All line/column positions in each edit are 1-indexed.
Inputs: edits (required), session_id (required), timeout_ms.
simulate_editA
Apply a range edit to a file within a simulation session. Changes are held in-memory only. The session captures baseline diagnostics on first edit to each file, then tracks versions for subsequent edits. Returns the new version number after the edit. All line/column positions are 1-indexed (matching editor line numbers).
Inputs: end_line (required), new_text (required), file_path (required), end_column (required), +3 more.
simulate_edit_atomicA
One-shot atomic operation: create session, apply edit, evaluate, and destroy. Returns evaluation result. Use for quick what-if checks without managing session lifecycle manually. Requires start_lsp to be called first. All line/column positions are 1-indexed. net_delta: 0 means the edit is safe to apply.
Inputs: end_line (required), new_text (required), file_path (required), end_column (required), +7 more.
start_lspA
Initialize or reinitialize the LSP server with a specific project root directory. Call this before using get_references, get_info_on_location, or get_diagnostics when working in a project different from the one the server was started with. root_dir should be the workspace root (directory containing go.mod, package.json, Cargo.toml, etc.). Optional language_id (e.g. "go", "typescript", "rust") selects a specific configured server in multi-server mode — use this when working in a mixed-language repo to ensure the correct server handles the workspace. If unsure which server is active, call get_server_capabilities first.
Inputs: root_dir (required), language_id.
type_hierarchyA
Show type hierarchy for a type at a position. Returns supertypes (parent classes/interfaces), subtypes (subclasses/implementations), or both depending on the direction parameter. Direction defaults to "both". Use this to understand class and interface inheritance relationships.
Inputs: line (required), column (required), file_path (required), direction, +1 more.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 50 tools
Each tool targets a distinct LSP operation or workflow step. Navigation tools (go_to_definition, go_to_declaration, go_to_implementation, go_to_type_definition, go_to_symbol) are clearly differentiated by which aspect of the symbol they resolve. Simulation tools form a clear pipeline (create, edit, evaluate, commit/discard/destroy) with no overlap. All tools have unique purposes.
Tool names consistently follow a verb_noun pattern (e.g., open_document, get_references, rename_symbol). Some use 'get_' vs 'simulate_' but the pattern is uniform. Even compound names like simulate_edit_atomic follow the same convention. No mixed cases or unrelated verbs.
50 tools is high but justified by the comprehensive coverage of LSP features and additional utilities (simulation, build, test, cross-repo references). A few tools could potentially be merged (e.g., simulate_edit and simulate_edit_atomic) but overall the count reflects the server's ambition and the complexity of code analysis.
The tool set covers the full lifecycle of code interaction: document management, navigation, diagnostics, editing (with simulation), formatting, refactoring, testing, and building. It also includes workspace management, cross-repo references, and server introspection. No obvious gaps for an LSP-based code agent.
Maintenance
Related MCP Connectors
Shared memory MCP server for Claude Code, Codex, Gemini CLI and Cursor. Cited, editable.
Hosted MCP server and Agent Skills for specs, engineering threads, and project memory.
MCP server for building and testing AI agents with multi-model experimentation and insights.
Real-time chat for AI agents. Claude Code, Cursor, Cline and Codex join channels over MCP.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server that combines Read+Edit file operations into single tool calls. 80-95% fewer tool calls formulti-file refactoring across Claude, Cursor, Windsurf, and more.315 npm3MIT
- AlicenseNot gradedqualityBmaintenanceLocal-first code intelligence and safety layer for AI coding agents. MCP server exposes dependency graph, impact analysis, and AST-compressed repo context, backed by typed local memory, patch-scope safety gates, and git-independent transaction rollback.1MIT
- FlicenseNot gradedqualityBmaintenanceA local-first MCP server that gives AI coding agents durable project memory, dependency graphs, and impact analysis to answer team knowledge and cross-file change questions before editing.9 npm1-
- AlicenseCqualityBmaintenanceLocal-first MCP runtime for coding agents with bounded workspace access, content-preconditioned writes, AST search, LSP navigation and diagnostics, and Git status/diff. Designed to give coding agents useful repository access without treating unrestricted shell access as the default integration boundary.133MIT