docs blog library
github

Language Server Protocol plugin

The LSP plugin gives coding agents compiler diagnostics, symbol definitions, references, and approved renames or formatting. Install the plugin and a language server separately; Jazz does not bundle a language server. Servers must support LSP 3.17 over stdio.

Install the published plugin through the normal plugin lifecycle. No repository clone or local build is needed; the published artifact includes its diff renderer:

jazz plugin add com.jazz.plugins.lsp
jazz plugin inspect com.jazz.plugins.lsp
jazz plugin trust com.jazz.plugins.lsp
jazz plugin enable com.jazz.plugins.lsp --agent default

Replace default with your agent name or ID, or omit --agent to enable it for every agent. Install your language-server executable separately and configure its command in ~/.jazz/lsp.json:

{
  "servers": [
    {
      "id": "typescript",
      "command": "typescript-language-server",
      "args": ["--stdio"],
      "extensions": {
        ".ts": "typescript",
        ".tsx": "typescriptreact"
      },
      "rootMarkers": ["tsconfig.json", "package.json"]
    },
    {
      "id": "javascript",
      "command": "typescript-language-server",
      "args": ["--stdio"],
      "extensions": {
        ".js": "javascript",
        ".jsx": "javascriptreact"
      },
      "rootMarkers": ["jsconfig.json", "package.json"]
    }
  ]
}

For HTML and CSS, use vscode-langservers-extracted (npm install --global vscode-langservers-extracted) with command: "vscode-html-language-server" for .html/.htm and command: "vscode-css-language-server" for .css, both with args: ["--stdio"]. The HTML server also reports diagnostics for CSS inside inline <style> blocks. Both use the LSP 3.17 pull model; the plugin queries textDocument/diagnostic directly. Avoid the older vscode-html-languageserver-bin / vscode-css-languageserver-bin packages: their pinned vscode-jsonrpc crashes at startup (messageReader.onClose is not a function). See the plugin README for a complete lsp.json example. Install typescript-language-server and a compatible typescript package containing tsserver.js before using this example. To configure another language, add an entry with its executable, argument vector, an extensions-to-language-ID map, and project-root markers. Each extension is bound to exactly one language ID because the language decides how the server parses the file: .tsx and .jsx must open as the React dialects (typescriptreact, javascriptreact), never as plain typescript or javascript. A legacy top-level languageId is rejected at load time with a message naming the replacement. The first entry whose extensions name a file’s extension wins. The plugin walks upward from the current directory to identify configured project roots and starts their servers before the first model request. It also starts a matching server when Jazz later touches a supported file outside those roots. If no marker exists, it uses the agent’s current directory. JAZZ_LSP_CONFIG can point to another JSON file. A missing or invalid config is reported to the agent.

The plugin reads source files from disk and sends didOpen and didChange as Jazz works with them. It checks tracked files again before each model request, including after external edits. It keeps diagnostics bounded and relevant to those files; it does not pour whole-workspace diagnostics into every turn. A failed server start is retried after a short delay rather than on every model request; an unavailable server does not stop the coding run. The model cannot choose the executable or its arguments.

The tools use 1-based line and UTF-16 character coordinates. code_actions lists available actions for a range. apply_code_action selects one by its exact title, with a zero-based index when titles repeat, and resolves lazy edits when the server supports it. Actions without an edit are rejected. rename_symbol, apply_code_action, and format_document turn the returned WorkspaceEdit into a multi-file diff for Jazz’s normal approval flow. Jazz persists the prepared edit if approval is parked. At execution, the plugin locks every target and checks its complete content digest before replacing files; a changed file produces a stale-edit error and writes nothing. It also rejects a server response if the source file changed while the server was preparing the edit. Resource operations such as create, delete, and move are rejected explicitly. LSP servers’ unsolicited workspace/applyEdit requests are refused.

Semantic query tools are declared read-only. Rename, code action application, and formatting are declared high-risk and use Jazz’s approval gate. The configured server command is part of the operator’s plugin setup and trust decision, not a model-authored shell command. The operator must trust that executable, just as with any plugin that runs local code. The server receives source contents from files Jazz reads or changes during the agent’s run, as well as files the agent explicitly queries through an LSP tool. Its stdout is untrusted protocol data; code action commands are never executed. The plugin performs no network egress itself, but a configured server may have its own network behavior. Review the server before enabling the plugin on a remote or unattended surface.

The current edit path validates all files before writing and uses sibling temporary files plus atomic per-file renames. A multi-file edit is not one filesystem transaction: an I/O failure during replacement can leave a partial set of files changed. External programs that ignore Jazz’s edit locks can also race after validation.

machine-readable: /docs/configure/lsp-plugin.md · /llms.txt · /llms-full.txt