MCP Hub
Back to servers

agent-lsp

Stateful LSP runtime for AI agents — 50+ tools across 30+ languages via MCP.

Registry
Updated
Apr 11, 2026

Quick Install

npx -y @blackwell-systems/agent-lsp

agent-lsp

Blackwell Systems LSP 3.17 Languages CI Coverage License Agent Skills

agent-lsp makes code operations reliable for AI agents.

It is a stateful runtime over real language servers, not a bridge. It keeps the language server's semantic index warm and adds a skill layer that turns multi-step code operations into single, correct workflows.

Most MCP-LSP tools fail in practice:

  • Stateless bridges — no session, no context, no cross-file awareness
  • Raw tools — agents skip steps or use them incorrectly

The tools exist. The workflow doesn't reliably happen.

agent-lsp fixes both. The persistent session indexes your workspace once and keeps it warm. The skill layer encodes correct tool sequences so workflows actually happen.

Example: call /lsp-rename and it will validate the rename, preview all affected files, show diagnostic impact, and apply atomically. One command. No missed steps.

50 tools. 49 CI-verified end-to-end. 30 languages. Built to LSP 3.17 spec.

Work across all your projects in one AI session. Point your AI assistant at your ~/code/ directory. One agent-lsp process automatically routes .go files to gopls, .ts files to typescript-language-server, .py to pyright; no reconfiguration when you switch projects.

Persistent session, warm index. Unlike per-request bridges, agent-lsp maintains a live language server session. start_lsp indexes the workspace once; every subsequent call hits the warm index. get_references returns all 12 call sites without loading files into context. get_diagnostics returns only the errors. get_info_on_location returns the type signature at one position without loading the module. The language server's index stays fresh automatically: agent-lsp watches the workspace using kernel-level filesystem events (inotify/kqueue/FSEvents) and forwards changes to keep the session synchronized. High-churn directories (.git/, node_modules/, etc.) are excluded; rapid edits are debounced at 150ms. No did_change_watched_files calls required.

Fuzzy position fallback. When an AI assistant gets a line/column slightly wrong, go_to_definition, get_references, and rename_symbol fall back to workspace symbol search by hover name and retry, returning results instead of silently returning empty.

Semantic token classification. get_semantic_tokens classifies every token in a range as function, parameter, variable, type, keyword, etc.; the same data an IDE uses to colorize code. No other MCP-LSP server exposes this.

Skills

The skill layer is the behavioral reliability layer. Raw tools get ignored; skills get used. Each skill encodes the correct tool sequence for a workflow; the agent reads the skill, follows the steps, and uses the tools in the right order without per-prompt orchestration instructions. This is the difference between tools that are available and workflows that actually happen.

Fourteen skills ship with agent-lsp:

SkillPurpose
/lsp-safe-editSpeculative preview before disk write (simulate_edit_atomic); refactor/rename preview via simulate_chain; before/after diagnostic diff; surfaces code actions on introduced errors; multi-file aware
/lsp-edit-exportSafe editing of exported symbols; finds all callers first
/lsp-edit-symbolEdit a named symbol without knowing its file or position
/lsp-renameprepare_rename safety gate, preview all sites, confirm, then apply atomically
/lsp-verifyFull three-layer check: diagnostics + build + tests; apply code actions on errors
/lsp-simulateSpeculative editing: test changes without touching the file
/lsp-impactBlast-radius analysis before renaming or deleting a symbol; accepts a file path to surface all exported-symbol impact at once via get_change_impact
/lsp-dead-codeDetect zero-reference exports and unreachable symbols
/lsp-implementFind all concrete implementations of an interface or abstract type
/lsp-docsThree-tier documentation lookup: hover, offline toolchain (go doc, pydoc), source
/lsp-cross-repoMulti-root cross-repo caller analysis: find all usages of a library symbol across consumer repos in a single get_cross_repo_references call; partitioned by repo
/lsp-local-symbolsFile-scoped analysis: list all symbols, find all usages within the file, get type info; faster than workspace search for local queries
/lsp-test-correlationFind and run only the tests that cover an edited file; faster than the full suite for targeted post-edit verification
/lsp-format-codeFormat a file or selection using the language server's formatter (gofmt, prettier, rustfmt); full-file or range, applies edits to disk

Skills work with any MCP client that supports tool use, not just Claude Code.

cd skills && ./install.sh

See docs/tools.md for full parameter details.

Docker

Pre-built images on GitHub Container Registry for all major languages:

# 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,--stdio

# Multi-language (runtime install)
docker run --rm -i -v /your/project:/workspace \
  -e LSP_SERVERS=gopls,typescript-language-server \
  ghcr.io/blackwell-systems/agent-lsp:latest \
  go:gopls typescript:typescript-language-server,--stdio

See DOCKER.md for full tier documentation, per-language tags, docker-compose setup, and volume caching.

Installation

Linux / macOS — no Go required:

curl -fsSL https://raw.githubusercontent.com/blackwell-systems/agent-lsp/main/install.sh | sh

Homebrew:

brew install blackwell-systems/tap/agent-lsp

Go install:

go install github.com/blackwell-systems/agent-lsp@latest

To use agent-lsp as a library in your Go program (without running the MCP server), import the pkg/ packages directly — see Library Usage below.

If agent-lsp isn't found after install, add Go's bin directory to your PATH:

export PATH="$PATH:$(go env GOPATH)/bin"   # add to ~/.zshrc or ~/.bashrc to persist

Quick setup with agent-lsp init

After installing, run the setup wizard to auto-detect installed language servers and write the correct MCP config for your AI tool:

agent-lsp init

The wizard:

  1. Detects language servers installed on your PATH
  2. Asks which servers to include
  3. Asks which AI tool to configure (Claude Code, Claude Desktop, Cursor, Cline/VS Code, Windsurf, Gemini CLI, or custom path)
  4. Writes the MCP server config to the correct location and shows you what was written

For CI or scripted use (no prompts):

agent-lsp init --non-interactive

Detects all available servers and writes .mcp.json in the current directory targeting Claude Code. Edit the file afterward if needed.

Setup

Step 1: Install language servers for your stack

agent-lsp runs on top of real language servers. Install the servers for your stack and agent-lsp handles the rest.

LanguageServerInstall
TypeScript / JavaScripttypescript-language-servernpm i -g typescript-language-server typescript
Pythonpyright-langservernpm i -g pyright
Gogoplsgo install golang.org/x/tools/gopls@latest
Rustrust-analyzerrustup component add rust-analyzer
C / C++clangdapt install clangd / brew install llvm
Rubysolargraphgem install solargraph
PHPintelephensenpm i -g intelephense
Javajdtlseclipse.jdt.ls snapshots
YAMLyaml-language-servernpm i -g yaml-language-server
JSONvscode-json-language-servernpm i -g vscode-langservers-extracted
Dockerfiledocker-langservernpm i -g dockerfile-language-server-nodejs
C#csharp-lsdotnet tool install -g csharp-ls
Kotlinkotlin-language-serverGitHub releases
Lualua-language-serverGitHub releases
Swiftsourcekit-lspShips with Xcode / Swift toolchain
ZigzlsGitHub releases (match Zig version)
CSSvscode-css-language-servernpm i -g vscode-langservers-extracted
HTMLvscode-html-language-servernpm i -g vscode-langservers-extracted
Terraformterraform-lsreleases.hashicorp.com
Scalametalscs install metals (Coursier)
Gleamgleam (built-in)GitHub releases
Elixirelixir-lsGitHub releases
Prismaprisma-language-servernpm i -g @prisma/language-server
SQLsqlsgo install github.com/sqls-server/sqls@latest
Clojureclojure-lspGitHub releases
NixnilGitHub releases
Dartdart language-serverShips with Dart SDK (brew install dart)
MongoDBmongodb-language-servernpm i -g @mongodb-js/mongodb-language-server

Step 2: Add to your AI config

Add to .mcp.json (project) or your AI tool's global MCP config. List only the languages you use:

{
  "mcpServers": {
    "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). Single language? Use "args": ["go", "gopls"]. Complex setup with many servers or per-server options? Use "args": ["--config", "/path/to/agent-lsp.json"].

Step 3: Start working

Once your AI session opens, call start_lsp with your project root to initialize:

start_lsp(root_dir="/your/project")

Then use any of the 50 tools. The session persists; no need to restart when switching files.

Why agent-lsp

agent-lspother MCP-LSP implementations
Languages (CI-verified)30 (end-to-end integration tests)config-listed, untested
Tools503–18
Multi-server routing (one process, many languages)varies
LSP spec compliance3.17, built to specad hoc
Connection modelpersistent (warm index)per-request or cold-start
Cross-file referencesrarely
Real-time diagnostic subscriptions
Semantic token classification✗ (only one competitor)
Call hierarchy (single tool, direction param)✗ or 3 separate tools
Type hierarchy (single tool, direction param)✗ or untested
Fuzzy position fallback✗ or partial
Auto-watch (index stays fresh) (always-on, debounced)✗ (manual notify required)
Multi-root / cross-repo (add_workspace_folder)✗ or single-workspace only
Path traversal prevention
Distributionsingle Go binaryNode.js or Bun runtime required

Use Cases

  • Multi-project AI sessions: point your AI assistant at ~/code/, work across any project without reconfiguring
  • Polyglot 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 (e.g., extracting a Go library used by 3 services)
  • CI pipelines: validate against real language server behavior

Multi-Language Support

Every language below is integration-tested on every CI run with a real language server binary and a real fixture codebase. The test harness verifies Tier 1 (start_lsp, open_document, get_diagnostics, get_info_on_location) and Tier 2 (27 tools including navigation, analysis, refactoring, workspace, and session lifecycle) for each language. No other MCP-LSP implementation has an equivalent test matrix; competitors list supported languages in config examples but do not run integration tests against them.

Tier 2 results per language from the latest CI run:

LanguageTier 1symbolsdefinitionreferencescompletionsworkspaceformatdeclarationtype_hierarchyhovercall_hiersem_toksig_help
TypeScriptpasspasspasspasspasspasspasspasspasspasspasspass
Pythonpasspasspasspasspasspasspasspasspass
Gopasspasspasspasspasspasspasspasspasspasspass
Rustpasspasspasspasspasspasspasspasspasspass
Javapasspasspasspass
Cpasspasspasspasspasspasspasspasspasspasspass
PHPpasspasspasspasspasspasspasspasspasspass
C++passpasspasspasspasspasspasspasspasspasspass
JavaScriptpasspasspasspasspasspasspasspasspasspasspass
Rubypasspasspasspasspasspasspasspasspasspasspass
YAMLpasspasspasspasspass
JSONpasspasspasspasspass
Dockerfilepasspasspasspass
C#passpasspasspasspasspasspasspasspasspasspass
Kotlinpasspasspasspasspasspasspasspasspasspasspass
Luapasspasspasspasspasspasspasspasspass
Swiftpasspasspasspasspasspasspasspasspass
Zigpasspasspasspasspasspasspasspasspass
CSSpasspasspasspasspasspass
HTMLpasspasspasspasspass
Terraformpasspasspasspasspasspasspass
Scalapasspasspasspasspasspasspasspasspass
Gleampasspasspasspasspasspasspasspass
Elixirpasspasspasspasspasspasspasspass
Prismapasspasspasspasspasspass
SQLpasspasspasspasspasspasspass
Clojurepasspasspasspasspasspasspasspass
Nixpasspasspasspasspass
Dartpasspasspasspasspasspasspasspass
MongoDBpasspasspasspass

Java Tier 2 is skipped when jdtls does not finish indexing within the CI timeout (a known jdtls cold-start characteristic, not a tool bug). Scala (metals) runs in a separate CI job with continue-on-error: true and a 30-minute timeout; metals requires sbt compilation on first start and results are informational. Swift (sourcekit-lsp) runs on a macos-latest runner since sourcekit-lsp ships with Xcode. Prisma runs with continue-on-error: true; the language server works standalone after prisma generate initializes the client. Completions and workspace symbol search are not supported by this server. SQL (sqls) requires a live PostgreSQL service container; the CI job provisions postgres:16 automatically. type_hierarchy is tested on Java (jdtls) and TypeScript (typescript-language-server); TypeScript skips when the server does not return a hierarchy item at the configured position. Clojure (clojure-lsp), Nix (nil), Dart (dart language-server), and MongoDB (mongodb-language-server) CI-verified as of the ci-coverage-expansion IMPL. Nix runs with continue-on-error: true (Nix installer is slow in CI; nil installs via nix profile). MongoDB language server is extracted from the mongodb-js/vscode VS Code extension VSIX at dist/languageServer.js; the CI job has continue-on-error: true since the extracted server may behave differently outside VS Code extension host context. MongoDB requires a live mongo:7 service container; the CI job provisions it automatically.

Tools

All tools require start_lsp to be called first.

CI coverage: The following tools are end-to-end integration-tested against real language servers on every CI run across all 30 languages (34 tools in the multi-language harness; 50/50 total across all test suites):

  • Tier 1 (4 tools, all 30 languages): start_lsp, open_document, get_diagnostics, get_info_on_location
  • Tier 2 (34 tools): get_document_symbols, go_to_definition, get_references, get_completions, get_workspace_symbols, format_document, go_to_declaration, type_hierarchy, get_info_on_location, call_hierarchy, get_semantic_tokens, get_signature_help, get_document_highlights, get_inlay_hints, get_code_actions, prepare_rename, rename_symbol, get_server_capabilities, add_workspace_folder, go_to_type_definition, go_to_implementation, format_range, apply_edit, detect_lsp_servers, close_document, did_change_watched_files, run_build, run_tests, get_tests_for_file, get_symbol_source, go_to_symbol, restart_lsp_server, set_log_level, execute_command

Speculative session tools (create_simulation_session, simulate_edit, simulate_edit_atomic, simulate_chain, evaluate_session, commit_session, discard_session, destroy_session) are covered by TestSpeculativeSessions in test/speculative_test.go. All 50 tools are covered across the three test suites. get_change_impact and get_cross_repo_references are covered by TestGetChangeImpact and TestGetCrossRepoReferences in test/multi_lang_test.go. get_symbol_documentation is covered by TestGetSymbolDocumentation in test/documentation_test.go.

Session

ToolDescription
start_lspStart the language server with a project root
restart_lsp_serverRestart without restarting the MCP server
open_documentOpen a file for tracking (required before position queries)
close_documentStop tracking a file

Analysis

ToolDescription
get_diagnosticsErrors and warnings; omit file_path for whole project
get_info_on_locationHover info (type signatures, docs) at a position
get_completionsCompletion suggestions at a position
get_signature_helpFunction signature and active parameter at a call site
get_code_actionsQuick fixes and refactors for a range
get_document_symbolsAll symbols in a file (functions, classes, variables)
get_workspace_symbolsSearch symbols by name across the workspace; detail_level=hover enriches results with type signatures and docs without loading files into context
get_semantic_tokensClassify tokens in a range as function/parameter/variable/type/keyword/etc; the same data IDEs use for syntax highlighting
get_inlay_hintsInline type annotations and parameter name labels for a range; inferred type hints IDEs overlay on source code (Type and Parameter kinds)
get_change_impactEnumerate all exported symbols in one or more files, resolve their references across the workspace, and partition callers into test vs non-test; use before editing a file to understand blast radius
get_cross_repo_referencesFind all references to a library symbol across one or more consumer repos; adds consumer roots as workspace folders and partitions results by repo; use before changing a shared library API

Navigation

ToolDescription
get_referencesAll references to a symbol across the workspace
get_document_highlightsAll occurrences of a symbol in the current file; file-scoped, instant, returns read/write/text kinds; faster than get_references for local usage analysis
go_to_definitionJump to where a symbol is defined (with fuzzy position fallback)
go_to_type_definitionJump to the type definition of a symbol
go_to_implementationJump to all implementations of an interface or abstract method
go_to_declarationJump to the declaration of a symbol (distinct from definition; e.g. C/C++ headers)
call_hierarchyCallers and/or callees of a function; direction: "incoming", "outgoing", or "both" (default)
type_hierarchySupertypes and/or subtypes of a type; direction: "supertypes", "subtypes", or "both" (default)

Refactoring

ToolDescription
rename_symbolGet a WorkspaceEdit for renaming a symbol across the workspace (with fuzzy position fallback)
prepare_renameValidate a rename is possible before committing
format_documentGet TextEdit[] formatting edits for a file
format_rangeGet TextEdit[] formatting edits for a selection
apply_editApply a WorkspaceEdit to disk (use with rename_symbol or format_document)
execute_commandExecute a server-side command (e.g. from a code action)

Utilities

ToolDescription
did_change_watched_filesManually notify the server of file changes; not needed for normal edits (auto-watch handles those); use when an external process changes files outside the session
get_server_capabilitiesReturn the server capability map and classify every tool as supported or unsupported; use before calling capability-gated tools
set_log_levelChange log verbosity at runtime
detect_lsp_serversScan a workspace for source languages and check PATH for installed LSP servers; returns detected languages, server paths, and a suggested_config array ready to paste into your MCP config

Workspace

ToolDescription
add_workspace_folderAdd a directory to the LSP workspace; enables cross-repo references, definitions, and diagnostics across library + consumer repos in one session
remove_workspace_folderRemove a directory from the LSP workspace
list_workspace_foldersReturn the current workspace folder list

Speculative Execution

Safe what-if analysis: simulate edits in-memory, evaluate diagnostic changes (errors introduced/resolved), then commit or discard atomically. No disk writes until you call commit_session.

ToolDescription
create_simulation_sessionCreate a session with baseline diagnostics for a file
simulate_editApply an in-memory edit to the session (no disk write)
simulate_edit_atomicApply an edit, evaluate diagnostics, and discard in one call; returns net error delta; accepts optional session_id to reuse an existing session
simulate_chainApply a sequence of edits and evaluate after each step; use as a refactor preview or safe rename preview — chain definition + call-site edits, check cumulative_delta == 0, commit or discard
evaluate_sessionCompare current in-memory diagnostics against baseline; returns errors introduced and resolved
commit_sessionWrite the session's edits to disk
discard_sessionRevert in-memory edits without touching disk
destroy_sessionRelease all session resources

See docs/speculative-execution.md for session lifecycle examples and refactor/rename preview workflows.

Recommended agent workflow:

start_lsp(root_dir="/your/project")
open_document(file_path=..., language_id=...)
get_diagnostics()                          # whole project, no file_path
get_info_on_location(...) / get_references(...)
close_document(...)

Keeping the index fresh:

agent-lsp watches the workspace root for file changes and automatically notifies the language server; no did_change_watched_files calls required after edits. The watcher skips high-churn directories (.git/, node_modules/, target/, etc.) and debounces rapid edits at 150ms.

did_change_watched_files is still available for cases where files are changed by an external process that the watcher may not see immediately, or for explicit control over change notifications.

Rename workflow (prepare_renamerename_symbolapply_edit):

prepare_rename(file_path=..., line=..., column=...)        # confirm rename is valid at this position
rename_symbol(file_path=..., line=..., column=..., new_name="newName")  # returns WorkspaceEdit
apply_edit(edit=<WorkspaceEdit>)                           # writes all changed files to disk
# auto-watch notifies the server automatically — no did_change_watched_files needed

Language IDs: typescript, typescriptreact, javascript, javascriptreact, python, go, rust, java, kotlin, scala, swift, lua, zig, terraform, c, cpp, csharp, php, ruby, css, html, yaml, json, dockerfile, gleam, elixir, prisma

Resources

Diagnostic resources support real-time subscriptions; the server sends notifications/resources/updated when diagnostics change for a subscribed file.

SchemeDescription
lsp-diagnostics://All open files
lsp-diagnostics:///path/to/fileSpecific file (subscribable)
lsp-hover:///path/to/file?line=N&column=N&language_id=XHover at position
lsp-completions:///path/to/file?line=N&column=N&language_id=XCompletions at position

Subscribing to real-time diagnostics:

{ "method": "resources/subscribe", "params": { "uri": "lsp-diagnostics:///path/to/file.go" } }

The server sends notifications/resources/updated each time the language server publishes new diagnostics for that file. Read the resource after each notification to get the current diagnostic list:

{ "method": "resources/read", "params": { "uri": "lsp-diagnostics:///path/to/file.go" } }

LSP 3.17 Conformance

agent-lsp is implemented directly against the LSP 3.17 specification and validated through integration testing against real language servers. Coverage includes:

  • Full lifecycle (initializeinitializedshutdown) with graceful SIGINT/SIGTERM handling
  • Progress protocol: workspace-ready detection waits for all $/progress tokens to complete before sending references
  • Server-initiated requests (workspace/configuration, window/workDoneProgress/create, dynamic registration): all correctly responded to, unblocking servers that gate workspace loading on these responses
  • Correct JSON-RPC framing, error code handling, and response shape normalization across hover, completion, code actions, and diagnostics

See docs/lsp-conformance.md for the full method coverage matrix and spec section references.

See docs/tools.md for the full tool reference with example inputs and outputs.

See docs/architecture.md for the Go package structure, WithDocument pattern, URI handling, and resource subscription internals.

Extensions

The 50 core tools cover everything LSP exposes. Extensions add a second layer — language-specific tools that go beyond what the protocol provides.

Where the core tools stop at what the language server can answer, an extension can run arbitrary logic for that language. Examples of what extensions enable that core tools cannot:

LanguageExample extension tools
Gogo.mod dependency graph, go test -cover annotations, go generate runner
TypeScripttsconfig.json diagnostics, type coverage report
Pythonvirtual env detection, requirements.txt cross-reference
Rustcargo check integration, crate dependency tree

Extensions are registered at compile time — an extension for go only activates when go:gopls is in the server config. All extension tools are namespaced by language ID (e.g. go.mod_graph) so they never conflict with core tools.

No extensions ship with agent-lsp today. The infrastructure exists and is ready to use. To build one, create extensions/<language-id>/ implementing any subset of the extension interface and call extensions.RegisterFactory in an init() function. See docs/architecture.md for the interface definition.

Development

git clone https://github.com/blackwell-systems/agent-lsp.git
cd agent-lsp && go build ./...
go test ./...                   # all unit test suites
go test ./... -tags integration # integration tests (requires language servers)

Library Usage

The pkg/lsp, pkg/session, and pkg/types packages expose a stable public API for using agent-lsp's LSP client and speculative execution engine directly from Go programs, without running the MCP server.

Import the LSP client

import (
    "context"
    "github.com/blackwell-systems/agent-lsp/pkg/lsp"
)

client := lsp.NewLSPClient("gopls", []string{})
if err := client.Initialize(ctx, "/path/to/workspace"); err != nil {
    log.Fatal(err)
}
defer client.Shutdown(ctx)

locs, err := client.GetDefinition(ctx, fileURI, lsp.Position{Line: 10, Character: 4})

Import types

import "github.com/blackwell-systems/agent-lsp/pkg/types"

var pos types.Position = types.Position{Line: 0, Character: 0}

Speculative editing (simulate-before-apply)

import (
    "github.com/blackwell-systems/agent-lsp/pkg/lsp"
    "github.com/blackwell-systems/agent-lsp/pkg/session"
)

mgr := session.NewSessionManager(client) // client is a *lsp.LSPClient
id, _ := mgr.CreateSession(ctx, "/workspace", "go")
mgr.ApplyEdit(ctx, id, fileURI, editRange, newText)
result, _ := mgr.Evaluate(ctx, id, "file", 3000)
if result.NetDelta == 0 {
    mgr.Commit(ctx, id, "", true)
} else {
    mgr.Discard(ctx, id)
}

All pkg/ types are aliases of the internal implementation types and are fully interchangeable with them.

License

MIT

Reviews

No reviews yet

Sign in to write a review