From 27863c1f2e2fb306ea31cd5eccfcf491ddc88171 Mon Sep 17 00:00:00 2001 From: Christoph Emsenhuber Date: Fri, 28 Aug 2026 19:08:43 +0200 Subject: [PATCH] shelly-mcp: Build-Materialien (Dockerfile + Anleitung) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vorbereitung für Session B (Deploy auf DS923). Datei-Set reicht für Image-Build ohne weitere Quellen aus dem Repo: - Dockerfile: python:3.12-slim, mountbares /config ohne .env-COPY - requirements.txt: mcp[cli]>=1.0, starlette>=0.36 (StreamableHTTP) - BUILD.md: rsync → docker build → Portainer-Container-Deploy - .gitignore: .env (Schema-Vorlage lokal) + __pycache__ ausklammern Die Live-Instanz .env und der Container selbst werden in Session B gebaut, nicht hier. Kein Secret in Git. --- mcp/shelly/.gitignore | 4 +++ mcp/shelly/BUILD.md | 72 +++++++++++++++++++++++++++++++++++++ mcp/shelly/Dockerfile | 15 ++++++++ mcp/shelly/requirements.txt | 2 ++ 4 files changed, 93 insertions(+) create mode 100644 mcp/shelly/.gitignore create mode 100644 mcp/shelly/BUILD.md create mode 100644 mcp/shelly/Dockerfile create mode 100644 mcp/shelly/requirements.txt diff --git a/mcp/shelly/.gitignore b/mcp/shelly/.gitignore new file mode 100644 index 0000000..f3f57f8 --- /dev/null +++ b/mcp/shelly/.gitignore @@ -0,0 +1,4 @@ +# Secrets & runtime — niemals committen +.env +__pycache__/ +*.pyc diff --git a/mcp/shelly/BUILD.md b/mcp/shelly/BUILD.md new file mode 100644 index 0000000..308a311 --- /dev/null +++ b/mcp/shelly/BUILD.md @@ -0,0 +1,72 @@ +# shelly-mcp — Build-Anleitung (DS923, lokal) + +## Source-Tree (im Repo, gepflegt) +- `mcp/shelly/Dockerfile` — Multi-stage-frei, python:3.12-slim, COPY requirements.txt + server.py + discover.py +- `mcp/shelly/requirements.txt` — `mcp[cli]>=1.0`, `starlette>=0.36` +- `mcp/shelly/server.py` — FastMCP, StreamableHTTP `/mcp` + `/health` + `/` +- `mcp/shelly/discover.py` — Read-only-Sweep (CLI-Argument, nicht Env) + +## Secrets +- **SSoT:** `~/.secrets/credentials.env` + `~/.secrets/exports.zsh` +- **Niemals ins Image brennen.** Dockerfile macht **kein** `COPY .env`. +- **Im Stack:** `docs/nas-vlan20/stacks/shelly-mcp.yml` (gitignored) trägt die Werte als `environment:` — folgt der Konvention der anderen DS923-Stacks. + +## Build (auf der DS923, einmalig) + +```bash +# 1. Build-Verzeichnis auf der DS923 anlegen (außerhalb des Compose-Stacks) +ssh adm.christoph@10.40.20.10 "sudo -i mkdir -p /data/compose/shelly-mcp-build" + +# 2. Source rsyncen (vom Mac) +rsync -avz --delete \ + mcp/shelly/Dockerfile \ + mcp/shelly/requirements.txt \ + mcp/shelly/server.py \ + mcp/shelly/discover.py \ + adm.christoph@10.40.20.10:/data/compose/shelly-mcp-build/ + +# 3. Image bauen +ssh adm.christoph@10.40.20.10 "sudo -i docker build -t bf/shelly-mcp:0.1 /data/compose/shelly-mcp-build" + +# 4. Stack deployen (Portainer → Stacks → Add stack → Repository upload +# ODER Portainer-API CreateStack mit Git-Repository-Pfad) +ssh adm.christoph@10.40.20.10 "sudo -i cd /data/compose && docker stack deploy -c shelly-mcp.yml shelly-mcp" +# (Hinweis: der pve-mcp-Stack wurde via Portainer-UI deployed, nicht docker-stack. +# Vorzugsweise Portainer-API CreateStack mit GitRepo-Ref auf docs/nas-vlan20/stacks/shelly-mcp.yml.) + +# 5. IP am DHCP-Server (crs326-core, dhcp-v20) als statische Reservierung eintragen +# MAC wird nach dem ersten Boot sichtbar (docker inspect shelly-mcp | jq '.[0].NetworkSettings.Networks.vlan20.MacAddress') +# Reservierung in Nautobot/RouterOS: dhcp-server lease add ... server=dhcp-v20 +``` + +## Abnahme +```bash +# Health-Endpoint +curl http://10.40.20.180:3030/health + +# MCP-Discovery (StreamableHTTP erwartet initialize) +curl -X POST http://10.40.20.180:3030/mcp \ + -H "Accept: application/json, text/event-stream" \ + -H "Content-Type: application/json" \ + -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"probe","version":"0.0"}}}' +# → serverInfo.name = "shelly-mcp" + +# Live-Sweep aus dem Container heraus +docker exec shelly-mcp python3 discover.py 10.40.30.180-250 +# → erwartet 23 Shellys (s. Handoff 2026-08-28) + +# MCP-Client-Konfiguration (in ~/.claude.json + ~/.config/opencode/opencode.jsonc): +# { +# "shelly-mcp": { +# "url": "http://10.40.20.180:3030/mcp", +# "enabled": true, +# "headers": {} # falls Bearer gewünscht: "Authorization": "Bearer ${SHELLY_MCP_BEARER}" +# } +# } +``` + +## Rollback +```bash +docker rm -f shelly-mcp +docker rmi bf/shelly-mcp:0.1 +``` diff --git a/mcp/shelly/Dockerfile b/mcp/shelly/Dockerfile new file mode 100644 index 0000000..a546c93 --- /dev/null +++ b/mcp/shelly/Dockerfile @@ -0,0 +1,15 @@ +FROM python:3.12-slim + +WORKDIR /app + +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +COPY server.py discover.py ./ + +EXPOSE 3030 + +ENV SHELLY_MCP_HOST=0.0.0.0 \ + SHELLY_MCP_PORT=3030 + +CMD ["python3", "server.py"] diff --git a/mcp/shelly/requirements.txt b/mcp/shelly/requirements.txt new file mode 100644 index 0000000..61e462c --- /dev/null +++ b/mcp/shelly/requirements.txt @@ -0,0 +1,2 @@ +mcp[cli]>=1.0 +starlette>=0.36