agy-lsp
# agy-lsp — Language Server Protocol MCP Bridge for Antigravity CLI
[](#13-development-testing--qa)
[](#13-development-testing--qa)
[](https://www.python.org/downloads/)
[](#13-development-testing--qa)
[](https://modelcontextprotocol.io)
[](LICENSE)
*Read this in other languages: [English](README.md) | [Deutsch](README.de.md)*
**agy-lsp** is a production-ready, professional plugin for the **Google Antigravity CLI (`agy`)**. It connects AI coding agents to native **Language Servers (LSP)** for C#, C/C++, TypeScript/JavaScript, Python, Rust, and Go via the standardized **Model Context Protocol (MCP)**.
> **Companion Plugin:** Pair `agy-lsp` (static semantic navigation & diagnostics) with [**agy-dap**](https://github.com/k0pfnicker/agy-dap) (hypothesis-driven runtime debugging via DAP).
---
## Table of Contents
1. [Purpose & Benefits](#1-purpose--benefits)
- [Empirical Benchmarks & Evaluation Results](#empirical-benchmarks--evaluation-results)
2. [Architecture](#2-architecture)
3. [MCP Tools Overview](#3-mcp-tools-overview)
4. [Supported Languages & Language Servers](#4-supported-languages--language-servers)
5. [Prerequisites](#5-prerequisites)
6. [Installation & Quickstart](#6-installation--quickstart)
- [Windows](#windows-powershell)
- [Linux / macOS](#linux--macos)
7. [Integration into Antigravity CLI](#7-integration-into-antigravity-cli)
8. [Language Server Installation](#8-language-server-installation)
9. [Configuration (`agy-lsp.json`)](#9-configuration-agy-lspjson)
10. [Token Efficiency & Context Optimization](#10-token-efficiency--context-optimization)
11. [Security Model](#11-security-model)
12. [Troubleshooting & Diagnostics](#12-troubleshooting--diagnostics)
13. [Development, Testing & QA](#13-development-testing--qa)
14. [Adding New Languages](#14-adding-new-languages)
15. [Known Limitations](#15-known-limitations)
16. [License](#16-license)
---
## 1. Purpose & Benefits
Large Language Models (LLMs) often face two major challenges when working in real-world software codebases:
1. **Inaccurate Search & Context Waste:** Plaintext keyword search and reading entire files consumes thousands of context tokens while frequently missing semantic relationships (such as method overloads, polymorphism, interface implementations, and namespaces).
2. **Missing Feedback Loops:** After modifying code, agents often fail to notice syntax, type-checking, or import errors until much later or not at all.
**agy-lsp** bridges this gap by giving the Antigravity agent direct compiler and type intelligence via standardized MCP tools:
- **Precise Symbol Navigation:** Jump to definitions and query all workspace references without guessing.
- **Automated Quality Control:** Fetch compiler diagnostics (errors, warnings, hints) immediately after edits.
- **Safe Refactoring:** Symbol renaming generates a unified preview diff before any changes are written to disk.
- **Minimized Token Usage:** Compact snippets, structural document outlines, and strict result limits prevent context bloat.
### Empirical Benchmarks & Evaluation Results
All claims below are continuously verified by our automated benchmark and E2E test suite ([`tests/test_benchmarks_and_value.py`](tests/test_benchmarks_and_value.py) and [`tests/test_e2e_real_lsp.py`](tests/test_e2e_real_lsp.py)) against real `clangd` (C/C++) and `pylsp` (Python) language server processes:
| Evaluation Scenario | Without `agy-lsp` (Grep / File Read / Raw LSP) | With `agy-lsp` (Smart MCP Bridge) | Measured Improvement |
| :--- | :--- | :--- | :--- |
| **1. Structural File Outline (`document_symbols`)**<br>*C header with 3 structs/enums (65 fields) & 4 functions* | **18,979 bytes** (`~4,745 tokens`) raw LSP JSON<br>**8,155 bytes** (`~2,039 tokens`) with uncollapsed fields | **1,647 bytes** (`~412 tokens`)<br>Collapses leaf struct/enum fields into `fields_count` | **-91.3% tokens** vs. Raw LSP<br>**-79.8% tokens** vs. Expanded |
| **2. Inaccurate LLM Column Estimates (`go_to_definition`)**<br>*10 imprecise calls: col 1 indentation, keywords (`int`, `const`), EOL, ±1 line* | **0 / 10 resolved (0% hit rate)**<br>Raw LSP fails when column lands on whitespace or keywords | **10 / 10 resolved (100% hit rate)**<br>Auto-snaps to identifier & supports `symbol_name` ±2 lines | **0% → 100% resolution rate** without LLM retry loops |
| **3. Semantic Navigation vs. Text Grep (`find_references` & `go_to_definition`)**<br>*Searching `execute_step` across C codebase with comments & string traps* | **8 grep matches (5 false positives = 62.5% noise)**<br>Requires reading full files (**3,975 bytes / ~994 tokens**) | **3 AST-verified references (0% false positives)**<br>Definition + 3-line snippet in **449 bytes (~112 tokens)** | **100% precision** (0 false positives)<br>**-88.7% context tokens** |
| **4. Real-Time Compiler Feedback & Cascade Filtering (`get_diagnostics`)**<br>*Detecting C type/identifier errors & filtering a 120-error template cascade* | No immediate feedback without full build;<br>Raw cascade: **145,680 bytes (~36,420 tokens)** | **2 errors detected in ~198 ms** via event-driven `didOpen`;<br>Deduplicated & capped: **27,912 bytes (~6,978 tokens)** | **< 200 ms** instant feedback<br>**-80.8% diagnostic noise** |
| **5. Safe Cross-File Refactoring (`rename_symbol`)**<br>*Renaming `execute_step` → `dispatch_op` across `engine.h` & `engine.c`* | Regex search/replace corrupts string literals (`"execute_step"`) and comments directly on disk | **2 files diffed (`applied: false` preview mode)**<br>Updates prototype, definition & call sites; strings/comments untouched | **Zero disk corruption**<br>100% AST-safe unified diff |
| **6. Zero-Read Call Graph Analysis (`call_hierarchy`)**<br>*Tracing callers & callees of `execute_step`* | Requires multiple `grep` passes and reading every candidate caller file | Single tool call returns incoming (`run_program`) & outgoing (`clamp_register`) calls directly from AST | **1 tool call** instead of multi-file inspection |
#### Why These Results Matter for AI Agents
1. **Massive Context Window Preservation (-80% to -91% Tokens):** In C/C++ and C# projects, headers and classes often contain dozens of struct fields or enum constants. Raw LSP dumps flood the LLM context window with thousands of lines of JSON coordinates. `agy-lsp` collapses leaf fields into `"fields_count": 34` by default while keeping every struct, class, enum, and function signature intact.
2. **Elimination of "Off-by-A-Few-Columns" Tool Failures (0% → 100% Hit Rate):** LLMs do not count 1-indexed character columns reliably—they frequently pass `character=1` (leading indentation) or land on return-type keywords (`static`, `int`, `const`, `def`). Standard LSP bridges return `null` on these positions, forcing the agent into expensive retry loops. `agy-lsp` automatically snaps to the nearest non-keyword identifier on the line (or matches `symbol_name` within ±2 lines) and retries alternative identifiers on the line if needed.
3. **Zero False Positives in Navigation & Refactoring:** Unlike `grep`/`ripgrep`, which matched **62.5% false positives** in comments and string literals in our benchmark, `agy-lsp` queries the compiler's AST (`clangd` / `pylsp` / `pyright` / `csharp-ls` / `tsserver`). When renaming symbols, string literals and comments are never accidentally modified, and changes are returned as a safe unified diff preview first.
4. **Sub-200ms Compiler Verification Without Running Full Builds:** Using event-driven `textDocument/publishDiagnostics` synchronization (`asyncio.Event`), the agent receives exact compiler errors (e.g., `"Use of undeclared identifier"`, `"Too many arguments to function call"`) within ~200 ms of opening or editing a file.
---
## 2. Architecture
```text
┌─────────────────────────────────────────────────────────────┐
│ Antigravity CLI (agy) │
│ │
│ Agent Turn / Reasoning ◄──► Skills / AGENTS.md Rules │
└─────────────────────────────┬───────────────────────────────┘
│
│ Stdio Transport (JSON-RPC)
▼
┌─────────────────────────────────────────────────────────────┐
│ agy-lsp (MCP-Server) │
│ │
│ ├── Tool Schemas (get_diagnostics, go_to_definition, ...) │
│ ├── Document Sync (didOpen, didChange, didClose, Cache) │
│ ├── Token Reducer (Snippet extraction, Dedup, Limits) │
│ └── Workspace Confinement Security Check │
└─────────────────────────────┬───────────────────────────────┘
│
│ Async Process I/O (Content-Length Framing)
▼
┌─────────────────────────────────────────────────────────────┐
│ Language Server (LSP) │
│ │
│ [Python] [C#] [C / C++] [TS / JS] │
│ pyright / csharp-ls / clangd typescript-│
│ pylsp Roslyn Server language- │
│ server │
└─────────────────────────────────────────────────────────────┘
```
The bridge launches Language Server processes **on demand (lazy loading)** only when a tool targets a file belonging to that language. Running processes are reused throughout the session and automatically recovered with bounded retries if a crash occurs.
---
## 3. MCP Tools Overview
The plugin registers 11 high-performance MCP tools:
| Tool | Purpose | Key Parameters | Return Value |
| :--- | :--- | :--- | :--- |
| `get_diagnostics` | Retrieve compiler errors, warnings, and hints for a file or workspace | `file_path`, `line_start`, `line_end`, `severity`, `limit` | List of deduplicated diagnostics with file, line, column, code, and message. |
| `go_to_definition` | Jump from a symbol position to its definition/declaration | `file_path`, `line`, `character`, `symbol_name`, `include_snippet` | Target file, line range, and optional compact code excerpt. |
| `find_references` | Locate all usages of a symbol across the workspace | `file_path`, `line`, `character`, `symbol_name`, `include_declaration`, `limit` | List of reference locations across files. |
| `rename_symbol` | Perform workspace-wide LSP rename refactoring | `file_path`, `line`, `character`, `new_name`, `apply`, `symbol_name` | **Unified preview diff** across all affected files. Disk writes require `apply=True` and `writeChanges=True`. |
| `document_symbols` | Structural outline of classes, methods, and properties | `file_path`, `query`, `include_fields`, `max_depth` | Symbol tree with kind, line ranges, and identifiers (struct fields/enum members collapsed into `fields_count` by default). |
| `workspace_symbols` | Search symbols across the entire project | `query`, `limit` | Matches with symbol name, kind, file, and position. |
| `hover` | Inspect signatures, types, and docstrings | `file_path`, `line`, `character`, `symbol_name` | Markdown-formatted hover information. |
| `prepare_call_hierarchy` | Verify support and return call hierarchy root item | `file_path`, `line`, `character`, `symbol_name` | Prepared symbol item for call graphs. |
| `call_hierarchy` | Find callers (`incoming`) or called functions (`outgoing`) | `file_path`, `line`, `character`, `direction`, `symbol_name` | List of callers or callee functions. |
| `get_type_hierarchy` | Inspect base types (`supertypes`) or derived classes (`subtypes`) | `file_path`, `line`, `character`, `direction`, `symbol_name` | Type inheritance hierarchy. |
| `lsp_status` | Health status of all servers, workspace root, and errors | *none* | JSON overview of server states (`RUNNING`, `AVAILABLE`, `NOT_INSTALLED`, `CRASHED`), PID, and root. |
*Note:* All line and column arguments and outputs are **1-indexed** for agent ergonomics. Position-based tools also automatically snap inaccurate column estimates (`character`) or optional `symbol_name` arguments to the identifier on that line.
---
## 4. Supported Languages & Language Servers
| Language | Primary Server | File Extensions | Project Discovery Markers |
| :--- | :--- | :--- | :--- |
| **Python** | `pyright-langserver` *(Fallbacks: `basedpyright-langserver`, `pylsp`, `pyright`)* | `.py`, `.pyi` | `pyproject.toml`, `setup.py`, `requirements.txt` |
| **C#** | `csharp-ls` *(Fallback: `roslyn-language-server`)* | `.cs` | `*.sln`, `*.slnx`, `*.csproj` |
| **C / C++** | `clangd` *(Fallback: `ccls`)* | `.c`, `.cpp`, `.cc`, `.cxx`, `.h`, `.hpp`, `.hxx` | `CMakeLists.txt`, `compile_commands.json`, `*.vcxproj` |
| **TypeScript / JS**| `typescript-language-server` *(Fallback: `vtsls`)* | `.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs` | `package.json`, `tsconfig.json` |
| **Rust** | `rust-analyzer` | `.rs` | `Cargo.toml` |
| **Go** | `gopls` | `.go` | `go.mod` |
---
## 5. Prerequisites
- **Operating System:** Windows 10/11, macOS, or Linux.
- **Python:** Python 3.9 or higher (Python 3.14+ fully supported).
- **Antigravity CLI:** `agy` installed.
- The corresponding language server for the language you wish to inspect (e.g. `pylsp` or `pyright` for Python, `clangd` for C++, etc.).
---
## 6. Installation & Quickstart
### Windows (PowerShell)
```powershell
# 1. Clone and enter the repository
git clone https://github.com/k0pfnicker/agy-lsp.git
cd agy-lsp
# 2. Create virtual environment and install dependencies (note the quotes around ".[dev]" in PowerShell)
python -m venv .venv
.\.venv\Scripts\pip.exe install -e ".[dev]"
# 3. Optional: Install Python & C/C++ language servers directly into .venv (no admin rights required)
.\.venv\Scripts\pip.exe install python-lsp-server clangd
# 4. Run one-step workspace & MCP setup
.\.venv\Scripts\python.exe setup_agy.py --workspace D:\YourProject
```
### Linux / macOS
```bash
# 1. Clone and enter the repository
git clone https://github.com/k0pfnicker/agy-lsp.git
cd agy-lsp
# 2. Create virtual environment and install dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
# 3. Optional: Install Python & C/C++ language servers
pip install python-lsp-server clangd
# 4. Run one-step workspace & MCP setup
python setup_agy.py --workspace /path/to/your/project
```
---
## 7. Integration into Antigravity CLI
### Option A: Automated Setup via `setup_agy.py` (Recommended)
Running `python setup_agy.py --workspace <path>` automatically:
1. Detects the exact absolute path to `.venv/Scripts/agy-lsp` and `.venv/Scripts` (so language servers installed inside `.venv` are found automatically without modifying your global system `PATH`).
2. Registers `agy-lsp` in `~/.gemini/config/mcp_config.json`.
3. Installs the `SKILL.md` into `<workspace>/.agents/skills/agy-lsp/SKILL.md` without creating duplicate plugin MCP server entries.
### Option B: As a Discovered Plugin
The plugin also adheres to the official Antigravity plugin manifest specifications (`plugin.json` and `mcp_config.json`).
*(Note: Do not register both `~/.gemini/config/mcp_config.json` and `.agents/plugins/agy-lsp/mcp_config.json` simultaneously, or Antigravity will list two MCP server instances `agy-lsp` and `agy-lsp_agy-lsp`.)*
Validate the plugin with the official CLI command:
```bash
agy plugin validate .
```
Expected output:
```text
[ok] .
✔ skills : 1 processed
✔ mcpServers : 1 processed
```
---
## 8. Language Server Installation
If a language server is not installed, the plugin provides a clear, user-friendly error message with actionable installation commands. Executables installed inside the same `.venv` are discovered automatically:
### Python
```bash
# Option 1: python-lsp-server (pure Python, no Node.js required)
pip install python-lsp-server
# Option 2: Pyright
npm install -g pyright
```
### C# (.NET)
```bash
dotnet tool install -g csharp-ls
```
### C / C++
- **Python Wheel (Windows / Linux / macOS, no admin rights required):** `pip install clangd`
- **Windows:** `scoop install llvm` or `winget install LLVM.LLVM`
- **macOS:** `brew install llvm`
- **Linux (Debian/Ubuntu):** `sudo apt-get install clangd`
### TypeScript / JavaScript
```bash
npm install -g typescript-language-server typescript
```
---
## 9. Configuration (`agy-lsp.json`)
`agy-lsp` works out of the box with safe defaults. To customize behavior, place an `agy-lsp.json` file at your workspace root or under `~/.gemini/config/agy-lsp.json`:
```json
{
"defaultLanguage": "auto",
"workspaceRoot": null,
"maxResults": 50,
"includeCodeSnippets": false,
"snippetContextLines": 3,
"allowOutsideWorkspace": false,
"writeChanges": false,
"serverStartupTimeoutMs": 15000,
"requestTimeoutMs": 10000,
"maxRestartAttempts": 2,
"servers": {
"csharp": {
"command": "csharp-ls",
"args": []
},
"cpp": {
"command": "clangd",
"args": ["--background-index"]
},
"typescript": {
"command": "typescript-language-server",
"args": ["--stdio"]
},
"python": {
"command": "pyright-langserver",
"args": ["--stdio"],
"fallbacks": [
{ "command": "pylsp", "args": [] }
]
}
}
}
```
### Configuration Options Reference
| Key | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `defaultLanguage` | `string` | `"auto"` | Fallback language for files with unrecognized extensions. |
| `workspaceRoot` | `string \| null` | `null` | Explicit workspace root. If `null`, discovered automatically via `.git`, `.sln`, etc. |
| `maxResults` | `integer` | `50` | Maximum number of diagnostics, references, or symbols returned. |
| `includeCodeSnippets` | `boolean` | `false` | Whether to include code snippets with definition and reference locations. |
| `snippetContextLines` | `integer` | `3` | Number of context lines before and after target line in snippets. |
| `allowOutsideWorkspace` | `boolean` | `false` | **Security boundary:** Forbids accessing paths outside the workspace root. |
| `writeChanges` | `boolean` | `false` | **Write protection:** Enables writing rename refactorings directly to disk. |
| `serverStartupTimeoutMs`| `integer` | `15000` | Timeout in milliseconds for LSP process initialization handshake. |
| `requestTimeoutMs` | `integer` | `10000` | Timeout in milliseconds for individual LSP JSON-RPC requests. |
| `maxRestartAttempts` | `integer` | `2` | Maximum retry attempts when a server process crashes unexpectedly. |
---
## 10. Token Efficiency & Context Optimization
To prevent context bloat and optimize LLM token consumption, `agy-lsp` incorporates several efficiency mechanisms:
1. **No Full File Dumps:** Returns precise coordinates or compact snippets (default: 3 lines context) instead of entire files.
2. **Diagnostic Deduplication:** Merges redundant diagnostic reports at identical file locations.
3. **Message Truncation:** Overly verbose compiler error messages are truncated at 400 characters (`... [truncated]`).
4. **Result Limiting & Pagination:** Result lists are capped at `maxResults` and annotated with a `truncated: true` flag and total count.
5. **Compact Structure:** Omits empty optional keys and null values.
---
## 11. Security Model
- **Workspace Confinement:** All file paths are canonicalized (`resolve()`). Accessing files outside the workspace root is rejected unless `allowOutsideWorkspace: true` is set. Path traversal attacks (`../../`) are blocked.
- **No Shell Execution:** Subprocesses are launched directly using `asyncio.create_subprocess_exec` without a shell (`shell=False`).
- **Static Command Allowlist:** Server commands are loaded strictly from static configuration or defaults, never from dynamic agent tool arguments.
- **Secret Redaction:** Stderr logs automatically redact bearer tokens, API keys, and passwords.
- **Stderr Isolation:** All diagnostic logs are routed strictly to `sys.stderr`, preserving clean JSON-RPC communication on `sys.stdout`.
---
## 12. Troubleshooting & Diagnostics
### Checking Server Health
Invoke the `lsp_status` tool through the agent or MCP:
```json
{
"name": "lsp_status",
"arguments": {}
}
```
Output details:
- Status per language (`RUNNING`, `AVAILABLE`, `NOT_INSTALLED`, `CRASHED`),
- Process ID (PID) and workspace root,
- Detailed error messages and installation advice if a binary is missing.
### Error: "Language server command '...' was not found"
Ensure the language server is installed and available in `PATH`, or specify its absolute executable path in `agy-lsp.json`:
```json
{
"servers": {
"csharp": {
"command": "C:/Users/<User>/.dotnet/tools/csharp-ls.exe"
}
}
}
```
---
## 13. Development, Testing & QA
### Running the Test Suite & Empirical Benchmarks
The test suite contains **45 automated tests** across unit, integration, empirical benchmark, and real Language Server end-to-end categories (`pylsp` & `clangd`):
```powershell
# Run all 45 tests
.\.venv\Scripts\pytest.exe -v
# Run empirical benchmarks with detailed metrics output
.\.venv\Scripts\pytest.exe tests/test_benchmarks_and_value.py -v -s
# Run the real LSP process E2E tests (Python pylsp & C/C++ clangd)
.\.venv\Scripts\pytest.exe tests/test_e2e_real_lsp.py -v
```
### Linting & Formatting Check
```powershell
.\.venv\Scripts\ruff.exe check .
.\.venv\Scripts\ruff.exe format --check .
```
### Plugin Manifest Validation
```powershell
agy plugin validate .
```
---
## 14. Adding New Languages
To add a new language server (e.g. Rust via `rust-analyzer` or Go via `gopls`):
1. **Map file extensions:** In [`paths.py`](src/agy_lsp/utils/paths.py) in `EXTENSION_LANGUAGE_MAP`:
```python
".rs": "rust",
".go": "go",
```
2. **Register default server:** In [`config.py`](src/agy_lsp/config.py) in `DEFAULT_SERVERS`:
```python
"rust": ServerConfig(command="rust-analyzer", args=[]),
"go": ServerConfig(command="gopls", args=["serve"]),
```
3. **Add installation hint:** In [`adapters.py`](src/agy_lsp/lsp/adapters.py) in `INSTALL_HINTS`.
Alternatively, configure new languages purely declaratively in `agy-lsp.json` without modifying source code!
---
## 15. Known Limitations
- **C# on Modern .NET Previews:** On .NET 10 Preview environments, `dotnet tool install -g csharp-ls` may encounter packaging manifest issues. Configure an alternative Roslyn server path in `agy-lsp.json` if needed.
- **Multiple Workspace Roots:** The bridge currently targets one primary workspace root per session. Submodules and subfolders within the root are fully supported.
- **C/C++ Semantic Macro Expansion:** `clangd` yields optimal results when a `compile_commands.json` database is present in the workspace root.
---
## 16. License
This project is licensed under the [MIT License](LICENSE).
TDQS
Scored across 11 tools
Most tools target clearly distinct LSP operations: diagnostics, status, definitions, references, rename, symbols, hover, and hierarchies. The only mild overlap is between prepare_call_hierarchy and call_hierarchy, where the preparatory step could be confused with the actual hierarchy query.
Names are consistently snake_case and mostly follow verb_noun or clear noun_phrase patterns, e.g. go_to_definition, find_references, rename_symbol, get_type_hierarchy. Minor deviations include single-word hover and noun-style lsp_status/call_hierarchy, but the set remains predictable.
Eleven tools is well-scoped for an LSP server, covering navigation, diagnostics, refactoring, symbols, and hierarchy queries without obvious bloat. Each tool appears to earn its place in the surface.
The server covers core LSP workflows: diagnostics, definition lookup, references, rename, document/workspace symbols, hover, and call/type hierarchies. Some secondary LSP capabilities such as code actions, formatting, or signature help are absent, but the main agent-facing operations are present.