Harden docs MCP local exposure defaults
This commit is contained in:
@@ -18,6 +18,9 @@ CONTEXT_KIT_SEARXNG_SECRET=change-me-local-only
|
|||||||
CONTEXT_KIT_DOCS_PORT=8776
|
CONTEXT_KIT_DOCS_PORT=8776
|
||||||
# Override only if you proxy the service behind another hostname or path.
|
# Override only if you proxy the service behind another hostname or path.
|
||||||
# CONTEXT_KIT_DOCS_HTTP_URL=http://127.0.0.1:8776/mcp
|
# CONTEXT_KIT_DOCS_HTTP_URL=http://127.0.0.1:8776/mcp
|
||||||
|
# Browser CORS is disabled by default. If a browser-based local client needs
|
||||||
|
# access, set one or more exact origins separated by spaces. Avoid `*`.
|
||||||
|
# CONTEXT_KIT_DOCS_ALLOW_ORIGIN=http://127.0.0.1:3000
|
||||||
|
|
||||||
# Docs indexing defaults.
|
# Docs indexing defaults.
|
||||||
CONTEXT_KIT_DOCS_TTL=24h
|
CONTEXT_KIT_DOCS_TTL=24h
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ config that will not be committed.
|
|||||||
HTTP MCP) so every client shares one indexer and one Chroma writer. The
|
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
|
`bin/context-kit docs` stdio command is kept as a compatibility shim for
|
||||||
clients that cannot speak HTTP MCP.
|
clients that cannot speak HTTP MCP.
|
||||||
|
- `context-docs` browser CORS is disabled by default; set exact local origins
|
||||||
|
only when a browser-based client needs direct access.
|
||||||
- Docs and model caches live in `$HOME/.local/share/context-kit`.
|
- Docs and model caches live in `$HOME/.local/share/context-kit`.
|
||||||
- Docs refresh TTL defaults to `24h`.
|
- Docs refresh TTL defaults to `24h`.
|
||||||
- MCP containers are labeled `dev.context-kit=true` for safe inspection and cleanup.
|
- MCP containers are labeled `dev.context-kit=true` for safe inspection and cleanup.
|
||||||
|
|||||||
@@ -343,21 +343,24 @@ cmd_docs() {
|
|||||||
# Prefer the `type: remote` MCP config pointing at ${DOCS_HTTP_URL}.
|
# Prefer the `type: remote` MCP config pointing at ${DOCS_HTTP_URL}.
|
||||||
# This stdio entrypoint is kept for clients that cannot speak HTTP MCP:
|
# This stdio entrypoint is kept for clients that cannot speak HTTP MCP:
|
||||||
# it spawns a thin mcp-proxy bridge per call but all calls multiplex onto
|
# it spawns a thin mcp-proxy bridge per call but all calls multiplex onto
|
||||||
# the single long-lived docs-mcp container (no Chroma write contention).
|
# the single long-lived docs-mcp container over the Context Kit Docker
|
||||||
|
# network (no Chroma write contention, no host networking).
|
||||||
require_docker
|
require_docker
|
||||||
|
require_network
|
||||||
require_image "${DOCS_IMAGE}" "context-kit build"
|
require_image "${DOCS_IMAGE}" "context-kit build"
|
||||||
|
|
||||||
if ! docker ps --filter "name=^${DOCS_CONTAINER_NAME}$" --filter "status=running" --format '{{.Names}}' | grep -qx "${DOCS_CONTAINER_NAME}"; then
|
if ! docker ps --filter "name=^${DOCS_CONTAINER_NAME}$" --filter "status=running" --format '{{.Names}}' | grep -qx "${DOCS_CONTAINER_NAME}"; then
|
||||||
fail "long-lived docs-mcp not running; start it with: context-kit start"
|
fail "long-lived docs-mcp not running; start it with: context-kit start"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
local bridge_url="http://${DOCS_CONTAINER_NAME}:8000/mcp"
|
||||||
exec docker run --rm -i \
|
exec docker run --rm -i \
|
||||||
--label dev.context-kit=true \
|
--label dev.context-kit=true \
|
||||||
--network host \
|
--network "${NETWORK}" \
|
||||||
--entrypoint mcp-proxy \
|
--entrypoint mcp-proxy \
|
||||||
"${DOCS_IMAGE}" \
|
"${DOCS_IMAGE}" \
|
||||||
--transport streamablehttp \
|
--transport streamablehttp \
|
||||||
"${DOCS_HTTP_URL}"
|
"${bridge_url}"
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_repomix() {
|
cmd_repomix() {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ services:
|
|||||||
DOCS_MCP_TTL: "${CONTEXT_KIT_DOCS_TTL:-24h}"
|
DOCS_MCP_TTL: "${CONTEXT_KIT_DOCS_TTL:-24h}"
|
||||||
DOCS_MCP_MAX_GET_BYTES: "${CONTEXT_KIT_DOCS_MAX_GET_BYTES:-75000}"
|
DOCS_MCP_MAX_GET_BYTES: "${CONTEXT_KIT_DOCS_MAX_GET_BYTES:-75000}"
|
||||||
DOCS_MCP_EMBED_MODEL: "${CONTEXT_KIT_DOCS_EMBED_MODEL:-BAAI/bge-small-en-v1.5}"
|
DOCS_MCP_EMBED_MODEL: "${CONTEXT_KIT_DOCS_EMBED_MODEL:-BAAI/bge-small-en-v1.5}"
|
||||||
|
DOCS_MCP_ALLOW_ORIGIN: "${CONTEXT_KIT_DOCS_ALLOW_ORIGIN:-}"
|
||||||
# Preindex on startup is off by default; use the docs_refresh tool to
|
# Preindex on startup is off by default; use the docs_refresh tool to
|
||||||
# refresh on demand. Set CONTEXT_KIT_DOCS_PREINDEX=1 to restore eager.
|
# refresh on demand. Set CONTEXT_KIT_DOCS_PREINDEX=1 to restore eager.
|
||||||
DOCS_MCP_PREINDEX: "${CONTEXT_KIT_DOCS_PREINDEX:-0}"
|
DOCS_MCP_PREINDEX: "${CONTEXT_KIT_DOCS_PREINDEX:-0}"
|
||||||
|
|||||||
@@ -37,12 +37,17 @@ if [ "${DOCS_MCP_PREINDEX:-0}" = "1" ]; then
|
|||||||
preindex_flag=""
|
preindex_flag=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# shellcheck disable=SC2086 # intentional word-splitting on $sources / $preindex_flag
|
allow_origin_args=""
|
||||||
|
if [ -n "${DOCS_MCP_ALLOW_ORIGIN:-}" ]; then
|
||||||
|
allow_origin_args="--allow-origin ${DOCS_MCP_ALLOW_ORIGIN}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# shellcheck disable=SC2086 # intentional word-splitting on $sources / $preindex_flag / $allow_origin_args
|
||||||
exec mcp-proxy \
|
exec mcp-proxy \
|
||||||
--host "${DOCS_MCP_HTTP_HOST:-0.0.0.0}" \
|
--host "${DOCS_MCP_HTTP_HOST:-0.0.0.0}" \
|
||||||
--port "${DOCS_MCP_HTTP_PORT:-8000}" \
|
--port "${DOCS_MCP_HTTP_PORT:-8000}" \
|
||||||
--pass-environment \
|
--pass-environment \
|
||||||
--allow-origin "${DOCS_MCP_ALLOW_ORIGIN:-*}" \
|
$allow_origin_args \
|
||||||
-- \
|
-- \
|
||||||
llms-txt-mcp \
|
llms-txt-mcp \
|
||||||
--store-path /data \
|
--store-path /data \
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ shell code.
|
|||||||
| `CONTEXT_KIT_COMPOSE_PROJECT` | `context-kit` | Docker Compose project and network prefix |
|
| `CONTEXT_KIT_COMPOSE_PROJECT` | `context-kit` | Docker Compose project and network prefix |
|
||||||
| `CONTEXT_KIT_SEARXNG_PORT` | `8099` | Localhost SearXNG port |
|
| `CONTEXT_KIT_SEARXNG_PORT` | `8099` | Localhost SearXNG port |
|
||||||
| `CONTEXT_KIT_DOCS_PORT` | `8776` | Localhost port for the long-lived docs-mcp HTTP service |
|
| `CONTEXT_KIT_DOCS_PORT` | `8776` | Localhost port for the long-lived docs-mcp HTTP service |
|
||||||
| `CONTEXT_KIT_DOCS_HTTP_URL` | `http://127.0.0.1:${CONTEXT_KIT_DOCS_PORT}/mcp` | URL emitted into install snippets and used by the stdio bridge |
|
| `CONTEXT_KIT_DOCS_HTTP_URL` | `http://127.0.0.1:${CONTEXT_KIT_DOCS_PORT}/mcp` | URL emitted into HTTP MCP install snippets |
|
||||||
|
| `CONTEXT_KIT_DOCS_ALLOW_ORIGIN` | unset | Optional exact browser CORS origin(s) for docs-mcp, separated by spaces |
|
||||||
| `CONTEXT_KIT_DOCS_TTL` | `24h` | Docs re-fetch cadence |
|
| `CONTEXT_KIT_DOCS_TTL` | `24h` | Docs re-fetch cadence |
|
||||||
| `CONTEXT_KIT_DOCS_SOURCES` | `config/sources.default.txt` | Space-separated source profile files |
|
| `CONTEXT_KIT_DOCS_SOURCES` | `config/sources.default.txt` | Space-separated source profile files |
|
||||||
| `CONTEXT_KIT_DOCS_MAX_GET_BYTES` | `75000` | Max bytes returned by docs retrieval |
|
| `CONTEXT_KIT_DOCS_MAX_GET_BYTES` | `75000` | Max bytes returned by docs retrieval |
|
||||||
@@ -43,6 +44,19 @@ 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
|
require `bin/context-kit restart`. When freshness matters for one task, prefer
|
||||||
calling the `docs_refresh` MCP tool instead of lowering the global TTL.
|
calling the `docs_refresh` MCP tool instead of lowering the global TTL.
|
||||||
|
|
||||||
|
## Browser CORS
|
||||||
|
|
||||||
|
`context-docs` disables browser CORS by default. CLI assistants and server-side
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid `*`; the docs MCP is a local unauthenticated endpoint.
|
||||||
|
|
||||||
## Source Profiles
|
## Source Profiles
|
||||||
|
|
||||||
The docs MCP accepts one or more source files:
|
The docs MCP accepts one or more source files:
|
||||||
|
|||||||
@@ -33,3 +33,12 @@ their mount paths and permissions separately.
|
|||||||
|
|
||||||
Do not expose SearXNG or MCP servers to the public internet without a separate
|
Do not expose SearXNG or MCP servers to the public internet without a separate
|
||||||
review. The default setup is for localhost development.
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|||||||
Reference in New Issue
Block a user