Quick Start
1
Let the agent do it (nothing to configure)
2
Detect language and root yourself (advanced)
3
Probe availability before you use LSP
4
Talk to the client directly with a workspace-aware root
How It Works
Each language maps to a default server, its file extensions, and the root markers that pin a project root — the nearest marker wins.Adding or Overriding a Language Server
Register a new language or swap a built-in server by passingservers= — no package source edits needed.
The
Agent(tools=[lsp_*]) path spawns its own LSPClient and does not forward a servers= mapping today. Register custom languages with the direct-client pattern shown here — LSPClient(language=..., servers=...).Four Ways to Configure
- Add a language
- Override a built-in
- With init options
- Compose the registry
How the Merge Works
User entries override built-ins per language key; unset fields fall back to the built-in row.DEFAULT_SERVERS is never mutated by a merge — resolve_servers({...}) always returns a fresh dict.
Which Configuration Style?
User Interaction Flow
A registered language behaves exactly like a built-in one.User: “Where isAuthService.logindefined in this Maven repo?” Agent uses a Java LSP client registered viaservers=, which finds the nearestpom.xmlfor the root and queriesjdtls. Tool returns:src/main/java/com/acme/AuthService.java:42:5Agent replies: “AuthService.loginis defined insrc/main/java/com/acme/AuthService.javaat line 42.”
Which Helper Should I Use?
Public API Surface
These are pure helpers plus one new keyword and one new attribute onLSPClient.
Common Patterns
Guarded startup logging — log what the LSP layer would do for each language:client.last_error so the model picks a fallback intelligently:
Best Practices
Prefer probe() over try/except
Prefer probe() over try/except
LSPClient.start() no longer raises on a missing binary — it sets last_error and returns False. Reserve try/except for real IO failures.Pass workspace_file= to LSPClient in monorepos
Pass workspace_file= to LSPClient in monorepos
Without it, the client falls back to
os.getcwd(), which is almost never the file’s real project root. workspace_file lets detect_root_uri initialise the server against the nearest root marker.Do not parse the phrases
Do not parse the phrases
Error text like
install with \…`is for humans. For machine-readable data, callprobe(language)and read the(available, command, install_hint)` tuple.Treat the 'not found on PATH' note as a call to action
Treat the 'not found on PATH' note as a call to action
The
edit_tools note appears once per language per run. When you see it, install the server rather than ignore the diagnostic signal for the rest of the session.Pin the server your team uses
Pin the server your team uses
Define a
servers= mapping in your project bootstrap and pass it to every LSPClient, so contributors get the same server without installing an alternative. New teammates inherit the choice instead of debugging a mismatch.Set install_hint for internal tooling
Set install_hint for internal tooling
When you register a private or in-house server, include
install_hint. It flows into client.last_error so a teammate missing the binary sees exactly how to install it.Provide initialization_options in the registry
Provide initialization_options in the registry
Put server-specific tuning in the registry entry’s
initialization_options. It is auto-picked when the caller didn’t set its own — cleaner than passing the same options to every client.Related
LSP Navigation Tools
Go-to-definition, find-references, hover, and symbol search
LSP Tools (reference)
Per-tool parameters and output format
Post-Edit Formatter
Produces the new “diagnostics unavailable” note
Built-in Tool Registry
How
Agent(tools=[…]) resolves tool names
