feat(mcp): add 4 new tools — compare_versions, get_threat, list_threats, search_examples

New tools (8 → 12 total):
- compare_versions(from, to): diff Claude Code releases between two versions,
  aggregating highlights and breaking changes across the range
- get_threat(id): look up any CVE or attack technique (T-code) with full details,
  severity, mitigation, and source references
- list_threats(category?): browse the threat database — summary table or
  detailed view by section (cves, authors, skills, techniques, mitigations, sources)
- search_examples(query, limit?): semantic search across 199 templates with
  token-aware scoring and get_example() hints

Infrastructure:
- content.ts: add loadThreatDb() with memory cache and dual-mode loading
  (GUIDE_ROOT filesystem in dev, GitHub fetch in production)
- Threat DB interface with correct Record<string, string> type for minimum_safe_versions

Docs:
- mcp-server/README.md: document all 12 tools with usage examples
- mcp-server/IDEAS.md: future ideas (quiz, methodology, workflow, diff resource)
- CHANGELOG.md: [Unreleased] entry for all 4 tools
- README.md: promote MCP section to standalone ## after Quick Start (was ### inside Quick Start)
- guide/architecture.md: add MCP server to Extended Tool Ecosystem

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Florian BRUNIAUX 2026-02-28 19:22:20 +01:00
parent e62af76767
commit 7236362c1e
33 changed files with 7686 additions and 22 deletions

View file

@ -8,6 +8,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
### Added
- **MCP Server: 3 new tools** — compare_versions, get_threat/list_threats, search_examples
- `compare_versions(from, to?)` — diff entre deux versions Claude Code CLI : toutes les releases dans la plage, highlights agrégés, breaking changes agrégés
- `get_threat(id)` — lookup CVE (ex: `CVE-2025-53109`) ou technique d'attaque (ex: `T001`) depuis la threat database v2.4.0
- `list_threats(category?)` — browse la threat-db : résumé global avec counts (sans catégorie) ou liste détaillée par section (`cves`, `authors`, `skills`, `techniques`, `mitigations`, `sources`)
- `search_examples(query, limit?)` — recherche sémantique dans les 175 templates par intention (ex: `"hook lint"`, `"agent code review"`) — complémentaire à `get_example` (nom exact) et `list_examples` (catégorie)
- `mcp-server/IDEAS.md` — futures idées documentées : `get_quiz`, `get_methodology`, `get_workflow`, resource `diff`, prompt `security-review`
- Total : 8 tools → 12 tools (+ 3 resources + 1 prompt)
- **Terminal Personalization Settings** — documentation `spinnerVerbs` + `spinnerTipsOverride` dans `guide/ultimate-guide.md` §3.3 Settings & Permissions
- Nouvelle section "Terminal Personalization Settings" (ligne 4978) : exemples JSON pour `spinnerVerbs` (mode replace/add) et `spinnerTipsOverride` (avec `excludeDefault: true`)
- `settings.json` available keys enrichi : ajout `spinnerVerbs`, `spinnerTipsOverride`, `plansDirectory`, `enableAllProjectMcpServers`

View file

@ -10,6 +10,7 @@
<a href="./quiz/"><img src="https://img.shields.io/badge/Quiz-274_questions-orange?style=for-the-badge" alt="Quiz"/></a>
<a href="./examples/"><img src="https://img.shields.io/badge/Templates-175-green?style=for-the-badge" alt="Templates"/></a>
<a href="./guide/security-hardening.md"><img src="https://img.shields.io/badge/🛡_Threat_DB-24_CVEs_·_655_malicious_skills-red?style=for-the-badge" alt="Threat Database"/></a>
<a href="./mcp-server/"><img src="https://img.shields.io/badge/MCP_Server-npx_ready-blueviolet?style=for-the-badge" alt="MCP Server"/></a>
</p>
<p align="center">
@ -93,40 +94,39 @@ Both guides serve different needs. Choose based on your priority.
**Quickest path**: [Cheat Sheet](./guide/cheatsheet.md) — 1 printable page with daily essentials
**Interactive onboarding** (no clone needed):
**Interactive onboarding** (no setup needed):
```bash
claude "Fetch and follow the onboarding instructions from: https://raw.githubusercontent.com/FlorianBruniaux/claude-code-ultimate-guide/main/tools/onboarding-prompt.md"
```
**Browse directly**: [Full Guide](./guide/ultimate-guide.md) | [Visual Diagrams](./guide/diagrams/) | [Examples](./examples/) | [Quiz](./quiz/)
<details>
<summary><strong>Prerequisites & Minimal CLAUDE.md Template</strong></summary>
---
**Prerequisites**: Node.js 18+ | [Anthropic API key](https://console.anthropic.com/)
## 🔌 MCP Server — Use the guide from any Claude Code session
```markdown
# Project: [NAME]
No cloning needed. Add to `~/.claude.json` and ask questions directly from any session:
## Tech Stack
- Language: [e.g., TypeScript]
- Framework: [e.g., Next.js 14]
- Testing: [e.g., Vitest]
## Commands
- Build: `npm run build`
- Test: `npm test`
- Lint: `npm run lint`
## Rules
- Run tests before marking tasks complete
- Follow existing code patterns
- Keep commits atomic and conventional
```json
{
"mcpServers": {
"claude-code-guide": {
"type": "stdio",
"command": "npx",
"args": ["-y", "claude-code-ultimate-guide-mcp"]
}
}
}
```
Save as `CLAUDE.md` in your project root. Claude reads it automatically.
12 tools: `search_guide`, `read_section`, `get_cheatsheet`, `get_digest`, `get_example`, `list_examples`, `get_release`, `get_changelog`, `list_topics`, `compare_versions`, `get_threat`, `list_threats`, `search_examples` — plus 8 slash commands `/ccguide:*` and a Haiku agent.
</details>
**Onboarding one-liner** (once MCP is configured):
```bash
claude "Use the claude-code-guide MCP server. Activate the claude-code-expert prompt, then run a personalized onboarding: ask me 3 questions about my goal, experience level, and preferred tone — then build a custom learning path using search_guide and read_section to navigate the guide with live source links."
```
→ [MCP Server README](./mcp-server/README.md)
---

View file

@ -277,6 +277,7 @@ Beyond the 8 core tools, Claude Code can leverage:
- **Context7**: Official library documentation lookup
- **Sequential**: Structured multi-step reasoning
- **Playwright**: Browser automation and E2E testing
- **claude-code-ultimate-guide**: 12 tools — guide search, release tracking, `compare_versions`, security threat lookup (`get_threat`, `list_threats` with 28 CVEs + 655 malicious skills), template search (`search_examples`) — `npx -y claude-code-ultimate-guide-mcp`
**Community Plugins**:
- **ast-grep**: AST-based structural code search (explicit invocation)

78
mcp-server/IDEAS.md Normal file
View file

@ -0,0 +1,78 @@
# MCP Server — Future Ideas
Tracked ideas that didn't make it into the current release. Implementation complexity varies; all are technically feasible with existing data.
---
## Tools
### `get_quiz(topic?, count?)`
Interactive quiz from `machine-readable/questions.json` (274 questions, already used by the landing site).
- `topic` (optional string): filter by topic (e.g. "hooks", "agents", "mcp")
- `count` (optional number, default 5, max 20): number of questions to return
- Returns questions with options, correct answer, and explanation
- Useful for learning validation, onboarding, and teaching workflows
**Data**: `machine-readable/questions.json` — not currently bundled in the package; would need bundling or GitHub fetch.
---
### `get_methodology(name)`
Step-by-step workflows for TDD, SDD, BDD from `guide/methodologies.md`.
- `name` (string): `tdd | sdd | bdd | all`
- Returns the workflow steps, when to use it, and example commands
- Useful for agents doing test-driven development or spec-driven design
**Data**: `guide/methodologies.md` — fetched on demand (already in section-reader infrastructure).
---
### `get_workflow(name)`
Step-by-step workflows from `guide/workflows/` directory.
- `name` (string): partial name match (e.g. "code-review", "refactor", "debug")
- Returns the workflow with steps, triggers, and example prompts
- Could list available workflows when no name provided
**Data**: `guide/workflows/*.md` — fetched on demand.
---
## Resources
### `claude-code-guide://diff`
Shows what changed between the bundled YAML index version and the live GitHub version.
- Fetch live `machine-readable/reference.yaml` from GitHub
- Diff against bundled version (entry count, new keys, changed values)
- Helps users know when the package is stale vs. the guide
**Complexity**: Medium — requires async resource handler + structured diffing.
---
## Prompts
### `security-review`
Dedicated security audit workflow prompt using the threat database.
- Guides the model through: check CVEs → check authors → check skills → check techniques
- Returns a structured security posture report
- Reuses `list_threats` and `get_threat` tools internally
**Dependency**: Requires `threats.ts` tools (already implemented in v1.1.0).
---
## Notes
- All ideas use data already in the repo — no new data sources needed
- `get_quiz` requires bundling `questions.json` (currently not in npm package)
- `get_methodology` and `get_workflow` are low-effort since section-reader already handles arbitrary file fetching

230
mcp-server/README.md Normal file
View file

@ -0,0 +1,230 @@
# claude-code-ultimate-guide-mcp
MCP server for the [Claude Code Ultimate Guide](https://github.com/FlorianBruniaux/claude-code-ultimate-guide) — search, read, and explore 20,000+ lines of documentation directly from Claude Code or any MCP-compatible client.
No need to clone the repo. The guide's structured index is bundled in the package (~130KB compressed), and file content is fetched from GitHub on demand with 24h local cache.
## Installation
### Quick start (npx)
Add to `~/.claude.json` (user-level, all projects):
```json
{
"mcpServers": {
"claude-code-guide": {
"type": "stdio",
"command": "npx",
"args": ["-y", "claude-code-ultimate-guide-mcp"]
}
}
}
```
### Global install
```bash
npm install -g claude-code-ultimate-guide-mcp
```
```json
{
"mcpServers": {
"claude-code-guide": {
"type": "stdio",
"command": "claude-code-guide-mcp"
}
}
}
```
### Per-project
Add to `.claude/settings.json` at your repo root.
## Tools
### Search & Navigation
| Tool | Signature | Description |
|------|-----------|-------------|
| `search_guide` | `(query, limit?)` | Search by keyword or question across 882 indexed entries. Returns ranked results with GitHub links. |
| `read_section` | `(path, offset?, limit?)` | Read a file section with pagination (500 lines max per call). Returns GitHub + guide site links. |
| `list_topics` | `()` | Browse all 25 topic categories in the guide with entry counts. |
### Templates & Examples
| Tool | Signature | Description |
|------|-----------|-------------|
| `get_example` | `(name)` | Fetch a production-ready template by exact name (agents, hooks, commands, skills). |
| `list_examples` | `(category?)` | List all templates by category with GitHub links. Categories: `agents`, `commands`, `hooks`, `skills`, `scripts`. |
| `search_examples` | `(query, limit?)` | Semantic search across all templates by intent (e.g. `"hook lint"`, `"agent code review"`). |
### What's New
| Tool | Signature | Description |
|------|-----------|-------------|
| `get_changelog` | `(count?)` | Last N entries from the guide CHANGELOG (default 5, max 20). |
| `get_digest` | `(period)` | Combined digest of guide changes + Claude Code CLI releases. Period: `day`, `week`, `month`. |
| `get_release` | `(version?, count?)` | Claude Code CLI release details. Pass a version (e.g. `"2.1.59"`) or omit for latest + recent N. |
| `compare_versions` | `(from, to?)` | Diff between two Claude Code versions: aggregated highlights and breaking changes for all releases in range. |
### Security Intelligence
| Tool | Signature | Description |
|------|-----------|-------------|
| `get_threat` | `(id)` | Look up a CVE (e.g. `"CVE-2025-53109"`) or attack technique (e.g. `"T001"`) from the threat database. |
| `list_threats` | `(category?)` | Browse the threat database. Without category: global summary with counts. With category: full section list. Categories: `cves`, `authors`, `skills`, `techniques`, `mitigations`, `sources`. |
### Quick Reference
| Tool | Signature | Description |
|------|-----------|-------------|
| `get_cheatsheet` | `(section?)` | Full cheatsheet or filtered to a specific section (e.g. `"hooks"`, `"agents"`, `"mcp"`). |
## Resources
| URI | Description |
|-----|-------------|
| `claude-code-guide://reference` | Full structured index (94KB YAML, ~900 entries) — use as fallback when search isn't enough |
| `claude-code-guide://releases` | Claude Code official releases history (YAML) |
| `claude-code-guide://llms` | Guide identity/navigation file (llms.txt) |
## Prompts
| Prompt | Args | Description |
|--------|------|-------------|
| `claude-code-expert` | `question?` | Activates expert mode with optimal workflow: search → read → example → YAML fallback |
## Onboarding (first run)
After installing the MCP server, run this in any Claude Code session for a personalized guided tour:
```bash
claude "Use the claude-code-guide MCP server. Activate the claude-code-expert prompt, then run a personalized onboarding: ask me 3 questions about my goal, experience level, and preferred tone — then build a custom learning path using search_guide and read_section to navigate the guide with live source links."
```
This replaces the static URL-fetch approach with live search across 900+ indexed entries, always up to date, with GitHub + guide site links on every result.
## Usage examples
```
# Search
search_guide("hooks")
search_guide("cost optimization")
search_guide("custom agents")
# Read content
read_section("guide/ultimate-guide.md", 8077)
read_section("guide/cheatsheet.md")
# Templates
get_example("code-reviewer")
get_example("pre-commit hook")
list_examples("agents")
list_examples("hooks")
search_examples("hook lint")
search_examples("agent code review")
# What's new
get_digest("week")
get_digest("month")
get_changelog(10)
get_release()
get_release("2.1.59")
compare_versions("2.1.50", "2.1.59")
compare_versions("2.0.0")
# Security
get_threat("CVE-2025-53109")
get_threat("T001")
list_threats()
list_threats("cves")
list_threats("techniques")
# Quick reference
get_cheatsheet()
get_cheatsheet("hooks")
list_topics()
```
## Slash command shortcuts
Install the companion slash commands for one-keystroke access in Claude Code. They live in `.claude/commands/ccguide/` of the guide repo — copy or symlink to `~/.claude/commands/ccguide/` for global availability.
```bash
# From the guide repo root
cp -r .claude/commands/ccguide ~/.claude/commands/ccguide
```
Once installed, these commands are available in any Claude Code session:
| Command | Example | What it does |
|---------|---------|--------------|
| `/ccguide:search <query>` | `/ccguide:search hooks` | Search + auto-read top results |
| `/ccguide:cheatsheet [section]` | `/ccguide:cheatsheet hooks` | Full cheatsheet or filtered |
| `/ccguide:digest <period>` | `/ccguide:digest week` | Guide + CC releases digest |
| `/ccguide:example <name>` | `/ccguide:example code-reviewer` | Fetch a template |
| `/ccguide:examples [category]` | `/ccguide:examples agents` | List templates by category |
| `/ccguide:release [version]` | `/ccguide:release 2.1.59` | CC CLI release details |
| `/ccguide:changelog [count]` | `/ccguide:changelog 10` | Recent guide CHANGELOG |
| `/ccguide:topics` | `/ccguide:topics` | Browse all 25 categories |
## Custom agent
A `claude-code-guide` agent is included in `.claude/agents/claude-code-guide.md`. It uses Haiku (fast, cheap) and searches the guide automatically before answering Claude Code questions.
Copy to your `~/.claude/agents/` to use it globally:
```bash
cp .claude/agents/claude-code-guide.md ~/.claude/agents/claude-code-guide.md
```
Then invoke with: `use claude-code-guide agent to answer: how do I configure hooks?`
## Dev mode (local repo)
If you've cloned the guide repo, set `GUIDE_ROOT` to read files locally instead of fetching from GitHub:
```json
{
"mcpServers": {
"claude-code-guide": {
"type": "stdio",
"command": "node",
"args": ["/path/to/claude-code-ultimate-guide/mcp-server/dist/index.js"],
"env": {
"GUIDE_ROOT": "/path/to/claude-code-ultimate-guide"
}
}
}
}
```
With `GUIDE_ROOT` set:
- YAML indexes loaded from the local repo (stays in sync with local changes)
- File content read directly from disk (no GitHub fetch, no cache)
## Bundled content
The npm package includes (~130KB compressed total):
- `content/reference.yaml` — 94KB structured index (~900 entries, ~882 indexed)
- `content/claude-code-releases.yaml` — 27KB releases history (76 releases)
- `content/llms.txt` — 8KB identity file
Guide markdown files (3.5MB) are **not** bundled — they're fetched from GitHub on demand and cached at `~/.cache/claude-code-guide/{version}/`.
## Cache
File content is cached at `~/.cache/claude-code-guide/{package-version}/` with 24h TTL. If offline, stale cache is served as fallback. If no cache exists and offline, tools return inline summaries from the YAML index instead.
## MCP Inspector
Test locally with the official MCP Inspector:
```bash
cd mcp-server
npm run build
GUIDE_ROOT=.. npx @modelcontextprotocol/inspector node dist/index.js
```

View file

@ -0,0 +1,701 @@
# Claude Code Official Releases (condensed)
# Source: github.com/anthropics/claude-code/CHANGELOG.md
# Purpose: Track Claude Code product releases for documentation sync
# Maintained: Manual updates when new releases are announced
latest: "2.1.59"
updated: "2026-02-26"
# ════════════════════════════════════════════════════════════════
# RELEASES (newest first, condensed highlights only)
# ════════════════════════════════════════════════════════════════
releases:
# ─────────────────────────────────────────────────────────────
# 2.1.x Series (January-February 2026)
# ─────────────────────────────────────────────────────────────
- version: "2.1.59"
date: "2026-02-26"
highlights:
- "⭐ Auto-memory: Claude automatically saves useful context; manage with /memory"
- "⭐ /copy command: interactive picker for selecting individual code blocks or full response"
- "Smarter 'always allow' prefix suggestions for compound bash commands (per-subcommand prefixes)"
- "Fixed MCP OAuth token refresh race condition with multiple simultaneous instances"
- "Fixed config file corruption wiping authentication when multiple instances ran simultaneously"
breaking: []
- version: "2.1.58"
date: "2026-02-26"
highlights:
- "Remote Control expanded to more users"
breaking: []
- version: "2.1.56"
date: "2026-02-25"
highlights:
- "VSCode: Fixed another cause of 'command claude-vscode.editor.openLast not found' crashes"
breaking: []
- version: "2.1.55"
date: "2026-02-25"
highlights:
- "Fixed BashTool failing on Windows with EINVAL error"
breaking: []
- version: "2.1.53"
date: "2026-02-25"
highlights:
- "Stability fixes: panic on Windows, crashes on process spawn (Windows), WebAssembly crashes (Linux x64/Windows x64/ARM64)"
- "Fixed graceful shutdown leaving stale sessions with Remote Control; `--worktree` flag sometimes ignored on first launch"
- "Fixed UI flicker where user input disappeared briefly after submission; bulk agent kill (ctrl+f) single notification"
breaking: []
- version: "2.1.52"
date: "2026-02-24"
highlights:
- "VSCode: Fixed extension crash on Windows ('command claude-vscode.editor.openLast not found')"
breaking: []
- version: "2.1.51"
date: "2026-02-24"
highlights:
- "⭐ `claude remote-control` subcommand for external builds enabling local environment serving"
- "BashTool skips login shell by default when shell snapshot available (was `CLAUDE_BASH_NO_LOGIN=true`); tool results persist to disk at 50K chars (was 100K)"
- "SDK: `CLAUDE_CODE_ACCOUNT_UUID`, `CLAUDE_CODE_USER_EMAIL`, `CLAUDE_CODE_ORGANIZATION_UUID` env vars for account metadata"
- "/model picker shows human-readable labels (e.g., 'Sonnet 4.5') for pinned versions; custom npm registries for plugin installs"
breaking: []
- version: "2.1.50"
date: "2026-02-21"
highlights:
- "⭐ `WorktreeCreate` and `WorktreeRemove` hook events for custom VCS setup/teardown with agent worktree isolation"
- "`isolation: worktree` in agent definitions for declarative worktree isolation; `claude agents` CLI command to list configured agents"
- "Opus 4.6 (fast mode) now has full 1M context window; `CLAUDE_CODE_DISABLE_1M_CONTEXT` env var to disable it"
- "Major memory leak fixes + startup performance improvements for headless mode; `CLAUDE_CODE_SIMPLE` now fully minimal"
breaking: []
- version: "2.1.49"
date: "2026-02-20"
highlights:
- "⭐ `--worktree` / `-w` flag to start Claude in isolated git worktree; subagents support `isolation: 'worktree'`"
- "Agent definitions support `background: true` to always run as background task"
- "`ConfigChange` hook event for enterprise security auditing (fires when config files change during session)"
- "Simple mode now includes file edit tool; many bug fixes for background agents, permissions, sessions"
breaking: []
- version: "2.1.47"
date: "2026-02-19"
highlights:
- "VS Code plan preview auto-updates as Claude iterates, commenting enabled when plan is ready"
- "⭐ `ctrl+f` to kill all background agents (replaces double-ESC); background agents continue when ESC pressed"
- "Added `last_assistant_message` field to Stop/SubagentStop hook inputs"
- "70+ bug fixes: PDF compaction, Unicode curly quotes, parallel file edits, OSC 8 hyperlinks, Windows rendering, session persistence"
breaking: []
- version: "2.1.46"
date: "2026-02-19"
highlights:
- "Fixed orphaned Claude Code processes after terminal disconnect on macOS"
- "Added support for using claude.ai MCP connectors in Claude Code"
breaking: []
- version: "2.1.45"
date: "2026-02-17"
highlights:
- "⭐ Claude Sonnet 4.6 model support"
- "`spinnerTipsOverride` setting for customizable spinner tips (with `excludeDefault` option)"
- "SDK: `SDKRateLimitInfo` and `SDKRateLimitEvent` types for rate limit tracking"
- "Fixed Agent Teams on Bedrock/Vertex/Foundry; improved memory for large shell outputs"
breaking: []
- version: "2.1.44"
date: "2026-02-17"
highlights:
- "Fixed auth refresh errors"
breaking: []
- version: "2.1.43"
date: "2026-02-17"
highlights:
- "Fixed AWS auth refresh hanging indefinitely (3-minute timeout added)"
- "Fixed structured-outputs beta header sent unconditionally on Vertex/Bedrock"
- "Fixed spurious warnings for non-agent markdown files in `.claude/agents/`"
breaking: []
- version: "2.1.42"
date: "2026-02-14"
highlights:
- "Optimized startup via deferred Zod schema construction"
- "Improved prompt cache hit rate by moving date outside system prompt"
- "Opus 4.6 effort callout for eligible users"
- "Better error messaging for image dimension limits (suggests `/compact`)"
breaking: []
- version: "2.1.41"
date: "2026-02-13"
highlights:
- "Guard against launching Claude Code inside another Claude Code session"
- "`claude auth login/status/logout` CLI subcommands"
- "Windows ARM64 (win32-arm64) native binary support"
- "`speed` attribute in OTel events for fast mode visibility"
- "`/rename` auto-generates session name from conversation context"
- "Fixed Agent Teams wrong model for Bedrock/Vertex/Foundry"
- "Multiple stability fixes (FileReadTool FIFOs, MCP images, background tasks, stale permissions)"
breaking: []
- version: "2.1.39"
date: "2026-02-10"
highlights:
- "Improved terminal rendering performance"
- "Fixed fatal errors being swallowed instead of displayed"
- "Fixed process hanging after session close"
- "Fixed character loss at terminal screen boundary"
breaking: []
- version: "2.1.38"
date: "2026-02-10"
highlights:
- "Fixed VS Code terminal scroll-to-top regression"
- "Fixed Tab key queueing slash commands instead of autocompleting"
- "Security: Heredoc delimiter parsing to prevent command smuggling"
- "Security: Blocked writes to `.claude/skills` in sandbox mode"
breaking: []
- version: "2.1.37"
date: "2026-02-08"
highlights:
- "Fixed /fast not immediately available after enabling /extra-usage"
breaking: []
- version: "2.1.36"
date: "2026-02-08"
highlights:
- "⭐ Fast mode now available for Opus 4.6"
breaking: []
- version: "2.1.34"
date: "2026-02-07"
highlights:
- "Fixed crash when agent teams setting changed between renders"
- "Security fix: Sandbox-excluded commands could bypass Bash ask permission"
breaking:
- "Security fix: sandbox.excludedCommands / dangerouslyDisableSandbox bypass with autoAllowBashIfSandboxed"
- version: "2.1.33"
date: "2026-02-06"
highlights:
- "Agent teams fixes: tmux sessions, availability warnings"
- "`TeammateIdle` and `TaskCompleted` hook events for multi-agent workflows"
- "Agent frontmatter: `memory` field (user/project/local), `Task(agent_type)` sub-agent restriction"
- "VSCode: Remote sessions, branch/message count in session picker"
breaking: []
- version: "2.1.32"
date: "2026-02-05"
highlights:
- "⭐ Opus 4.6 is now available"
- "⭐ Agent teams preview (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)"
- "⭐ Automatic memory recording and recall"
- "'Summarize from here' for partial conversation summarization"
breaking: []
- version: "2.1.31"
date: "2026-02-03"
highlights:
- "Session resume hint on exit showing how to continue"
- "Fixed PDF errors locking sessions & bash sandbox errors"
- "LSP compatibility improvements & terminal rendering fixes"
breaking: []
- version: "2.1.30"
date: "2026-02-02"
highlights:
- "`pages` parameter for Read tool PDFs (e.g., `pages: '1-5'`)"
- "Pre-configured OAuth for MCP servers (Slack support)"
- "⭐ `/debug` command for session troubleshooting"
- "git log/show read-only flags support"
- "Task tool metrics (tokens, duration, tool uses)"
breaking: []
- version: "2.1.29"
date: "2026-01-31"
highlights:
- "Fixed startup performance with saved hook context"
- "Improved session recovery speed for long-duration sessions"
breaking: []
- version: "2.1.27"
date: "2026-01-29"
highlights:
- "`--from-pr` flag to resume sessions linked to GitHub PR number/URL"
- "Sessions auto-linked to PRs when created via `gh pr create`"
- "Windows: Fixed bash execution and console flashing issues"
- "VSCode: Fixed OAuth token expiration (401 errors)"
breaking: []
- version: "2.1.25"
date: "2026-01-30"
highlights:
- "Fixed beta header validation for Bedrock/Vertex gateway users"
breaking: []
- version: "2.1.23"
date: "2026-01-29"
highlights:
- "Customizable spinner verbs setting (spinnerVerbs)"
- "mTLS and corporate proxy connectivity fixes"
- "Improved terminal rendering performance"
breaking: []
- version: "2.1.22"
date: "2026-01-28"
highlights:
- "Improved task UI performance with virtualization"
- "Vim selection and deletion fixes"
- "LSP improvements: Kotlin support, UTF-16 ranges"
breaking: []
- version: "2.1.21"
date: "2026-01-28"
highlights:
- "Skills/commands can specify required/recommended Claude Code version"
- "New TaskCreate fields: category, checklist, parentId"
- "Automatic Claude Code update checking at session start"
- "Tasks appear in /context with 'Disable tasks' shortcut"
breaking: []
- version: "2.1.20"
date: "2026-01-27"
highlights:
- "TaskUpdate: status='deleted' for task removal"
- "PR review status indicator (colored dot + link)"
breaking: []
- version: "2.1.19"
date: "2026-01-25"
highlights:
- "New: CLAUDE_CODE_ENABLE_TASKS env var (set false for old task system)"
- "New: Shorthand $0, $1 for arguments in custom commands"
- "[VSCode] Session forking and rewind enabled for all users"
- "Fixed: Multiple session resuming/naming issues with git worktrees"
breaking:
- "Indexed argument syntax changed: $ARGUMENTS.0 → $ARGUMENTS[0] (bracket syntax)"
- version: "2.1.18"
date: "2026-01-24"
highlights:
- "⭐ Customizable keyboard shortcuts with /keybindings command"
- "Per-context keybindings, chord sequences, workflow personalization"
breaking: []
- version: "2.1.17"
date: "2026-01-23"
highlights:
- "Fix: Crashes on processors without AVX instruction support"
breaking: []
- version: "2.1.16"
date: "2026-01-22"
highlights:
- "⭐ New task management system with dependency tracking"
- "[VSCode] Native plugin management support"
- "[VSCode] OAuth users can browse/resume remote sessions"
- "Fixed: OOM crashes when resuming sessions with heavy subagent usage"
breaking: []
- version: "2.1.15"
date: "2026-01-22"
highlights:
- "⚠️ Deprecation notice for npm installations (use `claude install`)"
- "UI rendering performance improved with React Compiler"
- "Fixed: MCP stdio server timeout not killing child process"
breaking:
- "npm installations deprecated - migrate to native installer"
- version: "2.1.14"
date: "2026-01-21"
highlights:
- "History-based autocomplete in bash mode (! + Tab)"
- "Search in installed plugins list"
- "Git commit SHA pinning for plugins"
- "Multiple fixes: context window, memory, autocomplete"
breaking: []
- version: "2.1.12"
date: "2026-01-18"
highlights:
- "Bug fix: Message rendering"
breaking: []
- version: "2.1.11"
date: "2026-01-17"
highlights:
- "Fix: Excessive MCP connection requests for HTTP/SSE transports"
breaking: []
- version: "2.1.10"
date: "2026-01-17"
highlights:
- "New `Setup` hook event (--init, --init-only, --maintenance flags)"
- "Keyboard shortcut 'c' to copy OAuth URL"
- "File suggestions show as removable attachments"
- "[VSCode] Plugin install count + trust warnings"
breaking: []
- version: "2.1.9"
date: "2026-01-16"
highlights:
- "`auto:N` syntax for MCP tool search threshold"
- "`plansDirectory` setting for custom plan file locations"
- "Session URL attribution to commits/PRs from web sessions"
- "PreToolUse hooks can return `additionalContext`"
- "${CLAUDE_SESSION_ID} string substitution for skills"
breaking: []
- version: "2.1.7"
date: "2026-01-15"
highlights:
- "`showTurnDuration` setting to hide turn duration messages"
- "MCP tool search auto mode enabled by default"
- "Inline display of agent final response in task notifications"
breaking:
- "OAuth/API Console URLs: console.anthropic.com → platform.claude.com"
- "Security fix: Wildcard permission rules could match compound commands"
- version: "2.1.6"
date: "2026-01-14"
highlights:
- "Search functionality in /config command"
- "Date range filtering in /stats (r to cycle)"
- "Auto-discovery of skills from nested .claude/skills directories"
- "Updates section in /doctor showing auto-update channel"
breaking:
- "Security fix: Permission bypass via shell line continuation"
- version: "2.1.5"
date: "2026-01-13"
highlights:
- "`CLAUDE_CODE_TMPDIR` env var for custom temp directory"
breaking: []
- version: "2.1.4"
date: "2026-01-12"
highlights:
- "`CLAUDE_CODE_DISABLE_BACKGROUND_TASKS` env var"
breaking: []
- version: "2.1.3"
date: "2026-01-11"
highlights:
- "Merged slash commands and skills (simplified mental model)"
- "Release channel toggle (stable/latest) in /config"
- "/doctor warnings for unreachable permission rules"
breaking: []
- version: "2.1.2"
date: "2026-01-10"
highlights:
- "Windows Package Manager (winget) support"
- "Clickable hyperlinks for file paths (OSC 8 terminals)"
- "Shift+Tab shortcut in plan mode for auto-accept edits"
- "Large bash outputs saved to disk instead of truncated"
breaking:
- "Security fix: Command injection in bash command processing"
- "Deprecated: C:\\ProgramData\\ClaudeCode managed settings path"
- version: "2.1.0"
date: "2026-01-08"
highlights:
- "⭐ MAJOR: Automatic skill hot-reload"
- "⭐ MAJOR: Shift+Enter works OOTB (iTerm2, WezTerm, Ghostty, Kitty)"
- "⭐ MAJOR: New Vim motions (;, y, p, text objects, >>, <<, J)"
- "Unified Ctrl+B for backgrounding all tasks"
- "/plan command shortcut"
- "Slash command autocomplete anywhere in input"
- "`language` setting for response language"
- "Skills context: fork support"
- "Hooks support in agent/skill frontmatter"
- "MCP list_changed notifications support"
- "/teleport and /remote-env commands"
- "Tab support for disabling specific agents"
- "--tools flag in interactive mode"
- "YAML-style lists in frontmatter allowed-tools"
breaking:
- "OAuth URLs: console.anthropic.com → platform.claude.com"
- "Removed permission prompt for entering plan mode"
- "[SDK] Minimum zod peer dependency: ^4.0.0"
# ─────────────────────────────────────────────────────────────
# 2.0.x Series (December 2025 - January 2026)
# ─────────────────────────────────────────────────────────────
- version: "2.0.76"
date: "2026-01-05"
highlights:
- "Fix: macOS code-sign warning with Claude in Chrome"
breaking: []
- version: "2.0.74"
date: "2026-01-04"
highlights:
- "⭐ LSP (Language Server Protocol) tool for code intelligence"
- "/terminal-setup for Kitty, Alacritty, Zed, Warp"
- "Ctrl+T in /theme to toggle syntax highlighting"
- "Grouped skills/agents by source in /context"
breaking: []
- version: "2.0.73"
date: "2026-01-03"
highlights:
- "Clickable [Image #N] links"
- "Alt-Y yank-pop to cycle kill ring history"
- "Search filtering in plugin discover screen"
- "[VSCode] Tab icon badges (permissions, unread)"
breaking: []
- version: "2.0.72"
date: "2026-01-02"
highlights:
- "⭐ Claude in Chrome (Beta) - browser control from Claude Code"
- "Reduced terminal flickering"
- "QR code for mobile app"
- "Thinking toggle: Tab → Alt+T"
breaking: []
- version: "2.0.71"
date: "2026-01-01"
highlights:
- "/config toggle for prompt suggestions"
- "/settings alias for /config"
- "New Rust-based syntax highlighting engine"
breaking: []
- version: "2.0.70"
date: "2025-12-30"
highlights:
- "Enter key accepts/submits prompt suggestions immediately"
- "Wildcard syntax mcp__server__* for MCP tool permissions"
- "Auto-update toggle for plugin marketplaces"
- "3x memory usage improvement for large conversations"
breaking:
- "Removed # shortcut for quick memory entry"
- version: "2.0.68"
date: "2025-12-28"
highlights:
- "IME support for Chinese, Japanese, Korean"
- "Enterprise managed settings support"
- "Improved plan mode exit UX"
breaking: []
- version: "2.0.67"
date: "2025-12-26"
highlights:
- "⭐ Thinking mode enabled by default for Opus 4.5"
- "Thinking config moved to /config"
- "Search in /permissions with / shortcut"
breaking: []
- version: "2.0.65"
date: "2025-12-24"
highlights:
- "Alt+P to switch models while writing prompt"
- "Context window info in status line"
- "`fileSuggestion` setting for custom @ search"
- "CLAUDE_CODE_SHELL env var"
breaking: []
- version: "2.0.64"
date: "2025-12-22"
highlights:
- "⭐ Instant auto-compacting"
- "⭐ Async agents and bash commands with wake-up messages"
- "/stats with usage graphs, streaks, favorite model"
- "Named sessions: /rename, /resume <name>"
- "Support for .claude/rules/ directory"
- "Image dimension metadata for coordinate mappings"
breaking:
- "Unshipped AgentOutputTool/BashOutputTool → TaskOutputTool"
- version: "2.0.62"
date: "2025-12-20"
highlights:
- "`attribution` setting for commit/PR bylines"
- "(Recommended) indicator in multiple-choice questions"
breaking:
- "Deprecated: includeCoAuthoredBy (use attribution)"
- version: "2.0.60"
date: "2025-12-18"
highlights:
- "⭐ Background agents (work while you work)"
- "--disable-slash-commands CLI flag"
- "Model name in Co-Authored-By commits"
- "/mcp enable|disable [server-name]"
breaking: []
- version: "2.0.58"
date: "2025-12-16"
highlights:
- "⭐ Opus 4.5 available for Pro users"
breaking:
- "[Windows] Managed settings prefer C:\\Program Files\\ClaudeCode"
- version: "2.0.57"
date: "2025-12-15"
highlights:
- "Feedback input when rejecting plans"
- "[VSCode] Streaming message support"
breaking: []
- version: "2.0.55"
date: "2025-12-13"
highlights:
- "Improved AskUserQuestion auto-submit"
- "Better fuzzy matching for @ file suggestions"
breaking:
- "Proxy DNS opt-in: CLAUDE_CODE_PROXY_RESOLVES_HOSTS=true"
- version: "2.0.51"
date: "2025-12-10"
highlights:
- "⭐ MAJOR: Opus 4.5 released"
- "⭐ MAJOR: Claude Code for Desktop"
- "Updated usage limits for Opus 4.5"
- "Plan Mode builds more precise plans"
breaking: []
- version: "2.0.45"
date: "2025-12-05"
highlights:
- "⭐ Microsoft Foundry support"
- "PermissionRequest hook for auto-approve/deny"
- "& prefix for background tasks to web"
breaking: []
- version: "2.0.43"
date: "2025-12-03"
highlights:
- "`permissionMode` field for custom agents"
- "`skills` frontmatter for auto-loading subagent skills"
- "SubagentStart hook event"
breaking: []
- version: "2.0.41"
date: "2025-12-01"
highlights:
- "Model parameter for prompt-based stop hooks"
- "Plugins: sharing and installing output styles"
- "Allow more safe git commands without approval"
- "Teleporting from web auto-sets upstream branch"
breaking: []
- version: "2.0.37"
date: "2025-11-28"
highlights:
- "Matcher values for Notification hook events"
- "Output Styles: keep-coding-instructions option"
breaking: []
- version: "2.0.35"
date: "2025-11-26"
highlights:
- "Improved fuzzy search for commands"
- "CLAUDE_CODE_EXIT_AFTER_STOP_DELAY env var"
breaking:
- "Migrated ignorePatterns to deny permissions"
- version: "2.0.32"
date: "2025-11-23"
highlights:
- "Output styles un-deprecated (community feedback)"
- "`companyAnnouncements` setting"
breaking: []
- version: "2.0.30"
date: "2025-11-20"
highlights:
- "`allowUnsandboxedCommands` sandbox setting"
- "`disallowedTools` for custom agent definitions"
- "Prompt-based stop hooks"
- "SSE MCP servers on native build"
breaking:
- "Deprecated: Output styles (later un-deprecated in 2.0.32)"
- "Removed: Custom ripgrep configuration"
- version: "2.0.28"
date: "2025-11-18"
highlights:
- "⭐ Plan mode: introduced Plan subagent"
- "Subagents: resume capability"
- "Subagents: dynamic model selection"
- "--max-budget-usd flag (SDK)"
- "Git-based plugins branch/tag support (#branch)"
breaking: []
- version: "2.0.27"
date: "2025-11-15"
highlights:
- "New UI for permission prompts"
- "Branch filtering and search in session resume"
breaking: []
- version: "2.0.25"
date: "2025-11-12"
highlights: []
breaking:
- "Removed legacy SDK entrypoint → @anthropic-ai/claude-agent-sdk"
- version: "2.0.24"
date: "2025-11-10"
highlights:
- "Claude Code Web: Web → CLI teleport"
- "Sandbox mode for BashTool (Linux & Mac)"
- "Bedrock: awsAuthRefresh output display"
breaking: []
# ════════════════════════════════════════════════════════════════
# SUMMARY - Key Breaking Changes by Area
# ════════════════════════════════════════════════════════════════
breaking_summary:
urls:
- "OAuth/API Console: console.anthropic.com → platform.claude.com (v2.1.0, v2.1.7)"
windows:
- "Managed settings: C:\\ProgramData\\ClaudeCode → C:\\Program Files\\ClaudeCode (v2.0.58, deprecated v2.1.2)"
sdk:
- "Removed legacy SDK entrypoint → @anthropic-ai/claude-agent-sdk (v2.0.25)"
- "Minimum zod peer dependency: ^4.0.0 (v2.1.0)"
shortcuts:
- "Removed # shortcut for quick memory (v2.0.70)"
security:
- "Command injection fix in bash processing (v2.1.2)"
- "Wildcard permission rules compound commands fix (v2.1.7)"
- "Shell line continuation permission bypass fix (v2.1.6)"
- "Sandbox-excluded commands bypass with autoAllowBashIfSandboxed (v2.1.34)"
- "Heredoc delimiter command smuggling prevention (v2.1.38)"
installation:
- "npm installations deprecated - use native installer (v2.1.15)"
behavior:
- "ultrathink/think keywords now cosmetic only — thinking default with Opus 4.5 (v2.0.67)"
syntax:
- "Indexed argument syntax changed: $ARGUMENTS.0 → $ARGUMENTS[0] (v2.1.19)"
# ════════════════════════════════════════════════════════════════
# MILESTONE FEATURES (quick reference)
# ════════════════════════════════════════════════════════════════
milestones:
"2.1.36": "Fast mode for Opus 4.6"
"2.1.32": "Opus 4.6, Agent teams preview, Automatic memory"
"2.1.18": "Customizable keyboard shortcuts with /keybindings"
"2.1.16": "New task management system with dependency tracking"
"2.1.0": "Skill hot-reload, Shift+Enter OOTB, Vim motions, /plan command"
"2.0.74": "LSP tool for code intelligence"
"2.0.72": "Claude in Chrome (browser control)"
"2.0.67": "Thinking mode default for Opus 4.5"
"2.0.64": "Instant auto-compact, async agents, named sessions"
"2.0.60": "Background agents"
"2.0.51": "Opus 4.5, Claude Code for Desktop"
"2.0.45": "Microsoft Foundry, PermissionRequest hook"
"2.0.28": "Plan subagent, subagent resume/model selection"
"2.0.24": "Web teleport, Sandbox mode"

166
mcp-server/content/llms.txt Normal file
View file

@ -0,0 +1,166 @@
# The Ultimate Claude Code Guide
> A comprehensive, self-contained guide to mastering Claude Code - Anthropic's official CLI for AI-assisted development.
## What This Repository Contains
This repository provides everything needed to go from Claude Code beginner to power user:
1. **Complete Guide** (`guide/ultimate-guide.md`) - 9,600+ lines covering all aspects of Claude Code
2. **Cheatsheet** (`guide/cheatsheet.md`) - 1-page printable daily reference
3. **Architecture Internals** (`guide/architecture.md`) - How Claude Code works under the hood (master loop, tools, context)
4. **Audit Prompt** (`tools/audit-prompt.md`) - Self-contained prompt to analyze your Claude Code setup against best practices
## Target Audience
- **Beginners**: Installation, first workflow, essential commands (15 min to productivity)
- **Intermediate**: Memory files, agents, skills, hooks configuration
- **Power Users**: MCP servers, Trinity pattern, CI/CD integration, autonomous workflows
## Key Topics Covered
### Core Concepts
- Context Management (the most critical concept - context windows, compaction, zones)
- Plan Mode (safe read-only exploration before making changes)
- Memory Files (CLAUDE.md for persistent context across sessions)
- Rewind (undo mechanism for file changes)
### Customization
- **Agents**: Custom AI personas with specific tools and instructions
- **Skills**: Reusable knowledge modules for complex domains
- **Commands**: Custom slash commands for frequent workflows
- **Hooks**: Event-driven automation (PreToolUse, PostToolUse, UserPromptSubmit)
### Advanced Features
- **MCP Servers**: Model Context Protocol for extended capabilities
- Serena (codebase indexation + session memory)
- Context7 (library documentation lookup)
- Sequential (structured multi-step reasoning)
- Playwright (browser automation)
- **Trinity Pattern**: Combining Plan Mode + Extended Thinking + MCP for complex tasks
- **CI/CD Integration**: Headless mode, GitHub Actions, Verify Gate pattern
### Best Practices
- Single Source of Truth pattern for conventions
- Shell Scripts vs AI Agents decision framework
- Tight feedback loops for rapid iteration
- Continuous improvement mindset
## File Structure
```
claude-code-ultimate-guide/
├── README.md # Overview and quick start
├── CONTRIBUTING.md # Contribution guidelines
├── CHANGELOG.md # Version history
├── LICENSE # CC BY-SA 4.0
├── guide/ # Core documentation
│ ├── ultimate-guide.md # Complete guide (main content)
│ ├── cheatsheet.md # 1-page reference
│ ├── architecture.md # How Claude Code works internally
│ └── adoption-approaches.md # Implementation strategy
├── tools/ # Interactive utilities
│ ├── audit-prompt.md # Setup audit tool
│ ├── onboarding-prompt.md # Personalized onboarding
│ └── mobile-access.md # Mobile access setup
├── machine-readable/ # LLM/AI consumption
│ ├── reference.yaml # Machine-optimized index
│ └── llms.txt # This file (for AI indexation)
├── exports/ # Generated outputs
│ ├── notebooklm.pdf # Visual overview
│ └── kimi.pdf # Full text export
├── examples/ # Ready-to-use templates
│ ├── agents/ # Custom AI personas
│ ├── skills/ # Knowledge modules
│ ├── commands/ # Slash commands
│ ├── hooks/ # Event automation (bash + PowerShell)
│ ├── config/ # Configuration files
│ └── memory/ # CLAUDE.md templates
└── quiz/ # Interactive knowledge quiz
```
## Guide Structure (10 Sections + Architecture)
**Architecture Deep Dive** (`guide/architecture.md`):
- Master Loop: `while(tool_call)` - no DAGs, no classifiers, no RAG
- 8 Core Tools: Bash, Read, Edit, Write, Grep, Glob, Task, TodoWrite
- Context: ~200K tokens, auto-compact at 75-92%
- Sub-agents: isolated context, max depth=1
- Philosophy: "less scaffolding, more model"
**Main Guide Sections** (`guide/ultimate-guide.md`):
1. **Quick Start** - Installation, first workflow, essential commands
2. **Core Concepts** - Context management, Plan Mode, Rewind, Mental Model
3. **Memory & Settings** - CLAUDE.md files, .claude/ folder, precedence rules
4. **Agents** - Custom AI personas, Tool SEO, orchestration patterns
5. **Skills** - Reusable knowledge modules
6. **Commands** - Custom slash commands, variable interpolation
7. **Hooks** - Event-driven automation (security, formatting, logging)
8. **MCP Servers** - Serena, Context7, Sequential, Playwright, Postgres
9. **Advanced Patterns** - Trinity, CI/CD, feedback loops, vibe coding
10. **Reference** - Commands, shortcuts, troubleshooting, checklists
## Key Commands Reference
| Command | Purpose |
|---------|---------|
| `/help` | Show all available commands |
| `/status` | Check context usage and session state |
| `/compact` | Compress context (use when >70%) |
| `/clear` | Fresh start (reset conversation) |
| `/plan` | Enter safe read-only planning mode |
| `/rewind` | Undo recent changes |
## Context Management Rules
- **Green Zone (0-50%)**: Work freely
- **Yellow Zone (50-70%)**: Be selective with context loading
- **Red Zone (70-90%)**: Use `/compact` immediately
- **Critical (90%+)**: Use `/clear` to reset
## Platform Support
- **macOS/Linux**: Full support with bash/zsh examples
- **Windows**: PowerShell and batch file alternatives provided (note: Windows commands are AI-generated and not tested by the author)
## Related Resources
- Official: https://docs.anthropic.com/en/docs/claude-code
- Official llms.txt (index): https://code.claude.com/docs/llms.txt
- Official llms-full.txt (complete): https://code.claude.com/docs/llms-full.txt
- DeepWiki: https://deepwiki.com/FlorianBruniaux/claude-code-ultimate-guide
- Inspiration: https://claudelog.com/
- Whitepapers (FR + EN): https://www.florian.bruniaux.com/guides — 9 focused whitepapers on Claude Code (foundations, prompting, customization, security, architecture, team, privacy, reference, agent teams)
## Author
Florian BRUNIAUX - Founding Engineer at Méthode Aristote
- GitHub: https://github.com/FlorianBruniaux
- LinkedIn: https://www.linkedin.com/in/florian-bruniaux-43408b83/
## License
CC BY-SA 4.0 - Free to share and adapt with attribution.
## How to Use This Guide
1. **New to Claude Code?** Start with README.md Quick Start section
2. **Choose your path** See Learning Paths in README for audience-specific guides
3. **Want comprehensive learning?** Read guide/ultimate-guide.md
4. **Need daily reference?** Print guide/cheatsheet.md
5. **Want to audit your setup?** Use tools/audit-prompt.md
6. **Need templates?** Browse examples/ folder for ready-to-use configs
## Machine-Optimized Reference
For fast LLM parsing, see `machine-readable/reference.yaml` (~2K tokens) - structured YAML with:
- Decision tree for task routing
- Prompting formula (WHAT/WHERE/HOW/VERIFY)
- Commands, shortcuts, CLI flags
- Context management zones and symptoms
- MCP servers, extended thinking, cost optimization
- Anti-patterns and troubleshooting
## Keywords
Claude Code, Anthropic, CLI, AI-assisted development, coding assistant, context management, MCP servers, agents, skills, hooks, commands, Plan Mode, CLAUDE.md, memory files, CI/CD integration, autonomous workflows, developer productivity, AI coding tools

File diff suppressed because it is too large Load diff

2604
mcp-server/package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

42
mcp-server/package.json Normal file
View file

@ -0,0 +1,42 @@
{
"name": "claude-code-ultimate-guide-mcp",
"version": "1.0.0",
"description": "MCP server for the Claude Code Ultimate Guide — search, read, and explore 20K+ lines of documentation directly from Claude Code",
"keywords": ["mcp", "claude-code", "anthropic", "documentation", "guide"],
"author": "Florian Bruniaux",
"license": "MIT",
"homepage": "https://github.com/FlorianBruniaux/claude-code-ultimate-guide",
"repository": {
"type": "git",
"url": "https://github.com/FlorianBruniaux/claude-code-ultimate-guide.git",
"directory": "mcp-server"
},
"type": "module",
"main": "./dist/index.js",
"bin": {
"claude-code-guide-mcp": "./dist/index.js"
},
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"content"
],
"scripts": {
"build": "tsup",
"dev": "GUIDE_ROOT=.. node --watch dist/index.js",
"start": "node dist/index.js",
"prepublishOnly": "npm run build"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.6.0",
"yaml": "^2.4.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"tsup": "^8.0.0",
"typescript": "^5.4.0"
},
"engines": {
"node": ">=18.0.0"
}
}

13
mcp-server/src/index.ts Normal file
View file

@ -0,0 +1,13 @@
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { createServer } from './server.js';
async function main(): Promise<void> {
const server = createServer();
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch((err) => {
process.stderr.write(`[claude-code-guide] Fatal error: ${err}\n`);
process.exit(1);
});

View file

@ -0,0 +1,36 @@
export interface ChangelogEntry {
version: string;
date: string;
dateObj: Date;
content: string;
}
export function parseChangelog(raw: string): ChangelogEntry[] {
const entries: ChangelogEntry[] = [];
// Match headers like: ## [3.27.0] - 2026-02-20 or ## [Unreleased]
const headerRe = /^## \[([^\]]+)\](?:\s*-\s*(\d{4}-\d{2}-\d{2}))?/m;
const blocks = raw.split(/^(?=## \[)/m).filter((b) => b.trim());
for (const block of blocks) {
const match = block.match(headerRe);
if (!match) continue;
const version = match[1];
const dateStr = match[2] ?? '';
const dateObj = dateStr ? new Date(dateStr) : new Date(0);
entries.push({ version, date: dateStr, dateObj, content: block.trim() });
}
return entries;
}
export function filterByPeriod(
entries: ChangelogEntry[],
period: 'day' | 'week' | 'month',
): ChangelogEntry[] {
const MS = { day: 86_400_000, week: 7 * 86_400_000, month: 30 * 86_400_000 };
const cutoff = Date.now() - MS[period];
return entries.filter(
// Include [Unreleased] (treat as today) + dated entries within the window
(e) => e.version === 'Unreleased' || e.dateObj.getTime() >= cutoff,
);
}

View file

@ -0,0 +1,278 @@
import { readFileSync } from 'fs';
import { resolve, join, sep } from 'path';
import { parse as parseYaml } from 'yaml';
import { fileURLToPath } from 'url';
import { fetchFile } from './fetcher.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = resolve(__filename, '..');
// Dual mode: GUIDE_ROOT env var = local dev, else bundled content
const GUIDE_ROOT = process.env.GUIDE_ROOT
? resolve(process.env.GUIDE_ROOT)
: null;
const CONTENT_DIR = GUIDE_ROOT
? resolve(GUIDE_ROOT, 'machine-readable')
: resolve(__dirname, '../../content');
const ALLOWED_EXTENSIONS = new Set([
'.md', '.yaml', '.yml', '.sh', '.ts', '.js', '.json', '.py', '.txt',
]);
// ─── Types ───────────────────────────────────────────────────────────────────
export type DeepDiveTarget =
| { type: 'line'; file: 'guide/ultimate-guide.md'; line: number }
| { type: 'file'; path: string; line?: number }
| { type: 'url'; url: string }
| { type: 'inline'; text: string }
| { type: 'structured'; data: unknown };
export interface IndexEntry {
key: string;
section: string;
value: unknown;
searchableText: string;
target?: DeepDiveTarget;
}
export interface ReferenceData {
version: string;
entries: IndexEntry[];
raw: Record<string, unknown>;
}
export interface ReleasesData {
latest: string;
updated: string;
releases: unknown[];
raw: Record<string, unknown>;
}
export interface ThreatDbData {
version: string;
updated: string;
sources: unknown[];
malicious_authors: unknown[];
malicious_skills: unknown[];
cve_database: unknown[];
attack_techniques: unknown[];
minimum_safe_versions: Record<string, string>;
raw: Record<string, unknown>;
}
// ─── Path resolver ────────────────────────────────────────────────────────────
export function resolveContentPath(relativePath: string): string | null {
const base = GUIDE_ROOT ?? resolve(__dirname, '../../..');
// Layer 1: resolve and check starts with base
const resolved = resolve(base, relativePath);
if (!resolved.startsWith(base + sep)) return null;
// Layer 2: extension whitelist
const ext = relativePath.slice(relativePath.lastIndexOf('.'));
if (!ALLOWED_EXTENSIONS.has(ext)) return null;
return resolved;
}
export function isDevMode(): boolean {
return GUIDE_ROOT !== null;
}
export function getGuideRoot(): string {
return GUIDE_ROOT ?? resolve(__dirname, '../../..');
}
// ─── YAML cache ───────────────────────────────────────────────────────────────
let referenceCache: ReferenceData | null = null;
let releasesCache: ReleasesData | null = null;
let threatDbCache: ThreatDbData | null = null;
export function loadReference(): ReferenceData {
if (referenceCache) return referenceCache;
const filePath = join(CONTENT_DIR, 'reference.yaml');
const raw = parseYaml(readFileSync(filePath, 'utf8')) as Record<string, unknown>;
const entries: IndexEntry[] = [];
flattenReference(raw, '', entries);
referenceCache = {
version: (raw.version as string) ?? 'unknown',
entries,
raw,
};
return referenceCache;
}
export function loadReleases(): ReleasesData {
if (releasesCache) return releasesCache;
const filePath = join(CONTENT_DIR, 'claude-code-releases.yaml');
const raw = parseYaml(readFileSync(filePath, 'utf8')) as Record<string, unknown>;
releasesCache = {
latest: (raw.latest as string) ?? 'unknown',
updated: (raw.updated as string) ?? 'unknown',
releases: (raw.releases as unknown[]) ?? [],
raw,
};
return releasesCache;
}
export async function loadThreatDb(): Promise<ThreatDbData> {
if (threatDbCache) return threatDbCache;
const THREAT_DB_PATH = 'examples/commands/resources/threat-db.yaml';
let content: string;
if (GUIDE_ROOT) {
content = readFileSync(join(GUIDE_ROOT, THREAT_DB_PATH), 'utf8');
} else {
const fetched = await fetchFile(THREAT_DB_PATH);
if (!fetched) throw new Error('Failed to load threat-db.yaml');
content = fetched;
}
const raw = parseYaml(content) as Record<string, unknown>;
threatDbCache = {
version: (raw.version as string) ?? 'unknown',
updated: (raw.updated as string) ?? 'unknown',
sources: (raw.sources as unknown[]) ?? [],
malicious_authors: (raw.malicious_authors as unknown[]) ?? [],
malicious_skills: (raw.malicious_skills as unknown[]) ?? [],
cve_database: (raw.cve_database as unknown[]) ?? [],
attack_techniques: (raw.attack_techniques as unknown[]) ?? [],
minimum_safe_versions: (raw.minimum_safe_versions as Record<string, string>) ?? {},
raw,
};
return threatDbCache;
}
export function loadLlmsTxt(): string {
const filePath = join(CONTENT_DIR, 'llms.txt');
return readFileSync(filePath, 'utf8');
}
export function getReferenceYamlRaw(): string {
const filePath = join(CONTENT_DIR, 'reference.yaml');
return readFileSync(filePath, 'utf8');
}
export function getReleasesYamlRaw(): string {
const filePath = join(CONTENT_DIR, 'claude-code-releases.yaml');
return readFileSync(filePath, 'utf8');
}
// ─── Deep dive resolver ───────────────────────────────────────────────────────
export function resolveDeepDive(value: unknown): DeepDiveTarget | undefined {
if (value === null || value === undefined) return undefined;
if (typeof value === 'number') {
return { type: 'line', file: 'guide/ultimate-guide.md', line: value };
}
if (typeof value === 'string') {
if (value.startsWith('http://') || value.startsWith('https://')) {
return { type: 'url', url: value };
}
// File path with optional :line suffix
const filePathMatch = value.match(/^(guide\/|examples\/|whitepapers\/|machine-readable\/)(.+?)(?::(\d+))?$/);
if (filePathMatch) {
return {
type: 'file',
path: filePathMatch[1] + filePathMatch[2],
line: filePathMatch[3] ? parseInt(filePathMatch[3], 10) : undefined,
};
}
return { type: 'inline', text: value };
}
if (typeof value === 'object') {
return { type: 'structured', data: value };
}
return { type: 'inline', text: String(value) };
}
// ─── Reference flattener ──────────────────────────────────────────────────────
function flattenReference(
obj: Record<string, unknown>,
prefix: string,
entries: IndexEntry[],
): void {
for (const [key, value] of Object.entries(obj)) {
const fullKey = prefix ? `${prefix}_${key}` : key;
if (key === 'version' || key === 'generated' || key === 'description' || key === 'note') {
continue;
}
if (value === null || value === undefined) continue;
if (typeof value === 'object' && !Array.isArray(value)) {
const obj2 = value as Record<string, unknown>;
// Check if it's a leaf-like object (has deep_dive or simple scalar values)
const hasDeepDive = 'deep_dive' in obj2;
const hasNestedObjects = Object.values(obj2).some(
(v) => typeof v === 'object' && v !== null && !Array.isArray(v) && !('deep_dive' in (v as Record<string, unknown>)),
);
if (hasDeepDive || !hasNestedObjects) {
// Treat as leaf entry
const searchableText = buildSearchableText(fullKey, value);
const target = hasDeepDive
? resolveDeepDive((obj2 as Record<string, unknown>).deep_dive)
: resolveDeepDive(value);
entries.push({
key: fullKey,
section: prefix.split('_')[0] ?? fullKey,
value,
searchableText,
target,
});
} else {
flattenReference(obj2, fullKey, entries);
}
} else {
const searchableText = buildSearchableText(fullKey, value);
const target = resolveDeepDive(value);
entries.push({
key: fullKey,
section: prefix.split('_')[0] ?? fullKey,
value,
searchableText,
target,
});
}
}
}
function buildSearchableText(key: string, value: unknown): string {
const parts: string[] = [key.replace(/_/g, ' ')];
if (typeof value === 'string') {
parts.push(value);
} else if (typeof value === 'number') {
parts.push(String(value));
} else if (Array.isArray(value)) {
for (const item of value) {
if (typeof item === 'string') parts.push(item);
else if (typeof item === 'object' && item !== null) {
parts.push(JSON.stringify(item));
}
}
} else if (typeof value === 'object' && value !== null) {
parts.push(JSON.stringify(value));
}
return parts.join(' ').toLowerCase();
}

View file

@ -0,0 +1,69 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from 'fs';
import { resolve, dirname } from 'path';
import { homedir } from 'os';
import { createHash } from 'crypto';
const PACKAGE_VERSION = '1.0.0';
const GITHUB_RAW_BASE =
'https://raw.githubusercontent.com/FlorianBruniaux/claude-code-ultimate-guide/main';
const CACHE_DIR = resolve(homedir(), '.cache', 'claude-code-guide', PACKAGE_VERSION);
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24h
function getCachePath(filePath: string): string {
// Use hash to avoid path issues, but keep extension for readability
const hash = createHash('md5').update(filePath).digest('hex').slice(0, 8);
const safe = filePath.replace(/[^a-zA-Z0-9._-]/g, '_');
return resolve(CACHE_DIR, `${hash}_${safe}`);
}
function isCacheValid(cachePath: string): boolean {
if (!existsSync(cachePath)) return false;
const stat = statSync(cachePath);
return Date.now() - stat.mtimeMs < CACHE_TTL_MS;
}
export async function fetchFile(filePath: string): Promise<string | null> {
// Normalize path separators
const normalizedPath = filePath.replace(/\\/g, '/');
const cachePath = getCachePath(normalizedPath);
// Return cache if valid
if (isCacheValid(cachePath)) {
return readFileSync(cachePath, 'utf8');
}
// Fetch from GitHub
const url = `${GITHUB_RAW_BASE}/${normalizedPath}`;
try {
const response = await fetch(url, {
headers: { 'User-Agent': 'claude-code-ultimate-guide-mcp/1.0.0' },
signal: AbortSignal.timeout(10_000),
});
if (!response.ok) {
// Return stale cache if available (offline fallback)
if (existsSync(cachePath)) {
return readFileSync(cachePath, 'utf8');
}
return null;
}
const content = await response.text();
// Write to cache
mkdirSync(dirname(cachePath), { recursive: true });
writeFileSync(cachePath, content, 'utf8');
return content;
} catch {
// Offline fallback: return stale cache
if (existsSync(cachePath)) {
return readFileSync(cachePath, 'utf8');
}
return null;
}
}
export function getCacheDir(): string {
return CACHE_DIR;
}

View file

@ -0,0 +1,184 @@
import { loadReference, type IndexEntry } from './content.js';
// ─── Stop words ───────────────────────────────────────────────────────────────
const STOP_WORDS = new Set([
'the', 'a', 'an', 'is', 'are', 'was', 'were', 'be', 'been',
'do', 'does', 'did', 'have', 'has', 'had', 'will', 'would',
'can', 'could', 'should', 'may', 'might', 'shall',
'i', 'you', 'he', 'she', 'it', 'we', 'they', 'my', 'your',
'to', 'of', 'in', 'for', 'on', 'with', 'at', 'by', 'from',
'how', 'what', 'when', 'where', 'which', 'who', 'why',
'not', 'no', 'up', 'out', 'if', 'about', 'into', 'that', 'this',
'and', 'or', 'but', 'so', 'yet', 'nor', 'use', 'using', 'used',
'get', 'set', 'add', 'run', 'make', 'see', 'all', 'new',
]);
// ─── Synonymes domaine ────────────────────────────────────────────────────────
const SYNONYMS: Record<string, string[]> = {
env: ['environment', 'env_var', 'variable', 'envvar'],
config: ['configuration', 'settings', 'configure', 'setup'],
cmd: ['command', 'commands', 'slash'],
auth: ['authentication', 'permission', 'permissions', 'authorize'],
hook: ['hooks', 'event', 'pre_tool', 'post_tool', 'events'],
agent: ['agents', 'subagent', 'teammate', 'subagents'],
mcp: ['model_context_protocol', 'mcp_server', 'mcp_servers', 'protocol'],
skill: ['skills', 'skill_module', 'modules'],
debug: ['debugging', 'troubleshoot', 'troubleshooting', 'diagnose'],
cost: ['token', 'tokens', 'pricing', 'budget', 'optimization', 'cost'],
security: ['secure', 'hardening', 'vulnerability', 'cve', 'threat'],
sandbox: ['isolation', 'container', 'docker', 'isolated'],
slash: ['command', 'commands', 'custom_command'],
install: ['installation', 'setup', 'installing'],
memory: ['persistence', 'serena', 'context'],
test: ['testing', 'tdd', 'bdd', 'spec', 'specs'],
workflow: ['workflows', 'process', 'flow'],
template: ['templates', 'example', 'examples', 'boilerplate'],
model: ['claude', 'opus', 'sonnet', 'haiku', 'llm'],
key: ['keyboard', 'shortcut', 'keybinding', 'keybindings'],
};
// ─── Levenshtein distance (inline, ~20 lines) ─────────────────────────────────
function levenshtein(a: string, b: string): number {
if (Math.abs(a.length - b.length) > 3) return 99; // fast bail
const m = a.length, n = b.length;
const dp: number[][] = Array.from({ length: m + 1 }, (_, i) =>
Array.from({ length: n + 1 }, (_, j) => (i === 0 ? j : j === 0 ? i : 0)),
);
for (let i = 1; i <= m; i++) {
for (let j = 1; j <= n; j++) {
dp[i][j] =
a[i - 1] === b[j - 1]
? dp[i - 1][j - 1]
: 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
}
}
return dp[m][n];
}
// ─── Query processing ─────────────────────────────────────────────────────────
export function tokenizeQuery(query: string): string[] {
const tokens = query
.toLowerCase()
.replace(/[^a-z0-9_\s-]/g, ' ')
.split(/\s+/)
.filter((t) => t.length > 1 && !STOP_WORDS.has(t));
// Expand synonyms
const expanded = new Set(tokens);
for (const token of tokens) {
const syns = SYNONYMS[token];
if (syns) {
for (const syn of syns) expanded.add(syn);
}
// Also check partial matches on synonym keys
for (const [key, syns2] of Object.entries(SYNONYMS)) {
if (key.startsWith(token) || token.startsWith(key)) {
expanded.add(key);
for (const s of syns2) expanded.add(s);
}
}
}
return Array.from(expanded);
}
// ─── Scoring ──────────────────────────────────────────────────────────────────
export interface SearchResult {
key: string;
section: string;
score: number;
value: unknown;
target: ReturnType<typeof import('./content.js').resolveDeepDive>;
hint: string;
}
function scoreEntry(entry: IndexEntry, tokens: string[], originalTokens: string[]): number {
let score = 0;
const keyLower = entry.key.toLowerCase();
const keySegments = keyLower.split('_');
for (const token of tokens) {
if (token.length < 2) continue;
if (keyLower === token) {
score += 20;
} else if (keyLower.includes(token)) {
score += 10;
} else if (keySegments.some((seg) => seg.startsWith(token))) {
score += 7;
} else if (entry.searchableText.includes(token)) {
score += 5;
}
}
// Fuzzy only if no exact matches and token is long enough
if (score === 0) {
for (const token of originalTokens) {
if (token.length <= 4) continue;
for (const seg of keySegments) {
if (seg.length > 4 && levenshtein(token, seg) <= 2) {
score += 2;
break;
}
}
}
}
return score;
}
function buildHint(entry: IndexEntry): string {
const { target } = entry;
if (!target) return `Key: ${entry.key}`;
switch (target.type) {
case 'line':
return `guide/ultimate-guide.md:${target.line}`;
case 'file':
return target.line ? `${target.path}:${target.line}` : target.path;
case 'url':
return target.url;
case 'inline':
return target.text.length > 100 ? target.text.slice(0, 100) + '…' : target.text;
case 'structured':
return `[structured data] — ${entry.key}`;
}
}
// ─── Main search function ─────────────────────────────────────────────────────
export function searchGuide(query: string, limit = 10): SearchResult[] {
const ref = loadReference();
const tokens = tokenizeQuery(query);
const originalTokens = query
.toLowerCase()
.split(/\s+/)
.filter((t) => t.length > 1 && !STOP_WORDS.has(t));
if (tokens.length === 0) return [];
const results: SearchResult[] = [];
for (const entry of ref.entries) {
const score = scoreEntry(entry, tokens, originalTokens);
if (score > 0) {
results.push({
key: entry.key,
section: entry.section,
score,
value: entry.value,
target: entry.target,
hint: buildHint(entry),
});
}
}
return results
.sort((a, b) => b.score - a.score)
.slice(0, Math.min(limit, 20));
}

View file

@ -0,0 +1,103 @@
import { readFileSync, existsSync } from 'fs';
import { resolveContentPath, isDevMode } from './content.js';
import { fetchFile } from './fetcher.js';
export interface SectionResult {
content: string;
startLine: number;
endLine: number;
totalLines: number;
hasMore: boolean;
nextOffset: number | null;
}
const MAX_LINES = 500;
// ─── Heading level detector ───────────────────────────────────────────────────
function getHeadingLevel(line: string): number | null {
const match = line.match(/^(#{1,6})\s/);
return match ? match[1].length : null;
}
// ─── Section extraction ───────────────────────────────────────────────────────
export function extractSection(
lines: string[],
offset: number,
limit: number,
): SectionResult {
const totalLines = lines.length;
const startLine = Math.max(1, Math.min(offset, totalLines));
const effectiveLimit = Math.min(limit, MAX_LINES);
// Find heading level of starting section (for boundary detection)
let sectionLevel: number | null = null;
for (let i = startLine - 1; i < Math.min(startLine + 5, totalLines); i++) {
const level = getHeadingLevel(lines[i]);
if (level !== null) {
sectionLevel = level;
break;
}
}
let inCodeFence = false;
let endLine = startLine - 1;
const collected: string[] = [];
for (let i = startLine - 1; i < totalLines && collected.length < effectiveLimit; i++) {
const line = lines[i];
// Track code fences
if (line.trimStart().startsWith('```')) {
inCodeFence = !inCodeFence;
}
// Check heading boundary (only outside code fences, only same/higher level)
if (!inCodeFence && i > startLine - 1 && sectionLevel !== null) {
const level = getHeadingLevel(line);
if (level !== null && level <= sectionLevel) {
break; // Stop at same or higher heading
}
}
collected.push(line);
endLine = i + 1;
}
const hasMore = endLine < totalLines && collected.length >= effectiveLimit;
return {
content: collected.join('\n'),
startLine,
endLine,
totalLines,
hasMore,
nextOffset: hasMore ? endLine + 1 : null,
};
}
// ─── Public API ───────────────────────────────────────────────────────────────
export async function readSection(
filePath: string,
offset = 1,
limit = MAX_LINES,
): Promise<SectionResult | null> {
let content: string | null = null;
if (isDevMode()) {
// Dev mode: read from local filesystem
const resolved = resolveContentPath(filePath);
if (!resolved || !existsSync(resolved)) return null;
content = readFileSync(resolved, 'utf8');
} else {
// Production: fetch from GitHub (with cache)
content = await fetchFile(filePath);
}
if (content === null) return null;
const lines = content.split('\n');
return extractSection(lines, offset, limit);
}

View file

@ -0,0 +1,23 @@
const GITHUB_BASE = 'https://github.com/FlorianBruniaux/claude-code-ultimate-guide/blob/main';
const GUIDE_SITE_BASE = 'https://cc.bruniaux.com/guide';
export function githubUrl(filePath: string, line?: number): string {
const base = `${GITHUB_BASE}/${filePath}`;
return line ? `${base}#L${line}` : base;
}
// Only ultimate-guide.md is rendered on the guide site
export function guideSiteUrl(filePath: string, line?: number): string | null {
if (filePath !== 'guide/ultimate-guide.md') return null;
// Line numbers don't map to anchors directly — link to the reader root
// If a line is provided, append a hint as a hash comment (not a real anchor)
return line ? `${GUIDE_SITE_BASE}/#L${line}` : GUIDE_SITE_BASE;
}
export function formatLinks(filePath: string, line?: number): string {
const gh = githubUrl(filePath, line);
const site = guideSiteUrl(filePath, line);
const parts = [`GitHub: ${gh}`];
if (site) parts.push(`Guide: ${site}`);
return parts.join(' | ');
}

View file

@ -0,0 +1,70 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
export function registerPrompts(server: McpServer): void {
server.prompt(
'claude-code-expert',
'Activate Claude Code expert mode with the optimal workflow for answering questions using the Ultimate Guide.',
{
question: z.string().optional().describe('Optional question to answer immediately'),
},
async ({ question }) => {
const systemPrompt = `You are an expert on Claude Code (Anthropic's CLI tool) with access to the Claude Code Ultimate Guide — a comprehensive 20,000+ line reference covering every feature, workflow, and best practice.
## How to answer Claude Code questions
**Step 1 Fast path (targeted questions)**
Use search_guide(query) with 1-3 keywords:
- "hooks" not "how do I configure hooks"
- "cost optimization" not "how to reduce token usage"
- "custom agents" not "how to create agent files"
If results have score > 10, follow the deep_dive links with read_section().
**Step 2 Fallback (broad questions or insufficient search results)**
Read the resource claude-code-guide://reference — it's 94KB of structured YAML with ~900 indexed entries. Parse it directly to find what you need.
**Step 3 Templates**
Use get_example(name) for production-ready code:
- Agents: get_example("code-reviewer"), get_example("backend-architect")
- Hooks: get_example("pre-commit"), get_example("notification")
- Commands: get_example("release"), get_example("audit")
- Skills: get_example("commit"), get_example("review-pr")
## Rules
- Always cite the source file and line number
- Never invent Claude Code features if you're not sure, say so
- If a feature isn't in the guide, check claude-code-guide://releases for recent additions
- Prefer concrete examples over abstract explanations
- For version-specific questions, check the releases resource first
- **Respond in the same language the user used** if they ask in French, answer in French; if English, answer in English. Tool output is in English but your response should match the user's language.
## Guide structure
- guide/ultimate-guide.md Main reference (20K+ lines)
- guide/cheatsheet.md Quick reference
- guide/architecture.md How Claude Code works internally
- examples/agents/ Custom agent templates
- examples/commands/ Slash command templates
- examples/hooks/ Event hook examples
- examples/skills/ Skill module templates
- machine-readable/reference.yaml Structured index (available via resource)`;
const messages = [
{
role: 'user' as const,
content: {
type: 'text' as const,
text: question
? `${systemPrompt}\n\n---\n\nQuestion: ${question}`
: systemPrompt,
},
},
];
return {
description: 'Claude Code expert mode activated',
messages,
};
},
);
}

View file

@ -0,0 +1,70 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { getReferenceYamlRaw, getReleasesYamlRaw, loadLlmsTxt } from '../lib/content.js';
export function registerResources(server: McpServer): void {
// Full reference YAML — the fallback when search isn't enough
server.resource(
'reference',
'claude-code-guide://reference',
{
description: 'Complete structured index of the Claude Code Ultimate Guide (94KB YAML, ~900 entries). Use as fallback when search_guide() results are insufficient.',
mimeType: 'text/yaml',
},
async () => {
const content = getReferenceYamlRaw();
return {
contents: [
{
uri: 'claude-code-guide://reference',
mimeType: 'text/yaml',
text: content,
},
],
};
},
);
// Releases history
server.resource(
'releases',
'claude-code-guide://releases',
{
description: 'Claude Code official releases history — condensed highlights and breaking changes for each version.',
mimeType: 'text/yaml',
},
async () => {
const content = getReleasesYamlRaw();
return {
contents: [
{
uri: 'claude-code-guide://releases',
mimeType: 'text/yaml',
text: content,
},
],
};
},
);
// Guide identity file
server.resource(
'llms',
'claude-code-guide://llms',
{
description: 'llms.txt — machine-readable identity and navigation file for the Claude Code Ultimate Guide.',
mimeType: 'text/plain',
},
async () => {
const content = loadLlmsTxt();
return {
contents: [
{
uri: 'claude-code-guide://llms',
mimeType: 'text/plain',
text: content,
},
],
};
},
);
}

56
mcp-server/src/server.ts Normal file
View file

@ -0,0 +1,56 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { registerSearchGuide } from './tools/search-guide.js';
import { registerReadSection } from './tools/read-section.js';
import { registerListTopics } from './tools/list-topics.js';
import { registerGetExample } from './tools/get-example.js';
import { registerChangelog } from './tools/changelog.js';
import { registerCheatsheet } from './tools/cheatsheet.js';
import { registerListExamples } from './tools/list-examples.js';
import { registerReleases } from './tools/releases.js';
import { registerCompareVersions } from './tools/compare-versions.js';
import { registerGetThreat, registerListThreats } from './tools/threats.js';
import { registerSearchExamples } from './tools/search-examples.js';
import { registerResources } from './resources/index.js';
import { registerPrompts } from './prompts/index.js';
import { loadReference, loadReleases, isDevMode } from './lib/content.js';
export function createServer(): McpServer {
const server = new McpServer({
name: 'claude-code-ultimate-guide',
version: '1.0.0',
});
// Pre-load YAML indexes into memory at startup
try {
const ref = loadReference();
const releases = loadReleases();
const mode = isDevMode() ? 'dev (local files)' : 'production (GitHub lazy fetch)';
process.stderr.write(
`[claude-code-guide] Loaded ${ref.entries.length} index entries | ${releases.releases.length} releases | mode: ${mode}\n`,
);
} catch (err) {
process.stderr.write(`[claude-code-guide] Warning: Failed to pre-load indexes: ${err}\n`);
}
// Register all tools
registerSearchGuide(server);
registerReadSection(server);
registerListTopics(server);
registerGetExample(server);
registerChangelog(server);
registerCheatsheet(server);
registerListExamples(server);
registerReleases(server);
registerCompareVersions(server);
registerGetThreat(server);
registerListThreats(server);
registerSearchExamples(server);
// Register resources
registerResources(server);
// Register prompts
registerPrompts(server);
return server;
}

View file

@ -0,0 +1,179 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { readSection } from '../lib/section-reader.js';
import { parseChangelog, filterByPeriod } from '../lib/changelog-parser.js';
import { githubUrl, guideSiteUrl } from '../lib/urls.js';
const CHANGELOG_PATH = 'CHANGELOG.md';
const CHANGELOG_GITHUB = githubUrl(CHANGELOG_PATH);
// ─── File path extractor ──────────────────────────────────────────────────────
// Matches paths like: guide/ultimate-guide.md, docs/resource-evaluations/xxx.md,
// examples/agents/foo.md, machine-readable/reference.yaml, guide/cheatsheet.md
const FILE_PATH_RE =
/\b((?:guide|docs|examples|machine-readable|whitepapers)\/[a-zA-Z0-9_./\-]+\.(?:md|yaml|yml|json|sh|ts|txt))/g;
interface ResourceLink {
path: string;
github: string;
site: string | null;
}
function extractResourceLinks(text: string): ResourceLink[] {
const seen = new Set<string>();
const links: ResourceLink[] = [];
for (const match of text.matchAll(FILE_PATH_RE)) {
const path = match[1];
if (seen.has(path)) continue;
seen.add(path);
links.push({
path,
github: githubUrl(path),
site: guideSiteUrl(path),
});
}
return links;
}
async function fetchChangelog(): Promise<string | null> {
const result = await readSection(CHANGELOG_PATH, 1, 500);
if (!result) return null;
// If truncated, fetch more until we have everything (max 3000 lines)
if (!result.hasMore) return result.content;
let full = result.content;
let offset = result.nextOffset!;
for (let i = 0; i < 5 && offset; i++) {
const next = await readSection(CHANGELOG_PATH, offset, 500);
if (!next) break;
full += '\n' + next.content;
offset = next.nextOffset ?? 0;
if (!next.hasMore) break;
}
return full;
}
export function registerChangelog(server: McpServer): void {
// ── get_changelog ─────────────────────────────────────────────────────────
server.tool(
'get_changelog',
'Return the last N entries from the Claude Code Ultimate Guide CHANGELOG. Shows what changed in the guide itself (not Claude Code CLI releases — use get_release() for that).',
{
count: z.number().min(1).max(20).optional().default(5).describe('Number of recent changelog entries to return (default 5)'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ count }) => {
const raw = await fetchChangelog();
if (!raw) {
return {
content: [{ type: 'text', text: 'CHANGELOG.md unavailable (offline and no cache).' }],
isError: true,
};
}
const entries = parseChangelog(raw);
const slice = entries.slice(0, count ?? 5);
if (slice.length === 0) {
return { content: [{ type: 'text', text: 'No changelog entries found.' }] };
}
const combinedText = slice.map((e) => e.content).join('\n\n');
const links = extractResourceLinks(combinedText);
const lines = [
`# Guide CHANGELOG — last ${slice.length} entries`,
`GitHub: ${CHANGELOG_GITHUB}`,
'',
combinedText,
];
if (links.length > 0) {
lines.push('', '---', '## Resources mentioned', '');
for (const l of links) {
lines.push(`**${l.path}**`);
lines.push(` GitHub: ${l.github}`);
if (l.site) lines.push(` Guide: ${l.site}`);
}
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
// ── get_digest ─────────────────────────────────────────────────────────────
server.tool(
'get_digest',
'Return a digest of guide and Claude Code CLI changes for a given period. Combines guide CHANGELOG entries + official Claude Code releases in the time window.',
{
period: z
.enum(['day', 'week', 'month'])
.describe('Time window: "day" (24h), "week" (7 days), "month" (30 days)'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ period }) => {
const labels = { day: 'last 24h', week: 'last 7 days', month: 'last 30 days' };
// Guide changelog
const raw = await fetchChangelog();
const guideEntries = raw ? filterByPeriod(parseChangelog(raw), period) : [];
// Claude Code releases
const { loadReleases } = await import('../lib/content.js');
const relData = loadReleases();
const MS = { day: 86_400_000, week: 7 * 86_400_000, month: 30 * 86_400_000 };
const cutoff = Date.now() - MS[period];
const ccReleases = (relData.releases as Array<{ version: string; date: string; highlights: string[] }>)
.filter((r) => new Date(r.date).getTime() >= cutoff);
const lines: string[] = [
`# Digest — ${labels[period]}`,
`Generated: ${new Date().toISOString().slice(0, 10)}`,
'',
];
// Guide section
lines.push('## Guide changes');
if (guideEntries.length === 0) {
lines.push('No guide updates in this period.');
lines.push('');
} else {
const guideText = guideEntries.map((e) => e.content).join('\n\n');
lines.push(guideText);
lines.push('');
// Resource links extracted from guide entries
const links = extractResourceLinks(guideText);
if (links.length > 0) {
lines.push('### Resources mentioned');
for (const l of links) {
const siteStr = l.site ? ` | Guide: ${l.site}` : '';
lines.push(`- \`${l.path}\` — GitHub: ${l.github}${siteStr}`);
}
lines.push('');
}
}
// CC releases section
lines.push('## Claude Code CLI releases');
if (ccReleases.length === 0) {
lines.push('No Claude Code releases in this period.');
} else {
for (const r of ccReleases) {
lines.push(`### v${r.version} (${r.date})`);
for (const h of r.highlights ?? []) lines.push(`- ${h}`);
// Link to the release tracking file
lines.push(`GitHub: ${githubUrl('guide/claude-code-releases.md')}`);
lines.push('');
}
}
lines.push('---');
lines.push(`Full changelog: ${CHANGELOG_GITHUB}`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
}

View file

@ -0,0 +1,58 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { readSection } from '../lib/section-reader.js';
import { formatLinks } from '../lib/urls.js';
const CHEATSHEET_PATH = 'guide/cheatsheet.md';
export function registerCheatsheet(server: McpServer): void {
server.tool(
'get_cheatsheet',
'Return the Claude Code cheatsheet — a compact 1-page reference covering the most important commands, shortcuts, config options, and workflows.',
{
section: z.string().optional().describe('Optional: filter to a specific section (e.g. "installation", "hooks", "agents", "mcp")'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ section }) => {
const result = await readSection(CHEATSHEET_PATH, 1, 500);
if (!result) {
return {
content: [{ type: 'text', text: 'Cheatsheet unavailable (offline and no cache).' }],
isError: true,
};
}
let content = result.content;
// Filter to section if requested
if (section) {
const sectionLower = section.toLowerCase();
const lines = content.split('\n');
const start = lines.findIndex(
(l) => l.toLowerCase().includes(sectionLower) && l.startsWith('#'),
);
if (start !== -1) {
// Find end of section (next heading of same or higher level)
const startLevel = (lines[start].match(/^#+/) ?? [''])[0].length;
let end = lines.length;
for (let i = start + 1; i < lines.length; i++) {
const m = lines[i].match(/^(#+)/);
if (m && m[1].length <= startLevel) { end = i; break; }
}
content = lines.slice(start, end).join('\n');
}
}
const header = [
`# Claude Code Cheatsheet`,
formatLinks(CHEATSHEET_PATH),
section ? `Filtered: "${section}"` : `Lines: ${result.startLine}-${result.endLine} of ${result.totalLines}`,
result.hasMore ? `Has more — use read_section("${CHEATSHEET_PATH}", ${result.nextOffset}) for rest` : '',
'---',
'',
].filter(Boolean).join('\n');
return { content: [{ type: 'text', text: header + content }] };
},
);
}

View file

@ -0,0 +1,116 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadReleases } from '../lib/content.js';
import { githubUrl } from '../lib/urls.js';
const RELEASES_GITHUB = githubUrl('guide/claude-code-releases.md');
interface ReleaseEntry {
version: string;
date: string;
highlights: string[];
breaking?: string[];
}
function parseSemver(v: string): [number, number, number] {
const parts = v.replace(/^v/, '').split('.').map(Number);
return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0];
}
function semverCompare(a: string, b: string): number {
const [am, an, ap] = parseSemver(a);
const [bm, bn, bp] = parseSemver(b);
if (am !== bm) return am - bm;
if (an !== bn) return an - bn;
return ap - bp;
}
export function registerCompareVersions(server: McpServer): void {
server.tool(
'compare_versions',
'Show what changed between two Claude Code CLI versions. Lists all releases in range with aggregated highlights and breaking changes.',
{
from: z.string().describe('Starting version (older), e.g. "2.1.50"'),
to: z.string().optional().describe('Ending version (newer). Omit to use the latest.'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ from, to }) => {
const data = loadReleases();
const releases = data.releases as ReleaseEntry[];
const fromClean = from.replace(/^v/, '');
const toClean = (to ?? data.latest).replace(/^v/, '');
// Ensure from <= to (by semver)
const fromVer = fromClean;
const toVer = toClean;
const ordered = semverCompare(fromVer, toVer) <= 0
? { older: fromVer, newer: toVer }
: { older: toVer, newer: fromVer };
// Validate both versions exist
const fromFound = releases.find((r) => r.version === ordered.older);
const toFound = releases.find((r) => r.version === ordered.newer);
if (!fromFound) {
const known = releases.slice(0, 10).map((r) => `v${r.version}`).join(', ');
return {
content: [{
type: 'text',
text: `Version v${ordered.older} not found.\n\nRecent versions: ${known}\n\nFull history: ${RELEASES_GITHUB}`,
}],
};
}
if (!toFound) {
const known = releases.slice(0, 10).map((r) => `v${r.version}`).join(', ');
return {
content: [{
type: 'text',
text: `Version v${ordered.newer} not found.\n\nRecent versions: ${known}\n\nFull history: ${RELEASES_GITHUB}`,
}],
};
}
// Collect versions in range (releases are newest-first)
const inRange = releases.filter(
(r) => semverCompare(r.version, ordered.older) >= 0 &&
semverCompare(r.version, ordered.newer) <= 0,
);
// Aggregate highlights and breaking changes
const allHighlights: string[] = [];
const allBreaking: string[] = [];
for (const r of inRange) {
for (const h of r.highlights ?? []) allHighlights.push(h);
for (const b of r.breaking ?? []) allBreaking.push(b);
}
const versionList = inRange
.slice()
.sort((a, b) => semverCompare(b.version, a.version)) // newest first
.map((r) => `v${r.version} (${r.date})`)
.join(', ');
const lines = [
`# Claude Code: v${ordered.older} → v${ordered.newer}`,
RELEASES_GITHUB,
'',
`**${inRange.length} release${inRange.length !== 1 ? 's' : ''} in range**: ${versionList}`,
'',
'## What changed',
...allHighlights.map((h) => `- ${h}`),
];
if (allBreaking.length > 0) {
lines.push('', '## Breaking changes');
for (const b of allBreaking) lines.push(`- ⚠️ ${b}`);
}
lines.push('', `---`);
lines.push(`${allHighlights.length} highlight${allHighlights.length !== 1 ? 's' : ''} | ${allBreaking.length} breaking change${allBreaking.length !== 1 ? 's' : ''} | Use get_release(version) for per-release details.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
}

View file

@ -0,0 +1,140 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadReference, resolveDeepDive } from '../lib/content.js';
import { readSection } from '../lib/section-reader.js';
import { tokenizeQuery } from '../lib/search.js';
import { githubUrl } from '../lib/urls.js';
export function registerGetExample(server: McpServer): void {
server.tool(
'get_example',
'Fetch a production-ready template or example from the guide (agents, skills, commands, hooks, scripts). Pass a partial name to search for matching examples.',
{
name: z.string().describe('Example name or partial match (e.g. "code-reviewer", "pre-commit hook", "custom agent")'),
},
{
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
async ({ name }) => {
const ref = loadReference();
const nameLower = name.toLowerCase();
const tokens = tokenizeQuery(name);
// Collect entries pointing to examples/
interface ExampleMatch {
key: string;
path: string;
score: number;
}
const matches: ExampleMatch[] = [];
for (const entry of ref.entries) {
const target = entry.target ?? resolveDeepDive(entry.value);
if (!target || target.type !== 'file') continue;
if (!target.path.startsWith('examples/')) continue;
const pathLower = target.path.toLowerCase();
const keyLower = entry.key.toLowerCase();
let score = 0;
// Exact match in path
if (pathLower.includes(nameLower)) score += 20;
if (keyLower.includes(nameLower)) score += 15;
// Token match
for (const token of tokens) {
if (pathLower.includes(token)) score += 5;
if (keyLower.includes(token)) score += 3;
}
if (score > 0) {
matches.push({ key: entry.key, path: target.path, score });
}
}
matches.sort((a, b) => b.score - a.score);
if (matches.length === 0) {
return {
content: [
{
type: 'text',
text: [
`No examples found matching: "${name}"`,
'',
'Available example categories:',
' • examples/agents/ — Custom agent templates',
' • examples/commands/ — Slash command templates',
' • examples/hooks/ — Event hook examples',
' • examples/skills/ — Skill module templates',
' • examples/scripts/ — Utility scripts',
'',
'Try: get_example("agent"), get_example("hook"), get_example("command")',
].join('\n'),
},
],
};
}
// Single match: fetch and return content
if (matches.length === 1 || matches[0].score >= 20) {
const match = matches[0];
const section = await readSection(match.path, 1, 500);
if (!section) {
return {
content: [
{
type: 'text',
text: [
`Example found: ${match.path}`,
`Key: ${match.key}`,
'',
'Content unavailable (offline or file not found).',
`Try: read_section("${match.path}")`,
].join('\n'),
},
],
};
}
return {
content: [
{
type: 'text',
text: [
`# ${match.path}`,
`Key: ${match.key}`,
`Lines: ${section.startLine}-${section.endLine} of ${section.totalLines}`,
`GitHub: ${githubUrl(match.path)}`,
'---',
'',
section.content,
section.hasMore ? `\n\n[truncated — use read_section("${match.path}", ${section.nextOffset}) for more]` : '',
].join('\n'),
},
],
};
}
// Multiple matches: list them
const lines = [
`Found ${matches.length} examples matching "${name}":`,
'',
];
for (const match of matches.slice(0, 10)) {
lines.push(`${match.path}`);
lines.push(` Key: ${match.key} | Score: ${match.score}`);
lines.push(` → get_example("${match.path.split('/').pop()?.replace(/\.(md|yaml|sh|ts)$/, '') ?? match.key}")`);
lines.push('');
}
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
},
);
}

View file

@ -0,0 +1,80 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadReference, resolveDeepDive } from '../lib/content.js';
import { githubUrl } from '../lib/urls.js';
const CATEGORIES = ['agents', 'commands', 'hooks', 'skills', 'scripts'] as const;
type Category = typeof CATEGORIES[number];
export function registerListExamples(server: McpServer): void {
server.tool(
'list_examples',
'List all production-ready templates in the guide by category (agents, commands, hooks, skills, scripts). Use get_example(name) to fetch the content of any specific template.',
{
category: z
.enum(CATEGORIES)
.optional()
.describe('Filter by category: agents | commands | hooks | skills | scripts. Omit for all.'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ category }) => {
const ref = loadReference();
// Collect all example paths from reference.yaml
const byCategory = new Map<Category, Array<{ key: string; path: string; description: string }>>();
for (const cat of CATEGORIES) byCategory.set(cat, []);
for (const entry of ref.entries) {
const target = entry.target ?? resolveDeepDive(entry.value);
if (!target || target.type !== 'file') continue;
if (!target.path.startsWith('examples/')) continue;
const parts = target.path.split('/'); // ['examples', 'agents', 'file.md']
const cat = parts[1] as Category;
if (!CATEGORIES.includes(cat)) continue;
if (category && cat !== category) continue;
const list = byCategory.get(cat)!;
// Deduplicate by path
if (list.some((e) => e.path === target.path)) continue;
// Build description from key
const desc = entry.key
.replace(/^deep_dive_/, '')
.replace(/_/g, ' ')
.replace(/\b\w/g, (c) => c.toUpperCase());
list.push({ key: entry.key, path: target.path, description: desc });
}
const lines: string[] = [
`# Claude Code Ultimate Guide — Templates`,
`GitHub: https://github.com/FlorianBruniaux/claude-code-ultimate-guide/tree/main/examples`,
'',
];
let total = 0;
for (const cat of CATEGORIES) {
if (category && cat !== category) continue;
const items = byCategory.get(cat)!;
if (items.length === 0) continue;
lines.push(`## ${cat.charAt(0).toUpperCase() + cat.slice(1)} (${items.length})`);
for (const item of items) {
const filename = item.path.split('/').pop() ?? item.path;
const gh = githubUrl(item.path);
lines.push(`- **${filename}** — ${item.description}`);
lines.push(` GitHub: ${gh}`);
lines.push(` → get_example("${filename.replace(/\.(md|yaml|sh|ts)$/, '')}")`);
}
lines.push('');
total += items.length;
}
lines.push('---');
lines.push(`${total} template(s) total. Use get_example(name) to fetch any template.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
}

View file

@ -0,0 +1,57 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { loadReference } from '../lib/content.js';
export function registerListTopics(server: McpServer): void {
server.tool(
'list_topics',
'List all top-level topics and categories in the Claude Code Ultimate Guide. Useful for exploring what the guide covers before searching.',
{},
{
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
async () => {
const ref = loadReference();
// Group entries by first key segment (before first underscore)
const categories = new Map<string, { count: number; samples: string[] }>();
for (const entry of ref.entries) {
const category = entry.key.split('_')[0] ?? entry.key;
if (!categories.has(category)) {
categories.set(category, { count: 0, samples: [] });
}
const cat = categories.get(category)!;
cat.count++;
if (cat.samples.length < 5) {
cat.samples.push(entry.key);
}
}
const sorted = Array.from(categories.entries()).sort((a, b) => b[1].count - a[1].count);
const lines: string[] = [
`Claude Code Ultimate Guide — ${ref.entries.length} indexed entries across ${sorted.length} categories`,
`Version: ${ref.version}`,
'',
'## Topics',
'',
];
for (const [category, { count, samples }] of sorted) {
lines.push(`### ${category} (${count} entries)`);
lines.push(`Examples: ${samples.join(', ')}`);
lines.push('');
}
lines.push('---');
lines.push('Use search_guide("topic") to search within any category.');
lines.push('Use read_section("guide/ultimate-guide.md") to browse the full guide.');
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
},
);
}

View file

@ -0,0 +1,79 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { readSection } from '../lib/section-reader.js';
import { resolveContentPath } from '../lib/content.js';
import { formatLinks } from '../lib/urls.js';
export function registerReadSection(server: McpServer): void {
server.tool(
'read_section',
'Read a section from a guide file (markdown, YAML, examples). Supports pagination via offset. Use after search_guide() to fetch the full content at a specific location.',
{
path: z.string().describe('Relative path from repo root (e.g. "guide/ultimate-guide.md", "examples/agents/code-reviewer.md")'),
offset: z.number().min(1).optional().default(1).describe('Line number to start reading from (1-based, default 1)'),
limit: z.number().min(1).max(500).optional().default(500).describe('Max lines to return (default 500, max 500)'),
},
{
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
async ({ path: filePath, offset, limit }) => {
// Security: validate path before attempting read
const resolved = resolveContentPath(filePath);
if (resolved === null) {
return {
content: [
{
type: 'text',
text: `Error: Invalid path "${filePath}". Only paths within the guide repo with allowed extensions (.md, .yaml, .yml, .sh, .ts, .js, .json, .py, .txt) are permitted.`,
},
],
isError: true,
};
}
const result = await readSection(filePath, offset ?? 1, limit ?? 500);
if (result === null) {
return {
content: [
{
type: 'text',
text: [
`File not found or unavailable: "${filePath}"`,
'',
'This may be because:',
' • The file does not exist in the guide repo',
' • Network unavailable (running offline without cache)',
'',
'Fallback: read the resource claude-code-guide://reference for inline summaries.',
].join('\n'),
},
],
isError: true,
};
}
const header = [
`File: ${filePath}`,
`Lines: ${result.startLine}-${result.endLine} of ${result.totalLines}`,
result.hasMore
? `Has more: yes — use offset=${result.nextOffset} for next section`
: 'Has more: no',
formatLinks(filePath, result.startLine),
'---',
'',
].join('\n');
return {
content: [
{
type: 'text',
text: header + result.content,
},
],
};
},
);
}

View file

@ -0,0 +1,82 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadReleases } from '../lib/content.js';
import { githubUrl } from '../lib/urls.js';
const RELEASES_GITHUB = githubUrl('guide/claude-code-releases.md');
interface ReleaseEntry {
version: string;
date: string;
highlights: string[];
breaking?: string[];
}
export function registerReleases(server: McpServer): void {
server.tool(
'get_release',
'Get details about Claude Code CLI official releases. Pass a version to get a specific release, or omit to get the latest and recent history.',
{
version: z.string().optional().describe('Specific version (e.g. "2.1.59"). Omit for latest + recent 5.'),
count: z.number().min(1).max(30).optional().default(5).describe('Number of recent releases to show when no version specified (default 5)'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ version, count }) => {
const data = loadReleases();
const releases = data.releases as ReleaseEntry[];
if (version) {
const found = releases.find(
(r) => r.version === version || r.version === version.replace(/^v/, ''),
);
if (!found) {
const versions = releases.slice(0, 10).map((r) => `v${r.version}`).join(', ');
return {
content: [{
type: 'text',
text: `Release v${version} not found.\n\nRecent versions: ${versions}\n\nFull history: ${RELEASES_GITHUB}`,
}],
};
}
const lines = [
`# Claude Code v${found.version} (${found.date})`,
RELEASES_GITHUB,
'',
'## Highlights',
...(found.highlights ?? []).map((h) => `- ${h}`),
];
if (found.breaking?.length) {
lines.push('', '## Breaking changes');
for (const b of found.breaking) lines.push(`- ⚠️ ${b}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
// Latest + recent N
const recent = releases.slice(0, count ?? 5);
const lines = [
`# Claude Code Releases`,
`Latest: v${data.latest} (updated: ${data.updated})`,
RELEASES_GITHUB,
'',
];
for (const r of recent) {
lines.push(`## v${r.version}${r.date}`);
for (const h of r.highlights ?? []) lines.push(`- ${h}`);
if (r.breaking?.length) {
for (const b of r.breaking) lines.push(` ⚠️ ${b}`);
}
lines.push('');
}
lines.push(`---`);
lines.push(`Showing ${recent.length} of ${releases.length} tracked releases. Use get_release(version) for details.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
}

View file

@ -0,0 +1,133 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadReference, resolveDeepDive } from '../lib/content.js';
import { tokenizeQuery } from '../lib/search.js';
import { githubUrl } from '../lib/urls.js';
interface ExampleResult {
path: string;
key: string;
score: number;
description: string;
githubUrl: string;
}
export function registerSearchExamples(server: McpServer): void {
server.tool(
'search_examples',
'Semantic search across all production-ready templates by intent (e.g. "hook lint", "agent code review"). Different from get_example (exact name) and list_examples (category browse).',
{
query: z.string().describe('Search query describing the template you need, e.g. "hook lint", "agent code review", "pre-commit typescript"'),
limit: z.number().min(1).max(20).optional().default(10).describe('Max results to return (default 10, max 20)'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ query, limit }) => {
const ref = loadReference();
const tokens = tokenizeQuery(query);
const queryLower = query.toLowerCase();
if (tokens.length === 0) {
return {
content: [{
type: 'text',
text: 'Query too short or contained only stop words. Try: "hook lint", "agent security", "pre-commit".',
}],
};
}
// Collect and score entries pointing to examples/
const results: ExampleResult[] = [];
const seen = new Set<string>();
for (const entry of ref.entries) {
const target = entry.target ?? resolveDeepDive(entry.value);
if (!target || target.type !== 'file') continue;
if (!target.path.startsWith('examples/')) continue;
// Deduplicate by path
if (seen.has(target.path)) continue;
const pathLower = target.path.toLowerCase();
const keyLower = entry.key.toLowerCase();
const textLower = entry.searchableText.toLowerCase();
let score = 0;
// Exact substring match on full query (highest signal)
if (pathLower.includes(queryLower)) score += 15;
for (const token of tokens) {
if (token.length < 2) continue;
if (pathLower.includes(token)) score += 10;
else if (keyLower.includes(token)) score += 7;
else if (textLower.includes(token)) score += 5;
else {
// Fuzzy: token length >= 5, levenshtein-like (segment starts with token)
if (token.length >= 5) {
const pathSegments = pathLower.replace(/[/_.-]/g, ' ').split(' ');
for (const seg of pathSegments) {
if (seg.length >= 4 && (seg.startsWith(token.slice(0, -1)) || token.startsWith(seg.slice(0, -1)))) {
score += 2;
break;
}
}
}
}
}
if (score > 0) {
// Build human-readable description from key
const description = entry.searchableText.slice(0, 120).replace(/\s+/g, ' ').trim();
seen.add(target.path);
results.push({
path: target.path,
key: entry.key,
score,
description,
githubUrl: githubUrl(target.path),
});
}
}
results.sort((a, b) => b.score - a.score);
const topResults = results.slice(0, limit ?? 10);
if (topResults.length === 0) {
return {
content: [{
type: 'text',
text: [
`No examples found for: "${query}"`,
'',
'Try broader terms or browse by category:',
' • list_examples("agents") — custom agent templates',
' • list_examples("hooks") — event hook examples',
' • list_examples("commands") — slash command templates',
' • list_examples("skills") — skill module templates',
' • list_examples("scripts") — utility scripts',
].join('\n'),
}],
};
}
const lines = [
`# Examples matching "${query}"`,
`Found ${topResults.length} result${topResults.length !== 1 ? 's' : ''} (of ${results.length} scored)`,
'',
];
for (const r of topResults) {
const name = r.path.split('/').pop()?.replace(/\.(md|yaml|sh|ts|js|py)$/, '') ?? r.key;
lines.push(`## ${r.path}`);
lines.push(`Score: ${r.score} | Key: ${r.key}`);
lines.push(r.description);
lines.push(`GitHub: ${r.githubUrl}`);
lines.push(`→ get_example("${name}")`);
lines.push('');
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
},
);
}

View file

@ -0,0 +1,86 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { searchGuide } from '../lib/search.js';
import { formatLinks, githubUrl } from '../lib/urls.js';
export function registerSearchGuide(server: McpServer): void {
server.tool(
'search_guide',
'Search the Claude Code Ultimate Guide by topic, keyword, or question. Returns ranked results with file locations and descriptions. Use this as the first step for any guide question.',
{
query: z.string().describe('Search query — topic, question, or keyword (e.g. "hooks", "custom agents", "cost optimization")'),
limit: z.number().min(1).max(20).optional().default(10).describe('Max results to return (default 10, max 20)'),
},
{
readOnlyHint: true,
destructiveHint: false,
openWorldHint: false,
},
async ({ query, limit }) => {
const results = searchGuide(query, limit ?? 10);
if (results.length === 0) {
return {
content: [
{
type: 'text',
text: [
`No results found for: "${query}"`,
'',
'Tips:',
' • Try shorter keywords: "hooks" instead of "how do I use hooks"',
' • Use the resource fallback: read claude-code-guide://reference for the full YAML index',
' • Try related terms: "commands", "agents", "mcp", "security", "cost"',
].join('\n'),
},
],
};
}
const lines: string[] = [
`Found ${results.length} result(s) for: "${query}"`,
'',
];
for (const result of results) {
lines.push(`## ${result.key} (score: ${result.score})`);
lines.push(`Section: ${result.section}`);
lines.push(`Location: ${result.hint}`);
if (result.target) {
switch (result.target.type) {
case 'line':
lines.push(`→ read_section("${result.target.file}", ${result.target.line})`);
lines.push(` ${formatLinks(result.target.file, result.target.line)}`);
break;
case 'file':
lines.push(
`→ read_section("${result.target.path}"${result.target.line ? `, ${result.target.line}` : ''})`,
);
lines.push(` ${formatLinks(result.target.path, result.target.line)}`);
break;
case 'url':
lines.push(`→ External: ${result.target.url}`);
break;
case 'inline':
lines.push(`${result.target.text.slice(0, 200)}${result.target.text.length > 200 ? '…' : ''}`);
break;
case 'structured':
lines.push(`→ [structured data — use read_section or view resource]`);
break;
}
}
lines.push('');
}
lines.push('---');
lines.push('Use read_section(path, line) to fetch the full content of any result.');
lines.push('Use claude-code-guide://reference resource for the complete YAML index.');
return {
content: [{ type: 'text', text: lines.join('\n') }],
};
},
);
}

View file

@ -0,0 +1,264 @@
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadThreatDb } from '../lib/content.js';
import { githubUrl } from '../lib/urls.js';
const THREAT_DB_GITHUB = githubUrl('examples/commands/resources/threat-db.yaml');
interface CveEntry {
id: string;
component: string;
severity: string;
cvss?: number;
description: string;
source: string;
fixed_in?: string;
mitigation?: string;
notes?: string;
}
interface TechniqueEntry {
id: string;
name: string;
description: string;
examples?: string[];
campaigns?: string[];
cves?: string[];
mitigation?: string;
}
const CATEGORY_LABELS: Record<string, string> = {
cves: 'CVE Database',
authors: 'Malicious Authors',
skills: 'Malicious Skills',
techniques: 'Attack Techniques',
mitigations: 'Minimum Safe Versions',
sources: 'Research Sources',
};
export function registerGetThreat(server: McpServer): void {
server.tool(
'get_threat',
'Look up a specific threat by ID from the security threat database. Supports CVE IDs (e.g. "CVE-2025-53109") and technique IDs (e.g. "T001").',
{
id: z.string().describe('Threat ID: a CVE identifier (e.g. "CVE-2025-53109") or attack technique ID (e.g. "T001")'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ id }) => {
const db = await loadThreatDb();
const idUpper = id.toUpperCase();
// Search CVE database
const cve = (db.cve_database as CveEntry[]).find(
(c) => c.id.toUpperCase() === idUpper,
);
if (cve) {
const lines = [
`# ${cve.id}${cve.component}`,
THREAT_DB_GITHUB,
'',
`**Severity**: ${cve.severity.toUpperCase()}${cve.cvss ? ` (CVSS ${cve.cvss})` : ''}`,
`**Component**: ${cve.component}`,
`**Source**: ${cve.source}`,
'',
`## Description`,
cve.description,
];
if (cve.fixed_in) {
lines.push('', `**Fixed in**: ${cve.fixed_in}`);
}
if (cve.mitigation) {
lines.push('', `## Mitigation`, cve.mitigation);
}
if (cve.notes) {
lines.push('', `## Notes`, cve.notes);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
// Search attack techniques
const technique = (db.attack_techniques as TechniqueEntry[]).find(
(t) => t.id.toUpperCase() === idUpper,
);
if (technique) {
const lines = [
`# ${technique.id}${technique.name}`,
THREAT_DB_GITHUB,
'',
`## Description`,
technique.description,
];
if (technique.examples?.length) {
lines.push('', '## Examples');
for (const ex of technique.examples) lines.push(`- ${ex}`);
}
if (technique.campaigns?.length) {
lines.push('', `**Campaigns**: ${technique.campaigns.join(', ')}`);
}
if (technique.cves?.length) {
lines.push(`**Related CVEs**: ${technique.cves.join(', ')}`);
}
if (technique.mitigation) {
lines.push('', `## Mitigation`, technique.mitigation);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
return {
content: [{
type: 'text',
text: [
`Threat ID "${id}" not found in the database.`,
'',
'Supported formats:',
' • CVE IDs: CVE-2025-53109, CVE-2026-24052, ...',
' • Technique IDs: T001, T002, ...',
'',
`Use list_threats("cves") or list_threats("techniques") to browse all entries.`,
`Full database: ${THREAT_DB_GITHUB}`,
].join('\n'),
}],
};
},
);
}
export function registerListThreats(server: McpServer): void {
server.tool(
'list_threats',
'Browse the security threat database. Without a category, returns a summary with counts. With a category, returns the full list for that section.',
{
category: z.enum(['cves', 'authors', 'skills', 'techniques', 'mitigations', 'sources'])
.optional()
.describe('Section to list: cves | authors | skills | techniques | mitigations | sources. Omit for a global summary.'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ category }) => {
const db = await loadThreatDb();
if (!category) {
// Global summary
const lines = [
`# Threat Database Summary`,
`Version ${db.version} — updated ${db.updated}`,
THREAT_DB_GITHUB,
'',
'| Category | Count |',
'|----------|-------|',
`| CVEs | ${db.cve_database.length} |`,
`| Malicious Authors | ${db.malicious_authors.length} |`,
`| Malicious Skills | ${db.malicious_skills.length} |`,
`| Attack Techniques | ${db.attack_techniques.length} |`,
`| Minimum Safe Versions | ${Object.keys(db.minimum_safe_versions).length} |`,
`| Research Sources | ${db.sources.length} |`,
'',
'Use list_threats(category) to browse a section, or get_threat(id) for details.',
'Categories: cves | authors | skills | techniques | mitigations | sources',
];
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
const label = CATEGORY_LABELS[category] ?? category;
if (category === 'cves') {
const cves = db.cve_database as CveEntry[];
const lines = [
`# ${label} (${cves.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const c of cves) {
lines.push(`## ${c.id}${c.component}`);
lines.push(`**Severity**: ${c.severity.toUpperCase()}${c.cvss ? ` (CVSS ${c.cvss})` : ''} | **Source**: ${c.source}`);
lines.push(c.description);
if (c.fixed_in) lines.push(`Fixed in: ${c.fixed_in}`);
if (c.mitigation) lines.push(`Mitigation: ${c.mitigation}`);
lines.push('');
}
lines.push(`---\nUse get_threat("CVE-XXXX-XXXXX") for full details on any CVE.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'techniques') {
const techniques = db.attack_techniques as TechniqueEntry[];
const lines = [
`# ${label} (${techniques.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const t of techniques) {
lines.push(`## ${t.id}${t.name}`);
lines.push(t.description);
if (t.mitigation) lines.push(`Mitigation: ${t.mitigation}`);
lines.push('');
}
lines.push(`---\nUse get_threat("T001") for full details including examples and CVE links.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'authors') {
const authors = db.malicious_authors as Array<{ name: string; source?: string; notes?: string }>;
const lines = [
`# ${label} (${authors.length} confirmed)`,
THREAT_DB_GITHUB,
'',
'Block ALL skills from these authors — confirmed malicious by security researchers.',
'',
];
for (const a of authors) {
lines.push(`- **${a.name}**${a.source ? `${a.source}` : ''}${a.notes ? ` (${a.notes})` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'skills') {
const skills = db.malicious_skills as Array<{ name: string; type?: string; source?: string; risk?: string; notes?: string }>;
const lines = [
`# ${label} (${skills.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const s of skills) {
const tags = [s.type, s.risk ? `risk:${s.risk}` : undefined].filter(Boolean).join(', ');
lines.push(`- **${s.name}**${tags ? ` [${tags}]` : ''}${s.source ? `${s.source}` : ''}${s.notes ? ` (${s.notes})` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'mitigations') {
const versions = db.minimum_safe_versions;
const entries = Object.entries(versions);
const lines = [
`# ${label} (${entries.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const [component, minVersion] of entries) {
lines.push(`- **${component}**: >= ${minVersion}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'sources') {
const sources = db.sources as Array<{ name: string; url?: string; date?: string }>;
const lines = [
`# ${label} (${sources.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const s of sources) {
lines.push(`- **${s.name}**${s.date ? ` (${s.date})` : ''}${s.url ? `\n ${s.url}` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
return {
content: [{ type: 'text', text: `Unknown category: "${category}". Use: cves | authors | skills | techniques | mitigations | sources` }],
};
},
);
}

19
mcp-server/tsconfig.json Normal file
View file

@ -0,0 +1,19 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}

14
mcp-server/tsup.config.ts Normal file
View file

@ -0,0 +1,14 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
target: 'es2022',
outDir: 'dist',
clean: true,
dts: true,
sourcemap: true,
banner: {
js: '#!/usr/bin/env node',
},
});