Ajay Krishnan b4e863562c feat: run docs-mcp as a long-lived shared HTTP service
context-docs was previously spawned per call as a fresh stdio container,
which meant every MCP request paid full cold-start cost (embedding model
load + Chroma open) and concurrent clients raced for the same Chroma
writer. The 50+ orphan container build-up I saw during the publish audit
was the visible symptom.

This refactor runs docs-mcp as one long-lived service:

- compose: docs-mcp leaves the 'mcp' profile, gets container_name,
  restart: unless-stopped, healthcheck, and a host port (127.0.0.1:8776
  by default). Runs as the host UID/GID so bind mounts don't end up
  root-owned.
- docker image: adds mcp-proxy (0.12.0) and an entrypoint that fronts
  llms-txt-mcp's stdio as Streamable HTTP. Reads sources from a flat
  file mounted at /etc/context-kit/docs-sources.txt. Disables eager
  preindex by default; callers refresh on demand via the docs_refresh
  tool. Set CONTEXT_KIT_DOCS_PREINDEX=1 to restore eager behavior.
- bin/context-kit: 'start' brings up the docs service alongside SearXNG,
  generates the sources file from CONTEXT_KIT_DOCS_SOURCES, and waits
  for the HTTP endpoint to become ready (up to 180s for first-run model
  download). 'docs' still works for stdio-only clients but is now a
  thin mcp-proxy bridge onto the shared HTTP service. 'doctor' and
  'status' both surface the new endpoint.
- install snippets: context-docs is now 'type: remote'/'type: http'
  pointing at ${CONTEXT_KIT_DOCS_HTTP_URL}. HTTP-capable MCP clients
  bypass the bridge entirely. snippets/*.json and the install command
  output stay byte-identical.
- docs and .env.example updated for new vars (CONTEXT_KIT_DOCS_PORT,
  CONTEXT_KIT_DOCS_HTTP_URL, CONTEXT_KIT_DOCS_PREINDEX) and the new
  24h TTL default (down from 7d; the long-lived service makes shorter
  defaults cheap).

Verified end-to-end:
- compose config -q, bash -n, sh -n all clean
- HTTP /status returns 200
- stdio bridge returns initialize + tools/list with the same 3 tools
  (docs_sources, docs_refresh, docs_query)
- doctor passes all 10 checks including the new HTTP probe
- web-search and repomix MCP handshakes still work
- redaction-check clean
- install JSON valid for both targets + --absolute
2026-05-24 08:47:28 -07:00
2026-05-21 08:43:38 -07:00
2026-05-21 08:43:38 -07:00
2026-05-21 08:43:38 -07:00

Context Kit

Local context tools for Claude Code and OpenCode.

Local web search. Local docs. Repo packing. No API keys required.

What You Get

Context Kit gives coding agents three local MCP servers:

Server Purpose Default
context-web-search Current web search and URL fetch through local SearXNG Enabled
context-docs Semantic search over curated llms.txt documentation Enabled
context-repomix Pack local or remote repositories into AI-friendly context Enabled

The first public release deliberately keeps the surface area small: web search, docs search, and repository packing.

Quick Start

git clone https://gitea.krishnan.ca/ajaynomics/context-kit.git
cd context-kit
cp .env.example .env
export PATH="$PWD/bin:$PATH"
bin/context-kit start
bin/context-kit doctor

Then connect your assistant.

For Claude Code:

bin/context-kit install claude

Copy the printed JSON into your project's .mcp.json, or use the equivalent claude mcp add commands if you prefer managing servers through the Claude CLI. The default snippet uses context-kit on PATH, which is the right shape for shared project config. For a private user-only config, you can print absolute paths with bin/context-kit install claude --absolute.

For OpenCode:

bin/context-kit install opencode

Merge the printed mcp block into your opencode.json, then restart OpenCode. The default snippet uses context-kit on PATH. Use bin/context-kit install opencode --absolute only for private, machine-local config that will not be committed.

Defaults

  • SearXNG binds to 127.0.0.1:8099 only.
  • context-docs runs as a long-lived service on 127.0.0.1:8776 (Streamable HTTP MCP) so every client shares one indexer and one Chroma writer. The bin/context-kit docs stdio command is kept as a compatibility shim for clients that cannot speak HTTP MCP.
  • Docs and model caches live in $HOME/.local/share/context-kit.
  • Docs refresh TTL defaults to 24h.
  • MCP containers are labeled dev.context-kit=true for safe inspection and cleanup.
  • Repomix mounts only the current project read-only, not your whole home directory.
  • No code-editing MCP server is enabled by default.

Docs Sources

The default docs index is intentionally small:

  • Claude Code docs
  • OpenAI API docs and reference
  • Anthropic docs
  • OpenRouter docs
  • Model Context Protocol docs

Optional profiles live in config/:

  • sources.ruby-ai.txt
  • sources.js.txt
  • sources.cloudflare.txt

Example:

CONTEXT_KIT_DOCS_SOURCES="config/sources.default.txt config/sources.js.txt" \
  bin/context-kit docs

Cloudflare is opt-in because it can expand to thousands of sections and take a while to embed.

Commands

bin/context-kit start
bin/context-kit stop
bin/context-kit build
bin/context-kit status
bin/context-kit doctor
bin/context-kit redaction-check

MCP entrypoints:

bin/context-kit web-search
bin/context-kit docs
bin/context-kit repomix

Security Model

Context Kit is local-first, but MCP tools still extend what your agent can do.

  • Treat fetched web pages as untrusted input.
  • Do not expose SearXNG publicly without changing the secret and reviewing its configuration.
  • Keep docs profiles curated. More sources means more background indexing and more untrusted text in your retrieval corpus.
  • Be cautious when adding code-editing MCP servers. Context Kit's default MCP servers either read remote content or mount the current project read-only.

See docs/security.md for details.

Requirements

  • Docker with Compose v2
  • Bash
  • curl for health checks

No hosted API keys are required for the default stack.

License

MIT

Description
Local MCP servers for coding agents: web search, docs, repo packing. No API keys required.
Readme MIT 74 KiB
Languages
Shell 90.6%
Dockerfile 9.4%