CodeGraph LSP Server

CPG-powered Language Server Protocol (LSP) implementation that provides real-time code intelligence from the CodeGraph Code Property Graph database.

Table of Contents

Overview

The CodeGraph LSP Server connects any LSP-compatible editor to the CodeGraph CPG (Code Property Graph) managed by GoCPG. At runtime the LSP server is a gRPC client: it does not open DuckDB directly and only issues read-only queries through GoCPG. It provides:

  • Security diagnostics – findings from 190+ pattern rules (CWE-mapped)
  • Dead code detection – methods with no callers (fan_in=0)
  • Complexity warnings – cyclomatic complexity above configurable threshold
  • Pattern violations – structural code quality issues
  • Method metrics on hover – complexity, fan-in/fan-out, callers, security findings
  • CodeLens indicators – caller/callee counts and taint flow info above each method
  • Autofix actions – quick-fix for 22 autofix rules (SQL injection, buffer overflow, shell injection)

Supports 11 languages: C, C++, C#, Go, Java, JavaScript, Kotlin, PHP, Python, Ruby, TypeScript.

Installation

The LSP server is included in the CodeGraph package:

pip install -e .

This registers the codegraph-lsp CLI entry point. You can also run directly:

python -m codegraph_lsp --db <path-to-duckdb>

--db identifies the target CPG database managed by GoCPG. The LSP process itself does not own or open the DuckDB file directly.

Dependencies

  • pygls>=2.0.0 – Python LSP framework
  • lsprotocol – LSP type definitions
  • Running GoCPG gRPC server with access to the target CPG database

Quick Start

  1. Build the CPG for your project (if not already done):
gocpg parse --input=. --output=project.duckdb --lang=python
  1. Start GoCPG so the CPG is available over gRPC:
gocpg serve --data-dir .
  1. Start the LSP server:
python -m codegraph_lsp --db project.duckdb
  1. Configure your editor to use the server (see editor-specific sections below).

Diagnostics

The server publishes diagnostics on file open and file save.

Security Findings (severity: Error)

Findings from cpg_pattern_results where category = 'security'. Each diagnostic includes: - CWE-mapped rule ID as the diagnostic code - Exact line and column from CPG analysis - Message describing the vulnerability

Example in editor:

Error [CWE-89]: SQL injection — user input concatenated into query (line 42)

Dead Methods (severity: Hint, tag: Unnecessary)

Methods where fan_in = 0 AND is_entry_point = false AND is_external = false AND is_test = false. Shown with strikethrough styling in editors that support the Unnecessary tag.

Example:

Hint [dead-method]: Dead method: 'unused_helper' has no callers (fan_in=0) (line 25)

Complexity Warnings

Methods where cyclomatic_complexity exceeds the configured threshold:

Complexity Severity
threshold–19 Information
20–49 Warning
≥50 Error

Example:

Warning [high-complexity]: Cyclomatic complexity of 'process_data' is 25 (threshold: 10) (line 100)

Pattern Violations

Non-security findings from cpg_pattern_results. Severity is mapped from the pattern rule’s severity field.

Hover

Hovering over a method shows a markdown table with:

Metric Description
Cyclomatic complexity Method complexity score
Fan-in (callers) Number of distinct caller methods
Fan-out (callees) Number of distinct called methods
Callers Callers from edges_call
LOC Lines of code
Parameters Number of parameters
Security findings Count of security findings in the file
Flags entry point, external, test, dead code

CodeLens

Each method gets a CodeLens indicator showing:

3 callers | 5 callees | taint: read_inputexecute_query
  • Callers/callees from fan_in/fan_out in nodes_method
  • Taint flow shown when the method participates in a data flow path (via edges_reaching_def)

CodeAction (Autofix)

For pattern violations with available autofix rules, the server provides Quick Fix code actions. The 22 autofix rules include:

Rule Language Description
autofix-py-format-sql Python Replace %-format SQL with parameterized query
autofix-py-concat-sql Python Replace string concat SQL with parameterized query
autofix-py-fstring-sql Python Replace f-string SQL with parameterized query
autofix-py-ctypes-string-at Python Replace ctypes.string_at with safer alternative
autofix-py-subprocess-shell Python Replace shell=True with direct command
autofix-go-concat-sql Go Replace string concat SQL with parameterized query
autofix-go-sprintf-sql Go Replace fmt.Sprintf SQL with parameterized query
autofix-go-exec-shell Go Replace shell execution with direct command
autofix-go-cgo-strcpy Go Replace CGO strcpy with safer buffer copy
autofix-c-strcpy-to-strncpy C Replace strcpy with strncpy
autofix-c-sprintf-to-snprintf C Replace sprintf with snprintf
autofix-c-null-assert C Add NULL check after function call
Plus hardcoded-string rules for 10 languages

Autofix applies when match_data in cpg_pattern_results contains a fix field with the replacement code.

OpenCode Integration

Add the LSP server to opencode.json (example configuration):

{
  "lsp": {
    "codegraph": {
      "command": ["python", "-m", "codegraph_lsp", "--db", "project.duckdb"],
      "languages": ["python", "go", "javascript", "typescript", "java", "c", "cpp"]
    }
  }
}

OpenCode will automatically: - Start the LSP server when opening files in supported languages - Show diagnostics inline and in the problems panel - Include diagnostics in LLM context via experimental.chat.system.transform - Provide quick-fix suggestions for autofix-capable patterns

Connection Pool

The LSP server uses a read-only GoCPG-backed query pool:

  • Max logical connections: 3 (configurable)
  • gRPC-only: the LSP process does not open DuckDB directly
  • Read-only workload: all diagnostics, hover, CodeLens, and code actions go through GoCPG query RPCs
  • Thread-safe: uses threading.Lock for pool access
  • Snapshot change detection: the pool checks the database file modification time (mtime) and reconnects idle handles after the CPG snapshot changes

DuckDB ownership stays inside GoCPG. When GoCPG updates or rebuilds the CPG, the LSP client sees the new snapshot through subsequent RPC calls.

Configuration

CLI Options

Option Default Description
--db (required) Target CPG database path used by GoCPG
--complexity-threshold 10 Cyclomatic complexity warning threshold
--transport stdio Transport: stdio or tcp
--host 127.0.0.1 TCP host (only for --transport tcp)
--port 2087 TCP port (only for --transport tcp)
--log-level info Log level: debug, info, warning, error

Transport Modes

stdio (default): Editor starts the server as a subprocess and communicates via stdin/stdout. Best for local usage.

python -m codegraph_lsp --db project.duckdb

tcp: Server listens on a TCP port. Useful for remote LSP connections or shared instances.

python -m codegraph_lsp --db project.duckdb --transport tcp --port 2087

Troubleshooting

No Diagnostics Appearing

  • Verify GoCPG gRPC is reachable and serving the target database.
  • Verify the target DuckDB file exists and contains CPG data by checking GoCPG lifecycle/query endpoints or gocpg stats --db project.duckdb.
  • Verify file paths in the database match the workspace paths (forward slashes, relative paths).

“Connection Pool Exhausted” Error

This means 3 concurrent read requests are active. This can happen if: - GoCPG queries are slow because the CPG is very large - Multiple files were opened simultaneously

Solution: close some files or increase the pool size (requires code change).

Stale Diagnostics After CPG Update

If diagnostics seem stale: - Close and reopen the file - Verify GoCPG finished the update/reparse and reports read_available=true - Re-check lifecycle status with the CodeGraph /status or dogfood status workflow

Server Fails to Start

  • Verify pygls is installed: python -c "import pygls; print(pygls.__version__)"
  • Verify GoCPG gRPC server is running and reachable from the LSP process
  • Check logs on stderr for error messages

Windows Path Issues

The server normalizes paths from file URIs (file:///C:/...C:/...) and uses forward slashes internally. If your CPG database has backslash paths, diagnostics may not match. Rebuild the CPG to ensure consistent paths.