iCloud-Kalender in Claude: eigener MCP-Server für Claude Code und die Claude-App
Claude kann deine Termine lesen und neue Termine eintragen, direkt in deinem iCloud-Kalender. Dafür brauchst du einen MCP-Server (Model Context Protocol, also einen kleinen Dienst, der eine Schnittstelle so verpackt, dass Claude sie als Tool benutzen kann). In diesem Guide erfährst du, wie du so einen Server für den Apple-Kalender selbst hostest und ihn in Claude Code und in der Claude-App einbindest. Bei mir läuft genau dieses Setup, und ich nutze es jeden Tag: „Was steht morgen an?“ oder „Trag mir Freitag 14 Uhr Zahnarzt ein“ landet direkt in meinem Kalender auf iPhone und Mac.
Kurz erklärt
- Der Server
caldav-mcpspricht mit iCloud über CalDAV, das Standard-Protokoll für Kalender. Claude bekommt dadurch Tools wielist-calendars,list-eventsundcreate-event. - Zum Anmelden bei iCloud nimmst du ein app-spezifisches Passwort von Apple, nie dein normales Apple-Passwort.
- Alles läuft mit Docker in einem kleinen LXC (einem Linux-Container auf Proxmox). Caddy als Reverse Proxy davor prüft einen geheimen Schlüssel, eine Firewall-Regel lässt nur Caddy an den Container.
- Claude Code erreicht den Server über eine interne Adresse. Für die Claude-App im Browser und am Handy gibt es optional einen zweiten, öffentlichen Eingang mit Login, den nur Anthropics Server benutzen dürfen.
- Alle Dateien aus diesem Guide findest du im Repo mapplebox/homelab-mcp-stack:
Dockerfile,docker-compose.yml,.env.example,auth.env.exampleundREADME.mdim Ordnercalendar/, die Firewall-Unitmcp-firewall.serviceund die Caddy-BlöckeCaddyfile.snippetsim Ordnercommon/.
Was du brauchst
- Einen Proxmox-Server oder irgendeinen anderen Linux-Rechner mit Docker. Ich zeige es mit Proxmox, die Docker-Teile funktionieren überall gleich.
- Caddy als Reverse Proxy (ein Webserver, der Anfragen annimmt, HTTPS macht und sie an den richtigen Dienst weiterreicht), installiert aus dem Debian-Paket, und eine eigene Domain. Mehr Hintergrund zu Caddy und Zertifikaten für interne Hostnamen steht in meinem Guide zu sicheren MCP-Connectors im Homelab.
- Eine Apple-ID mit Zwei-Faktor-Authentifizierung. Ohne 2FA kannst du kein app-spezifisches Passwort erstellen.
- Claude Code und/oder einen Claude-Account für die App. Custom Connectors gibt es laut Anthropic in den Plänen Free, Pro und Max (im Free-Plan genau einer) sowie in Team und Enterprise.
- Für den optionalen öffentlichen Eingang: eine echte öffentliche IPv4-Adresse an deinem Anschluss (mehr dazu in Schritt 8).
- Grundwissen in der Linux-Shell: Dateien mit
nanoanlegen, Befehle als root ausführen.
Im Guide stehen Platzhalter, die du durch deine Werte ersetzt: 192.168.1.10 ist dein Caddy, 192.168.1.21 der Kalender-LXC, mcp-cal.int.example.com die interne und cal.example.com die öffentliche Adresse.
Schritt 1: App-spezifisches Passwort bei Apple erstellen
Ein app-spezifisches Passwort ist ein Zusatzpasswort, mit dem sich eine fremde App bei deinem iCloud-Konto anmelden kann, ohne dein echtes Passwort zu kennen. So kannst du eins erstellen:
- Melde dich auf account.apple.com an.
- Geh zu „Anmelden und Sicherheit“ und dann zu „App-spezifische Passwörter“.
- Klick auf „App-spezifisches Passwort erstellen“, gib einen Namen wie „Claude Kalender“ ein und folg den Schritten.
- Kopier das angezeigte Passwort direkt in einen Passwortmanager. Du brauchst es in Schritt 4.
Laut Apple-Support kannst du bis zu 25 solcher Passwörter gleichzeitig haben. Wenn du dein Haupt-Passwort änderst, widerruft Apple alle app-spezifischen Passwörter automatisch. Bei mir ist außerdem Advanced Data Protection an, die Kalender funktionieren trotzdem.
Schritt 2: LXC mit Docker anlegen
Gib dem Kalender-Server einen eigenen, unprivilegierten LXC mit Debian. So liegt das Apple-Passwort getrennt von allem anderen in deinem Homelab. Leg den Container in der Proxmox-Oberfläche an und gib ihm eine feste IP. Alternativ richtest du eine DHCP-Reservierung ein, also eine feste Zuordnung von IP-Adresse zu Gerät im Router. Dann schaltest du die Features nesting und keyctl ein, damit Docker darin läuft. Auf dem Proxmox-Host geht das so, <vmid> ist die ID deines Containers:
pct set <vmid> --features nesting=1,keyctl=1
pct reboot <vmid>
Im LXC installierst du dann Docker. Am schnellsten geht das mit Dockers offiziellem Installationsscript, alle anderen Wege stehen in der Docker-Doku für Debian:
apt update && apt install -y curl
curl -fsSL https://get.docker.com -o get-docker.sh
sh get-docker.sh
mkdir -p /opt/mcp-calendar && cd /opt/mcp-calendar
Alle weiteren Dateien für den Container legst du in /opt/mcp-calendar an.
Schritt 3: Dockerfile für caldav-mcp und supergateway
caldav-mcp spricht von sich aus nur stdio, also Ein- und Ausgabe im Terminal. Claude braucht aber eine HTTP-Adresse. Diese Lücke schließt supergateway: Es startet caldav-mcp und stellt ihn per Streamable HTTP (der aktuelle HTTP-Transport von MCP) unter /mcp bereit. Beide Pakete baust du in ein eigenes kleines Image. Leg die Datei Dockerfile an:
# CalDAV-only MCP (iCloud calendars + to-dos) exposed as Streamable HTTP via supergateway
FROM node:22-alpine
RUN npm install -g caldav-mcp@0.10.0 supergateway@4.1.0 && npm cache clean --force
USER node
EXPOSE 3000
CMD ["supergateway", "--stdio", "caldav-mcp", "--outputTransport", "streamableHttp", "--port", "3000", "--healthEndpoint", "/healthz"]
Die Versionen sind festgenagelt, damit ein Neubau nicht plötzlich eine andere Version zieht. Das sind die, die bei mir laufen. Für ein Update trägst du neue Versionsnummern im Dockerfile (und beim Auth-Proxy in der Compose-Datei) ein und baust mit docker compose up -d --build neu. Der Container läuft als eingeschränkter Benutzer node, und unter /healthz antwortet supergateway mit „ok“, das ist praktisch zum Testen.
Schritt 4: docker-compose.yml und .env-Dateien
Die Compose-Datei beschreibt zwei Container. caldav-mcp ist der eigentliche Kalender-Server. auth-proxy ist mcp-auth-proxy, eine Login-Schicht mit OAuth 2.1 (dem Anmeldeverfahren, das die Claude-App für Custom Connectors nutzt). Leg docker-compose.yml an:
# iCloud calendar MCP (/opt/mcp-calendar)
# caldav-mcp (CalDAV only) behind supergateway, plus an OAuth front door for claude.ai.
services:
caldav-mcp:
build: .
image: local/caldav-mcp:0.10.0
container_name: caldav-mcp
restart: unless-stopped
ports: ["0.0.0.0:3000:3000"]
env_file: .env
environment:
CALDAV_BASE_URL: https://caldav.icloud.com
TZ: Europe/Berlin
auth-proxy: # OAuth 2.1 front door for claude.ai custom connector
image: ghcr.io/sigbit/mcp-auth-proxy:v2.10.2
container_name: mcp-auth-proxy
restart: unless-stopped
depends_on: [caldav-mcp]
ports: ["0.0.0.0:8080:8080"]
env_file: auth.env
environment:
EXTERNAL_URL: https://cal.example.com
NO_AUTO_TLS: "true"
LISTEN: ":8080"
DATA_PATH: /data
TZ: Europe/Berlin
volumes:
- ./auth-data:/data
command: ["http://caldav-mcp:3000"]
Das 0.0.0.0: vor den Ports ist Absicht. Ohne diese Angabe veröffentlicht Docker die Ports auch über IPv6, und dort greift die IPv4-Firewall-Regel aus Schritt 5 nicht. https://caldav.icloud.com ist die übliche CalDAV-Adresse von iCloud. Apple dokumentiert sie nicht auf einer eigenen Seite, bei mir funktioniert sie so. TZ ist deine Zeitzone, ersetz Europe/Berlin also durch deine. Beim Auth-Proxy ist EXTERNAL_URL die öffentliche Adresse, NO_AUTO_TLS schaltet das eigene HTTPS ab, weil Caddy das übernimmt, und das letzte Argument http://caldav-mcp:3000 sagt dem Proxy, wohin er weiterleiten soll. Alle Optionen findest du in der Doku von mcp-auth-proxy.
In die Datei .env kommen deine Apple-ID und das app-spezifische Passwort:
CALDAV_USERNAME=deine-apple-id@example.com
CALDAV_PASSWORD=<app-spezifisches-passwort>
Die Datei auth.env enthält das Passwort für die Login-Seite, über die sich die Claude-App anmeldet. Diese Seite ist öffentlich erreichbar, und wer das Passwort kennt, kann seinen Claude mit deinem Kalender verbinden. Erzeug es deshalb zufällig:
openssl rand -base64 24
PASSWORD=<ausgabe-von-openssl>
Wählst du selbst ein Passwort, lass das Zeichen $ weg. Docker Compose liest es als Beginn einer Variable und verändert dein Passwort dabei. Mach beide Dateien nur für root lesbar und leg den Datenordner an:
chmod 600 .env auth.env
mkdir -p auth-data
Starte die Container noch nicht, erst kommt die Firewall. Die .env-Dateien gehören nie in Git, im Repo liegen deshalb nur die Vorlagen .env.example und auth.env.example. Nimm den Ordner auth-data in dein Backup auf, dort legt der Proxy seine Daten ab.
Wenn dir Claude Code reicht
Den Auth-Proxy brauchst du nur für die Claude-App. Willst du den Kalender nur in Claude Code nutzen, löschst du in der docker-compose.yml den kompletten Block auth-proxy, legst weder auth.env noch auth-data an, trägst in Schritt 5 bei --dports nur 3000 ein und lässt Schritt 8 weg. Dann bleibt alles in deinem LAN.
Schritt 5: Firewall-Unit, nur Caddy darf rein
Sobald die Container laufen, könnte jeder in deinem LAN direkt Port 3000 erreichen und an Caddy vorbei mit deinem Kalender reden. Das verhinderst du mit einer iptables-Regel (iptables ist die Firewall im Linux-Kernel). Ports, die Docker veröffentlicht, umgehen die normalen Regeln. Deine Regel gehört deshalb in die Chain DOCKER-USER. Eine Chain ist eine Liste von Regeln, die iptables der Reihe nach prüft, und DOCKER-USER ist die Liste, die Docker genau für eigene Regeln vorsieht.
Prüf zuerst, wie das Netzwerk-Interface heißt, über das der Traffic von außen kommt:
ip -br link
In einem LXC heißt es meist eth0, in einer VM oft ens18. Steht bei dir etwas anderes, ersetzt du eth0 in der Unit unten überall. Mit einem falschen Namen greift die Regel nicht oder Caddy bekommt später einen 502.
Damit die Regel jeden Neustart übersteht, packst du sie in eine systemd-Unit. Das ist eine kleine Konfigurationsdatei, mit der Linux beim Booten Dienste und Befehle startet. Leg /etc/systemd/system/mcp-firewall.service an:
[Unit]
Description=Only Caddy (192.168.1.10) may reach the MCP ports 3000 and 8080
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c "iptables -D DOCKER-USER -i eth0 -p tcp -m multiport --dports 3000,8080 ! -s 192.168.1.10 -j DROP 2>/dev/null; iptables -I DOCKER-USER -i eth0 -p tcp -m multiport --dports 3000,8080 ! -s 192.168.1.10 -j DROP"
ExecStop=/sbin/iptables -D DOCKER-USER -i eth0 -p tcp -m multiport --dports 3000,8080 ! -s 192.168.1.10 -j DROP
[Install]
WantedBy=multi-user.target
ExecStart löscht zuerst eine eventuell vorhandene alte Regel und setzt sie dann neu, so steht sie nie doppelt drin. Das -i eth0 sorgt dafür, dass die Regel nur Pakete von außen trifft. Ohne diese Angabe blockiert sie auch den Verkehr zwischen den beiden Containern, und der Auth-Proxy erreicht den Kalender-Server nicht mehr. Aktivier die Unit, prüf die Regel und starte erst danach die Container:
systemctl daemon-reload
systemctl enable --now mcp-firewall.service
iptables -L DOCKER-USER -n -v --line-numbers
cd /opt/mcp-calendar
docker compose up -d --build
In der Ausgabe von iptables -L muss deine DROP-Regel genau einmal stehen. Meldet iptables ein fehlendes Kernel-Modul, lädst du es auf dem Proxmox-Host nach. Wie das geht, steht im Sicherheits-Guide.
Schritt 6: Interner Eingang in Caddy mit Bearer Token
Diesen Schritt machst du auf dem Rechner, auf dem Caddy läuft. Ich gehe von Caddy aus dem Debian-Paket aus, das Caddyfile liegt dann unter /etc/caddy/Caddyfile. Für Claude Code reicht ein Eingang, der nur aus deinem LAN und über Tailscale erreichbar ist. Tailscale ist ein VPN, mit dem deine Geräte auch von unterwegs in dein Heimnetz kommen, seine Geräte haben Adressen aus dem Bereich 100.64.0.0/10.
Erzeug zuerst einen langen Zufallstoken. Ein Bearer Token ist ein geheimer Schlüssel, den der Client in jedem Request im Header Authorization mitschickt. Speicher ihn in deinem Passwortmanager, im Container brauchst du ihn nicht, nur Caddy und Claude Code kennen ihn:
openssl rand -hex 32
Im Caddyfile nutze ich einen Snippet, also einen wiederverwendbaren Baustein, den alle internen Seiten importieren. Er holt das Zertifikat per DNS-Challenge (Caddy beweist die Domain über einen DNS-Eintrag, deshalb klappt das auch für Hostnamen, die aus dem Internet nicht erreichbar sind) und blockt alles, was nicht aus privaten Netzen oder dem Tailscale-Bereich kommt. Das Beispiel nutzt das DNS-Modul für IONOS, für andere Provider gibt es eigene Module bei caddy-dns:
(int_only) {
tls {
dns ionos {env.IONOS_API_TOKEN}
}
@outside not remote_ip private_ranges 100.64.0.0/10
respond @outside 403
}
mcp-cal.int.example.com {
import int_only
@nokey not header Authorization "Bearer <token-aus-openssl>"
respond @nokey 401
reverse_proxy 192.168.1.21:3000
}
Fehlt der Token oder stimmt er nicht, antwortet Caddy mit 401. Das Caddy aus dem Debian-Paket kennt das DNS-Modul noch nicht. Du fügst es mit caddy add-package hinzu, das lädt eine neue Caddy-Datei mit dem Modul herunter und ersetzt die alte. Der Befehl ist laut Caddy-Doku noch als experimentell markiert. Für einen anderen Provider nimmst du sein Modul aus caddy-dns:
caddy add-package github.com/caddy-dns/ionos
caddy list-modules | grep dns.providers
Ein Update von Caddy per apt ersetzt die Datei wieder durch die Standard-Version. Führ caddy add-package danach einfach noch mal aus. Den API-Token deines DNS-Providers gibst du Caddy als Umgebungsvariable. systemctl edit caddy öffnet einen Editor für eine Zusatz-Konfiguration des Dienstes, dort trägst du ein:
[Service]
Environment=IONOS_API_TOKEN=<dein-ionos-api-token>
Der Name IONOS_API_TOKEN muss genau so heißen wie im Snippet bei {env.IONOS_API_TOKEN}. Der Hostname mcp-cal.int.example.com muss in deinem LAN auf die IP von Caddy zeigen, etwa über einen DNS-Eintrag in deinem Router oder Pi-hole. Weil jetzt ein Token im Caddyfile steht, setz die Rechte auf 640 mit Gruppe caddy und starte Caddy neu, damit er die neue Datei und die Variable lädt:
chown root:caddy /etc/caddy/Caddyfile
chmod 640 /etc/caddy/Caddyfile
systemctl restart caddy
Schritt 7: Kalender in Claude Code eintragen
Auf deinem Rechner fügst du den Server mit einem Befehl hinzu. --scope user heißt, dass er in allen deinen Projekten verfügbar ist, Claude Code speichert ihn dann in ~/.claude.json:
claude mcp add --transport http --scope user calendar \
https://mcp-cal.int.example.com/mcp \
--header "Authorization: Bearer <token-aus-openssl>"
Der Token steht danach im Klartext in ~/.claude.json und in der History deiner Shell. Behandle die Datei wie ein Passwort und lösch die Zeile aus der History, bei Bash zum Beispiel in ~/.bash_history. Der Befehl speichert nur die Konfiguration. Ob der Token passt, zeigt dir claude mcp list, dort sollte calendar als „Connected“ stehen. Danach kannst du in Claude Code einfach fragen: „Welche Kalender siehst du?“ oder „Was steht diese Woche in meinem Kalender?“
Schritt 8 (optional): Öffentlicher Eingang für die Claude-App
Laut Anthropic kommen die Requests der Claude-App von Anthropics Servern, egal ob du im Browser, am Desktop oder am Handy bist. Dein Kalender-Server muss dafür aus dem Internet erreichbar sein, und deshalb sichere ich diesen Eingang doppelt ab. Die erste Schicht ist der Login von mcp-auth-proxy aus Schritt 4. Als zweite Schicht lässt Caddy Anfragen auf /mcp nur aus dem IP-Bereich durch, den Anthropic für ausgehende Verbindungen nutzt. Die Login-Seiten bleiben öffentlich, weil du dich dort selbst im Browser anmeldest, dein Passwort schützt sie.
Dafür brauchst du eine echte öffentliche IPv4-Adresse. Viele Kabel- und Glasfaser-Anschlüsse laufen mit DS-Lite oder CGNAT, dann teilst du dir die IPv4 mit anderen Kunden und Portweiterleitungen kommen nie bei dir an. Ob das bei dir so ist, steht meist in deinem Router oder du fragst deinen Provider. In dem Fall ist ein kleiner VPS (ein gemieteter Server mit eigener IPv4) mit Caddy darauf die übliche Alternative, der die Anfragen zum Beispiel per Tailscale an dein Heimnetz weiterreicht. Hast du eine öffentliche IPv4, braucht cal.example.com einen DNS-Eintrag auf diese IP, und du leitest im Router die Ports 80 und 443 an Caddy weiter. Über diese Ports holt Caddy das Let’s-Encrypt-Zertifikat für den öffentlichen Namen.
cal.example.com {
# Public OAuth front door for the claude.ai connector. MCP traffic only from Anthropic outbound IPs;
# the OAuth login pages stay reachable (password-protected).
@mcp_not_anthropic {
path /mcp /mcp/*
not remote_ip 160.79.104.0/21
}
respond @mcp_not_anthropic "Forbidden" 403
reverse_proxy 192.168.1.21:8080
}
160.79.104.0/21 ist der ausgehende IPv4-Bereich, den Anthropic auf seiner Seite zu IP-Adressen nennt. Schau dort vor dem Übernehmen nach, ob er noch aktuell ist. Nach systemctl reload caddy trägst du den Connector in Claude ein. So kannst du in den Plänen Free, Pro und Max vorgehen, bei Team und Enterprise legt ein Owner den Connector in den Organisationseinstellungen an:
- Öffne in Claude „Customize“ und dann „Connectors“.
- Klick auf „+ Add“ und „Add custom connector“.
- Gib einen Namen wie „Apple Calendar“ ein und als URL
https://cal.example.com/mcp, dann „Continue“. - Claude zeigt die erkannten Auth-Einstellungen. Klick wieder „Continue“. Wähl bei Authentication „Sign in now“, lass bei OAuth client die erkannte Voreinstellung stehen und trag bei Request headers nichts ein.
- Klick auf „Add“. Es öffnet sich die Login-Seite von mcp-auth-proxy, dort gibst du das Passwort aus
auth.envein.
In einem Chat schaltest du den Connector über das „+“ unten links unter „Connectors“ ein. Ab dann geht es auch in der App am iPhone. Die Menünamen ändern sich ab und zu, im Zweifel gilt die Hilfeseite von Anthropic.
So prüfst du, ob es läuft
- Im LXC:
docker compose pszeigt beide Container als „running“, undcurl http://localhost:3000/healthzantwortet mit „ok“. - Von deinem Rechner ohne Token:
curl -i https://mcp-cal.int.example.com/mcpliefert 401. - Mit Token:
curl -i -H "Authorization: Bearer <token>" https://mcp-cal.int.example.com/mcpdarf kein 401 mehr liefern. Ein anderer Fehlercode ist hier okay, curl spricht ja kein MCP. - Direkt auf den Container von einem anderen Rechner im LAN:
curl -m 5 http://192.168.1.21:3000/healthzläuft in einen Timeout. Dann greift die Firewall. - In Claude Code:
claude mcp listzeigt „Connected“. Bei „Failed to connect“ zeigtclaude mcp get calendarden Grund. - Nur mit öffentlichem Eingang:
curl -s -o /dev/null -w "%{http_code}\n" https://cal.example.com/.well-known/oauth-authorization-serverliefert 200, die OAuth-Seiten sind also erreichbar. - Nur mit öffentlichem Eingang, aus deinem Heimnetz:
curl -i https://cal.example.com/mcpliefert 403, weil du nicht aus Anthropics IP-Bereich kommst. - Sobald Port 443 weitergeleitet ist, testest du den internen Eingang von außen. Schalte am Laptop über den Hotspot deines Handys ins Mobilfunknetz und ruf ihn über deine öffentliche IP auf:
curl -i --resolve mcp-cal.int.example.com:443:<deine-öffentliche-ip> https://mcp-cal.int.example.com/mcp. Hier muss 403 kommen. - Lass Claude einen Termin für morgen anlegen und schau auf dem iPhone nach, ob er auftaucht.
Häufige Probleme
dav-mcp stürzt bei iCloud ab
Mein erster Versuch war der Server dav-mcp, der Kalender und Kontakte in einem kann. Er meldet sich immer auch per CardDAV (dem Protokoll für Kontakte) an, und zwar unter derselben URL wie für den Kalender. Bei iCloud liegen die Kontakte aber auf einem anderen Server, also ist er jedes Mal daran gescheitert. caldav-mcp beschränkt sich auf CalDAV, damit läuft es bei mir stabil.
Anmeldung bei iCloud schlägt fehl
Schau mit docker compose logs caldav-mcp in die Logs. Meist steckt eins davon dahinter: In CALDAV_PASSWORD steht dein normales Apple-Passwort statt des app-spezifischen, oder du hast dein Apple-Passwort inzwischen geändert und damit alle app-spezifischen Passwörter widerrufen. Erstell dann ein neues, trag es in die .env ein und starte mit docker compose up -d neu. CALDAV_USERNAME ist die E-Mail-Adresse deiner Apple-ID.
Und was ist mit To-dos?
caldav-mcp kann auch CalDAV-Aufgaben anlegen (create-todo). Seit Apple die Erinnerungen mit iOS 13 auf ein neues Format umgestellt hat, tauchen diese Aufgaben aber nicht in der Erinnerungen-App auf, und deine bestehenden Erinnerungen sind über CalDAV nicht erreichbar. Ich nutze den Server deshalb nur für den Kalender.
Caddy meldet 502
Dann kommt Caddy nicht bis zum Container. Prüf, ob in der Firewall-Unit die richtige IP von Caddy steht und ob der Interface-Name hinter -i zu der Ausgabe von ip -br link passt.
Caddy startet nach dem Neustart nicht
Mit journalctl -u caddy -n 50 siehst du den Grund. Meldet Caddy ein unbekanntes Modul dns.providers.ionos, fehlt das DNS-Modul, oft nach einem apt-Update. Führ dann caddy add-package erneut aus. Setzt du das Caddyfile auf 600, kann Caddy es nicht mehr lesen, weil es als eigener Benutzer läuft. Ist mir passiert. Nimm 640 mit Gruppe caddy wie in Schritt 6.
Der Connector in der Claude-App verbindet nicht
Prüf zuerst, ob die URL auf /mcp endet. Danach, ob der IP-Bereich im Caddy-Block noch zu Anthropics Seite passt, sonst blockt Caddy die Anfragen mit 403. Kommt die Login-Seite gar nicht, stimmt meist EXTERNAL_URL nicht mit der Adresse überein, die du in Claude eingetragen hast, oder dein Anschluss hat keine eigene öffentliche IPv4.
Was du zur Sicherheit wissen solltest
- Laut Apple kann eine App mit einem app-spezifischen Passwort auf Informationen wie E-Mails, Kontakte und Kalender in deiner iCloud zugreifen. Wer die
.envin die Finger bekommt, kommt also an deine iCloud-Mails, Kontakte und Kalender. Deshalb der eigene LXC,chmod 600und die Firewall. - Du kannst das Passwort jederzeit auf account.apple.com unter „App-spezifische Passwörter“ widerrufen. Der Server ist dann sofort abgemeldet, der Rest deiner Apple-ID bleibt unberührt.
- Claude kann über den Server auch Termine löschen (
delete-event). Lies bei Schreibaktionen kurz mit, was Claude vorhat, bevor du zustimmst. - Das Login-Passwort in
auth.envschützt eine öffentliche Seite. Nutz es nirgends sonst. - Öffentliche Hostnamen werden schnell gefunden. Bei mir standen kurz nach dem Ausstellen der Zertifikate die ersten Scanner in den Logs. Mehr dazu und zu CrowdSec im Sicherheits-Guide für MCP-Connectors.
Fazit
Mit zwei Containern, einer Firewall-Regel und zwei Caddy-Blöcken hast du deinen iCloud-Kalender in Claude Code und in der Claude-App. Ich nutze das jeden Tag, um Termine nachzuschauen, einzutragen und zu verschieben, ein Satz an Claude reicht dafür. Wenn dir Claude Code genügt, nimmst du den kürzeren Weg aus Schritt 4 ohne Auth-Proxy. Die Dateien aus diesem Guide liegen im Repo mapplebox/homelab-mcp-stack in den Ordnern calendar/ und common/.
Welche Dienste hast du schon an Claude angebunden? Schreib es in die Kommentare.
Hat dir der Guide geholfen? Dann spendier mir gern einen Kaffee auf Ko-fi. Damit bleibt MappleBox werbefrei.