MCP-Server — Neuinstallation von Grund auf¶
Diese Seite dokumentiert den vollständigen Aufbau des MCP-Servers von Null — für eine Neuinstallation oder als Vorlage für ein anderes Heimnetz.
Architektur und laufendes System: mcp-server.md
Arbeitsregeln für KIs: mcp-arbeitsregeln.md
Überblick¶
Was am Ende läuft:
Cloudflare Access (JWT-Auth)
│
▼
mcp.diebrocks.com (Cloudflare Tunnel, CT 102)
│
├── /mcp → :3000 MCP-Server (Node.js, User mcp)
└── /admin → :3001 Admin-UI (Node.js, root)
│
(beide in CT 108, 10.10.10.33)
│
SSH als mcp-agent → Proxmox, ebusd-*, cloudflared, mcp-server
SSH als ssh → Home Assistant
SSH als mcp → MikroTik
wiki.diebrocks.com (Cloudflare Pages)
│
└── GitHub Repo (HerrBausW/smarthome-wiki) → Cloudflare Pages Build
Build-Befehl: pip install -r requirements.txt && mkdocs build
Output: site/
Branch: master — automatische Bereitstellung aktiv
Cloudflare Pages baut automatisch bei jedem git push
Anpassen für ein anderes Heimnetz: IPs, Domain, Cloudflare-Team-Domain, AUD-Tag, Admin-E-Mail und die HOSTS-Map in index.js müssen auf die eigene Umgebung angepasst werden. Der restliche Code und alle Systemd-Units sind generisch.
Voraussetzungen¶
- Proxmox-Host läuft, Netz ist konfiguriert
- Cloudflare-Account mit eigener Domain und Zero Trust (kostenlos)
- Cloudflare Tunnel (CT 102) läuft — siehe cloudflare-tunnel.md
- GitHub-Repo für das Wiki (oder Wiki-Teil weglassen)
1. LXC-Container anlegen (Proxmox)¶
Im Proxmox-UI oder per CLI:
# Debian 13 Template vorher herunterladen:
# Datacenter → pve → local → CT Templates → debian-13-standard herunterladen
pct create 108 local:vztmpl/debian-13-standard_13.x_amd64.tar.zst \
--hostname mcp-server \
--unprivileged 1 \
--features nesting=1 \
--memory 512 \
--swap 512 \
--cores 1 \
--rootfs local-lvm:8 \
--net0 name=eth0,bridge=vmbr0,ip=10.10.10.33/24,gw=10.10.10.1 \
--nameserver 10.10.10.1 \
--start 1
Start-Reihenfolge setzen (Proxmox UI → CT 108 → Optionen → Start/Shutdown): - Order: 2 (nach cloudflared) - Up: 10 s - Down: 30 s
2. Grundkonfiguration (im Container)¶
pct enter 108
apt-get update && apt-get upgrade -y
apt-get install -y ssh curl git openssh-server
systemctl enable --now ssh
passwd
3. User mcp anlegen¶
Der MCP-Server läuft als unprivilegierter User mcp (uid 999).
useradd -m -u 999 -s /bin/bash mcp
passwd -l mcp # Kein Passwort-Login, nur SSH
mkdir -p /home/mcp/.ssh
chmod 700 /home/mcp/.ssh
chown mcp:mcp /home/mcp/.ssh
4. SSH-Keys generieren¶
Alle Keys werden als User mcp erzeugt:
su - mcp
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "mcp-remote" -N ""
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_wiki -C "mcp-wiki" -N ""
cat > ~/.ssh/config << 'EOF'
Host github-wiki
HostName github.com
User git
IdentityFile ~/.ssh/id_ed25519_wiki
StrictHostKeyChecking no
EOF
chmod 600 ~/.ssh/config
echo "=== mcp-remote ===" && cat ~/.ssh/id_ed25519.pub
echo "=== wiki ===" && cat ~/.ssh/id_ed25519_wiki.pub
exit
5. Ziel-Hosts vorbereiten¶
5a. Proxmox-Host¶
useradd -m -s /bin/bash mcp-agent
mkdir -p /home/mcp-agent/.ssh && chmod 700 /home/mcp-agent/.ssh
echo 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAA...KEY... mcp-remote' \
>> /home/mcp-agent/.ssh/authorized_keys
chmod 600 /home/mcp-agent/.ssh/authorized_keys
chown -R mcp-agent:mcp-agent /home/mcp-agent/.ssh
echo "mcp-agent ALL=(root) NOPASSWD: /usr/local/bin/mcp-pct, /usr/local/bin/mcp-maintenance" \
> /etc/sudoers.d/mcp-agent
chmod 440 /etc/sudoers.d/mcp-agent
5b. Arbeits-Container (cloudflared/102, ebusd-heizung/106, ebusd-lueftung/107)¶
useradd -m -s /bin/bash mcp-agent
mkdir -p /home/mcp-agent/.ssh && chmod 700 /home/mcp-agent/.ssh
echo 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAA...KEY... mcp-remote' \
>> /home/mcp-agent/.ssh/authorized_keys
chmod 600 /home/mcp-agent/.ssh/authorized_keys
chown -R mcp-agent:mcp-agent /home/mcp-agent/.ssh
echo "mcp-agent ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/mcp-agent
chmod 440 /etc/sudoers.d/mcp-agent
5c. MCP-Server selbst (CT 108)¶
# KEIN sudoers-Eintrag — Gate-Schutz
echo 'no-port-forwarding,no-agent-forwarding,no-X11-forwarding ssh-ed25519 AAAA...KEY... mcp-remote' \
>> /home/mcp-agent/.ssh/authorized_keys
5d. Home Assistant¶
- Einstellungen → Add-ons → Advanced SSH & Web Terminal installieren
- Public Key aus Schritt 4 im Addon eintragen
5e. MikroTik¶
/user add name=mcp group=read password=""
/user ssh-keys import user=mcp public-key-file=mcp-remote.pub
6. sudo-Wrapper installieren¶
6a. mcp-pct auf dem Proxmox-Host¶
cat > /usr/local/bin/mcp-pct << 'SCRIPT'
#!/bin/bash
set -euo pipefail
cmd="${1:-}"; shift || true
case "$cmd" in
list) exec /usr/sbin/pct list ;;
status|start|stop|restart)
id="${1:?Container-ID fehlt}"
[[ "$id" =~ ^[0-9]+$ ]] || { echo "Ungueltige ID" >&2; exit 1; }
exec /usr/sbin/pct "$cmd" "$id" ;;
exec)
id="${1:?Container-ID fehlt}"; shift
[[ "$id" =~ ^[0-9]+$ ]] || { echo "Ungueltige ID" >&2; exit 1; }
sub="${1:-}"
case "$sub" in
systemctl)
action="${2:-}"; svc="${3:-}"
[[ "$action" =~ ^(status|start|stop|restart)$ ]] || { echo "Aktion verboten" >&2; exit 1; }
[[ "$svc" =~ ^[A-Za-z0-9@._-]+$ ]] || { echo "Ungueltiger Service" >&2; exit 1; }
exec /usr/sbin/pct exec "$id" -- systemctl "$action" "$svc" --no-pager ;;
journalctl-unit)
svc="${2:?Service fehlt}"; n="${3:-50}"
[[ "$svc" =~ ^[A-Za-z0-9@._-]+$ && "$n" =~ ^[0-9]+$ ]] || { echo "Ungueltige Argumente" >&2; exit 1; }
exec /usr/sbin/pct exec "$id" -- journalctl -u "$svc" -n "$n" --no-pager ;;
journalctl-clear)
exec /usr/sbin/pct exec "$id" -- bash -c "journalctl --rotate && journalctl --vacuum-time=1s && echo OK" ;;
*) echo "Subkommando verboten: $sub" >&2; exit 1 ;;
esac ;;
*) echo "Nutzung: mcp-pct list|status|start|stop|restart|exec ..." >&2; exit 1 ;;
esac
SCRIPT
chmod 755 /usr/local/bin/mcp-pct && chown root:root /usr/local/bin/mcp-pct
6b. mcp-maintenance auf allen Debian-Hosts¶
cat > /usr/local/bin/mcp-maintenance << 'SCRIPT'
#!/bin/bash
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
case "${1:-}" in
check) apt-get update -qq 2>/dev/null || true; apt list --upgradable 2>/dev/null ;;
upgrade) apt-get upgrade -y 2>&1 ;;
cleanup) apt-get autoremove -y 2>&1; apt-get autoclean 2>&1; echo '=== Fertig ===' ;;
*) echo "Nutzung: mcp-maintenance check|upgrade|cleanup" >&2; exit 1 ;;
esac
SCRIPT
chmod 755 /usr/local/bin/mcp-maintenance && chown root:root /usr/local/bin/mcp-maintenance
7. Node.js installieren (CT 108)¶
pct enter 108
curl -fsSL https://deb.nodesource.com/setup_22.x | bash -
apt-get install -y nodejs
node --version # sollte v22.x ausgeben
8. MCP-Server einrichten (CT 108)¶
Verzeichnisse anlegen¶
mkdir -p /opt/mcp-shell && chown root:root /opt/mcp-shell && chmod 755 /opt/mcp-shell
touch /var/log/mcp-shell-audit.jsonl
chown mcp:mcp /var/log/mcp-shell-audit.jsonl && chmod 640 /var/log/mcp-shell-audit.jsonl
package.json¶
cat > /opt/mcp-shell/package.json << 'EOF'
{
"name": "mcp-shell",
"version": "1.0.0",
"type": "module",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.29.0",
"express": "^5.2.1",
"jsonwebtoken": "^9.0.3",
"jwks-rsa": "^4.1.0",
"zod": "^4.4.3"
}
}
EOF
cd /opt/mcp-shell && npm install
chown -R root:root /opt/mcp-shell/node_modules
index.js¶
Anpassen: TEAM_DOMAIN, AUD, IDENTITIES, HOSTS, PROXMOX_SSH.
# index.js nach /opt/mcp-shell/index.js schreiben (siehe produktiver Stand)
chown root:root /opt/mcp-shell/index.js && chmod 644 /opt/mcp-shell/index.js
tool-config.json¶
cat > /opt/mcp-shell/tool-config.json << 'EOF'
{
"disabled_tools": [],
"write_allow": {
"ebusd-heizung": ["/etc/ebusd/", "/tmp/"],
"ebusd-lueftung": ["/etc/ebusd/", "/tmp/"],
"home-assistant": ["/config/", "/tmp/"],
"mcp-server": ["/tmp/"],
"proxmox": [],
"cloudflared": []
}
}
EOF
chown root:root /opt/mcp-shell/tool-config.json && chmod 644 /opt/mcp-shell/tool-config.json
9. Admin-UI einrichten (CT 108)¶
mkdir -p /opt/mcp-admin
ln -s /opt/mcp-shell/node_modules /opt/mcp-admin/node_modules
# server.js nach /opt/mcp-admin/server.js schreiben (TEAM_DOMAIN, AUD, ADMIN_EMAILS anpassen)
chown root:root /opt/mcp-admin/server.js && chmod 644 /opt/mcp-admin/server.js
10. Systemd-Services einrichten (CT 108)¶
cat > /etc/systemd/system/mcp-shell.service << 'EOF'
[Unit]
Description=MCP Shell Server (laeuft als unprivilegierter User mcp)
After=network.target
[Service]
Type=simple
User=mcp
Group=mcp
WorkingDirectory=/opt/mcp-shell
ExecStart=/usr/bin/node index.js
Restart=always
RestartSec=3
NoNewPrivileges=yes
[Install]
WantedBy=multi-user.target
EOF
cat > /etc/systemd/system/mcp-admin.service << 'EOF'
[Unit]
Description=MCP Admin UI (root, Port 3001)
After=network.target
[Service]
Type=simple
User=root
WorkingDirectory=/opt/mcp-admin
ExecStart=/usr/bin/node server.js
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now mcp-shell mcp-admin
11. Wiki-Repo klonen & Cloudflare Pages einrichten¶
Das Wiki wird als statische Site über Cloudflare Pages ausgeliefert. Der MCP-Server pusht Änderungen per git push ins GitHub-Repo — Cloudflare Pages baut dann automatisch mit mkdocs build.
11a. GitHub-Repo anlegen¶
- Neues GitHub-Repo anlegen (z.B.
smarthome-wiki) mkdocs.yml,requirements.txtunddocs/-Verzeichnis committen- Public Key
~/.ssh/id_ed25519_wiki.pubals Deploy Key mit Write-Zugriff eintragen: - GitHub Repo → Settings → Deploy Keys → Add deploy key → Allow write access
requirements.txt Mindestinhalt:
11b. Wiki-Repo auf CT 108 klonen¶
11c. Cloudflare Pages konfigurieren¶
- Cloudflare Dashboard → Workers & Pages → Create → Pages → Connect to Git
- GitHub-Repo auswählen
- Build-Einstellungen:
| Einstellung | Wert |
|---|---|
| Build-Befehl | pip install -r requirements.txt && mkdocs build |
| Build-Ausgabe | site |
| Stammverzeichnis | (leer) |
| Build-Systemversion | 3 |
| Produktions-Branch | master |
| Automatische Bereitstellungen | Aktiviert |
- Save and Deploy — erster Build startet automatisch
11d. Eigene Domain verknüpfen¶
Pages-Projekt → Benutzerdefinierte Domänen → Domäne hinzufügen → wiki.DEINE-DOMAIN.com
Cloudflare fügt den CNAME automatisch ein (da Domain bereits bei Cloudflare liegt).
11e. Automatischer Build bei Wiki-Änderungen¶
Ab jetzt reicht ein git push vom MCP-Server — wird automatisch durch wiki_write ausgeführt. Cloudflare Pages erkennt den Push und baut die Site neu (~30 Sekunden). Kein Webhook oder Cronjob nötig.
12. Cloudflare Zero Trust konfigurieren¶
12a. Access Application anlegen¶
- Zero Trust → Access → Applications → Self-hosted
- Domain:
mcp.DEINE-DOMAIN.com - AUD-Tag nach dem Anlegen notieren → in
index.jsundserver.jseintragen
12b. Access Policy¶
- Action:
Allow - Include:
Emails→ eigene E-Mail
12c. Service Token für KI-Connector¶
- Zero Trust → Access → Service Auth → Service Tokens → Create
- Name: z.B.
claude-mcp - Client ID und Secret sofort notieren — Secret wird nur einmal angezeigt
13. Cloudflare Tunnel Ingress ergänzen (CT 102)¶
ingress:
- hostname: mcp.DEINE-DOMAIN.com
path: "^/admin"
service: http://10.10.10.33:3001
- hostname: mcp.DEINE-DOMAIN.com
service: http://10.10.10.33:3000
- service: http_status:404
14. KI-Client konfigurieren¶
{
"mcpServers": {
"heimnetz-mcp": {
"type": "http",
"url": "https://mcp.DEINE-DOMAIN.com/mcp",
"headers": {
"CF-Access-Client-Id": "<client-id>",
"CF-Access-Client-Secret": "<client-secret>"
}
}
}
}
15. Funktionstest¶
curl -X POST https://mcp.DEINE-DOMAIN.com/mcp \
-H "Content-Type: application/json" \
-H "CF-Access-Client-Id: <id>" \
-H "CF-Access-Client-Secret: <secret>" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Checkliste Neuinstallation¶
- [ ] CT 108 angelegt, Debian installiert, SSH aktiv
- [ ] User
mcpangelegt (uid 999, kein sudo) - [ ] SSH-Keys generiert (
id_ed25519,id_ed25519_wiki) - [ ]
mcp-agentauf Proxmox, CT 102, 106, 107, 108 eingerichtet (authorized_keys + sudoers) - [ ] SSH-User auf HA und MikroTik eingerichtet
- [ ]
mcp-pctauf Proxmox installiert - [ ]
mcp-maintenanceauf allen Debian-Hosts installiert - [ ] Node.js installiert
- [ ]
/opt/mcp-shell/mitindex.js,package.json,tool-config.json(root-owned) - [ ]
/opt/mcp-admin/mitserver.js(root-owned), Symlink auf node_modules - [ ] Audit-Log angelegt (
/var/log/mcp-shell-audit.jsonl, Owner mcp) - [ ] Systemd-Services
mcp-shellundmcp-adminaktiviert und laufend - [ ] GitHub-Repo angelegt,
requirements.txtundmkdocs.ymlcommittet - [ ] Deploy Key (
id_ed25519_wiki) in GitHub eingetragen - [ ] Wiki-Repo in
/opt/wikigeklont (Owner mcp) - [ ] Cloudflare Pages konfiguriert (Build:
pip install -r requirements.txt && mkdocs build, Output:site, System v3) - [ ] Eigene Domain in Cloudflare Pages verknüpft
- [ ] Cloudflare Application angelegt (AUD notiert, in Code eingetragen)
- [ ] Service Token angelegt (Secret notiert)
- [ ] Cloudflare Tunnel Ingress für
mcp.DEINE-DOMAIN.comergänzt - [ ] KI-Client konfiguriert
- [ ] Funktionstest erfolgreich