Der Server aus #19 läuft (2.4.0), auf stdio und streamable-http, beide gegen den echten
Korpus gegengeprüft. Was fehlt, ist der Weg vom Repo zu einem laufenden Ding: ein Image, ein
Build, ein Push in die Registry.
Dieses Issue fasst zusammen, was schon feststeht. Die Details sind bewusst noch offen — sie
brauchen Entscheidungen des Betreibers, und die Liste unten sagt, welche. Wer das aufgreift,
soll nicht bei null anfangen, aber auch nicht glauben, hier stünde schon ein Plan.
Seit 2026-09-04 trägt dieses Issue auch den Abschluss des Master-Issues #36. Dessen letztes
offenes Kriterium — ein Konsument führt über die Traefik-Middleware nachweislich search gegen
den Server aus — hing vollständig an einem Deployment und damit an diesem Image. #36 ist als
Entscheidungsprotokoll geschlossen; der Nachweis steht unten als eigenes Akzeptanzkriterium. Damit ist dies das letzte offene Issue auf dem Weg zum MCP-Leseserver. Die Entscheidungen,
die dort getroffen wurden und hier nicht neu aufgemacht werden (Python statt Go, Traefik statt
eigener Auth, Polling statt Webhook, Direktimport statt Subprozess, Deployment gehört nicht in
dieses Repo), stehen im geschlossenen Body von #36 samt gemessener Grundlage.
Abgrenzung, die bleibt: Cluster, Ingress-Hosts, Secret-Store und die FluxCD-Quelle gehören nicht hierher. Dies ist ein öffentlicher Tracker, das ist private Infrastruktur. Was hierher
gehört, ist alles, was eine Eigenschaft der Software ist: das Dockerfile, der Workflow, was
das Image an Konfiguration erwartet.
Was schon feststeht
Was ausgeliefert wird.tools/chemenu/mcp/, gestartet als python -m chemenu.mcp --transport streamable-http --host 0.0.0.0 --port 8000. Endpunkt /mcp. Lesend, ohne Schreibpfad — strukturell, weil nichts unter chemenu/commands/ importiert
wird.
Konfiguration, die das Image kennen muss (alles heute schon implementiert):
Variable
Zweck
Ohne sie
CHEMENU_ROOT
Welcher Korpus bedient wird
der Checkout, in dem das Paket liegt
WIKI_TRACE=0oderWIKI_TRACE_DIR außerhalb des Korpus
Telemetrie aus dem bedienten Baum halten
der Server verweigert den Start — bewusst, nicht als Bug
Abhängigkeiten.tools/requirements.txt plus tools/requirements-mcp.txt (letzteres zieht mcp, und damit pydantic/starlette/uvicorn/cryptography). Dazu ripgrep im Image — das ist
die Falle, die ein reines pip install-Dockerfile übersieht: search shellt nach rg aus und
hat absichtlich keinen Python-Fallback.
Authentifizierung ist gelöst und liegt woanders: https://gitea.nehmer.net/torben/gitea-mcp-forward-auth — Traefik-ForwardAuth, Bearer-Token
gegen SHA-256-Hashes. Der Server authentifiziert selbst nichts. Rate Limiting gehört an
dieselbe Stelle, nicht in den Iteration Budget Gate (Begründung in #19).
Menschendoku steht:INSTALL-MCP.md, Betriebsablauf in instructions/mcp-read-server.md.
Startpunkte, konkret
Zwei Vorlagen im eigenen Bestand, und sie taugen für verschiedene Hälften:
torben/gitea-mcp-forward-auth, .gitea/workflows/release.yaml — die nähere Vorlage.
Sie pusht dorthin, wo wir auch hin wollen:
Registry gitea.nehmer.net/torben, Plattform bislang nur linux/amd64
torben/gitea-mcp — Dockerfile-Muster, aber nicht der Push. Dessen Workflows pushen nach DockerHub (DOCKER_ORG: gitea), weil das Repo ein Fork des Upstream ist; als Registry-Vorlage
also unbrauchbar. Wofür es taugt, ist die Image-Form: Multi-Stage, --platform=$BUILDPLATFORM, --mount=type=cache für den Dependency-Download, ARG VERSION ins Binary, non-root Runtime auf distroless, OCI-Labels (org.opencontainers.image.version/.source). Dazu ein Muster, das
gitea-mcp hat und forward-auth nicht: ein nightly-Workflow auf main mit git describe --tags --always als Version.
Ebenfalls im forward-auth-Repo und übernehmenswert: scripts/test-registry-image.sh — zieht das veröffentlichte Image, startet es und prüft es end-to-end, mit ephemerem Login (temporäres DOCKER_CONFIG bzw. REGISTRY_AUTH_FILE, nichts in ~/.docker/config.json).
Stand im Repo, geprüft 2026-09-04 gegen 4.5.0: es gibt weiterhin kein Dockerfile und keinen
Image-Workflow. .gitea/workflows/ enthält ci.yml, nightly.yml, release.yml.
Was zu klären ist
Das ist die eigentliche Arbeit dieses Issues — jede Zeile ist eine Entscheidung, keine Aufgabe.
Was steckt im Image, Stack oder Stack+Korpus? Der Server liest einen Arbeitsbaum. Zwei
Formen: (a) Image trägt nur den Stack, der Korpus kommt als Volume und wird von einem
Sidecar/CronJob gesynct; (b) Image trägt einen Korpus-Stand und wird bei jeder Änderung neu
gebaut. (a) passt zum Polling-Design aus #19 und hält den Korpus aus der Registry heraus —
was bei einer privaten Instanz der Punkt ist. (b) macht das Image reproduzierbar und den
Sync überflüssig. Erst entscheiden, dann Dockerfile.
Wer führt git fetch && git reset --hard aus? Sidecar, CronJob, oder ein Loop im
Entrypoint. Braucht ein Read-Credential für das Korpus-Repo — für die öffentliche Instanz
keins, für die private schon. Hängt an 1.
Basis-Image.distroless wie die beiden Vorlagen geht bei Go, hier aber nicht ohne
Weiteres: es braucht einen Python-Interpreter und das rg-Binary. Realistisch python:3.13-slim plus ripgrep per apt, oder ein Multi-Stage, das rg statisch
hereinkopiert. Non-root-Runtime sollte in beiden Fällen bleiben.
Wie kommt die Version ins Image? Der Stack hat VERSION und wikitool version bump;
CI taggt bereits bei VERSION-Bewegung (.gitea/workflows/release.yml). Naheliegend ist,
den bestehenden Release-Trigger mitzubenutzen, statt einen zweiten Tag-Begriff einzuführen.
Zu prüfen: ob der Image-Build an denselben Tag hängt oder an einen eigenen.
linux/arm64 mitbauen? forward-auth baut nur amd64, gitea-mcp beides. Kostet Buildzeit;
nur entscheiden, wenn ein Ziel es braucht.
Healthcheck. Der Server hat heute keinen — /healthz gibt es beim Auth-Proxy, nicht
hier. Für k8s-Probes braucht es entweder einen Endpunkt (dann: neuer Code im Server, ohne
Auth erreichbar, wie beim Proxy) oder eine Probe über den MCP-Endpunkt. Das ist die einzige
Zeile hier, die auf eine Änderung in diesem Repo hinausläuft.
Registry-Pfad und Image-Name. Analog gitea.nehmer.net/torben/<name>. Nur festlegen.
OCI-Labels. forward-auth hat heute keine, das Testskript prüft sie optional. Beim
Neubauen gleich richtig setzen (image.source, image.version, image.title).
Wie wird der Golden-Test im Image-Kontext gefahren, wenn überhaupt? Die Suite läuft in
CI gegen den Checkout. Ob ein Smoke-Test gegen das gebaute Image dazukommt (Vorbild: test-registry-image.sh), ist eine eigene Entscheidung — die Analogie wäre: Image ziehen,
starten, list_tools und ein status gegen den mitgelieferten Demo-Korpus.
Akzeptanzkriterien
Entscheidung zu Punkt 1 (Korpus im Image oder als Volume) getroffen und im Issue vermerkt
Dockerfile im Repo, non-root, mit ripgrep, beide requirements-Dateien installiert
Gebautes Image startet mit --transport streamable-http --host 0.0.0.0 und beantwortet list_tools sowie ein status
Der Trace-Guard ist im Image erfüllt (WIKI_TRACE=0 oder WIKI_TRACE_DIR außerhalb) —
sonst startet der Container gar nicht, und das soll niemanden überraschen
Workflow pusht nach gitea.nehmer.net/torben/<name>, Tag-Schema festgelegt und
dokumentiert
Sync-Mechanismus aus Punkt 2 gebaut oder ausdrücklich als Deployment-Sache abgegrenzt
Entscheidung zu Punkt 6 (Healthcheck) — wenn er kommt, mit Test und Version-Bump
INSTALL-MCP.md um den Container-Weg ergänzt; der Verweis auf „ein Container-Image ist
als eigenes Vorhaben erfasst" dort aufgelöst
Übernommen aus #36: Ein Konsument führt über die Traefik-Middleware nachweislich search gegen den laufenden Server aus. Das ist der Abschlussnachweis für den gesamten
Weg zum MCP-Leseserver, nicht nur für das Image — er kann erst erbracht werden, wenn ein
Deployment steht, und deshalb steht er hier.
Hängt ab von:#19 (geschlossen, 2.4.0). Schließt ab:#36 (geschlossen 2026-09-04, letztes
Kriterium hierher übernommen). Verwandt:#32 — eine Ingest-Queue würde einen Schreibpfad und
damit ein anderes Container-Profil brauchen; nicht vorwegnehmen.
Der Server aus #19 läuft (2.4.0), auf `stdio` und `streamable-http`, beide gegen den echten
Korpus gegengeprüft. Was fehlt, ist der Weg vom Repo zu einem laufenden Ding: ein Image, ein
Build, ein Push in die Registry.
**Dieses Issue fasst zusammen, was schon feststeht.** Die Details sind bewusst noch offen — sie
brauchen Entscheidungen des Betreibers, und die Liste unten sagt, welche. Wer das aufgreift,
soll nicht bei null anfangen, aber auch nicht glauben, hier stünde schon ein Plan.
**Seit 2026-09-04 trägt dieses Issue auch den Abschluss des Master-Issues #36.** Dessen letztes
offenes Kriterium — ein Konsument führt über die Traefik-Middleware nachweislich `search` gegen
den Server aus — hing vollständig an einem Deployment und damit an diesem Image. #36 ist als
Entscheidungsprotokoll geschlossen; der Nachweis steht unten als eigenes Akzeptanzkriterium.
**Damit ist dies das letzte offene Issue auf dem Weg zum MCP-Leseserver.** Die Entscheidungen,
die dort getroffen wurden und hier nicht neu aufgemacht werden (Python statt Go, Traefik statt
eigener Auth, Polling statt Webhook, Direktimport statt Subprozess, Deployment gehört nicht in
dieses Repo), stehen im geschlossenen Body von #36 samt gemessener Grundlage.
**Abgrenzung, die bleibt:** Cluster, Ingress-Hosts, Secret-Store und die FluxCD-Quelle gehören
**nicht** hierher. Dies ist ein öffentlicher Tracker, das ist private Infrastruktur. Was hierher
gehört, ist alles, was eine Eigenschaft der *Software* ist: das Dockerfile, der Workflow, was
das Image an Konfiguration erwartet.
---
## Was schon feststeht
**Was ausgeliefert wird.** `tools/chemenu/mcp/`, gestartet als
`python -m chemenu.mcp --transport streamable-http --host 0.0.0.0 --port 8000`. Endpunkt
`/mcp`. Lesend, ohne Schreibpfad — strukturell, weil nichts unter `chemenu/commands/` importiert
wird.
**Konfiguration, die das Image kennen muss** (alles heute schon implementiert):
| Variable | Zweck | Ohne sie |
|---|---|---|
| `CHEMENU_ROOT` | Welcher Korpus bedient wird | der Checkout, in dem das Paket liegt |
| `WIKI_TRACE=0` **oder** `WIKI_TRACE_DIR` außerhalb des Korpus | Telemetrie aus dem bedienten Baum halten | **der Server verweigert den Start** — bewusst, nicht als Bug |
**Abhängigkeiten.** `tools/requirements.txt` plus `tools/requirements-mcp.txt` (letzteres zieht
`mcp`, und damit pydantic/starlette/uvicorn/cryptography). Dazu **`ripgrep` im Image** — das ist
die Falle, die ein reines `pip install`-Dockerfile übersieht: `search` shellt nach `rg` aus und
hat absichtlich keinen Python-Fallback.
**Authentifizierung ist gelöst und liegt woanders:**
<https://gitea.nehmer.net/torben/gitea-mcp-forward-auth> — Traefik-ForwardAuth, Bearer-Token
gegen SHA-256-Hashes. Der Server authentifiziert selbst nichts. Rate Limiting gehört an
dieselbe Stelle, **nicht** in den Iteration Budget Gate (Begründung in #19).
**Menschendoku steht:** [`INSTALL-MCP.md`](../src/branch/main/INSTALL-MCP.md), Betriebsablauf in
`instructions/mcp-read-server.md`.
---
## Startpunkte, konkret
Zwei Vorlagen im eigenen Bestand, und sie taugen für **verschiedene Hälften**:
**`torben/gitea-mcp-forward-auth`, `.gitea/workflows/release.yaml` — die nähere Vorlage.**
Sie pusht dorthin, wo wir auch hin wollen:
- `runs-on: container-builder`, Job-Image `debian:trixie-slim`
- CI-Deps per apt: `git nodejs curl docker-cli docker-buildx unzip ca-certificates iproute2 gawk`
- Secrets über `1password/load-secrets-action@v2` (`OP_SERVICE_ACCOUNT_TOKEN`), Registry-User
und PAT aus `op://CI-CD/gitea-package-token/...`
- Remote-BuildKit: `HOST_IP=$(ip route | awk '/default/ { print $3 }')`, dann
`docker buildx create --driver remote tcp://$HOST_IP:1234 --use --bootstrap`
- Trigger auf Tags `v*.*.*`; stabile Tags `vX.Y.Z` pushen zusätzlich `:latest`, Pre-Releases
stattdessen `:prerelease-tag`
- Registry `gitea.nehmer.net/torben`, Plattform bislang nur `linux/amd64`
**`torben/gitea-mcp` — Dockerfile-Muster, aber nicht der Push.** Dessen Workflows pushen nach
**DockerHub** (`DOCKER_ORG: gitea`), weil das Repo ein Fork des Upstream ist; als Registry-Vorlage
also unbrauchbar. Wofür es taugt, ist die Image-Form: Multi-Stage, `--platform=$BUILDPLATFORM`,
`--mount=type=cache` für den Dependency-Download, `ARG VERSION` ins Binary, non-root Runtime auf
`distroless`, OCI-Labels (`org.opencontainers.image.version`/`.source`). Dazu ein Muster, das
gitea-mcp hat und forward-auth nicht: ein **nightly**-Workflow auf `main` mit
`git describe --tags --always` als Version.
Ebenfalls im forward-auth-Repo und übernehmenswert: `scripts/test-registry-image.sh` — zieht das
**veröffentlichte** Image, startet es und prüft es end-to-end, mit ephemerem Login (temporäres
`DOCKER_CONFIG` bzw. `REGISTRY_AUTH_FILE`, nichts in `~/.docker/config.json`).
**Stand im Repo, geprüft 2026-09-04 gegen 4.5.0:** es gibt weiterhin kein `Dockerfile` und keinen
Image-Workflow. `.gitea/workflows/` enthält `ci.yml`, `nightly.yml`, `release.yml`.
---
## Was zu klären ist
Das ist die eigentliche Arbeit dieses Issues — jede Zeile ist eine Entscheidung, keine Aufgabe.
1. **Was steckt im Image, Stack oder Stack+Korpus?** Der Server liest einen Arbeitsbaum. Zwei
Formen: (a) Image trägt nur den Stack, der Korpus kommt als Volume und wird von einem
Sidecar/CronJob gesynct; (b) Image trägt einen Korpus-Stand und wird bei jeder Änderung neu
gebaut. (a) passt zum Polling-Design aus #19 und hält den Korpus aus der Registry heraus —
was bei einer **privaten** Instanz der Punkt ist. (b) macht das Image reproduzierbar und den
Sync überflüssig. Erst entscheiden, dann Dockerfile.
2. **Wer führt `git fetch && git reset --hard` aus?** Sidecar, CronJob, oder ein Loop im
Entrypoint. Braucht ein Read-Credential für das Korpus-Repo — für die öffentliche Instanz
keins, für die private schon. Hängt an 1.
3. **Basis-Image.** `distroless` wie die beiden Vorlagen geht bei Go, hier aber nicht ohne
Weiteres: es braucht einen Python-Interpreter *und* das `rg`-Binary. Realistisch
`python:3.13-slim` plus `ripgrep` per apt, oder ein Multi-Stage, das `rg` statisch
hereinkopiert. Non-root-Runtime sollte in beiden Fällen bleiben.
4. **Wie kommt die Version ins Image?** Der Stack hat `VERSION` und `wikitool version bump`;
CI taggt bereits bei `VERSION`-Bewegung (`.gitea/workflows/release.yml`). Naheliegend ist,
den bestehenden Release-Trigger mitzubenutzen, statt einen zweiten Tag-Begriff einzuführen.
Zu prüfen: ob der Image-Build an denselben Tag hängt oder an einen eigenen.
5. **`linux/arm64` mitbauen?** forward-auth baut nur amd64, gitea-mcp beides. Kostet Buildzeit;
nur entscheiden, wenn ein Ziel es braucht.
6. **Healthcheck.** Der Server hat heute **keinen** — `/healthz` gibt es beim Auth-Proxy, nicht
hier. Für k8s-Probes braucht es entweder einen Endpunkt (dann: neuer Code im Server, ohne
Auth erreichbar, wie beim Proxy) oder eine Probe über den MCP-Endpunkt. Das ist die einzige
Zeile hier, die auf eine Änderung **in diesem Repo** hinausläuft.
7. **Registry-Pfad und Image-Name.** Analog `gitea.nehmer.net/torben/<name>`. Nur festlegen.
8. **OCI-Labels.** forward-auth hat heute keine, das Testskript prüft sie optional. Beim
Neubauen gleich richtig setzen (`image.source`, `image.version`, `image.title`).
9. **Wie wird der Golden-Test im Image-Kontext gefahren, wenn überhaupt?** Die Suite läuft in
CI gegen den Checkout. Ob ein Smoke-Test gegen das *gebaute* Image dazukommt (Vorbild:
`test-registry-image.sh`), ist eine eigene Entscheidung — die Analogie wäre: Image ziehen,
starten, `list_tools` und ein `status` gegen den mitgelieferten Demo-Korpus.
---
## Akzeptanzkriterien
- [ ] Entscheidung zu Punkt 1 (Korpus im Image oder als Volume) getroffen und im Issue vermerkt
- [ ] Dockerfile im Repo, non-root, mit `ripgrep`, beide requirements-Dateien installiert
- [ ] Gebautes Image startet mit `--transport streamable-http --host 0.0.0.0` und beantwortet
`list_tools` sowie ein `status`
- [ ] Der Trace-Guard ist im Image erfüllt (`WIKI_TRACE=0` oder `WIKI_TRACE_DIR` außerhalb) —
sonst startet der Container gar nicht, und das soll niemanden überraschen
- [ ] Workflow pusht nach `gitea.nehmer.net/torben/<name>`, Tag-Schema festgelegt und
dokumentiert
- [ ] Sync-Mechanismus aus Punkt 2 gebaut oder ausdrücklich als Deployment-Sache abgegrenzt
- [ ] Entscheidung zu Punkt 6 (Healthcheck) — wenn er kommt, mit Test und Version-Bump
- [ ] `INSTALL-MCP.md` um den Container-Weg ergänzt; der Verweis auf „ein Container-Image ist
als eigenes Vorhaben erfasst" dort aufgelöst
- [ ] **Übernommen aus #36:** Ein Konsument führt über die Traefik-Middleware nachweislich
`search` gegen den laufenden Server aus. Das ist der Abschlussnachweis für den gesamten
Weg zum MCP-Leseserver, nicht nur für das Image — er kann erst erbracht werden, wenn ein
Deployment steht, und deshalb steht er hier.
**Hängt ab von:** #19 (geschlossen, 2.4.0). **Schließt ab:** #36 (geschlossen 2026-09-04, letztes
Kriterium hierher übernommen). **Verwandt:** #32 — eine Ingest-Queue würde einen Schreibpfad und
damit ein anderes Container-Profil brauchen; nicht vorwegnehmen.
Changelog: Dieses Issue trägt seit der Triage-Sitzung 2026-09-04 den Abschluss von #36, das dabei geschlossen wurde.
Neues, letztes Akzeptanzkriterium: „Ein Konsument führt über die Traefik-Middleware nachweislich search gegen den laufenden Server aus." Es stand als einziger offener Punkt in #36 und hing dort vollständig an einem Deployment und damit an diesem Image — es gehört zu den Entscheidungen, die hier ohnehin getroffen werden, nicht in ein Master-Issue, das nichts mehr steuert.
Kopfabsatz ergänzt: dies ist das letzte offene Issue auf dem Weg zum MCP-Leseserver. Die getroffenen Entscheidungen (Python statt Go, Traefik statt eigener Auth, Polling statt Webhook, Direktimport statt Subprozess, Deployment gehört nicht in dieses Repo) stehen im geschlossenen Body von #36 und werden hier nicht neu aufgemacht.
Repo-Stand gegen 4.5.0 nachgeprüft und im Text festgehalten: weiterhin kein Dockerfile, kein Image-Workflow, .gitea/workflows/ hat ci.yml, nightly.yml, release.yml.
Labels unverändert: area/distribution, kind/decision, prio/planned, size/M. Die neun offenen Punkte sind Betreiberentscheidungen, nicht Umsetzungszeit — kind/decision bleibt richtig.
**Changelog:** Dieses Issue trägt seit der Triage-Sitzung 2026-09-04 den Abschluss von **#36**, das dabei geschlossen wurde.
- Neues, letztes Akzeptanzkriterium: „Ein Konsument führt über die Traefik-Middleware nachweislich `search` gegen den laufenden Server aus." Es stand als einziger offener Punkt in #36 und hing dort vollständig an einem Deployment und damit an diesem Image — es gehört zu den Entscheidungen, die hier ohnehin getroffen werden, nicht in ein Master-Issue, das nichts mehr steuert.
- Kopfabsatz ergänzt: **dies ist das letzte offene Issue auf dem Weg zum MCP-Leseserver.** Die getroffenen Entscheidungen (Python statt Go, Traefik statt eigener Auth, Polling statt Webhook, Direktimport statt Subprozess, Deployment gehört nicht in dieses Repo) stehen im geschlossenen Body von #36 und werden hier nicht neu aufgemacht.
- Repo-Stand gegen 4.5.0 nachgeprüft und im Text festgehalten: weiterhin kein `Dockerfile`, kein Image-Workflow, `.gitea/workflows/` hat `ci.yml`, `nightly.yml`, `release.yml`.
- Abhängigkeitszeile um „**Schließt ab:** #36" ergänzt.
Labels unverändert: `area/distribution`, `kind/decision`, `prio/planned`, `size/M`. Die neun offenen Punkte sind Betreiberentscheidungen, nicht Umsetzungszeit — `kind/decision` bleibt richtig.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Der Server aus #19 läuft (2.4.0), auf
stdioundstreamable-http, beide gegen den echtenKorpus gegengeprüft. Was fehlt, ist der Weg vom Repo zu einem laufenden Ding: ein Image, ein
Build, ein Push in die Registry.
Dieses Issue fasst zusammen, was schon feststeht. Die Details sind bewusst noch offen — sie
brauchen Entscheidungen des Betreibers, und die Liste unten sagt, welche. Wer das aufgreift,
soll nicht bei null anfangen, aber auch nicht glauben, hier stünde schon ein Plan.
Seit 2026-09-04 trägt dieses Issue auch den Abschluss des Master-Issues #36. Dessen letztes
offenes Kriterium — ein Konsument führt über die Traefik-Middleware nachweislich
searchgegenden Server aus — hing vollständig an einem Deployment und damit an diesem Image. #36 ist als
Entscheidungsprotokoll geschlossen; der Nachweis steht unten als eigenes Akzeptanzkriterium.
Damit ist dies das letzte offene Issue auf dem Weg zum MCP-Leseserver. Die Entscheidungen,
die dort getroffen wurden und hier nicht neu aufgemacht werden (Python statt Go, Traefik statt
eigener Auth, Polling statt Webhook, Direktimport statt Subprozess, Deployment gehört nicht in
dieses Repo), stehen im geschlossenen Body von #36 samt gemessener Grundlage.
Abgrenzung, die bleibt: Cluster, Ingress-Hosts, Secret-Store und die FluxCD-Quelle gehören
nicht hierher. Dies ist ein öffentlicher Tracker, das ist private Infrastruktur. Was hierher
gehört, ist alles, was eine Eigenschaft der Software ist: das Dockerfile, der Workflow, was
das Image an Konfiguration erwartet.
Was schon feststeht
Was ausgeliefert wird.
tools/chemenu/mcp/, gestartet alspython -m chemenu.mcp --transport streamable-http --host 0.0.0.0 --port 8000. Endpunkt/mcp. Lesend, ohne Schreibpfad — strukturell, weil nichts unterchemenu/commands/importiertwird.
Konfiguration, die das Image kennen muss (alles heute schon implementiert):
CHEMENU_ROOTWIKI_TRACE=0oderWIKI_TRACE_DIRaußerhalb des KorpusAbhängigkeiten.
tools/requirements.txtplustools/requirements-mcp.txt(letzteres ziehtmcp, und damit pydantic/starlette/uvicorn/cryptography). Dazuripgrepim Image — das istdie Falle, die ein reines
pip install-Dockerfile übersieht:searchshellt nachrgaus undhat absichtlich keinen Python-Fallback.
Authentifizierung ist gelöst und liegt woanders:
https://gitea.nehmer.net/torben/gitea-mcp-forward-auth — Traefik-ForwardAuth, Bearer-Token
gegen SHA-256-Hashes. Der Server authentifiziert selbst nichts. Rate Limiting gehört an
dieselbe Stelle, nicht in den Iteration Budget Gate (Begründung in #19).
Menschendoku steht:
INSTALL-MCP.md, Betriebsablauf ininstructions/mcp-read-server.md.Startpunkte, konkret
Zwei Vorlagen im eigenen Bestand, und sie taugen für verschiedene Hälften:
torben/gitea-mcp-forward-auth,.gitea/workflows/release.yaml— die nähere Vorlage.Sie pusht dorthin, wo wir auch hin wollen:
runs-on: container-builder, Job-Imagedebian:trixie-slimgit nodejs curl docker-cli docker-buildx unzip ca-certificates iproute2 gawk1password/load-secrets-action@v2(OP_SERVICE_ACCOUNT_TOKEN), Registry-Userund PAT aus
op://CI-CD/gitea-package-token/...HOST_IP=$(ip route | awk '/default/ { print $3 }'), danndocker buildx create --driver remote tcp://$HOST_IP:1234 --use --bootstrapv*.*.*; stabile TagsvX.Y.Zpushen zusätzlich:latest, Pre-Releasesstattdessen
:prerelease-taggitea.nehmer.net/torben, Plattform bislang nurlinux/amd64torben/gitea-mcp— Dockerfile-Muster, aber nicht der Push. Dessen Workflows pushen nachDockerHub (
DOCKER_ORG: gitea), weil das Repo ein Fork des Upstream ist; als Registry-Vorlagealso unbrauchbar. Wofür es taugt, ist die Image-Form: Multi-Stage,
--platform=$BUILDPLATFORM,--mount=type=cachefür den Dependency-Download,ARG VERSIONins Binary, non-root Runtime aufdistroless, OCI-Labels (org.opencontainers.image.version/.source). Dazu ein Muster, dasgitea-mcp hat und forward-auth nicht: ein nightly-Workflow auf
mainmitgit describe --tags --alwaysals Version.Ebenfalls im forward-auth-Repo und übernehmenswert:
scripts/test-registry-image.sh— zieht dasveröffentlichte Image, startet es und prüft es end-to-end, mit ephemerem Login (temporäres
DOCKER_CONFIGbzw.REGISTRY_AUTH_FILE, nichts in~/.docker/config.json).Stand im Repo, geprüft 2026-09-04 gegen 4.5.0: es gibt weiterhin kein
Dockerfileund keinenImage-Workflow.
.gitea/workflows/enthältci.yml,nightly.yml,release.yml.Was zu klären ist
Das ist die eigentliche Arbeit dieses Issues — jede Zeile ist eine Entscheidung, keine Aufgabe.
Was steckt im Image, Stack oder Stack+Korpus? Der Server liest einen Arbeitsbaum. Zwei
Formen: (a) Image trägt nur den Stack, der Korpus kommt als Volume und wird von einem
Sidecar/CronJob gesynct; (b) Image trägt einen Korpus-Stand und wird bei jeder Änderung neu
gebaut. (a) passt zum Polling-Design aus #19 und hält den Korpus aus der Registry heraus —
was bei einer privaten Instanz der Punkt ist. (b) macht das Image reproduzierbar und den
Sync überflüssig. Erst entscheiden, dann Dockerfile.
Wer führt
git fetch && git reset --hardaus? Sidecar, CronJob, oder ein Loop imEntrypoint. Braucht ein Read-Credential für das Korpus-Repo — für die öffentliche Instanz
keins, für die private schon. Hängt an 1.
Basis-Image.
distrolesswie die beiden Vorlagen geht bei Go, hier aber nicht ohneWeiteres: es braucht einen Python-Interpreter und das
rg-Binary. Realistischpython:3.13-slimplusripgrepper apt, oder ein Multi-Stage, dasrgstatischhereinkopiert. Non-root-Runtime sollte in beiden Fällen bleiben.
Wie kommt die Version ins Image? Der Stack hat
VERSIONundwikitool version bump;CI taggt bereits bei
VERSION-Bewegung (.gitea/workflows/release.yml). Naheliegend ist,den bestehenden Release-Trigger mitzubenutzen, statt einen zweiten Tag-Begriff einzuführen.
Zu prüfen: ob der Image-Build an denselben Tag hängt oder an einen eigenen.
linux/arm64mitbauen? forward-auth baut nur amd64, gitea-mcp beides. Kostet Buildzeit;nur entscheiden, wenn ein Ziel es braucht.
Healthcheck. Der Server hat heute keinen —
/healthzgibt es beim Auth-Proxy, nichthier. Für k8s-Probes braucht es entweder einen Endpunkt (dann: neuer Code im Server, ohne
Auth erreichbar, wie beim Proxy) oder eine Probe über den MCP-Endpunkt. Das ist die einzige
Zeile hier, die auf eine Änderung in diesem Repo hinausläuft.
Registry-Pfad und Image-Name. Analog
gitea.nehmer.net/torben/<name>. Nur festlegen.OCI-Labels. forward-auth hat heute keine, das Testskript prüft sie optional. Beim
Neubauen gleich richtig setzen (
image.source,image.version,image.title).Wie wird der Golden-Test im Image-Kontext gefahren, wenn überhaupt? Die Suite läuft in
CI gegen den Checkout. Ob ein Smoke-Test gegen das gebaute Image dazukommt (Vorbild:
test-registry-image.sh), ist eine eigene Entscheidung — die Analogie wäre: Image ziehen,starten,
list_toolsund einstatusgegen den mitgelieferten Demo-Korpus.Akzeptanzkriterien
ripgrep, beide requirements-Dateien installiert--transport streamable-http --host 0.0.0.0und beantwortetlist_toolssowie einstatusWIKI_TRACE=0oderWIKI_TRACE_DIRaußerhalb) —sonst startet der Container gar nicht, und das soll niemanden überraschen
gitea.nehmer.net/torben/<name>, Tag-Schema festgelegt unddokumentiert
INSTALL-MCP.mdum den Container-Weg ergänzt; der Verweis auf „ein Container-Image istals eigenes Vorhaben erfasst" dort aufgelöst
searchgegen den laufenden Server aus. Das ist der Abschlussnachweis für den gesamtenWeg zum MCP-Leseserver, nicht nur für das Image — er kann erst erbracht werden, wenn ein
Deployment steht, und deshalb steht er hier.
Hängt ab von: #19 (geschlossen, 2.4.0). Schließt ab: #36 (geschlossen 2026-09-04, letztes
Kriterium hierher übernommen). Verwandt: #32 — eine Ingest-Queue würde einen Schreibpfad und
damit ein anderes Container-Profil brauchen; nicht vorwegnehmen.
torben referenced this issue2026-09-02 06:07:30 +00:00
Changelog: Dieses Issue trägt seit der Triage-Sitzung 2026-09-04 den Abschluss von #36, das dabei geschlossen wurde.
searchgegen den laufenden Server aus." Es stand als einziger offener Punkt in #36 und hing dort vollständig an einem Deployment und damit an diesem Image — es gehört zu den Entscheidungen, die hier ohnehin getroffen werden, nicht in ein Master-Issue, das nichts mehr steuert.Dockerfile, kein Image-Workflow,.gitea/workflows/hatci.yml,nightly.yml,release.yml.Labels unverändert:
area/distribution,kind/decision,prio/planned,size/M. Die neun offenen Punkte sind Betreiberentscheidungen, nicht Umsetzungszeit —kind/decisionbleibt richtig.