context-mode

MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.

npm · fingerprint fc78f92deb7790577d93336e · repository · RSS

11tools
2recorded versions
1dtracked
changed today

What changed

Changed 2026-09-03 07:12 UTC

8 descriptions rewritten, 3 schema or annotation changes with the description left byte-identical.

--- pinned/ctx_batch_execute
+++ observed/ctx_batch_execute
  {
-   "annotations": {
-     "destructiveHint": true,
-     "idempotentHint": false,
-     "openWorldHint": true,
-     "readOnlyHint": false
-   },
-   "description": "Run multiple commands in ONE call. Every command's output is auto-indexed into the knowledge base; if you also pass `queries`, the matching sections come back in the same round trip so a follow-up search call is not needed.\n\nConcurrency parallelizes the FETCH phase (run-the-commands). The DERIVATION phase — turning raw output into an answer — still belongs in code: add a processing command that consumes the indexed output and prints only the answer, so the raw bytes never enter your conversation (Think-in-Code, same principle as the sandbox tool).\n\nWHEN:\n  - You have 3+ related commands you would otherwise run sequentially (multi-issue lookups, git log + git diff + git blame, multi-file reads, multi-region cloud queries)\n  - You want to gather AND query in one round trip — pass `queries` so the matching sections come back inline\n  - You want to parallelize I/O-bound work — pass `concurrency` 2-8 (network calls, gh CLI, cloud APIs, multi-repo git reads)\n  - The combined output is large enough that piping it through ctx_search later would itself be expensive — let auto-index + inline queries do both in one shot\n\nWHEN NOT:\n  - Single command with no follow-up query — run it in the sandbox tool directly\n  - CPU-bound or stateful commands — keep concurrency at 1 (npm test, build, lint, port-binding servers, lock-file holders, anything that races on the same resource)\n\nRETURNS:\n  Auto-indexed section list per command label, plus top matches per query (when `queries` is passed). Raw output is NOT echoed in full — only the matched windows. Concurrency>1 switches each command to its own per-command timeout (no shared budget); concurrency=1 preserves the legacy shared-budget cascading-skip-on-timeout path. Use 4-8 for I/O-bound batches; keep at 1 for CPU work or shared-state commands; lower the value when target hosts enforce per-IP rate limits.\n\nEXAMPLE: ctx_batch_execute(\n  commands: [\n    {label: \"issue 1\", command: \"gh issue view 1\"},\n    {label: \"issue 2\", command: \"gh issue view 2\"},\n    {label: \"summarize\", command: \"echo done\"}\n  ],\n  queries: [\"root cause\", \"proposed fix\"],\n  concurrency: 2\n)",
+   "description": "Execute multiple commands in ONE call, auto-index all output, and search with multiple queries. Returns search results directly — no follow-up calls needed.\n\nTHIS IS THE PRIMARY TOOL. Use this instead of multiple ctx_execute() calls.\n\nOne ctx_batch_execute call replaces 30+ ctx_execute calls + 10+ ctx_search calls.\nProvide all commands to run and all queries to search — everything happens in one round trip.\n\nPARALLELIZE I/O: For I/O-bound batches (network calls, slow API queries, multi-URL fetches), ALWAYS pass concurrency: 4-8 — speeds up by 3-5x on real workloads.\n  ✅ Use concurrency: 4-8 for: gh API calls, curl/web fetches, multi-region cloud queries, multi-repo git reads, dig/DNS, docker inspect.\n  ❌ Keep concurrency: 1 for: npm test, build, lint, image processing (CPU-bound), or commands sharing state (ports, lock files, same-repo writes).\n  Example: [gh issue view 1, gh issue view 2, gh issue view 3] → concurrency: 3.\n  Speedup depends on workload — applies to I/O wait, not CPU work.\n\nTHINK IN CODE — NON-NEGOTIABLE: When commands produce data you need to analyze, count, filter, compare, or transform — add a processing command that runs JavaScript and console.log() ONLY the answer. NEVER pull raw output into context to reason over. Concurrency parallelizes the FETCH; THINK IN CODE owns the PROCESSING. One programmed analysis replaces ten read-and-reason rounds. Pure JavaScript, Node.js built-ins (fs, path, child_process), try/catch, null-safe.",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "commands": {
          "description": "Commands to execute as a batch. Output is labeled with the section header. Default order is sequential; pass concurrency>1 to run in parallel (output stays in input order).",
+           "additionalProperties": false,
            "properties": {
              "command": {
                "description": "Shell command to execute",
-       "cwd": {
-         "description": "Optional working directory for all shell commands in this batch.",
-         "type": "string"
-       },
        "queries": {
          "description": "Search queries to extract information from indexed output. Use 5-8 comprehensive queries. Each returns top 5 matching sections with full content. This is your ONLY chance — put ALL your questions here. No follow-up calls needed.",
          "items": {
-       "query_scope": {
-         "default": "batch",
-         "description": "Scope for `queries` (default: `batch`). `batch` searches ONLY the chunks produced by this batch's commands — useful when you want answers about the just-fetched output. `global` searches the entire persistent index (same scope as ctx_search) — useful when you want the batch commands to enrich context and the queries to also surface related prior knowledge in one round trip.",
-         "enum": [
-           "batch",
-           "global"
-         ],
-         "type": "string"
-       },
        "timeout": {
          "description": "Max execution time in ms. When omitted, no server-side timer fires — the MCP host's RPC timeout governs. With concurrency=1, the value (when set) is a shared budget across commands; with concurrency>1, it is applied per-command.",
          "type": "number"
--- pinned/ctx_doctor
+++ observed/ctx_doctor
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": true,
-     "openWorldHint": false,
-     "readOnlyHint": true
-   },
    "description": "Diagnose context-mode installation. Runs all checks server-side and returns a plain-text status report with [OK]/[FAIL]/[WARN] prefixes (renderer-safe across MCP clients). No CLI execution needed.",
    "execution": {
      "taskSupport": "forbidden"
+     "additionalProperties": false,
      "properties": {},
      "type": "object"
    },
--- pinned/ctx_execute
+++ observed/ctx_execute
  {
-   "annotations": {
-     "destructiveHint": true,
-     "idempotentHint": false,
-     "openWorldHint": true,
-     "readOnlyHint": false
-   },
-   "description": "Run code in a sandboxed subprocess. Languages: javascript, shell, python, go, rust, perl.\n\nThink-in-Code — the core philosophy: the bytes your code processes never enter your conversation memory; only what you console.log() does. Reading a 700 KB log directly means 700 KB of your remaining reasoning capacity gets spent on raw bytes. Running code over that same log in this sandbox and printing a 3 KB summary leaves you with 697 KB of capacity for the actual work.\n\nConcrete shape — analyze 47 source files without reading any of them:\n  ctx_execute(language: \"javascript\", code: `\n    const fs = require('fs');\n    const files = fs.readdirSync('src').filter(f => f.endsWith('.ts'));\n    files.forEach(f => {\n      const lines = fs.readFileSync('src/'+f,'utf8').split('\\\\n').length;\n      console.log(f + ': ' + lines + ' lines');\n    });\n  `)\n  // 47 files analyzed, 15,314 LoC summarized — output ~3.6 KB instead of 47 Read() calls = ~700 KB.\n\nWHEN:\n  - You intend to derive an answer FROM data (filter, count, aggregate, parse, compare, transform) — do the derivation in code and print only the answer\n  - Output shape or size cannot be predicted before execution (recursive finds, repo-wide greps, list endpoints, query results, log scans)\n  - You would otherwise read raw output and then mentally compute — that compute belongs here, in code, where its inputs stay out of your conversation\n  - You need to keep a long-running process alive (dev server, watcher, daemon) — pass `background: true` to detach on timeout instead of killing the process\n  - The output may legitimately be large but you only want recall-by-topic later — pass an `intent` string; outputs over ~5KB are auto-indexed into the knowledge base and only the section titles + previews come back, retrievable via ctx_search\n\nWHEN NOT:\n  - Single observational command whose entire short output you intend to consume verbatim (whoami, pwd, git status on a clean tree) — Bash is simpler\n  - File mutations (Edit/Write) or navigation (cd/ls) — Bash is the right surface\n  - You already know the output is one short fixed line and you want to read it as-is\n\nRETURNS:\n  Only what your code prints. Wrap risky calls in try/catch — uncaught errors go to stderr and may leak more than intended. When `intent` is set and output exceeds the auto-index threshold, the response carries searchable section titles + previews instead of the raw stdout; use ctx_search(queries: [...]) to drill into specific sections.\n\nEXAMPLE: ctx_execute(language: \"javascript\", code: \"const out = require('child_process').execSync('npm test', {encoding:'utf8', stdio:['ignore','pipe','pipe']}); console.log(out.split('\\\\n').filter(l => /(FAIL|✗|×|Error:|Tests +.*(failed|passed))/i.test(l)).slice(0, 60).join('\\\\n'))\")\nEXAMPLE: ctx_execute(language: \"javascript\", code: \"const out = require('child_process').execSync('gh issue list --json number,title --limit 100', {encoding:'utf8'}); const hooks = JSON.parse(out).filter(i => /hook|routing/i.test(i.title)); console.log(`${hooks.length} hook-related issues`)\")",
+   "description": "MANDATORY: Use for any command where output exceeds 20 lines. Execute code in a sandboxed subprocess. Only stdout enters context — raw data stays in the subprocess. Available: javascript, shell, python, ruby, go, rust, php, perl.\n\nPREFER THIS OVER BASH for: API calls (gh, curl, aws), test runners (npm test, pytest), git queries (git log, git diff), data processing, and ANY CLI command that may produce large output. Bash should only be used for file mutations, git writes, and navigation.\n\nTHINK IN CODE: When you need to analyze, count, filter, compare, or process data — write code that does the work and console.log() only the answer. Do NOT read raw data into context to process mentally. Program the analysis, don't compute it in your reasoning. Write robust, pure JavaScript (no npm dependencies). Use only Node.js built-ins (fs, path, child_process). Always wrap in try/catch. Handle null/undefined. Works on both Node.js and Bun.",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "background": {
          "default": false,
-       "cwd": {
-         "description": "Optional working directory for shell commands. Non-shell languages still execute from their sandbox temp directory.",
-         "type": "string"
-       },
        "intent": {
          "description": "What you're looking for in the output. When provided and output is large (>5KB), indexes output into knowledge base and returns section titles + previews — not full content. Use ctx_search(queries: [...]) to retrieve specific sections. Example: 'failing tests', 'HTTP 500 errors'.\n\nTIP: Use specific technical terms, not just concepts. Check 'Searchable terms' in the response for available vocabulary.",
          "type": "string"
-   "title": "Run code in a sandbox (executes the supplied code)"
+   "title": "Execute Code"
  }
--- pinned/ctx_execute_file
+++ observed/ctx_execute_file
  {
-   "annotations": {
-     "destructiveHint": true,
-     "idempotentHint": false,
-     "openWorldHint": true,
-     "readOnlyHint": false
-   },
-   "description": "Read a file into a sandboxed FILE_CONTENT variable and run code over it. Only what you console.log() enters your conversation — the file bytes stay in the sandbox.\n\nThink-in-Code applied to file-level analysis: Reading the whole file means every byte enters your conversation memory and costs reasoning capacity for the rest of the session. Running code over it here lets you keep the raw bytes out and only the derived answer in. Same principle as ctx_execute, scoped to one named file via the FILE_CONTENT variable.\n\nWHEN:\n  - You want to KNOW SOMETHING ABOUT a file (line count, matches of a pattern, parsed structure, statistical aggregate) without needing to SEE all of it\n  - The file is structured (CSV, JSON, log, code) and a code-level derivation is cheaper than reading verbatim\n  - The file is large enough that reading the full content would burn meaningful conversation memory you need for the actual work\n  - The derivation may itself produce a large output you want recall-by-topic on later — pass an `intent` string; outputs over ~5KB are auto-indexed and only matching sections come back, retrievable via ctx_search\n\nWHEN NOT:\n  - You intend to EDIT the file — use Read so the subsequent Edit can match the exact text\n  - You only need one specific line and you know its offset — Read with offset/limit is the simplest path\n  - The file is small AND you will consume all of it for understanding/editing — Read directly\n\nRETURNS:\n  Only what your code prints. The FILE_CONTENT variable holds the raw bytes inside the sandbox; nothing else leaves. When `intent` is set and output exceeds the auto-index threshold, the response carries searchable section titles + previews instead of the raw stdout.\n\nEXAMPLE: ctx_execute_file(path: \"huge.log\", language: \"javascript\", code: \"const errs = FILE_CONTENT.split('\\\\n').filter(l => /ERROR|FATAL/.test(l)); console.log(`${errs.length} error lines`); console.log(errs.slice(-5).join('\\\\n'))\")\nEXAMPLE: ctx_execute_file(path: \"data.csv\", language: \"javascript\", code: \"const rows = FILE_CONTENT.split('\\\\n'); console.log(`rows: ${rows.length - 1}, header: ${rows[0]}`)\")",
+   "description": "Read a file and process it without loading contents into context. The file is read into a FILE_CONTENT variable inside the sandbox. Only your printed summary enters context.\n\nPREFER THIS OVER Read/cat for: log files, data files (CSV, JSON, XML), large source files for analysis, and any file where you need to extract specific information rather than read the entire content.\n\nTHINK IN CODE: Write code that processes FILE_CONTENT and console.log() only the answer. Don't read files into context to analyze mentally. Write robust, pure JavaScript — no npm deps, try/catch, null-safe. Node.js + Bun compatible.",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "code": {
          "description": "Code to process FILE_CONTENT (file_content in Elixir). Print summary via console.log/print/echo/IO.puts/Console.WriteLine.",
-   "title": "Run code over a file (executes code, reads the given path)"
+   "title": "Execute File Processing"
  }
--- pinned/ctx_fetch_and_index
+++ observed/ctx_fetch_and_index
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": false,
-     "openWorldHint": true,
-     "readOnlyHint": false
-   },
-   "description": "Fetches URL content, converts HTML to markdown (JSON is chunked by key paths, plain text indexed directly), persists it in a searchable knowledge base, and returns a small preview window per source. The raw page bytes never enter your conversation — they live in storage and you retrieve any section on-demand via ctx_search.\n\nCaching: every fetch is cached on disk and reused for repeat calls within the TTL window. The default TTL is 24 hours; override per-call with the `ttl` parameter (milliseconds, `ttl: 0` bypasses cache like `force: true`). Stored content older than 14 days is cleaned up on startup.\n\nWHEN:\n  - You need web content (docs, changelogs, API references, spec pages) and the raw page bytes should NOT enter your conversation\n  - Multi-URL research (library evaluation, migration scans, doc comparisons): pass the `requests` array and a `concurrency` value 2-8 for parallel I/O\n  - You want repeat lookups against the same URL to be cheap (TTL cache hits return only a hint, no re-fetch)\n  - You want a long-lived cache window (override `ttl` upward for stable specs) or a guaranteed-fresh fetch (`ttl: 0` or `force: true`)\n\nWHEN NOT:\n  - You already have the content locally — store it via the inline index tool\n  - The page is SPA-rendered (JavaScript-required to materialize content) — this is a plain HTTP fetch, no headless browser\n\nRETURNS:\n  Per-source preview windows extracted around indexable headings plus indexing metadata (chunk counts, source labels, cache state). Raw content is NOT echoed back — retrieve any section on-demand via ctx_search(source: \"<label>\"). Concurrency parallelizes the fetch phase up to your chosen value (capped by the host's logical CPU count); the FTS5 write phase always runs serially because SQLite is a single-writer store. Net latency = max(fetch latency across the pool) + sum(per-source index write time). Cache hits skip both phases and return a small freshness hint instead of re-fetching. Use 4-8 for stable I/O-bound batches; lower the value when the target host enforces a per-IP rate limit you cannot raise.\n\nEXAMPLE: ctx_fetch_and_index(\n  requests: [{url: \"https://react.dev/...\", source: \"react\"}, {url: \"https://vuejs.org/...\", source: \"vue\"}],\n  concurrency: 5\n)",
+   "description": "Fetches URL content, converts HTML to markdown, indexes into searchable knowledge base, and returns a ~3KB preview. Full content stays in sandbox — use ctx_search() for deeper lookups.\n\nBetter than WebFetch: preview is immediate, full content is searchable, raw HTML never enters context.\n\nContent-type aware: HTML is converted to markdown, JSON is chunked by key paths, plain text is indexed directly.\n\nPARALLELIZE I/O: For multi-URL research (library evaluation, migration scans, doc comparisons), pass `requests: [{url, source}, ...]` with `concurrency: 4-8` — speeds up by 3-5x on real workloads.\n  ✅ Use concurrency: 4-8 for: library docs sweep, multi-changelog scan, competitive pricing pages, multi-region docs, GitHub raw file pulls.\n  ❌ Single URL → use the legacy {url, source} shape (concurrency irrelevant).\n  Example: requests: [{url: 'https://react.dev/...', source: 'react'}, {url: 'https://vuejs.org/...', source: 'vue'}], concurrency: 5.\n  Fetches parallelize up to your concurrency setting; FTS5 indexing serializes the writes after (SQLite single-writer rule).",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "concurrency": {
          "default": 1,
+           "additionalProperties": false,
            "properties": {
              "source": {
                "description": "Label for this URL's indexed content",
-       "ttl": {
-         "description": "Override the cache freshness window for this call, in milliseconds. `ttl: 0` bypasses the cache like `force: true`; omit to use the default 24h TTL.",
-         "minimum": 0,
-         "type": "integer"
-       },
        "url": {
          "description": "Single URL to fetch and index (legacy single-shape)",
          "type": "string"
--- pinned/ctx_index
+++ observed/ctx_index
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": false,
-     "openWorldHint": false,
-     "readOnlyHint": false
-   },
-   "description": "Store content in a searchable knowledge base (BM25 over FTS5). Splits markdown by headings, keeps code blocks intact, and persists the raw chunks. The full content stays in storage — retrieve any section on-demand via ctx_search; nothing is summarized or truncated.\n\nWHEN:\n  - Documentation from Context7, Skills, or MCP tools (API docs, framework guides, code examples)\n  - API references (endpoint details, parameter specs, response schemas)\n  - MCP tools/list output (exact tool signatures and descriptions)\n  - Skill prompts and instructions that are too large to keep verbatim in conversation\n  - README files, migration guides, changelog entries\n  - Any content with code examples you may need to reference precisely later\n\nWHEN NOT:\n  - Log files, test output, CSV, or build output — use ctx_execute_file, which processes in-sandbox without persisting bytes\n  - Single-use ephemeral content you will not query later — keep it inline if it fits, or ctx_execute_file it\n\nRETURNS:\n  Indexing metadata: chunk counts (total, code-bearing), source label, and the exact ctx_search call shape to query the indexed content. Raw content is NOT echoed back — it lives in storage, retrievable via ctx_search(source: \"<label>\"). When `path` is provided, a content hash is stored so ctx_search results auto-flag staleness on future calls.\n\nEXAMPLE: ctx_index(content: \"# React useEffect\\n\\nThe Effect Hook lets you ...\", source: \"react-useeffect-docs\")\nEXAMPLE: ctx_index(path: \"/path/to/large-spec.md\", source: \"openapi-v2-spec\")",
+   "description": "Index documentation or knowledge content into a searchable BM25 knowledge base. Chunks markdown by headings (keeping code blocks intact) and stores in ephemeral FTS5 database. The full content does NOT stay in context — only a brief summary is returned.\n\nWHEN TO USE:\n- Documentation from Context7, Skills, or MCP tools (API docs, framework guides, code examples)\n- API references (endpoint details, parameter specs, response schemas)\n- MCP tools/list output (exact tool signatures and descriptions)\n- Skill prompts and instructions that are too large for context\n- README files, migration guides, changelog entries\n- Any content with code examples you may need to reference precisely\n\nAfter indexing, use 'ctx_search' to retrieve specific sections on-demand.\nWhen `path` is provided, a content hash is stored for automatic stale detection in search results.\nDo NOT use for: log files, test output, CSV, build output — use 'ctx_execute_file' for those.",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "content": {
          "description": "Raw text/markdown to index. Provide this OR path, not both.",
-       "exclude": {
-         "description": "Directory-only: glob patterns to exclude. Merged with defaults (node_modules, .git, dist, build, .next, coverage, .venv, __pycache__, .DS_Store).",
-         "items": {
-           "type": "string"
-         },
-         "type": "array"
-       },
-       "extensions": {
-         "description": "Directory-only: allowed file extensions (default: .md .mdx .txt .json .yaml .yml .ts .tsx .js .jsx .py .rs .go .sh).",
-         "items": {
-           "type": "string"
-         },
-         "type": "array"
-       },
-       "followSymlinks": {
-         "description": "Directory-only: follow directory symlinks (default: false — cycle hazard + escape risk).",
-         "type": "boolean"
-       },
-       "include": {
-         "description": "Directory-only: glob patterns to include (default: all matching extensions).",
-         "items": {
-           "type": "string"
-         },
-         "type": "array"
-       },
-       "maxDepth": {
-         "description": "Directory-only: max recursion depth from root (default: 5).",
-         "minimum": 0,
-         "type": "integer"
-       },
-       "maxFiles": {
-         "description": "Directory-only: hard cap on files indexed (default: 200) — FTS5 blow-up guard.",
-         "minimum": 1,
-         "type": "integer"
-       },
        "path": {
-         "description": "File OR directory path to read and index (content never enters context). Provide this OR content. Directory paths trigger a bounded recursive walk (#687).",
+         "description": "File path to read and index (content never enters context). Provide this OR content.",
          "type": "string"
        },
-       "respectGitignore": {
-         "description": "Directory-only: apply nearest .gitignore (default: true).",
-         "type": "boolean"
-       },
        "source": {
          "description": "Label for the indexed content (e.g., 'Context7: React useEffect', 'Skill: frontend-design')",
          "type": "string"
--- pinned/ctx_insight
+++ observed/ctx_insight
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": true,
-     "openWorldHint": true,
-     "readOnlyHint": false
-   },
-   "description": "Opens the context-mode Insight dashboard (https://context-mode.com/insight) in your default browser — a dashboard launcher for the hosted analytics layer, not a Q&A engine. Insight surfaces per-engineer productive rate, retry waste, blocker detection, and role-narrowed views for CTO, EM, IC, CISO, FinOps, and DevOps. For natural-language queries over your indexed content, use ctx_search.",
+   "description": "Opens the context-mode Insight dashboard in the browser. Shows personal analytics: session activity, tool usage, error rate, parallel work patterns, project focus, and actionable insights. First run installs dependencies (~30s). Subsequent runs open instantly.",
    "execution": {
      "taskSupport": "forbidden"
    },
-     "properties": {},
+     "additionalProperties": false,
+     "properties": {
+       "contentDir": {
+         "description": "Override INSIGHT_CONTENT_DIR: directory containing context-mode content/index .db files",
+         "type": "string"
+       },
+       "insightContentDir": {
+         "description": "Alias for contentDir / INSIGHT_CONTENT_DIR",
+         "type": "string"
+       },
+       "insightSessionDir": {
+         "description": "Alias for sessionDir / INSIGHT_SESSION_DIR",
+         "type": "string"
+       },
+       "port": {
+         "description": "Port to serve on (default: 4747)",
+         "maximum": 65535,
+         "minimum": 1,
+         "type": "integer"
+       },
+       "sessionDir": {
+         "description": "Override INSIGHT_SESSION_DIR: directory containing context-mode session .db files",
+         "type": "string"
+       }
+     },
      "type": "object"
    },
    "name": "ctx_insight",
--- pinned/ctx_purge
+++ observed/ctx_purge
  {
-   "annotations": {
-     "destructiveHint": true,
-     "idempotentHint": true,
-     "openWorldHint": false,
-     "readOnlyHint": false
-   },
-   "description": "DESTRUCTIVE: permanently delete indexed content. Cannot be undone. Requires confirm:true and exactly one scope.\n\nWHEN:\n  - User explicitly asks to clear a specific session ('purge this session', 'wipe this conversation')\n  - User explicitly asks to reset the whole project ('reset everything', 'wipe the knowledge base')\n\nWHEN NOT:\n  - User says 'reset', 'clear', or 'wipe' without naming a scope -> ask which scope before calling\n  - User wants to free memory or improve performance -> recommend ctx_stats first, do not purge\n\nSCOPES (pass exactly one):\n  - Per-session: ctx_purge(confirm: true, sessionId: \"<uuid>\") deletes that session's events (auto-captured decisions, errors, plans, user prompts, rejected approaches, etc.) and per-session FTS5 chunks; sibling sessions and stats file are preserved.\n  - Per-project: ctx_purge(confirm: true, scope: \"project\") wipes FTS5 knowledge base, every session DB row, events markdown, and resets the stats file. Use ctx_stats first to preview category counts before purging.\n\nCONTRACT:\n  - confirm:true is required; confirm:false returns 'purge cancelled'.\n  - sessionId and scope:'project' together return 'ambiguous - pick one'.\n  - scope:'session' without sessionId throws (sessionId required).\n  - Bare {confirm:true} is deprecated: maps to scope:'project' with a stderr warning; will hard-error in a future major.\n\nRETURNS:\n  A summary of removed rows + the resolved scope.\n\nEXAMPLE: ctx_purge(confirm: true, sessionId: \"7c8a-1234-5678-9abc-def012345678\")\nEXAMPLE: ctx_purge(confirm: true, scope: \"project\")",
+   "description": "DESTRUCTIVE — permanently delete indexed content. CANNOT be undone.\n\nYou MUST specify exactly ONE scope:\n\n  • { confirm: true, sessionId: \"<uuid>\" }\n      Deletes ONLY that session's events + per-session FTS5 chunks.\n      Preserves stats file and ALL other sessions.\n\n  • { confirm: true, scope: \"project\" }\n      Wipes the ENTIRE project: FTS5 knowledge base, every session DB row,\n      events markdown, AND resets the stats file.\n\nREFUSAL RULES (tool returns an error):\n  • confirm: false                              → 'purge cancelled'\n  • Both sessionId AND scope:'project' provided → 'ambiguous — pick one'\n  • scope:'session' without sessionId           → throws (sessionId required)\n  • Neither sessionId NOR scope provided        → DEPRECATED: maps to\n    scope:'project' with a deprecation warning to stderr. Will be a hard\n    error in a future major.\n\nUse sessionId when the user asks to clear a specific conversation's data.\nUse scope:'project' ONLY when the user explicitly asks to reset everything.\nNEVER call with bare {confirm:true} — always specify the scope.",
    "execution": {
      "taskSupport": "forbidden"
    },
-     "$schema": "http://json-schema.org/draft-07/schema#",
-     "properties": {
-       "confirm": {
-         "description": "MUST be true. Destructive operation; false returns 'purge cancelled'.",
-         "type": "boolean"
-       },
-       "scope": {
-         "description": "Explicit scope selector. 'session' REQUIRES sessionId. 'project' wipes the entire project (FTS5 + every session + stats). Omit only for the deprecated bare-{confirm:true} back-compat path.",
-         "enum": [
-           "session",
-           "project"
-         ],
-         "type": "string"
-       },
-       "sessionId": {
-         "description": "UUID of a single session. Pairs with confirm:true to wipe only that session's events + per-session FTS5 chunks. Sibling sessions and the stats file are preserved. MUST NOT be combined with scope:'project'.",
-         "type": "string"
-       }
-     },
-     "required": [
-       "confirm"
-     ],
+     "properties": {},
      "type": "object"
    },
    "name": "ctx_purge",
--- pinned/ctx_search
+++ observed/ctx_search
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": true,
-     "openWorldHint": false,
-     "readOnlyHint": true
-   },
-   "description": "Search a unified knowledge base with a multi-strategy ranking pipeline. Two parallel matchers run on every query: a Porter-stemming matcher (\"caching\" finds \"cached\", \"caches\", \"cach\") and a trigram-substring matcher (\"useEff\" finds \"useEffect\"). Their ranked lists are merged via Reciprocal Rank Fusion, so a document that ranks well in both surfaces above one that wins only on a single strategy. Multi-term queries get an additional proximity-rerank pass that boosts passages where the query terms appear close together. Typos are corrected via Levenshtein distance and re-searched. Result snippets are window-extracted around the matched terms, not blindly truncated.\n\nThe knowledge base is unified: queries reach indexed content you stored (ctx_index, ctx_fetch_and_index, ctx_batch_execute output) AND auto-captured session memory written by hooks (decisions, errors, blockers, plans, user prompts, rejected approaches, tool failures, compaction guides — 26 event categories). File-backed sources carry a content hash and auto-flag staleness when the source file changes.\n\nWHEN:\n  - You want to recall something that exists in storage (recently indexed content, prior session events, auto-memory) instead of re-reading raw sources\n  - You have multiple related questions about the same body of knowledge — batch every question into one call (the ranking pipeline runs per-query but the round-trip cost is paid once)\n  - You want to scope the query to one labelled source (pass `source` — partial match is fine)\n  - You want a chronological view across current session + prior sessions + persistent auto-memory (pass `sort: \"timeline\"` — the default `relevance` mode only ranks within the current session)\n  - You want to filter ranked results by content shape (pass `contentType: \"code\"` to surface implementation snippets or `contentType: \"prose\"` to surface explanations)\n\nWHEN NOT:\n  - The data you want to query has never been stored in the knowledge base AND no session memory has accumulated around it — capture first (run a gather-and-index call), then come back here to query\n  - You have one ad-hoc question against data that is not in the knowledge base — answer it inline by running code in the sandbox tool; one round-trip instead of capture-then-query\n\nRETURNS:\n  Per-query ranked sections with window-extracted snippets. Use 2-4 specific technical terms per query. Common session-memory source labels: `decision` (user corrections / preferences), `error` and `error-resolution` (past failures + their fixes), `blocker`, `plan`, `user-prompt`, `rejected-approach`, `compaction` (post-compact session guide). See ctx_stats for live category counts. Each response carries a throttle counter (call #N/M in the rolling time window); results taper toward the soft cap and calls block after the hard cap. Tune via CONTEXT_MODE_SEARCH_WINDOW_MS, CONTEXT_MODE_SEARCH_MAX_RESULTS_AFTER, CONTEXT_MODE_SEARCH_BLOCK_AFTER.\n\nEXAMPLE: ctx_search(queries: [\"root cause\", \"proposed fix\", \"test coverage\"], source: \"issue-#683\")\nEXAMPLE: ctx_search(queries: [\"what did we decide about caching\"], source: \"decision\", sort: \"timeline\")\nEXAMPLE: ctx_search(queries: [\"useEffect cleanup pattern\"], source: \"react-docs\", contentType: \"code\", limit: 5)\nEXAMPLE: ctx_search(queries: [\"last user prompt\", \"active skills\", \"open blockers\"], sort: \"timeline\")",
+   "description": "Search indexed content. Requires prior indexing via ctx_batch_execute, ctx_index, or ctx_fetch_and_index. Pass ALL search questions as queries array in ONE call. File-backed sources are auto-refreshed when the source file changes.\n\nTIPS: 2-4 specific terms per query. Use 'source' to scope results.\n\nSESSION STATE: If skills, roles, or decisions were set earlier in this conversation, they are still active. Do not discard or contradict them.",
    "execution": {
      "taskSupport": "forbidden"
    },
+     "additionalProperties": false,
      "properties": {
        "contentType": {
          "description": "Filter results by content type: 'code' or 'prose'.",
--- pinned/ctx_stats
+++ observed/ctx_stats
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": true,
-     "openWorldHint": false,
-     "readOnlyHint": true
-   },
    "description": "Returns context consumption statistics for the current session. Shows total bytes returned to context, breakdown by tool, call counts, estimated token usage, and context savings ratio.",
    "execution": {
      "taskSupport": "forbidden"
+     "additionalProperties": false,
      "properties": {},
      "type": "object"
    },
--- pinned/ctx_upgrade
+++ observed/ctx_upgrade
  {
-   "annotations": {
-     "destructiveHint": false,
-     "idempotentHint": true,
-     "openWorldHint": false,
-     "readOnlyHint": false
-   },
    "description": "Upgrade context-mode to the latest version. Returns a shell command to execute. You MUST run the returned command using your shell tool (Bash, shell_execute, run_in_terminal, etc.) and display the output as a checklist. Tell the user to restart their session after upgrade.",
    "execution": {
      "taskSupport": "forbidden"
+     "additionalProperties": false,
      "properties": {},
      "type": "object"
    },

Current tools

Show all 11 tool fingerprints
ctx_batch_execute
8962813ed995aaeb
ctx_doctor
3507ceeaf23dff50
ctx_execute
d1553ed2648bd3b2
ctx_execute_file
51508725238b11d3
ctx_fetch_and_index
d90c78bebdc3c0ec
ctx_index
e7beded9022f8055
ctx_insight
46f53c8dd67ffe45
ctx_purge
ae54040acda024a5
ctx_search
6aaa27c3ff8a2e9d
ctx_stats
9a3a6cd4936317b7
ctx_upgrade
836a6f1dbce836c6

Watch this server yourself

If you run this server, put the proxy in front of it. It pins these exact fingerprints on first connect and stops the session if they move.

npx --yes mcp-pin@0.1.0 -- <your context-mode command>

Or subscribe to this page's RSS feed to be told when it changes.

Badge

mcp-pin status badge for context-mode

The badge states one fact about time and nothing else. It never claims a server is safe.

[![mcp-pin](https://mcp-pin.gautamkhosla.com/badge/305cc381c2f9a37f.svg)](https://mcp-pin.gautamkhosla.com/servers/305cc381c2f9a37f.html)