Files
mcpctl/templates/docs-mcp.yaml

40 lines
1.5 KiB
YAML
Raw Normal View History

feat(servers): persistent volumes + self-hosted web search and docs templates Instances are immutable and get recreated on any server edit, so anything an MCP server wrote to its container filesystem was lost at exactly that point. That ruled out every stateful MCP server, docs-mcp among them: its index is a SQLite file (better-sqlite3 + sqlite-vec) and it has no external-database mode, so no amount of Postgres helps. A server or template can now declare volumes. The backing store is keyed on the server, not the instance — `mcpctl-<server>-<name>` — which is the whole point: an instance-scoped claim would be destroyed precisely when the data needs to survive. On Kubernetes that is a PVC ensured in the servers namespace before the pod is created and never deleted with it; on Docker, a named volume (named, not anonymous, so `removeContainer`'s `v: true` leaves it alone). Claims are ReadWriteOnce, so volumes and replicas > 1 are mutually exclusive; validation rejects that pair instead of leaving the extra replicas unschedulable. storageClassName is omitted rather than sent empty when no class is configured — to Kubernetes those mean different things. Also fixes a pre-existing bug in the same path: seedTemplates dropped `runtime`, so every PyPI-backed template seeded from YAML silently defaulted to node and would run `npx` against a package that only exists on PyPI. `unifi-network` declares `runtime: python` and had been seeding with runtime unset. Templates added, all self-hosted and none needing an API key: - duckduckgo — no backing service at all - searxng — needs a SearXNG engine (compose profile in stack/) - docs-mcp — open-source Context7/Ref alternative, uses the new volume Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017BMXdb2qZbPSh8Q7XpTyjB
2026-08-09 18:17:32 +01:00
name: docs-mcp
version: "1.0.0"
description: Self-hosted library documentation index — version-pinned docs scraped from sites, GitHub, npm and PyPI
dockerImage: "ghcr.io/arabold/docs-mcp-server:latest"
transport: SSE
containerPort: 6280
repositoryUrl: https://github.com/arabold/docs-mcp-server
command:
- --protocol
- http
- --host
- 0.0.0.0
- --port
- "6280"
# The scraped index is a SQLite file (better-sqlite3 + sqlite-vec) under /data.
# There is no external-database mode, so the volume below is what makes the
# index outlive instance recreation. Its claim is named after the server
# (mcpctl-<server>-data), not the instance, so a server edit re-attaches to the
# same data instead of starting empty.
#
# Health check omitted deliberately: `search_docs` requires a library argument,
# so a synthetic probe would need a library that is only present after a scrape
# and would report unhealthy on a fresh instance.
volumes:
- name: data
mountPath: /data
sizeGb: 20
env:
- name: DOCS_MCP_EMBEDDING_MODEL
description: >-
Embedding model as provider:name. Unset = keyword search only. For local
embeddings use openai:nomic-embed-text with OPENAI_API_BASE on Ollama.
required: false
- name: OPENAI_API_BASE
description: OpenAI-compatible embeddings endpoint, e.g. http://ollama:11434/v1
required: false
- name: OPENAI_API_KEY
description: Embeddings API key. Literal "ollama" when pointing at a local Ollama.
required: false