Skip to main content
Glama
jpsweeney97

claude-code-docs

by jpsweeney97
README.md
# claude-code-docs MCP Server

**Version:** 1.0.0  
**Runtime:** Node.js >=18 (TypeScript, ESM)  
**Key dependencies:** `@modelcontextprotocol/sdk`, `zod`, `yaml`, `stemmer`  
**License:** Not specified in this package

## Problem Statement
Claude Code's documentation is large and frequently updated, but most MCP clients need fast, local search results rather than full-document scans. This server fetches the official docs, chunks them into semantic sections, builds an in-memory BM25 index, and exposes MCP tools that return ranked snippets.

The result is a small, focused MCP server that provides deterministic, query-focused results with minimal client integration surface: a stdio transport, four tools, and a cache-backed indexing pipeline.

## Quick Start
1. From this directory, install dependencies:
   `npm install`
2. Build the server:
   `npm run build`
3. Start the MCP server (stdio transport):
   `npm start`

To use the server from an MCP client, see Client Configuration below.

## How It Works
Pipeline overview:
1. Fetch official docs from the configured URL and parse `Source:` markers into sections.
2. Synthesize frontmatter (topic/id/category) and chunk each section at semantic boundaries.
3. Tokenize and build a BM25 index (with heading-based score boosting).
4. Serve MCP tool calls against the in-memory index.

Design properties:
- Two-cache model: a raw content cache (TTL-based) and a serialized index cache (version-gated).
- Fail-open on expected fetch/validation errors by falling back to stale cache when allowed.
- Fail-closed on programmer errors to avoid masking regressions.
- Concurrency-safe index loading with a shared in-flight promise and retry backoff.

## Configuration
Environment variables:

| Variable | Default | Purpose | Constraints / Behavior |
| --- | --- | --- | --- |
| `DOCS_URL` | `https://code.claude.com/docs/llms-full.txt` | Source documentation URL. | Validated on startup; must be a valid `https` URL. |
| `DOCS_TRUST_MODE` | `official` | Trust mode controlling source validation and canary policy. | `official`: pins source to `code.claude.com`, full canary evaluation (fallback-segment delta + relative-drift checks + absolute fallback-ratio warn). `unsafe`: accepts any HTTPS URL, structural canaries only (count + size checks). Use `unsafe` only for local testing or private mirrors. |
| `RETRY_INTERVAL_MS` | `60000` | Retry backoff for failed index loads. | Validated on startup; must be an integer between `1000` and `600000`. |
| `CACHE_TTL_MS` | `86400000` | Content cache freshness window in milliseconds. | Integer >=0. `0` means the cache is never considered fresh (fetch each load); values > 1 year are capped. |
| `DOCS_CACHE_MAX_STALE_MS` | `0` | Maximum allowed age for stale cache fallback. | Validated on startup; must be an integer >=0. `0` disables the limit. |
| `MIN_SECTION_COUNT` | (unset) | Override for the canary's index floor. | Integer >=0. Unset → canary uses its trust-mode default (official: 40, unsafe: 3). `0` disables the index floor. Does NOT affect the content-cache write guard, which is fixed at 40 (`CACHE_WRITE_MIN_SECTIONS`) and is NOT env-disableable. |
| `MAX_INDEX_CACHE_BYTES` | `52428800` | Max serialized index size in bytes before writing cache. | Validated on startup; must be an integer >0. If exceeded, index cache write is skipped (server keeps in-memory index). |
| `MAX_RESPONSE_BYTES` | `10485760` | Max HTTP response size in bytes. | Integer >0. If declared or streamed size exceeds, fetch fails and falls back to stale cache when available. |
| `FETCH_TIMEOUT_MS` | `30000` | HTTP fetch timeout in milliseconds. | Integer >=0. `0` results in immediate timeout. |
| `CACHE_PATH` | unset | Override the content cache file path. | Must include a filename (not just a directory). Does not move the index cache. |
| `XDG_CACHE_HOME` | unset | Base cache directory for defaults. | When set, affects default content and index cache paths. |

Default cache locations:
- macOS content cache: `~/Library/Caches/claude-code-docs/llms-full.txt`
- macOS index cache: `~/Library/Caches/claude-code-docs/llms-full.index.json`
- Linux content cache: `$XDG_CACHE_HOME/claude-code-docs/llms-full.txt` (or `~/.cache/claude-code-docs/llms-full.txt`)
- Linux index cache: same directory, `llms-full.index.json`

Notes:
- `CACHE_PATH` overrides only the content cache file path. The index cache always uses the default cache directory derived from `XDG_CACHE_HOME` or OS defaults.
- Content cache writes use a lock file (`.lock`) to coordinate concurrent writers.

## Tools

### `search_docs`
Searches the indexed Claude Code docs.

Parameters:

| Name | Type | Required | Default | Notes |
| --- | --- | --- | --- | --- |
| `query` | string | yes | - | Max 500 chars, trimmed, must be non-empty. |
| `limit` | integer | no | `5` | 1-20. |
| `category` | string | no | - | Canonical categories or aliases (see below). |

Canonical categories:
`hooks`, `skills`, `commands`, `agents`, `plugins`, `plugin-marketplaces`, `mcp`, `channels`, `settings`, `memory`, `overview`, `getting-started`, `cli`, `best-practices`, `interactive`, `security`, `providers`, `gateways`, `environments`, `ide`, `ci-cd`, `automation`, `agent-sdk`, `desktop`, `integrations`, `config`, `operations`, `troubleshooting`, `changelog`, `uncategorized`

Aliases:
`subagents` -> `agents`, `sub-agents` -> `agents`, `slash-commands` -> `commands`, `claude-md` -> `memory`, `configuration` -> `config`, `gateway` -> `gateways`

Return shape:

| Field | Type | Description |
| --- | --- | --- |
| `results[]` | object | Array of matches. |
| `results[].chunk_id` | string | Chunk identifier. |
| `results[].content` | string | Full chunk content. |
| `results[].snippet` | string | Snippet best matching the query. |
| `results[].category` | string | Derived category. |
| `results[].source_file` | string | Source URL/path. |
| `meta` | object | Index provenance attached to each search response. |
| `meta.trust_mode` | string | Active trust mode: `official` or `unsafe`. |
| `meta.source_kind` | string or null | How content was obtained: `fetched`, `cached`, `stale-fallback`, or `bundled-snapshot`. Null if no corpus loaded. |
| `meta.index_created_at` | string or null | ISO timestamp when the BM25 index was built. Null if not yet loaded. |
| `meta.corpus_age_ms` | integer or null | Milliseconds since the corpus content was obtained (`Date.now() - corpus.obtainedAt`). Null if no corpus loaded. |
| `error` | string | Present only on failure. |

### `reload_docs`
Forces a refresh of the docs and rebuilds the index.

Parameters: none.

Return:
- Text message indicating success, chunk count, and any parse warnings.

### `get_status`
Returns a lightweight runtime status snapshot. Use this to check index health, trust configuration, and canary evaluation results without triggering a reload or dumping the full metadata.

Parameters: none.

Return shape:

| Field | Type | Description |
| --- | --- | --- |
| `trust_mode` | string | Active trust mode: `official` or `unsafe`. |
| `docs_origin` | string | Hostname of the documentation source URL. |
| `docs_url` | string | Full documentation source URL. |
| `source_kind` | string or null | How content was obtained: `fetched`, `cached`, `stale-fallback`, or `bundled-snapshot`. Null if no corpus loaded. |
| `index_created_at` | string or null | ISO timestamp when the BM25 index was built. Null if not yet loaded. |
| `corpus_age_ms` | number or null | Milliseconds since corpus content was obtained. Null if no corpus loaded. |
| `corpus_obtained_at` | string or null | ISO timestamp when corpus content was obtained. Null if no corpus loaded. |
| `last_load_attempt_at` | string or null | ISO timestamp of the most recent load attempt. Null if never attempted. |
| `last_load_error` | string or null | Error message from the most recent failed load. Null if last load succeeded. |
| `warning_codes` | string[] | Active warning codes: `fallback_segment_drift`, `fallback_ratio_high`, `parse_issues`, `section_count_drift`, `stale_corpus`. |
| `is_loading` | boolean | Whether a load/reload is currently in progress. |

### `dump_index_metadata`
Returns structured index metadata useful for debugging ingestion, category mapping, and chunk coverage without dumping the full corpus.

Parameters: none.

Return shape:

| Field | Type | Description |
| --- | --- | --- |
| `index_version` | string | Serialized index format version. |
| `built_at` | string | ISO timestamp for the response build time. |
| `docs_epoch` | string or null | Content hash for the currently loaded docs. |
| `categories[]` | object | Per-category chunk metadata. |
| `categories[].name` | string | Canonical category name. |
| `categories[].aliases` | string[] | Accepted aliases for the category. |
| `categories[].chunk_count` | integer | Number of chunks in the category. |
| `categories[].chunks[]` | object | Chunk-level metadata for debugging and inventory building. |

## Resources
None.

## Transport
The server uses stdio transport via the MCP SDK.

## Client Configuration
Example `.mcp.json` entry:

```json
{
  "mcpServers": {
    "claude-code-docs": {
      "command": "node",
      "args": ["/absolute/path/to/claude-code-docs/dist/index.js"]
    }
  }
}
```

## Tests
Run:
`npm test`

The suite covers parser, chunker, loader, lifecycle, fetcher, metadata, and cache behavior. Special cases:

- `tests/integration.test.ts` is skipped unless `INTEGRATION=1`.
- `tests/corpus-validation.test.ts` depends on a populated content cache.

## Known Limitations
- Stdio transport only; no HTTP/SSE transport.
- No background refresh loop; use `reload_docs` for refreshes.
- Category filtering is limited to the predefined list above.

TDQS

A4.1/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: reloading docs, searching, getting server status, and dumping index metadata. No overlap or ambiguity.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern using snake_case (e.g., reload_docs, search_docs, get_status, dump_index_metadata), making them predictable.

Tool Count5/5

Four tools is well-scoped for a documentation management server, covering all necessary operations without being excessive or insufficient.

Completeness4/5

The tool set covers the core lifecycle: reloading, searching, status, and metadata inspection. A minor gap could be a tool to add or update documentation sources, but current set is largely complete.

Maintenance

ActivityMaintained
ResponsivenessNo issues