Files
chemenu/INSTALL-MCP.md
T
torben 54d9540c08
CI / verify (push) Successful in 56s
Release / release (push) Successful in 36s
stack: Konfidenz-Mechanismus ersatzlos entfernt, Korpus migriert (schliesst #60, #86)
Files changed:
- .wikitool-kb.json
- AGENTS.md
- CHANGES.md
- INSTALL-MCP.md
- INSTALL.md
- README.md
- VERSION
- instructions/capture-session.md
- instructions/dev/issue-tracking.md
- instructions/german-terminology.md
- instructions/kb-profiles.md
- instructions/migrate-corpus.md
- instructions/migrations/5.0.0-confidence-removal.md
- instructions/private-instance.md
- instructions/setup-instance.md
- instructions/wiki-lint/SKILL.md
- instructions/wiki-manage/SKILL.md
- instructions/wiki-query/SKILL.md
- kb/CONTRACT.md
- kb/CONVENTIONS.md
- kb/CONVENTIONS.md.template
- kb/concepts/architectures/Consolidation Tiers.md
- kb/concepts/architectures/Context Isolation.md
- kb/concepts/architectures/Cross-platform Agent Skills.md
- kb/concepts/architectures/Episodic Memory.md
- kb/concepts/architectures/Hybrid Search.md
- kb/concepts/architectures/Implementation Spectrum.md
- kb/concepts/architectures/Knowledge Graph.md
- kb/concepts/architectures/LLM Wiki Pattern.md
- kb/concepts/architectures/MCP-Leseserver.md
- kb/concepts/architectures/Memory Lifecycle.md
- kb/concepts/architectures/OKF Compatibility.md
- kb/concepts/architectures/Optional Instance Context File.md
- kb/concepts/architectures/Personalization Plane.md
- kb/concepts/architectures/Procedural Memory.md
- kb/concepts/architectures/RAG.md
- kb/concepts/architectures/Scale Ceiling.md
- kb/concepts/architectures/Semantic Memory.md
- kb/concepts/architectures/Three-Layer Architecture.md
- kb/concepts/architectures/Token Economics.md
- kb/concepts/architectures/Working Memory.md
- kb/concepts/decisions/Delete Rather Than Anonymize.md
- kb/concepts/decisions/Denylist over Allowlist.md
- kb/concepts/decisions/Diff-Reviewable Agent Edits.md
- kb/concepts/decisions/Dual Licensing by File Plan.md
- kb/concepts/decisions/Issue Label Scheme.md
- kb/concepts/decisions/KB Stack Versioning.md
- kb/concepts/decisions/Structural Enforcement over Documented Rule.md
- kb/concepts/patterns/Audit Trail.md
- kb/concepts/patterns/BM25.md
- kb/concepts/patterns/Command Round-Trip Integrity.md
- kb/concepts/patterns/Confidence Scoring.md
- kb/concepts/patterns/Contradiction Resolution.md
- kb/concepts/patterns/Entity Extraction.md
- kb/concepts/patterns/Filter on Ingest.md
- kb/concepts/patterns/Forgetting.md
- kb/concepts/patterns/Graph Traversal.md
- kb/concepts/patterns/Mesh Sync.md
- kb/concepts/patterns/Quality Scoring.md
- kb/concepts/patterns/Reciprocal Rank Fusion.md
- kb/concepts/patterns/Self-Healing.md
- kb/concepts/patterns/Shared vs Private.md
- kb/concepts/patterns/Typed Relationships.md
- kb/concepts/patterns/Vector Search.md
- kb/concepts/patterns/Work Coordination.md
- kb/concepts/problems/Ambient Environment Dependency.md
- kb/concepts/problems/Detect-Repair Asymmetry.md
- kb/concepts/problems/Green Suite Blind Spot.md
- kb/concepts/problems/Naming Convention Conflict.md
- kb/concepts/problems/Write-Once Frontmatter Fields.md
- kb/concepts/protocols/CPPC.md
- kb/concepts/protocols/Modbus.md
- kb/concepts/protocols/SSD TRIM.md
- kb/concepts/workflows/Anti-Cramming Heuristic.md
- kb/concepts/workflows/Bulk Operations.md
- kb/concepts/workflows/CI Integration.md
- kb/concepts/workflows/Checkpoint Audit.md
- kb/concepts/workflows/Claude Code Auto Mode.md
- kb/concepts/workflows/Content Quality Control.md
- kb/concepts/workflows/Crystallization.md
- kb/concepts/workflows/Event-Driven Automation.md
- kb/concepts/workflows/Hooks.md
- kb/concepts/workflows/Index Scaling.md
- kb/concepts/workflows/Iteration and Cost Limits.md
- kb/concepts/workflows/KB Migration.md
- kb/concepts/workflows/Knowledge Compounding.md
- kb/concepts/workflows/Lint Workflow.md
- kb/concepts/workflows/Mass-Update Gate.md
- kb/concepts/workflows/Multi-Agent Collaboration.md
- kb/concepts/workflows/Privacy and Governance.md
- kb/concepts/workflows/Publish-Remote Gate.md
- kb/concepts/workflows/Quality and Self-Correction.md
- kb/concepts/workflows/Semantic Lint Automation.md
- kb/concepts/workflows/Session Orientation.md
- kb/concepts/workflows/Split Merge Reclassify.md
- kb/concepts/workflows/Split Threshold.md
- kb/concepts/workflows/Stub Threshold.md
- kb/concepts/workflows/Supersession.md
- kb/concepts/workflows/User Management.md
- kb/concepts/workflows/Workflow Extraction.md
- kb/concepts/workflows/Workflow Orchestration.md
- kb/entities/people/Andrej Karpathy.md
- kb/entities/people/E3DC GmbH.md
- kb/entities/people/Rohit Gupta.md
- kb/entities/people/Vannevar Bush.md
- kb/entities/projects/BCDModule.md
- kb/entities/projects/Chemenu.md
- kb/entities/projects/andybalholm-edl.md
- kb/entities/projects/goresponsiveness.md
- kb/entities/projects/ha-core.md
- kb/entities/projects/hacs-e3dc.md
- kb/entities/projects/hacs-integration-blueprint.md
- kb/entities/projects/llm-wiki-skills.md
- kb/entities/projects/plugnburn-edl.md
- kb/entities/projects/wiki-skills-vanillaflava.md
- kb/entities/projects/wiki-skills.md
- kb/entities/systems/AGENTS.md.md
- kb/entities/systems/CLAUDE.md.md
- kb/entities/systems/E3DC.md
- kb/entities/systems/ENVIRONMENT.md.md
- kb/entities/systems/Memex.md
- kb/entities/systems/Tolkien Gateway.md
- kb/entities/technologies/Arch Linux.md
- kb/entities/technologies/Disk Encryption.md
- kb/entities/technologies/Docker.md
- kb/entities/technologies/GRUB.md
- kb/entities/technologies/Gitea Actions.md
- kb/entities/technologies/Gitea.md
- kb/entities/technologies/Go.md
- kb/entities/technologies/Home Assistant.md
- kb/entities/technologies/Kernel PM Governors.md
- kb/entities/technologies/LVM.md
- kb/entities/technologies/Linux Kernel.md
- kb/entities/technologies/MQTT.md
- kb/entities/technologies/OPC UA.md
- kb/entities/technologies/Python.md
- kb/entities/technologies/Rust.md
- kb/entities/technologies/Wine GE.md
- kb/entities/technologies/Wine-Staging.md
- kb/entities/technologies/acpi-cpufreq.md
- kb/entities/technologies/amd-pstate.md
- kb/entities/technologies/iii Engine.md
- kb/entities/tools/AUR.md
- kb/entities/tools/Act Runner.md
- kb/entities/tools/Agent Memory.md
- kb/entities/tools/Aura.md
- kb/entities/tools/Bottles.md
- kb/entities/tools/ChatGPT.md
- kb/entities/tools/Claude Code.md
- kb/entities/tools/Codex CLI.md
- kb/entities/tools/Dataview.md
- kb/entities/tools/GPG.md
- kb/entities/tools/GitHub Copilot.md
- kb/entities/tools/Gitea MCP Server.md
- kb/entities/tools/Lutris.md
- kb/entities/tools/Marp.md
- kb/entities/tools/Mistral Vibe.md
- kb/entities/tools/NotebookLM.md
- kb/entities/tools/Obsidian Web Clipper.md
- kb/entities/tools/Obsidian.md
- kb/entities/tools/OpenAI Codex.md
- kb/entities/tools/OpenCode.md
- kb/entities/tools/Pi.md
- kb/entities/tools/Proton.md
- kb/entities/tools/Steam.md
- kb/entities/tools/Wine.md
- kb/entities/tools/awesome-llm-wiki.md
- kb/entities/tools/farzaa gist.md
- kb/entities/tools/gdeploy.md
- kb/entities/tools/makepkg.md
- kb/entities/tools/pascalandy schema.md
- kb/entities/tools/qmd.md
- kb/entities/tools/wikitool.md
- kb/index.md
- kb/log.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/api.py
- tools/chemenu/cli.py
- tools/chemenu/commands/confidence_decay.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/index_build.py
- tools/chemenu/commands/new_page.py
- tools/chemenu/commands/search.py
- tools/chemenu/commands/touch.py
- tools/chemenu/commands/version_cmd.py
- tools/chemenu/conventions.py
- tools/chemenu/corpus_diff.py
- tools/chemenu/frontmatter_io.py
- tools/chemenu/lint_core.py
- tools/chemenu/mcp/server.py
- tools/chemenu/page.py
- tools/chemenu/search/base.py
- tools/chemenu/search/filters.py
- tools/chemenu/search/ripgrep.py
- tools/chemenu/search/service.py
- tools/chemenu/search/types.py
- tools/chemenu/tests/conftest.py
- tools/chemenu/tests/test_api.py
- tools/chemenu/tests/test_confidence_decay.py
- tools/chemenu/tests/test_corpus_diff.py
- tools/chemenu/tests/test_docs_verify.py
- tools/chemenu/tests/test_frontmatter_io.py
- tools/chemenu/tests/test_index_build.py
- tools/chemenu/tests/test_kb_scan.py
- tools/chemenu/tests/test_lint.py
- tools/chemenu/tests/test_mcp_server.py
- tools/chemenu/tests/test_new_page.py
- tools/chemenu/tests/test_page_ops.py
- tools/chemenu/tests/test_provenance.py
- tools/chemenu/tests/test_raw_cmd.py
- tools/chemenu/tests/test_search.py
- tools/chemenu/tests/test_touch.py
- tools/chemenu/tests/test_type_resolver.py
- tools/chemenu/tests/test_version_cmd.py
- tools/chemenu/tests/test_xref.py
- tools/chemenu/version.py
- types/concept.md
- types/concept.schema.yaml
- types/entity.md
- types/entity.schema.yaml
- types/instruction.md
- types/type-spec.md
2026-09-10 19:51:48 +02:00

9.7 KiB

MCP-Leseserver installieren

Dieses Dokument richtet sich an Menschen. Es beschreibt, wie der MCP-Leseserver eines Chemenu- Wikis lokal läuft, wie ein Client ihn einbindet, und wie er hinter einer Authentifizierung erreichbar wird. Der agent-seitige Betriebsablauf steht in instructions/mcp-read-server.md; die vollständige Kommandoreferenz in tools/CONTRACT.md.

Was der Server ist. Ein zweiter Konsument desselben Kerns, nicht ein zweites Programm. CLI und Server rufen dieselben Funktionen auf; ein Golden-Test hält ihre Ausgaben gegeneinander. Was tools/wikitool search --json liefert, liefert das MCP-Tool search auch — plus den Commit, aus dem die Antwort berechnet wurde.

Was er nicht ist. Kein Schreibpfad. Es gibt kein Tool, das eine Seite anlegt, ändert oder publiziert — nicht weil eine Liste gefiltert wird, sondern weil der Server nichts unter tools/chemenu/commands/ importiert. Die Funktionen sind aus diesem Prozess heraus nicht erreichbar.

Voraussetzungen

  • Eine funktionierende Instanz nach INSTALL.md — inklusive tools/.venv und ripgrep
  • Python 3.11 oder neuer (wie die CLI)

Schritt 1: Abhängigkeit installieren

Sie liegt bewusst nicht in tools/requirements.txt. Eine Instanz, die nur die CLI benutzt, soll dafür nicht pydantic, starlette, uvicorn und cryptography mitinstallieren müssen.

tools/.venv/bin/pip install -r tools/requirements-mcp.txt

Schritt 2: Lokal starten (stdio)

stdio ist der Weg zum Ausprobieren und für einen Client auf derselben Maschine: ein Prozess pro Konsument, lokal gestartet, kein Netzwerk.

WIKI_TRACE=0 tools/.venv/bin/python -m chemenu.mcp

Der Prozess spricht MCP über stdin/stdout und gibt für sich genommen nichts aus — das ist richtig so. Gestartet wird er normalerweise nicht von Hand, sondern vom Client (Schritt 3).

WIKI_TRACE=0 ist nicht optional. Telemetrie ist per Default an und schreibt nach reports/telemetry/ im Repo. Der Server verweigert den Start, solange das so ist, statt still umzuleiten:

ERROR Telemetry is on and would write into the served checkout (...). Set WIKI_TRACE=0,
or point WIKI_TRACE_DIR outside the corpus.

Beide Auswege sind gleichwertig: WIKI_TRACE=0 schaltet ab, WIKI_TRACE_DIR=/var/log/chemenu lenkt um. Der Grund steht in Schritt 6 — der Sync darf reports/ wegräumen.

Schritt 3: Einen Client einbinden

Die Konfiguration folgt der üblichen MCP-Client-Form. Absolute Pfade, weil der Client kein Arbeitsverzeichnis erbt:

{
  "mcpServers": {
    "chemenu": {
      "command": "/pfad/zur/instanz/tools/.venv/bin/python",
      "args": ["-m", "chemenu.mcp"],
      "cwd": "/pfad/zur/instanz/tools",
      "env": {
        "WIKI_TRACE": "0",
        "CHEMENU_ROOT": "/pfad/zur/instanz"
      }
    }
  }
}

CHEMENU_ROOT sagt, welches Wiki bedient wird. Ohne die Variable nimmt der Server den Checkout, in dem das Paket selbst liegt — für eine einzelne Instanz reicht das, aber wer mehrere Korpora hat, setzt sie besser immer.

Danach kennt der Client fünf Werkzeuge:

Tool Was es beantwortet
search Seiten in kb/ nach Text, nach Frontmatter (!sources, tags~k8s) oder beidem
types Welche Seitentypen dieses Wiki kennt
describe_type Der vollständige Vertrag eines Typs: Felder, Pflichtangaben, Enums
lint Strukturelle Befunde: kaputte Wikilinks, Waisen, Index-Drift, Schema-Lücken
status Momentaufnahme: Seitenzahl, Verteilung auf Collections, Befundzahlen

Schritt 4: Ausgeliefert starten (streamable HTTP)

Der Transport für den Betrieb, und der einzige, vor den sich ein Reverse Proxy setzen kann.

WIKI_TRACE=0 CHEMENU_ROOT=/srv/chemenu \
  tools/.venv/bin/python -m chemenu.mcp \
    --transport streamable-http --host 0.0.0.0 --port 8000

Der Endpunkt ist dann http://<host>:8000/mcp.

--host 0.0.0.0 ist bewusst nicht der Default. Ohne die Angabe bindet der Server auf Loopback, was lokal richtig und im Container falsch ist — dort muss der Proxy ihn erreichen können. Wer 0.0.0.0 setzt, muss also auch dafür sorgen, dass davor etwas steht (Schritt 5).

sse wird nicht angeboten. Es ist der abgelöste Remote-Transport; jetzt darauf zu bauen verschiebt den Wechsel nur.

Schritt 5: Authentifizierung davor

Der Server authentifiziert nicht selbst, und das ist Absicht. Nicht sauber authentifizierte Zugriffe sollen den Python-Prozess gar nicht erst erreichen. Die Authentifizierung ist eine Traefik-ForwardAuth-Middleware:

https://gitea.nehmer.net/torben/gitea-mcp-forward-auth

Kurz, was sie tut: sie prüft Authorization: Bearer <token> gegen SHA-256-Hashes erlaubter Tokens, antwortet 200 bei gültigem und 401 bei fehlendem oder falschem Token, und hält GET /healthz immer offen. Klartext-Tokens liegen weder in der Konfiguration noch im Log — nur Hashes und ein kurzer Fingerprint. Konfiguriert wird sie über AUTH_PROXY_TOKEN_HASHES_DIR (ein Verzeichnis, eine Datei je Token-Hash — passend für ein Kubernetes-Secret-Volume) oder AUTH_PROXY_TOKEN_HASHES (kommagetrennte Liste). Einzelheiten, Referenzmanifeste und ein Testskript stehen im README dort.

Einen Token-Hash erzeugen:

echo -n "mein-token" | sha256sum | awk '{print $1}'

Rate Limiting gehört an dieselbe Stelle — vor den Prozess, neben die Authentifizierung. Nicht in den Iteration Budget Gate: der begrenzt eine Agenten-Session am unbemerkten Iterieren über den Wiki-Zustand, weshalb Retrieval von ihm ausgenommen ist. Ihn als Rate Limiter zu benutzen würde ihn dazu verwässern.

Schritt 6: Den Korpus aktuell halten

Der Server liest den Arbeitsbaum. Ein veralteter Checkout antwortet selbstbewusst falsch — deshalb trägt jede Antwort den Commit, aus dem sie berechnet wurde:

{ "commit": "<40-stelliger SHA>", "as_of": "<ISO-8601, UTC>", "count": 3, "...": "..." }

Aktuell gehalten wird der Baum durch Polling, aus einem Timer neben dem Server:

git -C "$CHEMENU_ROOT" fetch --quiet origin && \
  git -C "$CHEMENU_ROOT" reset --hard --quiet origin/main

Polling statt Webhook, weil es keinen eingehenden Endpunkt und keine Signaturprüfung braucht — eine kleinere Angriffsfläche als das, was es optimieren würde.

reset --hard ist dabei tragend und keine Bequemlichkeit: der Korpus-Cache verwendet einen Parse wieder, solange der Commit gleich bleibt, und cacht einen schmutzigen Baum überhaupt nicht. Ein abgedrifteter Checkout antwortet also zwar richtig, parst aber bei jeder Anfrage neu — und stempelt jede Antwort mit "commit": null, weil sie keiner Revision entspricht.

Verifikation

Läuft es? Der schnellste Test ohne Client — startet den Server über stdio, listet die Tools und stellt eine Frage:

cd tools && WIKI_TRACE=0 .venv/bin/python - <<'EOF'
import asyncio, os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def main():
    params = StdioServerParameters(
        command=".venv/bin/python", args=["-m", "chemenu.mcp"],
        env={"WIKI_TRACE": "0", "PATH": os.environ["PATH"]},
    )
    async with stdio_client(params) as (r, w):
        async with ClientSession(r, w) as s:
            await s.initialize()
            print("Tools:", [t.name for t in (await s.list_tools()).tools])
            out = await s.call_tool("status", {})
            d = getattr(out, "structuredContent", None) or out.structured_content
            print("Seiten:", d["pages"], "| Commit:", d["commit"])

asyncio.run(main())
EOF

Erwartete Ausgabe, sinngemäß:

Tools: ['search', 'types', 'describe_type', 'lint', 'status']
Seiten: 176 | Commit: 576df2cdddc96614a7e6641e562022d52112d411

Gegen die CLI gegenprüfen — beide müssen dieselbe Antwort geben:

tools/wikitool search "<begriff>" --json

Troubleshooting

ERROR Telemetry is on and would write into the served checkout — erwartetes Verhalten, kein Fehler in der Installation. WIKI_TRACE=0 setzen oder WIKI_TRACE_DIR aus dem Korpus heraus zeigen lassen (Schritt 2).

ModuleNotFoundError: No module named 'mcp' — Schritt 1 fehlt, oder der Client startet ein anderes Python als das der Instanz. Im Client den absoluten Pfad auf tools/.venv/bin/python setzen.

"commit": null in jeder Antwort — der bediente Baum hat uncommittete Änderungen. Entweder läuft der Sync nicht, oder etwas schreibt in den Korpus, das dort nichts zu suchen hat. Der Server selbst schreibt nie; ein Test prüft das, indem er alle fünf Tools aufruft und Dateibaum, HEAD und git status --porcelain vorher/nachher vergleicht.

commit nennt eine alte Revision — der Sync aus Schritt 6 läuft nicht.

Der Server antwortet anders als wikitool — das ist ein Defekt, keine Konfigurationsdifferenz: beide gehen durch dieselben Funktionen, und ein Golden-Test hält sie zusammen. Zuerst prüfen, ob beide auf denselben Root zeigen; CHEMENU_ROOT ist leicht für einen von beiden gesetzt und für den anderen nicht.

Von außen nicht erreichbar — ohne --host 0.0.0.0 bindet der Server auf Loopback (Schritt 4). Wenn er dann erreichbar ist, aber jeder Aufruf 401 bekommt, arbeitet die Middleware aus Schritt 5 korrekt und das Token stimmt nicht.

Was hier bewusst nicht steht

Deployment — Cluster, Ingress-Hosts, Secret-Store, FluxCD-Quelle. Das ist private Infrastruktur und dieses Repo ist öffentlich.

Ein Container-Image für den Betrieb gibt es noch nicht; es ist als eigenes Vorhaben erfasst, mitsamt den Entscheidungen, die dafür noch offen sind (Korpus im Image oder als Volume, wer den Sync ausführt, Basis-Image, Healthcheck): https://gitea.nehmer.net/torben/chemenu/issues/37. Bis dahin ist der Weg oben — venv, python -m chemenu.mcp, Proxy davor — der vollständige.