- TypeScript 94.4%
- JavaScript 5.4%
- Go Template 0.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
The daemon logged "Daemon listening" (its readiness signal, which the shutdown test and any supervisor key off) before registering its SIGTERM/SIGINT handlers. A signal delivered in that window took the default disposition and killed the process without draining sessions or checkpointing the WAL. Signalling immediately on readiness reproduced it 35/40 times for SIGINT and 15/20 for SIGTERM; it surfaced as the flaky "exits 0 on SIGINT" test. Move the readiness log after process.on() so readiness implies the shutdown path is armed. Repro now 0/40 for both signals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
| launchd | ||
| src | ||
| .gitignore | ||
| AGENTS.md | ||
| CLAUDE.md | ||
| eslint.config.js | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.eslint.json | ||
| tsconfig.json | ||
| vitest.config.ts | ||
mcp-code-index
An always-on macOS daemon that gives Claude persistent, queryable code context across sessions and across projects. It indexes your code with tree-sitter (TypeScript, JavaScript, Svelte), stores symbols, call/import graphs, references, and session notes in SQLite, and serves symbol, graph, and semantic (vector) search over the Model Context Protocol.
One daemon serves every registered project. There is no per-project process and no
MCP_CODE_INDEX_PROJECT env var: projects are registered explicitly (via the mci CLI or
REST) or auto-registered the first time a tool call names a valid project root.
How it works
- MCP over streamable HTTP at
http://127.0.0.1:7420/mcp(stateful sessions). - Localhost REST registry at
http://127.0.0.1:7420/api/*for managing tracked projects. - Bound to
127.0.0.1only. Loopback is the trust boundary; both surfaces validate theHost/Originheaders to defend against DNS-rebinding. No auth/TLS (single-user model). - Refresh-on-query freshness: symbol/graph/search calls block on an incremental
re-index first (inline for small deltas, a worker thread for large ones so the event loop
stays free). Embeddings regenerate on idle;
index_statusreportsembeddings_pending. - Per-project index DBs live in
$XDG_CACHE_HOME/mcp-code-index/indexes/<hash>/index.db(fallback~/.cache/...); a sharedregistry.dbin the same cache root holds the project list and cross-project context links.
Requirements
- Node.js >= 20 (macOS; launchd packaging is macOS-specific)
Install
npm install
npm run build
npm link # puts `mci` and `mcp-code-index` on PATH
mci install-service # load the launchd agent (runs at login, restarts on crash)
Run in the foreground instead of as a service with npm start (or node dist/index.js).
Set MCP_CODE_INDEX_PORT to change the port (default 7420).
Claude Code integration
Register the daemon once, globally, in ~/.claude.json — it then serves every project:
{
"mcpServers": {
"code-index": { "type": "http", "url": "http://127.0.0.1:7420/mcp" }
}
}
Managing projects (mci)
mci add [path] # register a project (defaults to cwd); auto-register also works
mci list # list registered projects
mci status # daemon status: projects, sessions, embeddings pending
mci remove <id|path> # stop tracking a project
mci install-service # install + load the launchd agent
mci uninstall-service # unload + remove it
The same operations are available over REST: POST/GET/DELETE /api/projects, GET /api/status.
MCP tools
Every tool takes a required project argument (the absolute project root). A registered root
resolves directly; an unregistered-but-valid root (contains .git or package.json) is
auto-registered; anything else is rejected.
| Tool | Description |
|---|---|
index_status |
Index health: file/symbol counts, stale files, embeddings_pending |
index_stale |
List files needing re-indexing (modified, deleted, or new) |
index_refresh |
Force re-indexing (bypasses the staleness check) |
index_search |
Search symbols by name pattern or semantic similarity |
index_symbol |
Look up a symbol's definition, callers, callees, and references |
index_graph |
Traverse call/import relationships with depth control |
index_annotate |
Store session context (decisions, patterns, notes) |
index_context |
Retrieve stored context from previous sessions |
index_embeddings |
Generate vector embeddings for semantic search |
index_link |
Attach non-code context (issue/PR/repo/URL/note) to a symbol, file, or project |
index_links |
Query context links for a symbol, file, or project (cross-project) |
Semantic search
index_refresh(or just query — freshness is automatic) to build the index.index_embeddingsto generate vectors (also happens automatically on idle).index_searchwithsemantic: truefor natural-language queries.
Embeddings use all-MiniLM-L6-v2 (384 dims) via @huggingface/transformers, stored with
sqlite-vec.
Development
npm run dev # tsx watch
npm run test # vitest (watch)
npm run test:run # vitest once
npm run typecheck # tsc --noEmit
npm run lint # eslint
License
MIT