shelly-mcp: Build-Materialien (Dockerfile + Anleitung)
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.
This commit is contained in:
4
mcp/shelly/.gitignore
vendored
Normal file
4
mcp/shelly/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
# Secrets & runtime — niemals committen
|
||||||
|
.env
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
72
mcp/shelly/BUILD.md
Normal file
72
mcp/shelly/BUILD.md
Normal file
@@ -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
|
||||||
|
```
|
||||||
15
mcp/shelly/Dockerfile
Normal file
15
mcp/shelly/Dockerfile
Normal file
@@ -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"]
|
||||||
2
mcp/shelly/requirements.txt
Normal file
2
mcp/shelly/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mcp[cli]>=1.0
|
||||||
|
starlette>=0.36
|
||||||
Reference in New Issue
Block a user