← Back to Skills Marketplace
zgjq

Lsp Assist

by zgjq · GitHub ↗ · v1.1.2 · MIT-0
cross-platform ✓ Security Clean
157
Downloads
0
Stars
1
Active Installs
6
Versions
Install in OpenClaw
/install lsp-assist
Description
Language Server Protocol integration for OpenClaw agents. Enables precise code navigation: go-to-definition, find-references, hover type info, diagnostics, a...
README (SKILL.md)

LSP Assist

Precise code navigation via Language Server Protocol.

Modes

Mode How When to use
Daemon (recommended) daemon --port 9876 then HTTP queries Multiple queries in a session (start once, query many)
One-shot goto/refs/hover/diag/symbols directly Single quick query, or scripting

Requirements

  • Runtime: Python 3.10+ (standard library only)
  • OS: Linux, macOS
  • Language servers (install separately):
    • TypeScript: npm i -g typescript-language-server typescript
    • Python: pip install pyright
  • Project config:
    • TypeScript: tsconfig.json in project root
    • Python: pyproject.toml or pyrightconfig.json

Security

Binding

Daemon binds to 127.0.0.1 only — no external/remote access:

server = HTTPServer(("127.0.0.1", port), DaemonHandler)

File Access Control

All file reads go through _open_file(), which enforces project-root containment:

def _open_file(self, filepath: str):
    path = Path(filepath).resolve()          # resolve symlinks, .., etc.
    if str(path) in self._opened_files:
        return                               # skip duplicate opens
    common = os.path.commonpath([str(path), self.root_path])
    if common != self.root_path:             # must be direct ancestor of root
        raise ValueError(f"File outside project root: {path}")
    # Only then: read file content and send didOpen to language server
  • Path.resolve() canonicalizes the path (resolves symlinks, .., ~)
  • os.path.commonpath rejects sibling dirs (e.g. /root/openclaw-backup/ when root is /root/openclaw)
  • Tested against: symlink escape, .. traversal, trailing-slash differences, sibling-prefix collision

Auth Token (optional)

When --token \x3Csecret> is passed, every HTTP request must include Authorization: Bearer \x3Csecret>:

def _check_auth(self) -> bool:
    expected = getattr(self.server, "auth_token", None)
    if expected is None:
        return True                          # no token required
    header = self.headers.get("Authorization", "")
    if header == f"Bearer {expected}":
        return True
    self._respond({"error": "unauthorized"}, 401)
    return False
  • Checked in both do_GET and do_POST before any handler logic
  • Without --token, daemon is open on localhost (intended for local single-user use)

Shutdown Handling

elif self.path == "/shutdown":
    self._respond({"status": "shutting down"})
    threading.Thread(target=lambda: (time.sleep(0.5), os._exit(0)), daemon=True).start()

Responds first, then exits after 0.5s delay to ensure the HTTP response is flushed.

Process Isolation

  • One-shot mode: fresh server per query, auto-terminates (15s timeout)
  • Daemon mode: persistent server, but is_alive() check returns 503 if the language server crashes
  • Language server communication is local stdio only

Quick Reference

Daemon Mode (recommended for multi-query)

# Start daemon (blocks, run in background or separate terminal)
python3 scripts/lsp_client.py daemon --lang typescript --root /path/to/project --port 9876

# Start with auth token (requests need Bearer token)
python3 scripts/lsp_client.py daemon --lang typescript --root /path/to/project --port 9876 --token mysecret

# Query via HTTP (all output JSON)
curl -s http://127.0.0.1:9876/goto   -d '{"file":"src/main.ts","line":10,"col":5}'
curl -s http://127.0.0.1:9876/refs   -d '{"file":"src/main.ts","line":10,"col":5}'
curl -s http://127.0.0.1:9876/hover  -d '{"file":"src/main.ts","line":10,"col":5}'
curl -s http://127.0.0.1:9876/diag   -d '{"file":"src/main.ts"}'
curl -s http://127.0.0.1:9876/symbols -d '{"query":"UserService"}'
curl -s http://127.0.0.1:9876/shutdown
curl -s http://127.0.0.1:9876/ping   # health check

# With auth token
curl -s -H "Authorization: Bearer mysecret" http://127.0.0.1:9876/ping

One-shot Mode

Action Command
Go to definition python3 scripts/lsp_client.py --lang ts --root \x3Cdir> goto --file \x3Cf> --line \x3Cn> --col \x3Cn>
Find references python3 scripts/lsp_client.py --lang ts --root \x3Cdir> refs --file \x3Cf> --line \x3Cn> --col \x3Cn>
Hover type info python3 scripts/lsp_client.py --lang ts --root \x3Cdir> hover --file \x3Cf> --line \x3Cn> --col \x3Cn>
Diagnostics python3 scripts/lsp_client.py --lang ts --root \x3Cdir> diag --file \x3Cf>
Symbol search python3 scripts/lsp_client.py --lang ts --root \x3Cdir> symbols [--query \x3Ctext>]

Language shorthand: --lang typescript or --lang ts or --lang python.

Output Format

All commands output JSON for structured consumption:

// goto / refs
[{"file": "/path/to/file.ts", "line": 42, "col": 10}]

// hover
"function foo(bar: string): number"

// diag
[{"severity": "ERROR", "line": 10, "message": "Cannot find name 'x'"}]

// symbols
[{"name": "UserService", "kind": 5, "file": "/path/to/file.ts", "line": 12, "container": "models"}]

When to Use vs Grep

Scenario Use
"Where is this function defined?" LSP goto
"Who calls this function?" LSP refs
"What type is this variable?" LSP hover
"Any compile errors?" LSP diag
"Find all classes matching X" LSP symbols
"Search for text pattern 'TODO'" grep
"Find all .json files" glob
"Search across non-code files" grep

Supported Languages

Language Server Install
TypeScript/JavaScript typescript-language-server npm i -g typescript-language-server typescript
Python pyright pip install pyright

Adding a language: edit SERVERS dict in lsp_client.py — add the server command and file extensions.

Usage Guidance
This skill appears to do what it says: run local LSP servers and expose query endpoints on 127.0.0.1. Before installing/using: (1) ensure you install the declared language servers (typescript-language-server, pyright) from trusted sources; (2) run the daemon with --token if you want to prevent other local users/processes from using it; (3) run it with --root set to the intended project directory (the client enforces containment, but verify the path you pass is correct); (4) avoid binding to non-loopback interfaces or running this in environments where 127.0.0.1 may be reachable from other tenants (multi-tenant containers, reverse proxies) unless you understand the exposure. If you need higher assurance, review the full lsp_client.py file locally or run it in an isolated dev container.
Capability Analysis
Type: OpenClaw Skill Name: lsp-assist Version: 1.1.2 The lsp-assist skill provides legitimate Language Server Protocol (LSP) integration for TypeScript and Python. The core logic in scripts/lsp_client.py implements a client that communicates with standard language servers via stdio and includes robust security measures, such as path traversal protection using os.path.commonpath and binding the daemon mode to 127.0.0.1 with optional Bearer token authentication. No evidence of malicious intent, data exfiltration, or unauthorized execution was found.
Capability Assessment
Purpose & Capability
Name/description match the provided code and SKILL.md. The script spawns language servers (typescript-language-server, pyright) and implements LSP queries (goto, refs, hover, diag, symbols) — exactly what an LSP assist tool should do. No unrelated credentials, binaries, or config paths are requested.
Instruction Scope
Runtime instructions and the code restrict network binding to localhost and enforce project-root containment for file reads. The daemon exposes HTTP endpoints (including /shutdown) and accepts an optional Bearer token; by default no token is required, which makes the API accessible to any local process. This behaviour is expected for a local LSP daemon but is worth noting because local processes can query it without additional authorization unless you start with --token.
Install Mechanism
No install spec (instruction-only) and included Python script uses only the standard library. It relies on externally installed language-server binaries (npm/pip) as documented — expected for this purpose and lower-risk than arbitrary downloads.
Credentials
The skill requests no environment variables, credentials, or unusual config paths. The optional --token is a local auth mechanism documented in SKILL.md; nothing requests unrelated secrets.
Persistence & Privilege
The skill is not always: true and uses normal daemon/one-shot modes. It does not require persistent system privileges or modify other skills. Autonomous invocation by the agent is allowed by default (platform normal), and does not combine with other red flags here.
How to Use
  1. Make sure OpenClaw is installed (local or Docker)
  2. Run the install command in chat: /install lsp-assist
  3. After installation, invoke the skill by name or use /lsp-assist
  4. Provide required inputs per the skill's parameter spec and get structured output
Version History
v1.1.2
Security docs: full implementation snippets in SKILL.md for binding, file-access, auth, and shutdown verification by ClawHub review.
v1.1.1
Security: add optional --token for Bearer auth on daemon HTTP API. Document _open_file path-check enforcement in SKILL.md.
v1.1.0
Daemon mode: persistent HTTP server for multi-query sessions. New symbols command. JSON output for all commands. Buffered read loop (no more byte-by-byte). File cache to skip duplicate didOpen. Concurrent-safe writes. Daemon alive detection. DIAG_SEVERITIES and SYMBOL_KINDS mapping. Argparse fix for daemon subcommand.
v1.0.2
Fix: path check uses os.path.commonpath instead of startswith to prevent prefix collision bypass (/proj vs /project)
v1.0.1
Fix: file path restricted to --root (assertion in _open_file), fix diagnostics name collision (renamed to _diagnostics/get_diagnostics), clarify 'no network calls' to 'no persistent network calls from this skill'
v1.0.0
Initial release – integrates Language Server Protocol (LSP) features for code navigation in OpenClaw agents. - Supports go-to-definition, find-references, hover type info, and diagnostics for TypeScript and Python projects. - Runs a fresh, stateless language server per query for improved security (no persistent daemon). - Provides clear usage instructions and example commands for common code navigation tasks. - Operates fully offline with no network calls; server access limited to project root files. - Compatible with Linux and macOS, requiring Python 3.10+ and user-installed language servers.
Metadata
Slug lsp-assist
Version 1.1.2
License MIT-0
All-time Installs 1
Active Installs 1
Total Versions 6
Frequently Asked Questions

What is Lsp Assist?

Language Server Protocol integration for OpenClaw agents. Enables precise code navigation: go-to-definition, find-references, hover type info, diagnostics, a... It is an AI Agent Skill for Claude Code / OpenClaw, with 157 downloads so far.

How do I install Lsp Assist?

Run "/install lsp-assist" in the OpenClaw or Claude Code chat to install it in one step — no extra setup required.

Is Lsp Assist free?

Yes, Lsp Assist is completely free, licensed under MIT-0. You can download, install and use it at no cost.

Which platforms does Lsp Assist support?

Lsp Assist is cross-platform and runs anywhere OpenClaw / Claude Code is available (cross-platform).

Who created Lsp Assist?

It is built and maintained by zgjq (@zgjq); the current version is v1.1.2.

💬 Comments