Lightweight Python LSP MCP server + grep-intercept hook for Claude Code
Project description
claude-pyls
A lightweight Python LSP MCP server + grep-intercept hook for Claude Code. Gives Claude token-efficient symbol navigation in any Python project.
Why
When Claude Code searches for a Python symbol using Grep, it reads large swaths of source into context. A targeted LSP lookup costs a fraction of that.
Measured savings (Haiku, claude -p, 400-file project):
| Metric | Without (Grep) | With (pyls) | Savings |
|---|---|---|---|
| Cost | $0.0586 | $0.0119 | 80% cheaper |
| Cache creation tokens | 39,124 | 2,953 | 92% less |
| Duration | 10.6s | 5.7s | 46% faster |
Modes
Small (single-repo, zero-startup)
Regex scan over class/def lines. Starts in 0.2s (raw JSON-RPC, no MCP SDK). Optionally enhances with jedi for precise goto/references. Ideal for per-project activation.
Big (environment-wide, daemon)
A persistent LSP daemon that starts on boot and serves an entire Python environment. Longer startup, higher accuracy, multi-repo awareness. Good for large monorepos or shared dev environments. (Planned — not yet implemented.)
Install
pip install claude-pyls # small mode (regex scan)
pip install claude-pyls[lsp] # + jedi for enhanced accuracy
Quick start
# Scaffold .mcp.json + hook into your project
claude-pyls setup
# Or manually add to .mcp.json:
# {"mcpServers": {"pyls": {"command": "claude-pyls", "args": ["serve"]}}}
Tools exposed
| Tool | Description |
|---|---|
find_definition |
File + line where a symbol is defined |
find_references |
All sites where a symbol is used |
find_symbols |
All definitions matching a name pattern |
Known limitations
- Textual scan only (small mode) — won't resolve dynamic attributes, decorated names, or re-exports
- jedi (when enabled) is lazy-loaded on first call (~3–4s first call, fast after)
- File cache is not invalidated mid-session — restart the server after large refactors
- Hook catches bare symbol names (PascalCase, camelCase, snake_case 2+ segments) — prefixed patterns pass through
Releasing
Publishing is manual for now (no CI/CD). The PyPI API token lives in a local .env file (gitignored) in the format pypi=pypi-....
# one-time: install hatch into the dev venv
pip install hatch
# build wheel + sdist
hatch build
# publish — reads the token out of .env WITHOUT exporting every line
# of .env into your shell (avoids leaking unrelated vars). Never commit .env.
HATCH_INDEX_USER=__token__ \
HATCH_INDEX_AUTH="$(grep '^pypi=' .env | cut -d= -f2-)" \
hatch publish
# tag the release (replace X.Y.Z with the version you just bumped
# in src/claude_pyls/__init__.py and pyproject.toml — see below)
git tag vX.Y.Z && git push origin vX.Y.Z
Version bump procedure
Before each release, bump the version in both locations (they must stay in sync):
src/claude_pyls/__init__.py—__version__ = "x.y.z"pyproject.toml—version = "x.y.z"
Then commit, build, publish, and tag as shown above.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_pyls-0.1.0.tar.gz.
File metadata
- Download URL: claude_pyls-0.1.0.tar.gz
- Upload date:
- Size: 13.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.5 cpython/3.12.13 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12b83d1ea2e9af9aeb4edd61da1cd152b6f9b459f6b4f1f1a6de97dcd1af65f8
|
|
| MD5 |
b7f410f91437cbc6eee576747d0205ea
|
|
| BLAKE2b-256 |
56bc5cc06562b52339869a896284e670c947786acd4efe24b73add62cee09cf5
|
File details
Details for the file claude_pyls-0.1.0-py3-none-any.whl.
File metadata
- Download URL: claude_pyls-0.1.0-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: Hatch/1.16.5 cpython/3.12.13 HTTPX/0.28.1
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e8138f4a368be68406c01f96d63b74b556595097f47608c71a61e5c4e2ec4b33
|
|
| MD5 |
4dfa4668c529e9798a12a477ca77c817
|
|
| BLAKE2b-256 |
6b761732e6ae299e45f67d1297607f1b312ca82482376e46e26906b6f23cdba3
|