Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Latias94/lspi

Repository files navigation

lspi

Giving AI the sight of LSP.

lspi is an MCP server that bridges Language Server Protocol (LSP) features (definition/references/rename/diagnostics, etc.) to AI coding CLIs (starting with Codex) over stdio.

If your agent keeps doing grep-like searches or fragile string edits, lspi gives it IDE-grade, symbol-aware tooling.

Why lspi

AI assistants are good at reasoning, but they usually lack reliable access to symbol relationships in a real codebase. With lspi, your agent can:

  • Jump to definitions, implementations, type definitions, and references
  • Inspect hover/type information at a cursor position
  • Use *_at tools with bounded position fuzzing (helps when the agent is off-by-one on line/column counting)
  • Perform preview-first, workspace-wide renames safely
  • Query call hierarchy (incoming/outgoing calls) when supported by the language server

How it works

  • You run lspi mcp as a stdio MCP server.
  • lspi starts and manages one or more LSP servers (your choice) and routes requests by file path / extension.
  • Tool results are returned as structured MCP responses, with output caps to keep results deterministic.

Quickstart (Codex, from zero)

  1. Install language server(s)

lspi does not bundle language servers. Install what you need:

  • Rust (recommended): rustup component add rust-analyzer
  • Go: go install golang.org/x/tools/gopls@latest
  • TypeScript: npm i -g typescript typescript-language-server
  • Python: npm i -g pyright
  • C# (OmniSharp): install omnisharp and ensure dotnet is available

If you prefer project-local installs (recommended for TS/Python), set servers[].command accordingly.

  1. Install lspi (one-time):
cargo binstall lspi
# or (build from source via crates.io):
cargo install lspi --locked
  1. Create a per-project lspi config (recommended):
cd /path/to/project
lspi setup --wizard --non-interactive --write
  1. Verify language server availability:
lspi doctor --workspace-root .
# or machine-readable:
lspi doctor --workspace-root . --json
  1. Configure Codex MCP (~/.codex/config.toml):
[mcp_servers.lspi]
command = "lspi"
args = ["mcp", "--workspace-root", "."]
  1. First tool calls (sanity check)
  • Prefer introspection first: get_current_config, list_servers, get_server_status
  • Then navigation: hover_at, find_definition_at, find_references_at, get_document_symbols

Notes:

  • Codex uses a global config; run codex from the project root you want to work on.
  • If your lspi config is not inside the workspace, pass it explicitly:
    • args = ["mcp", "--workspace-root", ".", "--config", "/path/to/lspi.toml"]
  • Optional: add --warmup to start language servers eagerly (reduces first-tool-call latency).
  • Optional: add --read-only (or set mcp.read_only=true) to expose a navigation-only toolset.
  • Optional: add --context codex for safe defaults (read-only + smaller output limits). Use --read-write to opt back into rename/control tools.
  • Optional: add --mode navigation (sugar for safe read-only defaults) or --mode refactor (sugar for read-write defaults).

For more details, see docs/CODEX.md.

Troubleshooting (common issues)

  • “No server found for extension …”:
    • Add/verify servers[].extensions, and ensure file_path matches the intended language server.
  • Tool call fails with an error:
    • Inspect structuredContent.next_steps for actionable debugging steps (introspection tools + config hints).
  • Language server not starting / command not found:
    • Install the language server, or set servers[].command / the corresponding LSPI_*_COMMAND env var.
    • Run lspi doctor --workspace-root . for actionable hints.
  • Off-by-one line/column:
    • Prefer *_at tools (they use bounded position fuzzing).
  • Large outputs / truncated results:
    • Set max_results / max_total_chars, and consider include_snippet=false for large reference sets.
  • TypeScript/Vue returns empty/odd results:
    • Configure servers[].workspace_configuration and/or tune initialize_options / client_capabilities.
    • Consider servers[].adapter = "tsserver" when using TypeScript/Vue tooling.
    • If calls time out on large workspaces, increase request_timeout_ms or set request_timeout_overrides_ms for slow methods (definition/references/rename/documentSymbol).

Language server support

lspi does not bundle language servers. You install the servers you need and configure them in lspi config.

There are two layers of support:

  • First-class server kinds (built-in defaults / extra compatibility):
    • Rust: kind = "rust_analyzer"
    • C#: kind = "omnisharp"
    • Python: kind = "pyright" / kind = "basedpyright"
  • Generic mode: for any LSP server that speaks JSON-RPC over stdio, use kind = "generic" and set command.

In practice, most “standard” language servers work well in generic mode (Go gopls, C++ clangd, Lua lua-language-server, etc.). TypeScript/Vue tooling tends to be more quirky; lspi includes a small adapter layer for server-specific behavior (see servers[].adapter, currently tsserver).

FAQ

Do I need to install language servers?

Yes. lspi does not bundle any language servers. Install the servers you need and point lspi at them via config. Use lspi doctor --workspace-root . to validate your setup.

Are Go / TypeScript supported?

Yes, via kind = "generic" (provided the LSP server speaks JSON-RPC over stdio). In practice:

  • Go (gopls) usually works well in generic mode.
  • TypeScript/Vue often needs extra tuning (runtime workspace/configuration, and sometimes servers[].adapter = "tsserver").

How does multi-root work?

Configure additional roots with servers[].workspace_folders. If you configure multiple LSP servers, tools like search_workspace_symbols should include file_path so lspi can route to the right server.

Will lspi modify my files automatically?

No. Rename tools default to preview mode (dry_run=true), and you must explicitly request applying edits (dry_run=false).

What should I do when a tool call fails?

  • Inspect structuredContent.error and follow structuredContent.next_steps.
  • Use introspection tools: get_current_config, list_servers, get_server_status.
  • If you can run local commands: lspi doctor --workspace-root . --json.

Why are results truncated?

To keep agent/tool behavior deterministic, responses are size-bounded. Tune max_results / max_total_chars, and consider include_snippet=false for large reference sets.

Configuration (what you will actually tweak)

Full schema and discovery order:

  • docs/CONFIG.md

Minimal .lspi/config.toml example

[[servers]]
id = "rust-analyzer"
kind = "rust_analyzer"
extensions = ["rs"]

[[servers]]
id = "ts"
kind = "generic"
extensions = ["ts", "tsx", "js", "jsx", "vue"]
language_id = "typescript"
command = "typescript-language-server"
args = ["--stdio"]
adapter = "tsserver"

# Optional (sometimes needed for TypeScript tooling):
# [servers.workspace_configuration]
# formattingOptions = { tabSize = 2, insertSpaces = true }

Common knobs (per server):

  • servers[].root_dir and servers[].workspace_folders (multi-root workspaces)
  • servers[].initialize_options and servers[].client_capabilities (improve compatibility for “generic” servers)
  • servers[].workspace_configuration (responses to workspace/configuration, e.g. formatting options)
  • servers[].request_timeout_overrides_ms (workspace-wide operations can be slow)
  • servers[].adapter (server quirks; currently tsserver)

Common environment variables:

  • LSPI_CONFIG_PATH: explicit config file path
  • LSPI_RUST_ANALYZER_COMMAND: override rust-analyzer command
  • LSPI_OMNISHARP_COMMAND: override omnisharp command
  • LSPI_PYRIGHT_COMMAND: override pyright-langserver command
  • LSPI_BASEDPYRIGHT_COMMAND: override basedpyright-langserver command

Safety model (rename / edits)

  • rename_symbol and rename_symbol_strict default to preview (dry_run=true).
  • To apply edits, pass dry_run=false.
  • Optional strict apply: provide expected_before_sha256 (per-file SHA-256) and enable backups.
  • Writes are restricted to within the configured workspace root(s).

MCP tools

Session / introspection:

  • get_current_config
  • list_servers
  • get_server_status

Read-only navigation:

  • hover_at
  • get_document_symbols
  • search_workspace_symbols
  • find_definition / find_definition_at
  • find_references / find_references_at
  • find_implementation_at
  • find_type_definition_at
  • find_incoming_calls / find_incoming_calls_at
  • find_outgoing_calls / find_outgoing_calls_at
  • get_diagnostics

Write / control:

  • rename_symbol / rename_symbol_strict
  • restart_server
  • stop_server

If you want a least-privilege toolset (e.g. read-only navigation), use mcp.tools allow/exclude in your config. If you want a “hard” read-only mode (no rename/control tools even if allowed), use mcp.read_only=true or lspi mcp --read-only.

Docs

  • Codex integration: docs/CODEX.md
  • Configuration: docs/CONFIG.md
  • MCP behavior (structuredContent / next_steps / debugging): docs/MCP.md
  • Agent prompt snippet (copy-paste): docs/AGENTS_SNIPPETS.md
  • Smoke tests: docs/SMOKE_TEST.md
  • Release notes: CHANGELOG.md

Acknowledgements / inspiration

lspi is inspired by and references ideas from:

Development

Run MCP server without installing:

cargo run -p lspi -- mcp --workspace-root .

Run tests:

cargo nextest run

About

Giving AI the sight of LSP.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors