Documentation
Troubleshooting
A map from symptom to fix for the most common prom.codes issues — MCP, indexer, dashboard, and embeddings.
When something is off, start here. Each section is keyed by what you see, not by what is wrong — so you can jump straight from the log line or the dashboard message to a fix.
MCP server won't connect
A server is missing from /mcp, or claude mcp list shows it as
failed.
- Run
claude mcp list— each server reports a connection status. A failed server points at the real problem. - Inside a session, run
/mcpto see live status and the server's stderr. A healthy boot announces its tool list and then waits; any earlier exit is the error. - Re-check the install. The
--separator is required and--envrepeats per variable:
See Install for Claude Code for the full set.claude mcp add context --env PROMETHEUS_API_KEY=prom_live_… -- npx -y @prom.codes/context-mcp@latest
"Could not locate the bindings file"
The server dies on boot with a better-sqlite3 bindings error (or a
tree-sitter native-module error).
context and memory use native modules — better-sqlite3 for the local
index, and context also uses tree-sitter plus its language grammars for
parsing. Those .node binaries are fetched or compiled by a package
install script. If that script is skipped, the binary is missing and the
server can't boot. Two situations skip it:
- npm v12+ (from July 2026): install scripts are opt-in. npm no longer
runs
preinstall/install/postinstall— including implicitnode-gypnative builds — for any dependency unless you explicitly allow it. That is a real supply-chain win (a single compromised transitive package can't run code at install time anymore), but it means our native deps need a one-time approval. Our own three packages ship zero install scripts; only their native dependencies (better-sqlite3,tree-sitter*) have them. ignore-scripts=truein your npm config (older corporate hardening) — same symptom on any npm version.
In a project (a repo with a package.json, or a committed .mcp.json
alongside one), review what wants to run and approve the deps you trust:
npm approve-scripts --allow-scripts-pending # lists the blocked packages
npm approve-scripts # approve better-sqlite3, tree-sitter, tree-sitter-*
npm approve-scripts writes the allowlist into package.json — commit it so
teammates and CI inherit it — then reinstall.
For a global install (recommended — immune to npx cache issues and faster
to start) there is no project package.json to hold the allowlist, so name the
packages on the command line and point Claude Code at the built binaries:
npm install -g @prom.codes/context-mcp @prom.codes/memory-mcp @prom.codes/saver \
--allow-scripts=better-sqlite3,tree-sitter
claude mcp add context --scope user -- node "$(npm root -g)/@prom.codes/context-mcp/dist/bin.js"
claude mcp add memory --scope user -- node "$(npm root -g)/@prom.codes/memory-mcp/dist/bin.js"
claude mcp add saver --scope user -- node "$(npm root -g)/@prom.codes/saver/dist/bin.js"
If --allow-scripts-pending also lists tree-sitter-* grammar packages, add
them to the comma-list — or set it once for every future install:
npm config set allow-scripts=better-sqlite3,tree-sitter --location=user.
The saver has no native dependency; it needs no approval and is in the global
command only so one line installs and upgrades all three in lockstep.
Too many node processes / high CPU from prom.codes
Your machine has many @prom.codes/* node processes running —
more than the editor windows you have open — and some pin a CPU
core.
Each editor window runs its own stdio MCP server, which is normal. The problem is abandoned servers: when an editor's extension host reconnects a server (or ends a session) without closing its stdin, the old process never receives the end-of-input signal it uses to exit. Its file watcher keeps it alive and it keeps re-indexing on every change, so abandoned servers accumulate over days.
Fixed in 0.10.1+: every server now also exits itself after 30
minutes with no MCP traffic (tunable via PROMETHEUS_IDLE_EXIT_MS, 0
disables). An in-use server resets that timer on every request; only truly
abandoned ones reap themselves, so they can no longer pile up. Upgrade all
three with the one command above, then reconnect.
To clear a backlog that already exists now (older versions don't self-reap), close your editor windows and kill the leftover servers, then reopen:
# macOS / Linux
pkill -f '@prom.codes/(context-mcp|memory-mcp|saver)'
# Windows PowerShell — only prom.codes servers, never other node.exe
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
Where-Object { $_.CommandLine -match '@prom\.codes[\\/](context-mcp|memory-mcp|saver)' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
The SQLite index is crash-safe (WAL), so killing a server mid-index is safe — it resumes on the next start. The local dashboard lists every running server so you can confirm the count before and after.
Code search is keyword-only / embedding 401
search_code still returns hits, but the result carries
"degraded": "lexical+graph-only" and the server logs a 401 from the
embedding proxy.
You are using a placeholder or format-only key. The api.prom.codes
proxy rejects anything but a real, four-part prom_live_… key with
HTTP 401. As of @prom.codes/context-mcp@0.4.3, search_code no
longer fails on this — it degrades gracefully to lexical
(keyword/BM25) + symbol-graph retrieval, which need no embeddings, and
flags the downgrade in its response (degraded, note, vectorError
fields). Keyword search and every structural tool (get_file,
get_symbol, find_callers, find_callees, find_references,
expand_context, framework_overview, list_workspaces) keep working
with no key at all.
To restore semantic ranking (the concept-query win), use a real
Prometheus key: sign in at app.prom.codes,
mint a key at /app/api-keys (it has the
shape prom_live_<tag>_<secret>), and set it as PROMETHEUS_API_KEY in
the server's env block, then restart the client. The same key
unlocks code embeddings and memory across all three servers — embeddings
route through the managed api.prom.codes proxy, so you never bring your
own provider key.
Once a working key is in place, re-index to backfill the embeddings that
were skipped while the key was invalid — ask the agent "reindex this project
with force" (the reindex tool clears the snapshot and re-embeds everything;
no DB deletion). See Verify your setup & re-indexing.
Server indexes too much / your home folder
The index is huge or seems to crawl outside the repo.
The project is auto-detected on recent versions. As of
@prom.codes/context-mcp@0.4.5 the server refuses to auto-index your
home directory or a filesystem root, and a later release extends that
to a folder that merely contains many projects (e.g. ~/Coding
with a dozen repos) — the cases that happen when you open a fresh window
or terminal with no single project, so the workspace falls back to the
host's working directory. It logs a hint and leaves the index empty
instead of crawling everything; call index_status to see the
resolved root and why indexing was skipped. A real project or monorepo
(anything with a .git, package.json, go.mod, … at its root) is
always indexed, however large. To index a real project, open its folder
(Claude Code passes it via CLAUDE_PROJECT_DIR) or set
PROMETHEUS_WORKSPACE_ROOT to the repo, then restart. To force-index an
unconventional root the guard refused, set PROMETHEUS_INDEX_ROOT_OK=1.
You should not need to set PROMETHEUS_WORKSPACE_ROOT otherwise — only
to point at a different folder than the one you are in.
Vendor / generated trees inflating the index. As of
@prom.codes/context-mcp@0.7.0 the indexer honours the repo's own
.gitignore (plus a .prometheusignore if you add one, same
syntax) on top of the built-in deny-list (node_modules, .next,
dist, …). So gitignored folders — vendored clones, large asset dirs
like public/cesium/, build output — are skipped automatically. If your
index looks bloated (run index_status; a file count far above your real
source is the tell), upgrade and run the reindex tool with force
once so the already-indexed extra paths are dropped. To index a path your
repo gitignores, either add a !negation to .prometheusignore or set
PROMETHEUS_RESPECT_GITIGNORE=false (the .prometheusignore file is still
honoured). Only the repo-root ignore files are read today.
Scoping what gets indexed — the workspace root is the allowlist. The
server only ever walks paths under its resolved workspace root; it never
climbs to the parent. So the simplest "index only these folders" control is to
point the root at exactly the folder you want — open that project, or set
PROMETHEUS_WORKSPACE_ROOT=/path/to/repo. Everything outside is invisible to
the indexer by construction. To allowlist a subtree within the root instead,
use .prometheusignore with the standard gitignore allowlist idiom — ignore
everything, then re-include what you want:
/*
!/.prometheusignore
!/src/
That indexes only src/ and skips the rest, without moving the root.
index_status is also the quickest way to answer "is it installed, which
folder, how much is indexed, does my key work?" — it reports the workspace
root, index counts, auto-index state, and a zero-cost embedding-key check.
search_code answers but results look generic
The tool responds, but the hits are vague rather than empty.
- First rule out the
401case above — a placeholder key drops search to keyword-only (degraded: "lexical+graph-only"), so concept queries rank worse until you add a working embedder. - Check the language coverage. The parser supports TS, JS, Python, Go, Rust, Java, and C# today. A repo dominated by an unsupported language indexes few or no symbols.
- The query may be too short or too generic. The hybrid retriever fuses lexical and semantic signals, but two-token queries still weight heavily on lexical match. Try a full sentence.
POST /index times out
The request hangs for several minutes and then 504s.
The synchronous worker has a 5-minute hard limit. For repos larger
than ~5k files, split with the options.include glob and run two
indices, or mail us to enable the async mode (POST /index?async=1)
on your workspace.
Dashboard says "Tenant not found"
Sign-in succeeds but /app/dashboard redirects to an error.
The signed prom_tenant cookie points to a tenant you no longer
belong to (most often because an admin removed you). The dashboard
deliberately fails closed instead of silently swapping you back in.
Sign out, sign in again, and the resolver falls back to your first
remaining membership.
Invite link is rejected
| Redirect | Cause | Fix |
|---|---|---|
?invite=expired | Token older than 7 days | Ask the admin to re-invite. |
?invite=already_used | Invite was already accepted | Sign in normally and switch tenants. |
?invite=revoked | Admin revoked the invite | Ask for a fresh one. |
?invite=email_mismatch | Signed-in email differs | Sign out, sign in with the invited address. |
?invite=invalid | Token malformed | Re-copy the link from the email; do not edit it. |
The /invite/{token} route is documented in detail under
Members & invitations.
Audit CSV export is empty
Click Export and download a CSV with just the header row.
That is the contract — the export reflects the current filter. Clear the filters (action, status, date range) and re-export, or widen the date range. RLS guarantees you only ever see your own tenant's rows, so an empty export on the widest filter genuinely means no activity.
429 Too Many Requests
You hit the per-tenant rate limit. The response carries
Retry-After and X-RateLimit-Remaining headers — see
Rate limits for the actual budgets
and the recommended backoff strategy.
Indexer claims an embedder failure
Response includes EMBED_FAILED or 503 after a long delay.
The default embedding provider is occasionally degraded. The worker has a per-tenant circuit breaker that trips after consecutive failures and recovers after 60 s. Just retry. If you see this for more than ~5 minutes, mail info@e-networkers.de — it is almost certainly already on our status feed but a direct ping helps us prioritise.
Still stuck?
Mail info@e-networkers.de with:
- Your tenant slug (visible top-left in the dashboard).
- The HTTP status / error code, if any.
- A request id from the worker response or the audit row.
- A timestamp in UTC.
That is enough for us to walk our side of the trace. We do not need — and explicitly do not want — your API key or any source code in the report.