@misterhuydo/cairn-mcp
v1.2.2
Published
MCP server that gives Claude Code persistent memory across sessions. Index your codebase once, search symbols, bundle source, scan for vulnerabilities, and checkpoint/resume work — across Java, TypeScript, Vue, Python, SQL and more.
Maintainers
Readme
Cairn MCP
Persistent polyglot knowledge graph for Claude Code. Index once, query forever.
Claude is stateless — every session starts at zero. On a multi-repo codebase with Java backends, TypeScript frontends, and Vue components, that means 50% of every session is archaeology: finding where things live before any real work can begin.
Cairn fixes this. It indexes your project into a local SQLite knowledge graph (stored in .cairn/) and exposes 8 MCP tools that give Claude instant, persistent memory across sessions.
Install
npm install -g @misterhuydo/cairn-mcpRequirements: Node.js >= 22.15.0
Setup
Add to ~/.claude.json:
{
"mcpServers": {
"cairn": {
"command": "cairn-mcp"
}
}
}Restart Claude Code. Done.
Passive hooks (recommended)
Install once and Cairn works automatically — no need to call cairn_bundle or cairn_checkpoint manually.
Global (all projects):
cairn install-hooks --globalProject-only:
cairn install-hooks| Hook | Trigger | Effect |
|---|---|---|
| PreToolUse[Read] | Every file read | Source files compressed ~68% before Claude sees them |
| Stop | Every response | Session auto-saved to .cairn/session.json |
| UserPromptSubmit | First message of session | Claude reminded of prior session, prompted to call cairn_resume |
How it works
Cairn works like git — it looks for .cairn/ in your current working directory. Run Claude Code from your project root and Cairn automatically stores the index at .cairn/index.db and bundles at .cairn/bundles/.
No root paths needed. No global config. Just cd to your project and go.
Tools
cairn_maintain — Index your project
Run once at the start of each session. The index persists in .cairn/index.db.
cairn_maintain()
cairn_maintain({ languages: ["typescript", "vue"] }) // limit to specific languages{
"repos_indexed": 1,
"files_by_language": { "java": 412, "typescript": 287, "vue": 94 },
"symbols_total": 6841,
"security_findings": 47,
"duration_ms": 4200
}cairn_search — Find anything across all languages
cairn_search({ query: "user authentication", language: "typescript" })[
{ "lang": "typescript", "kind": "function", "fqn": "src/composables/useAuth.ts::useAuth" },
{ "lang": "vue", "kind": "component", "fqn": "src/components/LoginForm.vue::LoginForm" },
{ "lang": "java", "kind": "class", "fqn": "com.example.auth.UserAuthenticator" }
]cairn_bundle — Minified source snapshot for Claude to read
Strips comments and empty lines, writes a compressed ### File: bundle. Use after cairn_search to give Claude readable source without blowing the context window.
cairn_bundle({ filter_paths: ["src/components/checkout"], bundle_name: "checkout" }){
"bundle_path": "/your/project/.cairn/bundles/checkout.txt",
"original_kb": 284,
"compressed_kb": 91,
"reduction_pct": 68
}cairn_describe — Summarize a module
cairn_describe({ path: "src/components/checkout" }){
"languages": ["vue", "typescript"],
"symbols": {
"component": ["CheckoutForm", "OrderSummary", "PaymentStep"],
"function": ["useCheckout", "usePayment"]
},
"imports_from": ["src/store/cart.ts", "src/api/orders.ts"],
"imported_by": ["src/views/CartView.vue"],
"external_deps": ["stripe", "@stripe/stripe-js"]
}cairn_code_graph — Dependency health
cairn_code_graph({ mode: "instability" }){
"modules": [
{ "name": "src/views", "instability": 1.0, "status": "safe_to_refactor" },
{ "name": "src/composables", "instability": 0.4, "status": "review_before_change" },
{ "name": "src/utils", "instability": 0.1, "status": "load_bearing" }
]
}Modes: instability · health · cycles
cairn_security — Vulnerability scan
cairn_security({ severity: "HIGH" }){
"total_findings": 12,
"by_language": { "typescript": 7, "java": 5 },
"findings": [
{ "severity": "HIGH", "cwe": "CWE-79", "file": "src/components/UserProfile.vue", "line": 84, "rule": "XSS via innerHTML" },
{ "severity": "HIGH", "cwe": "CWE-611", "file": "backend/src/.../XmlParser.java", "line": 47, "rule": "XXE" }
]
}Covers: XSS · XXE · SQL injection · command injection · weak crypto · hardcoded secrets · open redirect · unsafe deserialization
cairn_minify — Minify a single file
Minify one source file on demand. Returns compressed content with a [cairn: N → M lines] header. Useful when passive hooks are not installed.
cairn_minify({ file_path: "/abs/path/to/Service.java" })cairn_checkpoint — Save session state
Tell Cairn what you were working on so the next session can pick up where you left off.
cairn_checkpoint({
message: "Added multi-currency to CheckoutForm, still need PaymentStep",
active_files: ["src/components/checkout/CheckoutForm.vue"],
notes: ["CurrencyService expects ISO 4217 codes, not symbols"]
}){
"saved": true,
"checkpoint_at": "2026-02-25T14:30:00Z",
"active_files_tracked": 1,
"notes_saved": 1
}cairn_resume — Restore session + smart re-index
Call instead of cairn_maintain when resuming work. Detects which files changed and only re-indexes those.
cairn_resume(){
"last_checkpoint": "2026-02-25T14:30:00Z",
"message": "Added multi-currency to CheckoutForm, still need PaymentStep",
"index_status": "incremental",
"files_reindexed": 2,
"files_unchanged": 845,
"changed_since_checkpoint": [
{ "file": "src/components/checkout/PaymentStep.vue", "change": "modified" }
],
"active_files": ["src/components/checkout/CheckoutForm.vue"],
"notes": ["CurrencyService expects ISO 4217 codes, not symbols"],
"resume_summary": "Last session you were adding multi-currency support..."
}Supported Languages
| Language | What Cairn extracts | |---|---| | Java | packages, classes, interfaces, enums, records, methods | | TypeScript / JavaScript | classes, interfaces, functions, types, enums | | Vue | components, composables, script block symbols | | Python | classes, functions, decorators | | SQL | tables, views, stored procedures | | XML / HTML | bean ids, component names | | Config (YAML, properties, .env) | top-level keys | | Markdown | headings | | Build files (pom.xml, package.json, build.gradle) | dependencies |
Typical session
With passive hooks (recommended):
1. cairn_maintain → index project
2. cairn_search → find the symbols you need
3. cairn_describe → understand a module before modifying it
4. cairn_security → check for issues before a PR
(reads auto-compressed, session auto-saved — nothing else needed)Without hooks:
1. cairn_maintain → index project (persists between sessions)
2. cairn_search → find the symbols you need
3. cairn_bundle → get a readable snapshot of relevant files
4. cairn_describe → understand a module before modifying it
5. cairn_security → check for issues before a PR
6. cairn_checkpoint → save what you were working onResuming work:
1. cairn_resume → restore session + incremental re-index
2. cairn_search → continue where you left offComplete session lifecycle
─── START OF SESSION ──────────────────────────────────────────
You: "Hey Claude, please resume and continue"
Claude: cairn_resume
→ "Last session: adding multi-currency to checkout.
PaymentStep.vue was modified since checkpoint (2 files changed, re-indexed).
Notes: CurrencyService expects ISO 4217 codes. PaymentStep EUR bug not fixed yet.
Ready to continue."
─── DURING SESSION ────────────────────────────────────────────
Claude uses: cairn_search, cairn_code_graph, cairn_security
as needed — all reading from .cairn/index.db in cwd
(file reads auto-compressed by PreToolUse hook)
─── END OF SESSION ────────────────────────────────────────────
You: "Ok let's stop here for today"
(Stop hook fires → .cairn/session.json auto-saved)
→ Next session: cairn_resume picks up automaticallyLicense
MIT
