Metadata-Version: 2.4
Name: lcp
Version: 2.0.0
Summary: Python SDK for generating Library Context Protocol (LCP) files from Python packages
Project-URL: Homepage, https://github.com/zazza123/lcp
Project-URL: Repository, https://github.com/zazza123/lcp
Author: Andrea Zanini
License-Expression: MIT
License-File: LICENSE
Keywords: api-documentation,introspection,lcp,library-context-protocol
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Requires-Dist: docstring-parser>=0.16
Requires-Dist: fastmcp<4,>=3.0
Requires-Dist: jsonschema>=4.0
Requires-Dist: pydantic>=2.0
Provides-Extra: ai
Requires-Dist: anthropic>=0.20; extra == 'ai'
Requires-Dist: openai>=1.0; extra == 'ai'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.15.2; extra == 'dev'
Provides-Extra: docs
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
Requires-Dist: mkdocs>=1.6; extra == 'docs'
Requires-Dist: mkdocstrings[python]>=0.25; extra == 'docs'
Requires-Dist: pymdown-extensions>=10.0; extra == 'docs'
Description-Content-Type: text/markdown

<p align="center">
  <a href="https://zazza123.github.io/lcp">
    <img src="https://raw.githubusercontent.com/zazza123/lcp/main/docs/assets/logo.png" alt="LCP Logo" width="80">
  </a>
</p>
<h1 align="center">Library Context Protocol</h1>
<p align="center">
  <a href="https://pypi.org/project/lcp" target="_blank"><img src="https://img.shields.io/pypi/pyversions/lcp.svg?color=%2334D058" alt="Supported Python Versions" height="18"></a>
  <a href="https://pypi.org/project/lcp"><img src="https://img.shields.io/pypi/v/lcp?color=%2334D058&label=pypi" alt="PyPI version" height="18"></a>
  <a href="https://github.com/zazza123/lcp/actions/workflows/tests.yml?query=branch%3Amain+event%3Apush"><img src="https://github.com/zazza123/lcp/actions/workflows/tests.yml/badge.svg?branch=main&event=push" alt="Tests" height="18"></a>
  <a href="https://pepy.tech/project/lcp" target="_blank"><img src="https://static.pepy.tech/badge/lcp/month" alt="Downloads" height="18"></a>
  <a href="https://github.com/zazza123/lcp/blob/main/LICENSE" target="_blank"><img src="https://img.shields.io/github/license/zazza123/lcp.svg" alt="License" height="18"></a>
</p>

---

<p class="readme">
    <b>Documentation</b>: <a href="https://zazza123.github.io/lcp">https://zazza123.github.io/lcp</a>
</p>
<hr class="readme">

**lcp** (*Library Context Protocol*) is primarly a protocol designed to solve the problem of AI agents not having access to up-to-date library documentation, which leads to hallucinations and inaccurate code generation. The LCP SDK provides tools to scan Python packages, extract API information, and generate LCP-compliant JSON manifests. It also includes features for analyzing documentation coverage and generating missing docstrings using AI.

> **On niche and post-cutoff Python libraries, the shipped LCP plugin lifts a small model's task success rate from 28% to 66% and halves its API-misuse rate — beating, on task success, an agent that reads the installed source.** Full reproducible methodology and per-run data: [Benchmark](https://zazza123.github.io/lcp/benchmark/).

## Installation

```bash
pip install lcp
```

## Features

- Scans installed Python packages using `inspect` and `ast` modules
- Generates LCP v1 compliant JSON files
- Extracts functions, classes, methods, attributes, and constants
- Parses docstrings for summaries and descriptions
- Extracts type hints from function signatures
- Validates output against LCP JSON schema
- Documentation coverage analysis with JSON/Markdown reports
- Version diff to detect deprecated symbols across releases
- AI-powered docstring generation via OpenAI and Anthropic (`lcp[ai]`)
- Both CLI and Python API interfaces
- MCP server for AI agent integration

## When to choose LCP

Choose LCP when your AI agent needs **exact, offline ground truth about the library versions installed in your environment** — including private packages that no documentation service has ever seen. Choose a service like Context7 when you want curated narrative documentation (tutorials, guides) for popular public libraries: LCP does not compete on prose, it competes on being *provably right about your environment*.

|  | LCP | Context7 | llms.txt | Reading site-packages |
|---|:---:|:---:|:---:|:---:|
| Matches the *installed* version | yes | no | no | yes |
| Works offline | yes | no | no | yes |
| Private / internal packages | yes | no | no | yes |
| Token-dense structured answers | yes | narrative text | coarse summary | raw source (expensive) |

See the [full comparison](https://zazza123.github.io/lcp/introduction/#lcp-vs-alternatives) in the docs.

## Usage

### CLI

```bash
# Scan a package and output LCP JSON
lcp scan requests -o requests.lcp.json

# Include private symbols
lcp scan mypackage --include-private

# Skip validation
lcp scan mypackage --no-validate

# Start an MCP server for a library manifest
lcp serve requests.lcp.json
```

### Python API

```python
from lcp import scan

# Scan a package
lcp_doc = scan("requests")

# Save to file
lcp_doc.to_file("requests.lcp.json")

# Get as dict
data = lcp_doc.to_dict()

# Include private symbols
lcp_doc = scan("mypackage", include_private=True)
```

## Documentation Coverage

Analyze documentation completeness of a package to identify missing docstrings.

### CLI

```bash
# Generate coverage report (JSON)
lcp coverage requests -o coverage.json

# Generate coverage report (Markdown)
lcp coverage requests -o coverage.md --format markdown

# Generate both LCP manifest and coverage report in one scan
lcp scan requests -o requests.lcp.json --coverage coverage.json
```

### Python API

```python
from lcp import generate_coverage

# Generate coverage report
report = generate_coverage("requests")

# Check coverage percentage
print(f"Coverage: {report.summary.coverage_percent}%")
print(f"Documented: {report.summary.documented}/{report.summary.total_symbols}")

# List undocumented symbols
for symbol in report.undocumented:
    print(f"  - {symbol.module}:{symbol.entity} ({symbol.kind})")

# Save report
report.to_file("coverage.json")      # JSON format
report.to_file("coverage.md")        # Markdown format
```

## Version Diff

Compare two LCP manifests to detect symbols that were removed between versions and automatically generate deprecation entries.

### CLI

```bash
# Compare two versions and print the diff report
lcp diff v1.lcp.json v2.lcp.json

# Save the diff report to a file
lcp diff v1.lcp.json v2.lcp.json -o diff.json

# Automatically update the new manifest with deprecation entries
lcp diff v1.lcp.json v2.lcp.json --update
```

### Python API

```python
from lcp import diff_documents, load_lcp_document, update_document

# Load two versions
old = load_lcp_document("v1.lcp.json")
new = load_lcp_document("v2.lcp.json")

# Compare
result = diff_documents(old, new)
print(f"Removed: {len(result.removed)}, Added: {len(result.added)}")

for sid, dep in result.deprecated.items():
    print(f"  {sid}: deprecated in {dep.deprecated_in}")

# Merge deprecations into the new document
updated = update_document(new, result)
updated.to_file("v2.lcp.json")
```

## MCP Server

The SDK includes an MCP (Model Context Protocol) server that exposes LCP manifest data to AI agents. This allows agents to explore library APIs and generate accurate code.

### Starting the Server

```bash
# Universal server: resolves any installed library on demand
lcp serve-all

# Restrict and pre-warm specific libraries
lcp serve-all --expose requests --preload requests
```

### MCP Client Configuration

Add to your MCP client configuration (e.g., Claude Desktop):

```json
{
  "mcpServers": {
    "lcp": {
      "command": "lcp",
      "args": ["serve-all"]
    }
  }
}
```

### Available MCP Tools

| Tool | Description |
|------|-------------|
| `resolve_library(name, version?)` | Load a library (cache → live scan → registry). Call first. |
| `search(query, library?, module?, kind?, limit?)` | Ranked symbol search; empty query browses. Hits include the exact import line. |
| `get_symbol(ids, library?)` | Batch detail: full signatures, parameters, import lines; classes inline member summaries. |
| `get_overview(library?)` | Library identity plus the module tree with symbol counts. |

### Programmatic Usage

```python
from lcp.mcp_server import create_universal_server

server = create_universal_server(name="my-server", preload=["requests"])
server.run()  # serve on stdio

# Or invoke tools in-process, without the MCP protocol
server.tools["search"]("send get request", library="requests")
```

## AI Documentation Generation

Automatically generate missing docstrings using LLM providers (OpenAI, Anthropic). Requires the optional `ai` extra:

```bash
pip install lcp[ai]
```

### CLI

```bash
# Generate coverage report first
lcp coverage mypackage -o coverage.json

# Generate docstrings (dry-run to preview)
lcp docgen coverage.json --provider openai --dry-run

# Generate docstrings for real
lcp docgen coverage.json --provider openai

# Use Anthropic
lcp docgen coverage.json --provider anthropic --model claude-sonnet-4-20250514

# Filter by symbol kind
lcp docgen coverage.json --kinds class,function,method

# Provide a guiding description
lcp docgen coverage.json --description "A web framework for building REST APIs"

# Use OpenAI reasoning models (o1, o3)
lcp docgen coverage.json --provider openai --model o3 --reasoning
```

### Python API

```python
from lcp.ai import DocGenAgent, DocGenConfig, OpenAIProvider

# Create provider and agent
provider = OpenAIProvider(model="gpt-4o")
config = DocGenConfig(kinds=["class", "function"], dry_run=True)
agent = DocGenAgent(provider=provider, config=config)

# Run on a coverage JSON file
result = agent.run("coverage.json")

# Or pass a dict directly
result = agent.run(coverage_dict)

# Inspect results
print(f"Updated: {result.symbols_updated}")
print(f"Tokens: {result.total_usage.input_tokens} in / {result.total_usage.output_tokens} out")
for r in result.results:
    print(f"  {r.symbol_id}: {r.status}")
```

## Claude Code Plugin

The SDK ships a ready-to-install [Claude Code](https://code.claude.com) plugin in `plugin/lcp/`. It packages `lcp serve-all` as an MCP server so Claude Code can resolve any Python library on demand — including private packages installed in your project's virtualenv.

### Install `lcp` first

`lcp` introspects packages by importing them in-process, so it must run inside the **same Python environment** as your project's dependencies. For live introspection of project packages, install it in your project virtualenv:

```bash
# Inside your project virtualenv
uv pip install lcp      # recommended with uv
pip install lcp         # plain pip
```

The plugin auto-detects `.venv` under your project root — no extra configuration needed for the common case.

For a global install (public libraries via the registry; does not see project-specific packages unless also globally installed):

```bash
pipx install lcp        # recommended
uv tool install lcp
```

### Install the plugin

Add the marketplace and install the plugin in two slash commands:

```
/plugin marketplace add zazza123/lcp
/plugin install lcp@lcp
```

Once installed, Claude Code automatically starts the LCP MCP server on session start. The `lcp-universal` skill instructs the agent to call `resolve_library("package")` before writing code that depends on an external library.

For **local development** (when working on the plugin itself), load it directly instead:

```bash
claude --plugin-dir /path/to/lcp/plugin/lcp
```

### `.lcp-config.json` — per-project configuration

The plugin uses a `.lcp-config.json` file to select the correct `lcp` launcher for each project. The `SessionStart` hook auto-generates this file when absent, seeding it from `settings.json` `pluginConfigs` values; edit the file directly thereafter. Earlier versions named this file `.lcp.json`; the old name still works as a deprecated fallback — rename it to `.lcp-config.json`.

**Locations** (first found wins):
- `${CLAUDE_PROJECT_DIR}/.lcp-config.json` — per-project (safe to check in)
- `~/.lcp/config.json` — global fallback

**Schema** (all fields optional):

```jsonc
{
  "command":    "/path/to/lcp",            // explicit lcp binary
  "python":     "/path/to/python",         // interpreter → `python -m lcp`
  "registries": ["https://..."],           // registry URLs → lcp serve-all --registry
  "expose":     ["fastapi", "pydantic"],   // allow-list; omitted/empty = expose all packages
  "preload":    ["fastapi"]                // packages resolved at server startup
}
```

`command` and `python` are mutually exclusive; `command` wins if both are set. `expose` and `preload` are `.lcp-config.json`-only fields (not in `userConfig`).

To change an option: edit `.lcp-config.json` directly. To reset from `settings.json`, delete the file and restart the session — the hook regenerates it from `pluginConfigs.lcp@lcp.options`.

### Launcher resolution order

The wrapper probes each candidate with `--version`; the first that succeeds wins:

1. `.lcp-config.json` → `command`
2. `.lcp-config.json` → `python` → `python -m lcp`
3. Auto-detected project venv under `${CLAUDE_PROJECT_DIR}`: `.venv/bin/lcp`, `.venv/bin/python -m lcp`, `venv/bin/lcp`, `venv/bin/python -m lcp`
4. Active virtualenv via `$VIRTUAL_ENV`: `$VIRTUAL_ENV/bin/lcp`, `$VIRTUAL_ENV/bin/python -m lcp`
5. `uv run --project <dir> --with lcp lcp` if `uv` is present (ephemeral; layers `lcp` onto the project env)
6. Global fallback: `lcp` on `PATH` → `uvx lcp` → `pipx run lcp`

If none resolve, the plugin emits an actionable message — never a bare `-32000`.

### Shortcuts

| Shortcut | Action |
|----------|--------|
| `/lcp:resolve <package>` | Resolve a library and summarise its public API |
| `/lcp:scan <package>` | Scan a package and display module/symbol overview |

## License

MIT