Context Engine
MCP tools
The sixteen tools the prom.codes context server exposes over stdio. Includes input schemas and example responses.
The context server registers sixteen tools. Each one is callable by any MCP-aware host (Claude Code, Cursor, VS Code, your own runtime) once the server is wired up — see Claude Code for the canonical setup.
search_code
Hybrid retrieval over the indexed workspace. Combines lexical and semantic ranking over the indexed code, then expands one hop in the symbol graph.
{
"name": "search_code",
"arguments": {
"query": "validate incoming webhook signature",
"k": 8
}
}k is optional (default 10, capped at 50). Returns
{ query, k, reranked, results: [{ score, provenance, symbol }] }, where
each symbol carries { name, kind, language, container, exported, filePath, range } and provenance is the per-source score breakdown.
Graceful degradation (≥ 0.4.3). If the embedder is unavailable
(missing/invalid key → 401, provider outage, rate-limit), the semantic
leg is skipped and search continues on lexical + symbol-graph only. The
response then also carries degraded: "lexical+graph-only", a
human-readable note, and vectorError (the underlying cause), so the
caller knows ranking is keyword-based until a working embedder is
configured. The tool never fails outright on an embedding error.
get_symbol
Looks up symbols by exact name, returning each definition's kind,
language, container, export flag, file path, and range. Optional file
narrows the result to a single workspace-relative path; optional limit
caps the count (default 10, max 50).
{
"name": "get_symbol",
"arguments": { "name": "enqueue", "file": "src/queue.ts" }
}Returns { name, file, symbols: [symbol] }.
find_references
Lists all static references (calls / imports / member-access) whose target name matches.
{
"name": "find_references",
"arguments": { "name": "chargeCustomer", "limit": 20 }
}Returns { name, references: [{ name, kind, filePath, fromContainer, moduleSpecifier, range }] }.
find_callers
Inbound call-graph edge: every symbol whose body calls the named
symbol. Materialised from call / member_access references whose
byte-range is enclosed by the caller symbol's range, matched
case-insensitively on the seed name. Use this to answer "who calls
this?" without scanning the whole tree.
{
"name": "find_callers",
"arguments": { "name": "chargeCustomer", "limit": 20 }
}Returns { name, callers: [{ name, kind, language, filePath, ... }] }.
find_callees
Outbound call-graph edge: every symbol the named symbol calls.
Resolves call / member_access references emitted from inside the
seed symbol's body to their definitions (excluding the seed itself).
Use this to answer "what does this depend on?".
{
"name": "find_callees",
"arguments": { "name": "checkout", "limit": 20 }
}Returns { name, callees: [{ name, kind, language, filePath, ... }] }.
expand_context
One-hop (or two-hop) symbol-graph expansion around a single symbol
name. Returns neighbours bucketed by edge type and walk depth, so an
agent can grow a tight retrieval into something it can reason about.
depth is 1 (direct, default) or 2; limit caps the count
(default 10, max 50); edgeTypes optionally restricts the walk to a
subset of defines / calls / imports / same-file.
{
"name": "expand_context",
"arguments": {
"name": "RetryQueue",
"depth": 1,
"edgeTypes": ["calls", "imports"]
}
}Returns { name, depth, edgeTypes, neighbours: [{ via, depth, symbol }] }.
get_file
Verbatim UTF-8 file contents, resolved against the configured
workspace root (path traversal outside the root is rejected).
Optional startByte / endByte slice the file; the returned payload
is capped at 256 KiB and flags truncated when the slice exceeded it.
{
"name": "get_file",
"arguments": { "path": "src/queue.ts", "startByte": 0, "endByte": 4096 }
}Returns { path, startByte, endByte, truncated, content }.
list_changed_since
Returns file records with indexedAt greater than timestampMs,
ordered ascending — an incremental cursor for watchers and review
flows. Use the largest returned indexedAt (nextCursor) as the next
cursor. limit caps the page (default 10, max 50).
{
"name": "list_changed_since",
"arguments": { "timestampMs": 1717000000000, "limit": 50 }
}Returns { cursor, nextCursor, files: [{ path, language, contentHash, size, mtimeMs, indexedAt }] }.
list_workspaces
Metadata for every workspace this server indexes. The local SQLite MVP serves a single workspace; the Supabase backend is multi-tenant. Each entry carries the index roll-up (file / symbol / reference counts) and the per-language file distribution. Takes no arguments.
{
"name": "list_workspaces",
"arguments": {}
}Returns { workspaces: [{ id, name, root, storageBackend, regionMode, embeddingProvider, stats, languages }] }.
framework_overview
High-level shape of the workspace: frameworks detected from manifest
files (package.json, composer.json, requirements.txt,
pyproject.toml) plus the per-language file distribution from the
index. Heuristic and dependency-driven — absence of a hit means
"not declared in a manifest", not "not used". Takes no arguments.
{
"name": "framework_overview",
"arguments": {}
}Returns { workspaceRoot, manifestsInspected, frameworks: [{ name, version, source }], languages }.
get_architecture
One-call high-level map of the indexed workspace — the fast first
move when onboarding onto an unfamiliar repo, replacing a dozen
list/read calls. Optional hotspots caps the most-referenced-symbol
list (0 to skip it; default 20, max 50).
{
"name": "get_architecture",
"arguments": { "hotspots": 20 }
}Returns { workspaceRoot, index: { files, symbols, references, embeddingCoverage, lastIndexedAt }, languages, frameworks, packages: [{ name, path, manifest }], layout: [{ dir, files, dominantLanguage }], symbolKinds, hotspots: [{ name, kind, filePath, referenceCount }], entryPoints: [{ path, via }], notes }. hotspots are the most-referenced
locally-defined symbols — the code everything else leans on. notes
carries any per-run advisories (e.g. a large layout was capped to the
busiest folders).
index_status
Health check for the workspace's code index. Call it first when
search_code returns nothing, when you're unsure whether the right
folder is indexed, or to confirm the API key works. Takes no arguments.
{
"name": "index_status",
"arguments": {}
}Returns { installed, workspace: { id, name, root }, storage: { backend, dbPath, regionMode }, autoIndex: { managed, allowedForThisRoot, reason }, index: { indexed, files, symbols, references, languages, lastIndexedAt }, embeddings: { provider, reachable, coverage, error? }, hooks, update, summary }. autoIndex.allowedForThisRoot
is false when the workspace resolved to your home directory or a
filesystem root — the server refuses to crawl those (open a project
folder or set PROMETHEUS_WORKSPACE_ROOT, then restart). embeddings.reachable
is a zero-cost probe of the configured key (false with an error when the
key is missing/invalid; null when the provider can't be cheaply probed).
Two fields deserve special attention (both since 0.10.0):
embeddings.coverage is { embeddedChunks, totalChunks, percent } —
the share of code chunks that have a semantic vector. Below ~80 % the
summary suggests running reindex, which embeds only what is
missing. update is { current, latest, updateAvailable, command, lastResult? } — the cache-first version check (see
update_servers; lastResult reports what the last
detached update run did).
reindex
Rebuilds this workspace's index on demand: re-scans every file (parse +
hash-diff; entries for files deleted on disk are removed), then runs the
embedding pass. The embed pass is incremental by default — it embeds only
the new/changed symbols that are missing a vector, so this is the fast way to
populate embeddings after fixing an API key or to pick up changes without
restarting the host. Pass force: true to clear the snapshot and re-embed
every symbol from scratch (use after switching embedding providers, or to
repair a partial index). Requires a PROMETHEUS_API_KEY and a real project
folder (refused for the home directory / filesystem root).
{
"name": "reindex",
"arguments": { "force": false }
}Returns { ok, force, index: { scanned, indexed, skippedUnchanged, removed, errors }, embeddings: { embedded, provider, model, dimension, driftRecovered, embedMs }, summary }. When indexing is disabled (no key) or the workspace is the
home/root, returns { ok: false, reason } instead.
install_hooks
Installs (or removes) the Claude Code awareness hooks — the active layer that makes agents actually use these tools instead of falling back to grep out of habit. A SessionStart hook injects a binding directive at turn 0 (and after every compaction), a UserPromptSubmit hook re-asserts it per prompt, and the SessionStart hook also surfaces pending server updates.
{
"name": "install_hooks",
"arguments": { "scope": "user", "strict": false, "uninstall": false }
}scope: user (default — every project), project
(committed .claude/settings.json) or project-local (gitignored;
the auto-bootstrap target). strict: true additionally denies Grep/Glob
and redirects to search_code (opt-in). Idempotent, reversible, backs up
settings.json, preserves foreign hooks. Claude-Code-specific.
The context-handover trigger
The same install adds a Stop hook that watches how full the context
window is — something an MCP server cannot see, but the hook can:
Claude Code writes a usage block per API call into the transcript, and
input + cache_read + cache_creation is the current prompt size.
| Fill | What happens |
|---|---|
| ~40% of the window | You get a one-line notice; the agent asks on your next prompt whether to hand over now or keep going. No extra model turn is spent. |
| ~50% of the window | The agent actively proposes writing a handover file and continuing in a fresh session. |
Quality holds well up to about half a window and degrades after that, so handing over to a fresh agent both protects the answers and cuts cost (cost ≈ context size × turns). The decision is always yours — the hook never forces a handover and never stops work. It fires once per level per session and rearms after a compaction.
| Variable | Default | Purpose |
|---|---|---|
PROMETHEUS_HANDOVER_HINT | on | off disables the trigger entirely. |
PROMETHEUS_HANDOVER_INTERRUPT | on | off keeps the user-facing notice but never spends an extra model turn. |
PROMETHEUS_HANDOVER_NOTICE_TOKENS / _SUGGEST_TOKENS | 400000 / 500000 | Absolute thresholds. |
PROMETHEUS_HANDOVER_NOTICE_SHARE / _SUGGEST_SHARE | 0.4 / 0.5 | Relative thresholds; whichever trips first wins, so a 200k model hints at 80k/100k. |
PROMETHEUS_CONTEXT_WINDOW | auto | Override the window size. Detection deliberately assumes the large window when unsure — a wrong low guess would nag every long session. |
dashboard
Renders the local status dashboard as one self-contained HTML page and
returns its file path — running servers (via heartbeats), per-workspace
index health incl. embedding coverage %, memory roll-up, hooks/key
health and the current month's cloud usage. Read-only and local-first: only
the cloud tile queries the metered proxy. See the
Local dashboard guide for the full tour and
the CLI variant (… dashboard --out … --no-open --json).
{
"name": "dashboard",
"arguments": { "open": true }
}open: true also launches the default browser. Returns { ok, htmlPath, servers, currentWorkspace, workspacesIndexed, memoryRecords, hooksInstalled, keyValid, cloud, summary }.
update_servers
Safe, guided self-update for all three prom.codes servers. It never runs
npm install while servers are running (a running server locks its native
modules — the classic Windows EBUSY half-install trap). Instead it
reports the plan and launches a detached updater that waits until every
prom server has exited (you reload/close the editor windows), then runs the
one documented upgrade command. The outcome lands in
index_status.update.lastResult after the restart.
{
"name": "update_servers",
"arguments": { "dryRun": false, "force": false }
}dryRun: true only reports the plan (installed vs latest versions, install
kind, npm config get ignore-scripts, running servers). force: true —
always explicit, never assumed — lets the updater terminate the
remaining servers instead of waiting for their windows to close. Running via
npx …@latest? Then there is nothing to install — the response says to
simply restart the session. See the
Local dashboard & updates guide
for the full flow.