Skip to content

jgoz/cli-lsp-client

 
 

Repository files navigation

@jgoz/cli-lsp-client

CLI tool for getting LSP diagnostics. Uses a background daemon to keep LSP servers running.

Features

  • Get diagnostics from LSP servers
  • Get hover information for symbols (functions, variables, types)
  • Background daemon for fast repeated requests
  • Built in Claude Code hook to provide feedback on file edit tool calls
  • Comprehensive daemon management (list, stop-all commands)
  • Multi-project support with isolated daemon instances per directory
  • Custom language server support via config files

Supported Languages

Language LSP Server Auto-installed Notes
TypeScript/JavaScript typescript-language-server ✓ (via bunx) .ts, .tsx, .js, .jsx, .mjs, .cjs, .mts, .cts
Python pyright-langserver ✓ (via bunx) .py, .pyi
JSON vscode-json-language-server ✓ (via vscode-langservers-extracted) .json, .jsonc - includes schema validation
CSS vscode-css-language-server ✓ (via vscode-langservers-extracted) .css, .scss, .sass, .less
YAML yaml-language-server ✓ (via bunx) .yaml, .yml - includes schema validation
Bash/Shell bash-language-server ✓ (via bunx) .sh, .bash, .zsh - requires shellcheck (brew install shellcheck)
GraphQL graphql-language-service-cli ✓ (via bunx) .graphql, .gql
R R languageserver .r, .R, .rmd, .Rmd - see R Installation below
C# OmniSharp-Roslyn .cs - see C# Installation below
Swift SourceKit-LSP .swift - see Swift Configuration below
Go gopls Requires manual install: go install golang.org/x/tools/gopls@latest
Java jdtls (Eclipse JDT) .java - see Java Installation below
Lua lua-language-server .lua - requires manual install via package manager (brew, scoop) or from releases

How It Works

  • Daemon starts automatically when needed
  • LSP servers spawn based on file type
  • Finds project roots using config files (tsconfig.json, etc.)
  • Servers stay running for subsequent requests

Claude Code Integration

Plugin Installation (Recommended)

The easiest way to integrate with Claude Code is via the official plugin:

# Add the plugin marketplace
/plugin marketplace add jgoz/cli-lsp-client

# Install the plugin
/plugin install lsp-plugin

This automatically configures:

  • SessionStart hook: Starts the LSP daemon when Claude Code starts
  • PostToolUse hook: Runs diagnostics after file edits (Edit, Write, MultiEdit)

No manual configuration needed - the plugin handles everything!

Additional plugins available:

  • eslint-plugin: Automatically runs ESLint checks on file edits and blocks on linting errors
  • prettier-plugin: Automatically formats files with Prettier after edits

MCP Server

Add as an MCP server to enable Claude to access symbol definitions and hover information:

claude mcp add lsp --scope user -- bunx @jgoz/cli-lsp-client mcp-server

Manual Hook Configuration

For advanced users who want to customize their hook setup, you can manually configure Claude Code to use the built-in hook commands.

Get instant diagnostic feedback for TypeScript, Python, JSON, CSS, YAML, Bash, GraphQL, R, C#, Swift, Go, Java, and Lua files as you edit in Claude Code.

Setup

Add the following to your Claude Code settings.json:

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "hooks": {
    "SessionStart": [
      {
        "matcher": "startup|resume",
        "hooks": [
          {
            "type": "command",
            "command": "bunx @jgoz/cli-lsp-client start"
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bunx @jgoz/cli-lsp-client claude-code-hook"
          }
        ]
      }
    ]
  }
}

How It Works

  • SessionStart: Automatically starts LSP servers when Claude Code starts for faster initial diagnostics
  • PostToolUse: Runs diagnostics after each file edit (Edit, MultiEdit, Write tools)
  • Built-in file filtering for all supported languages (16 file types)
  • Shows errors, warnings, and hints inline
  • Graceful error handling - never breaks your editing experience
  • Uses the same fast daemon as the regular diagnostics command

Example Output

When you save a file with errors, you'll see immediate feedback:

Edit operation feedback:
- [bunx cli-lsp-client claude-code-hook]:
ERROR at line 3, column 9:
  Type 'number' is not assignable to type 'string'.
  Source: typescript
  Code: 2322

Custom Language Servers (Config File)

You can extend the built-in language servers by creating a custom configuration file. This allows you to add support for any LSP server not included by default.

Configuration File

Create a config file at ~/.config/cli-lsp-client/settings.json (default location) or use --config-file to specify a custom path:

{
  "servers": [
    {
      "id": "svelte",
      "extensions": [".svelte"],
      "rootPatterns": ["svelte.config.js", "package.json"],
      "command": ["bunx", "svelte-language-server", "--stdio"],
      "env": {
        "NODE_ENV": "development"
      },
      "initialization": {
        "settings": {
          "svelte": {
            "compilerWarnings": true
          }
        }
      }
    }
  ],
  "languageExtensions": {
    ".svelte": "svelte"
  }
}

Using Custom Config

Default config file location:

# Uses ~/.config/cli-lsp-client/settings.json automatically
npx cli-lsp-client diagnostics Component.svelte

Custom config file location:

# Specify custom config file path
npx @jgoz/cli-lsp-client --config-file ./my-config.json diagnostics Component.svelte
npx @jgoz/cli-lsp-client --config-file ./my-config.json hover Component.svelte myFunction
npx @jgoz/cli-lsp-client --config-file ./my-config.json status

Important: When using --config-file, you must include it on every command. The CLI automatically restarts the daemon when switching between different config files to ensure the correct language servers are loaded.

Config File Schema

  • servers: Array of custom language server definitions

    • id: Unique identifier for the server
    • extensions: File extensions this server handles (e.g. [".svelte"])
    • rootPatterns: Files/patterns used to detect project root (e.g. ["package.json"])
    • command: Command array to start the LSP server (e.g. ["bunx", "svelte-language-server", "--stdio"])
    • env: Optional environment variables for the server process
    • initialization: Optional LSP initialization parameters
  • languageExtensions: Maps file extensions to LSP language identifiers

Usage

Get Diagnostics

# Check a TypeScript file
npx @jgoz/cli-lsp-client diagnostics src/example.ts

# Check any supported file type
npx @jgoz/cli-lsp-client diagnostics app.py
npx @jgoz/cli-lsp-client diagnostics main.go
npx @jgoz/cli-lsp-client diagnostics analysis.R
npx @jgoz/cli-lsp-client diagnostics Program.cs

# Check Swift files (requires config file)
npx @jgoz/cli-lsp-client diagnostics Sources/App/main.swift

Exit codes: 0 for no issues, 2 for issues found.

$ npx @jgoz/cli-lsp-client diagnostics error.ts
ERROR at line 5, column 20:
  Argument of type 'string' is not assignable to parameter of type 'number'.
  Source: typescript
  Code: 2345

Get Hover Information

# Get hover info for a function
npx @jgoz/cli-lsp-client hover src/main.ts myFunction

# Get hover info for a variable or type
npx @jgoz/cli-lsp-client hover app.py MyClass
npx @jgoz/cli-lsp-client hover analysis.R mean
npx @jgoz/cli-lsp-client hover Program.cs Console

# Get hover info for Swift symbols (requires config file)
npx @jgoz/cli-lsp-client hover Sources/App/main.swift greetUser
$ npx @jgoz/cli-lsp-client hover src/client.ts runCommand
Location: src/client.ts:370:17
```typescript
export function runCommand(command: string, commandArgs: string[]): Promise<void>

### Daemon Management

```bash
# Check daemon status with uptime and running language servers
npx @jgoz/cli-lsp-client status

# List all running daemons across directories
npx @jgoz/cli-lsp-client list

# Stop current directory's daemon
npx @jgoz/cli-lsp-client stop

# Stop all daemons across all directories (useful after package updates)
npx @jgoz/cli-lsp-client stop-all

# Show version
npx @jgoz/cli-lsp-client --version

# Show help
npx @jgoz/cli-lsp-client help

The status command shows the current daemon's uptime and running language servers:

$ npx @jgoz/cli-lsp-client status
LSP Daemon Status
================
PID: 33502
Uptime: 1m 38s

Language Servers:
- typescript (.) - running 1m 33s
- pyright (.) - running 1m 10s

Total: 2 language servers running

The list command shows all running daemon instances with their working directories, PIDs, and status:

$ npx @jgoz/cli-lsp-client list

Running Daemons:
================
Hash   | PID   | Status    | Working Directory
----------------------------------------------------------
h0gx9u | 12345 | ● Running | /Users/user/project-a
94yi9w | 12346 | ● Running | /Users/user/project-b

2/2 daemon(s) running

Use stop-all when updating the CLI package to ensure all old daemon processes are terminated and fresh ones spawn with the updated code.

Java Installation Guide

Eclipse JDT Language Server requires Java 17+ and manual setup:

Installation Steps

  1. Download: Get the latest server from Eclipse JDT.LS downloads
  2. Extract: Unpack to your preferred location (e.g., /opt/jdtls/)
  3. Create wrapper script named jdtls in your PATH:
#!/bin/bash
java -Declipse.application=org.eclipse.jdt.ls.core.id1 \
     -Dosgi.bundles.defaultStartLevel=4 \
     -Declipse.product=org.eclipse.jdt.ls.core.product \
     -Xms1g -Xmx2G \
     -jar /opt/jdtls/plugins/org.eclipse.equinox.launcher_*.jar \
     -configuration /opt/jdtls/config_linux \
     -data "${1:-$HOME/workspace}" \
     --add-modules=ALL-SYSTEM \
     --add-opens java.base/java.util=ALL-UNNAMED \
     --add-opens java.base/java.lang=ALL-UNNAMED "$@"
  1. Make executable: chmod +x /usr/local/bin/jdtls

Alternative Installation Methods

Homebrew (macOS/Linux):

brew install jdtls

Arch Linux:

pacman -S jdtls

Configuration Notes

  • Replace config_linux with config_mac on macOS or config_win on Windows
  • Adjust the -data workspace path as needed
  • Requires Java 17 or higher to run

For detailed setup instructions, see the official Eclipse JDT.LS documentation.

R Installation Guide

The R language server requires R runtime and the languageserver package:

Installation Steps

  1. Install R: Download and install R from CRAN or use a package manager:

    macOS (Homebrew):

    brew install r

    Ubuntu/Debian:

    sudo apt-get update
    sudo apt-get install r-base

    Windows: Download installer from CRAN Windows

  2. Install R languageserver package: Open R and run:

    install.packages("languageserver")

    Or from command line:

    R --slave -e 'install.packages("languageserver", repos="https://cran.rstudio.com/")'

Verification

Test that the language server works:

R --slave -e 'languageserver::run()'

Project Detection

The R LSP automatically detects R projects based on these files:

  • DESCRIPTION (R packages)
  • NAMESPACE (R packages)
  • .Rproj (RStudio projects)
  • renv.lock (renv dependency management)
  • Any .r, .R, .rmd, .Rmd files

For more information, see the R languageserver documentation.

C# Installation Guide

The C# language server requires .NET SDK and OmniSharp-Roslyn:

Installation Steps

  1. Install .NET SDK: Download .NET 6.0+ from Microsoft .NET or use a package manager:

    macOS (Homebrew):

    brew install dotnet

    Ubuntu/Debian:

    # Add Microsoft package repository
    wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
    sudo dpkg -i packages-microsoft-prod.deb
    sudo apt-get update
    sudo apt-get install -y dotnet-sdk-8.0

    Windows: Download installer from .NET Downloads

  2. Install OmniSharp-Roslyn: Download the latest release from OmniSharp releases:

    Automatic script (recommended):

    # Download and extract OmniSharp to ~/.omnisharp/
    mkdir -p ~/.omnisharp
    curl -L https://github.com/OmniSharp/omnisharp-roslyn/releases/latest/download/omnisharp-osx-arm64-net6.0.tar.gz | tar -xz -C ~/.omnisharp/
    
    # Create symlink to make omnisharp available in PATH
    sudo ln -sf ~/.omnisharp/OmniSharp /usr/local/bin/omnisharp

    Manual installation:

    • Download the appropriate release for your platform (Windows: omnisharp-win-x64-net6.0.zip, Linux: omnisharp-linux-x64-net6.0.tar.gz)
    • Extract to a directory (e.g., ~/.omnisharp/)
    • Add the executable to your PATH or create a symlink
  3. Set environment variables:

    Fish shell:

    set -Ux DOTNET_ROOT ~/.dotnet

    Bash/Zsh:

    echo 'export DOTNET_ROOT=~/.dotnet' >> ~/.bashrc  # or ~/.zshrc
    source ~/.bashrc  # or ~/.zshrc

    Note: DOTNET_ROOT must be set in your shell environment for the C# language server to work. The CLI will only load OmniSharp if this environment variable is defined. Restart your terminal after setting the environment variable to ensure it's available.

Verification

Test that OmniSharp works:

# Verify DOTNET_ROOT is set
echo $DOTNET_ROOT

# Test OmniSharp command
omnisharp --help

Project Detection

The C# LSP automatically detects C# projects based on these files:

  • *.sln (Solution files)
  • *.csproj (Project files)
  • project.json (Legacy project files)
  • global.json (.NET global configuration)
  • Any .cs files

For more information, see the OmniSharp documentation.

Swift Configuration

Swift language support is available through SourceKit-LSP, which is included with Xcode Command Line Tools. Support for swift and other LSPs can be added via a config file.

Prerequisites

macOS (with Xcode Command Line Tools):

# Check if SourceKit-LSP is available
xcrun --find sourcekit-lsp

Alternative toolchains: If using Swift toolchains from swift.org, SourceKit-LSP is included and can be run with:

xcrun --toolchain swift sourcekit-lsp

Configuration

Create a config file at ~/.config/cli-lsp-client/settings.json:

{
  "servers": [
    {
      "id": "sourcekit_lsp",
      "extensions": [".swift"],
      "rootPatterns": ["Package.swift", ".xcodeproj", ".xcworkspace"],
      "command": ["xcrun", "sourcekit-lsp"],
      "env": {}
    }
  ],
  "languageExtensions": {
    ".swift": "swift"
  }
}

For more information about SourceKit-LSP, see the official documentation.

Additional Commands

# Start LSP servers for current directory (faster subsequent requests)
npx @jgoz/cli-lsp-client start

# Start servers for specific directory
npx @jgoz/cli-lsp-client start /path/to/project

# View daemon log file path
npx @jgoz/cli-lsp-client logs

Examples

# Check a specific file
npx @jgoz/cli-lsp-client diagnostics src/main.ts

# Get hover info for a symbol
npx @jgoz/cli-lsp-client hover src/main.ts myFunction

# List all daemon instances
npx @jgoz/cli-lsp-client list

# Stop all daemons after package update
npx @jgoz/cli-lsp-client stop-all

Development

Installation

# Install dependencies and build
bun install
bun run build    # Build executable
bun run typecheck
bun test

Add new LSP servers in src/lsp/servers.ts.

About

CLI tool for getting LSP diagnostics via background daemon

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 92.2%
  • Shell 4.0%
  • JavaScript 3.4%
  • Batchfile 0.4%