Bound shared MCP container lifecycle
This commit is contained in:
@@ -3,12 +3,14 @@
|
||||
Context Kit supports assistants that can run local stdio MCP servers, HTTP MCP
|
||||
servers, or both. The default transport split is simple:
|
||||
|
||||
- `context-web-search`: local stdio command.
|
||||
- `context-web-search`: local HTTP MCP service.
|
||||
- `context-docs`: local HTTP MCP service.
|
||||
- `context-repomix`: local stdio command.
|
||||
|
||||
`bin/context-kit docs` is a stdio fallback for clients that cannot use HTTP MCP.
|
||||
The included snippets cover Claude Code and OpenCode.
|
||||
`bin/context-kit web-search` and `bin/context-kit docs` are stdio fallbacks for
|
||||
clients that cannot use HTTP MCP. They bridge to the shared services and do not
|
||||
stop those services when the client exits. The included snippets cover Claude
|
||||
Code and OpenCode.
|
||||
|
||||
## Claude Code
|
||||
|
||||
|
||||
@@ -56,8 +56,10 @@ Only the variables below are part of the public configuration surface. Other
|
||||
| Variable | Default | Purpose |
|
||||
|---|---|---|
|
||||
| `CONTEXT_KIT_DATA_DIR` | `$HOME/.local/share/context-kit` | Persistent docs indexes and model cache |
|
||||
| `CONTEXT_KIT_COMPOSE_PROJECT` | `context-kit` | Docker Compose project and network prefix |
|
||||
| `CONTEXT_KIT_COMPOSE_PROJECT` | `context-kit` | Shared-service ownership boundary and Compose name prefix |
|
||||
| `CONTEXT_KIT_SEARXNG_PORT` | `8099` | Localhost SearXNG port |
|
||||
| `CONTEXT_KIT_WEB_SEARCH_PORT` | `8777` | Localhost port for the long-lived web-search HTTP service |
|
||||
| `CONTEXT_KIT_WEB_SEARCH_HTTP_URL` | `http://127.0.0.1:${CONTEXT_KIT_WEB_SEARCH_PORT}/mcp` | URL emitted into HTTP MCP install snippets |
|
||||
| `CONTEXT_KIT_WEB_SEARCH_MAX_BYTES` | `52428800` | Max bytes `context-web-search` accepts and downloads per fetch |
|
||||
| `CONTEXT_KIT_WEB_SEARCH_PROVIDER` | `searxng` | Default `search_web` provider; fallback order depends on this provider |
|
||||
| `CONTEXT_KIT_WEB_SEARCH_HTTP_TIMEOUT` | `15000` | HTTP timeout in milliseconds for search providers |
|
||||
@@ -76,26 +78,63 @@ Only the variables below are part of the public configuration surface. Other
|
||||
| `CONTEXT_KIT_DOCS_LOCAL_SOURCES_DIR` | `${CONTEXT_KIT_DATA_DIR}/local-sources` | Machine-local llms.txt tree mounted read-only into docs-mcp |
|
||||
| `CONTEXT_KIT_DOCS_LOCAL_SOURCES_PORT` | `8769` | Loopback port inside docs-mcp for serving local source files |
|
||||
|
||||
## Docker Ownership
|
||||
|
||||
One Compose project owns the shared `searxng`, `web-search-mcp`, and `docs-mcp`
|
||||
services. Compose derives stable container and network names from
|
||||
`CONTEXT_KIT_COMPOSE_PROJECT`; the default network is `context-kit_default`.
|
||||
Compose's existing labels remain the ownership markers for SearXNG, docs, the
|
||||
network, and `searxng-cache`. Their definitions are unchanged from
|
||||
`origin/main`, avoiding a resource-recreation prompt. The new web-search service
|
||||
also records `dev.context-kit.uid`.
|
||||
|
||||
`start`, `stop`, and `restart` use one canonical
|
||||
`/tmp/context-kit-PROJECT.lock` directory, which must be a non-symlink directory
|
||||
owned by the current uid with mode `0700`. Existing docs and web-search
|
||||
containers must have the same uid; cross-user lifecycle control is rejected.
|
||||
|
||||
`start` passes `--no-recreate` to Compose. On failure it removes only service
|
||||
containers that did not exist before the attempt, restores prior running/stopped
|
||||
states by exact container ID, and leaves the deterministic network and cache
|
||||
volume intact for reuse. `restart` operates on the same container IDs and uses
|
||||
the same state restoration. Neither command replaces an existing container.
|
||||
`stop` stops containers without removing them or their network.
|
||||
|
||||
The stdio bridge commands and Repomix create uniquely named client containers
|
||||
with `dev.context-kit.lifecycle=client` and an invocation-specific owner label.
|
||||
Their cleanup verifies that owner label before removing the exact container ID.
|
||||
|
||||
Web search runs stateless MCP sessions. Its front end accepts only loopback Host
|
||||
values or the internal `web-search-mcp:8000` service name and returns 403 for any
|
||||
request carrying Origin. It probes initialize and tools/list periodically; a
|
||||
dead stdio backend terminates the container so Docker can restart it.
|
||||
|
||||
`restart` restarts existing container IDs, so it reloads bind-mounted docs source
|
||||
files but does not apply rebuilt images or changed container environment. There
|
||||
is intentionally no automatic replacement path while the old container cannot
|
||||
be restored transactionally.
|
||||
|
||||
## TTL Guidance
|
||||
|
||||
`24h` is the default. Most reference docs do not need re-embedding more often,
|
||||
and the shared service does not re-fetch sources until the TTL elapses.
|
||||
|
||||
Use shorter TTLs for fast-moving APIs:
|
||||
Set a shorter TTL in `.env` for fast-moving APIs:
|
||||
|
||||
```sh
|
||||
CONTEXT_KIT_DOCS_TTL=6h bin/context-kit restart
|
||||
```dotenv
|
||||
CONTEXT_KIT_DOCS_TTL=6h
|
||||
```
|
||||
|
||||
Use longer TTLs for stable specs:
|
||||
Set a longer TTL for stable specs:
|
||||
|
||||
```sh
|
||||
CONTEXT_KIT_DOCS_TTL=30d bin/context-kit restart
|
||||
```dotenv
|
||||
CONTEXT_KIT_DOCS_TTL=30d
|
||||
```
|
||||
|
||||
The docs-mcp container reads `CONTEXT_KIT_DOCS_TTL` at startup, so changes
|
||||
require `bin/context-kit restart`. When freshness matters for one task, prefer
|
||||
calling the `docs_refresh` MCP tool instead of lowering the global TTL.
|
||||
The docs-mcp container environment is fixed when Compose creates it. A safe
|
||||
same-ID `restart` does not apply a changed TTL; it takes effect only when a new
|
||||
container is explicitly provisioned. When freshness matters for one task,
|
||||
prefer `docs_refresh` instead of replacing the shared container.
|
||||
|
||||
## Browser CORS
|
||||
|
||||
@@ -103,12 +142,13 @@ calling the `docs_refresh` MCP tool instead of lowering the global TTL.
|
||||
HTTP clients do not need CORS. If a browser-based local client must call the MCP
|
||||
endpoint directly, allow only the exact local origin(s) it uses:
|
||||
|
||||
```sh
|
||||
CONTEXT_KIT_DOCS_ALLOW_ORIGIN="http://127.0.0.1:3000 http://localhost:3000" \
|
||||
bin/context-kit restart
|
||||
```dotenv
|
||||
CONTEXT_KIT_DOCS_ALLOW_ORIGIN="http://127.0.0.1:3000 http://localhost:3000"
|
||||
```
|
||||
|
||||
Avoid `*`; the docs MCP is a local unauthenticated endpoint.
|
||||
Avoid `*`; the docs MCP is a local unauthenticated endpoint. Like other
|
||||
container-environment changes, this takes effect only on explicit provisioning
|
||||
of a new docs container, not a same-ID `restart`.
|
||||
|
||||
## Source Profiles
|
||||
|
||||
|
||||
@@ -5,8 +5,11 @@ Context Kit is designed to be safe by default for local development.
|
||||
## Defaults
|
||||
|
||||
- SearXNG is bound to `127.0.0.1` only.
|
||||
- Web-search and docs MCP HTTP endpoints are bound to `127.0.0.1` only.
|
||||
- No hosted API keys are required.
|
||||
- The web-search MCP image runs as the non-root `node` user.
|
||||
- Web-search MCP sessions are stateless. Its HTTP front end permits only
|
||||
loopback/internal Host values and rejects every supplied Origin with 403.
|
||||
- Repomix mounts only the current project read-only.
|
||||
- Docs indexing stores data under `$HOME/.local/share/context-kit` unless you
|
||||
override it.
|
||||
@@ -36,10 +39,14 @@ Do not expose SearXNG or MCP servers to the public internet without a separate
|
||||
review. The default setup is for localhost development.
|
||||
|
||||
The containers may bind to `0.0.0.0` internally, but the Compose file publishes
|
||||
SearXNG and docs-mcp only on `127.0.0.1`. If you run the images outside the
|
||||
provided Compose file, review port publishing, SearXNG's limiter/secret, and MCP
|
||||
authentication separately.
|
||||
SearXNG, web-search-mcp, and docs-mcp only on `127.0.0.1`. If you run the images
|
||||
outside the provided Compose file, review port publishing, SearXNG's
|
||||
limiter/secret, and MCP authentication separately.
|
||||
|
||||
Browser CORS for `context-docs` is disabled by default. Only set
|
||||
`CONTEXT_KIT_DOCS_ALLOW_ORIGIN` for exact local origins that need direct browser
|
||||
access; avoid wildcard origins for unauthenticated local MCP endpoints.
|
||||
|
||||
`context-web-search` does not expose browser CORS configuration. Browser requests
|
||||
carry Origin and are rejected; CLI/server-side MCP clients omit Origin. A local
|
||||
reverse proxy must preserve this policy and present an allowed loopback Host.
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
bin/context-kit doctor
|
||||
```
|
||||
|
||||
This checks Docker, Compose, images, the Docker network, SearXNG health, docs
|
||||
HTTP readiness, and docs source configuration.
|
||||
This checks Docker, Compose, images, the Docker network, SearXNG health, a real
|
||||
web-search MCP initialize/tools-list exchange, docs HTTP readiness, and docs
|
||||
source configuration.
|
||||
|
||||
For release-grade MCP protocol checks, run:
|
||||
|
||||
@@ -46,6 +47,65 @@ Build default images:
|
||||
bin/context-kit build
|
||||
```
|
||||
|
||||
## Repeated Per-Project Containers
|
||||
|
||||
Current OpenCode and Claude snippets connect web search and docs directly to the
|
||||
shared HTTP services. If every project still starts a web-search container,
|
||||
regenerate the snippet, update the assistant configuration, and restart the
|
||||
assistant:
|
||||
|
||||
```sh
|
||||
bin/context-kit install opencode
|
||||
bin/context-kit install claude
|
||||
```
|
||||
|
||||
For the upgrade from `origin/main`, build and start once. `start` creates only
|
||||
the missing web-search service and refuses to recreate existing services:
|
||||
|
||||
```sh
|
||||
bin/context-kit build
|
||||
bin/context-kit start
|
||||
```
|
||||
|
||||
Context Kit never performs a global Docker prune. Inspect labeled resources and
|
||||
their owners explicitly:
|
||||
|
||||
```sh
|
||||
docker ps -a --filter label=dev.context-kit=true \
|
||||
--format 'table {{.ID}}\t{{.Names}}\t{{.Status}}\t{{.Label "dev.context-kit.lifecycle"}}\t{{.Label "dev.context-kit.owner"}}\t{{.Label "com.docker.compose.service"}}'
|
||||
```
|
||||
|
||||
Containers from the old per-call web-search launcher have an empty Compose
|
||||
service and no lifecycle/owner labels. After all old assistant processes are
|
||||
stopped, remove only the exact legacy container IDs you verified; do not use a
|
||||
name-pattern or global prune.
|
||||
|
||||
Lifecycle commands for one Compose project use a canonical, uid-owned lock and
|
||||
reject cross-user control. Failed startup removes only newly-created service
|
||||
containers, restores existing container states by ID, and never removes the
|
||||
network or cache volume. `start` uses Compose `--no-recreate`, leaving an
|
||||
existing container unchanged when its image or environment differs from the
|
||||
current Compose model; it never silently replaces that container. Inspect the
|
||||
shared services without deleting them:
|
||||
|
||||
```sh
|
||||
bin/context-kit status
|
||||
docker compose -p "${CONTEXT_KIT_COMPOSE_PROJECT:-context-kit}" -f compose.yml logs web-search-mcp docs-mcp searxng
|
||||
```
|
||||
|
||||
Use the protocol-level doctor check. `/healthz` also performs initialize and
|
||||
tools/list rather than trusting the proxy's static `/status` metadata:
|
||||
|
||||
```sh
|
||||
bin/context-kit doctor
|
||||
curl http://127.0.0.1:8777/healthz
|
||||
```
|
||||
|
||||
`bin/context-kit status` lists legacy labeled containers that have neither a
|
||||
Compose service nor lifecycle label. This is diagnostic only; Context Kit never
|
||||
auto-removes them. Stop their old assistant owners before removing individually
|
||||
verified container IDs.
|
||||
|
||||
## Fetch URL Says Max Download Bytes Is Too Big
|
||||
|
||||
If `fetch_url` fails before making a network request with an MCP validation error
|
||||
|
||||
Reference in New Issue
Block a user