@prontosite/mcp
v0.10.1
Published
MCP-Server für ProntoSite – Website-Status, Export, Deploy und Veröffentlichen direkt aus einem KI-Assistenten (Claude Desktop). Dünner Client um die ProntoSite Deploy-API.
Maintainers
Readme
ProntoSite MCP-Server
Deploy, Export und Status deiner ProntoSite-Website direkt aus einem KI-Assistenten (z. B. Claude Desktop) – ohne Terminal. Der Server ist ein dünner Client um die bestehende ProntoSite Deploy-API; er hat keine eigene Logik und keinen Zustand. Die HTTP-API (curl/Terminal, Skripte) bleibt der primäre Weg – dies ist nur ein zusätzlicher Client obendrauf.
Voraussetzungen
- Node.js ≥ 18
- Ein ProntoSite API-Token (
psk_…) – im Dashboard unter Konto → API-Zugang (oder vom Betreuer erzeugt).
Einrichtung (empfohlen: npx)
Kein Klonen, kein Node-Projekt nötig – Claude Desktop startet den Server per npx:
// claude_desktop_config.json → "mcpServers"
{
"prontosite": {
"command": "npx",
"args": ["-y", "@prontosite/mcp"],
"env": { "PRONTOSITE_TOKEN": "psk_…", "PRONTOSITE_SITE": "meine-firma" }
}
}(Repo-Variante ohne npx: "command": "node", "args": ["/pfad/promptsite/mcp/prontosite/index.mjs"]. Vorher
cd mcp/prontosite && npm install.)
Konfiguration (Token nie im Chat)
Umgebungsvariablen oder ~/.prontosite.json. Zwei Formen:
Wichtig zum Site-Bezeichner: Nutze die stabile Site-ID (s-…, steht im Dashboard) oder "active" –
nicht den Slug. Der Slug/die Adresse kann sich ändern (eigene Domain, Umbenennung); die Site-ID nie.
Für ein Konto mit nur einer Website ist "active" der robusteste Wert.
Einzelne Website (ein Kunde):
{ "token": "psk_…", "site": "active", "host": "app.prontosite.io" }Env-Äquivalent: PRONTOSITE_TOKEN, PRONTOSITE_SITE, PRONTOSITE_HOST.
Mehrere Websites (Betreuer/Agentur) – zwei gleichwertige Wege: Bis ~5 Kunden am einfachsten je Kunde ein
eigener mcpServers-Eintrag (Token in env, terminalfrei) – siehe „Einrichtung (empfohlen: npx)" oben, den
Block je Kunde mit eigenem Server-Namen wiederholen. Ab ~5 wird die folgende sites-Map übersichtlicher (ein
Server, alle Kunden in einer Datei; sites_list zeigt alle auf einmal). Die Map – Schlüssel = frei wählbares
Label (das du im Chat sagst), site = stabile Site-ID, ein Token je Website:
{
"host": "app.prontosite.io",
"defaultSite": "mas-monti",
"sites": {
"mas-monti": { "site": "s-mth…", "token": "psk_…" },
"wallboxservice24": { "site": "s-msz…", "token": "psk_…" }
}
}Jedes Tool nimmt einen optionalen Parameter site (Label oder Site-ID). Ohne Angabe gilt defaultSite
bzw. die Einzel-Site. So verwaltest du mit einem Claude Desktop beliebig viele Kundenseiten – und die
Zuordnung bricht nicht, wenn ein Kunde seine Domain/Adresse ändert.
site– Site-ID (s-…, empfohlen) oder"active"; ein Slug wird zwar noch akzeptiert, kann aber veralten.host– Standardapp.prontosite.io.
Erst-Import (neue Website): In der Einzel-Config site:"new". In einer sites-Map ist "new" ein
reserviertes Schlüsselwort (kein Profil-Label) – adressiere den Erst-Import als site:"<label>:new"
(z. B. site:"rtk-kanzlei:new"); ProntoSite legt dann mit dem Token dieses Labels eine neue Website an. Ein
frisches Konto-Profil trägt zunächst "site":"active"; der erste site_deploy darauf legt die Website
automatisch an (solange das Konto noch keine hat). (Hinweis: "new" ohne Label ist in der Map mehrdeutig –
der Server nennt dann das richtige <label>:new.)
Datei anlegen/erweitern: Existiert ~/.prontosite.json noch nicht, lege sie mit obigem Inhalt an
(z. B. cat > ~/.prontosite.json <<'JSON' … JSON – ⚠ überschreibt eine vorhandene Datei!). Ist sie schon
da, NICHT überschreiben: die Datei öffnen und unter "sites" einen weiteren Eintrag ergänzen (vorher
sichern: cp ~/.prontosite.json ~/.prontosite.json.bak).
Tools
| Tool | Wirkung |
|------|---------|
| sites_list | Alle erreichbaren Websites (Slug, Plan, letzte Änderung, Publish-Bedarf). Lesend. |
| account_create({ name, email?, plan?, note?, override? }) | Nur mit Betreuer-Token. Legt ein neues Kundenkonto an (Dashboard-Weg „Kunde anlegen"). Mit email → eingeladenes Login-Konto (Invite-Mail), ohne → verwaltetes Konto. Partner/Agentur: Konto wird dem Betreuer zugeordnet (Agentur-Kunden automatisch agentur-kunde). Antwort nennt die neue Konto-ID (k-…) → danach site_deploy({ site: "<k-id>:new", zipPath }). Namens-/E-Mail-Dublette → Warnung mit vorhandener k-ID (override:true erzwingt die Namensdublette). Schreibend. |
| site_status({ site? }) | Plan, Slug, Live-URL, Publish-Bedarf. Lesend. |
| site_export({ site?, which, outDir }) | ZIP (published|draft|original) lokal speichern. Lesend. |
| site_deploy({ site?, zipPath, publish?, resetOverlay?, legal?, company?, siteOverride? }) | ZIP importieren, optional live; optional Firmendaten im selben Aufruf setzen. Beim lokalen Bauen Bausteine im HTML per data-ps markieren (formular:kontakt, impressum/datenschutz, link-impressum/link-datenschutz) → Marker-Syntax. Schreibend. |
| site_publish({ site? }) | Aktuellen Stand erneut veröffentlichen. Schreibend. |
| site_company_get({ site? }) | Firmendaten (Impressum/Footer) lesen. Lesend. |
| site_company_set({ site?, company, siteOverride? }) | Firmendaten setzen/ergänzen (Teil-Update); füllen Impressum/Datenschutz beim Deploy. Schreibend. |
| site_legal_options({ site?, impressum?, datenschutz? }) | Anzeige-Optionen der Rechtstexte (showTitle, showDate, draftNotice); ohne Rolle nur lesen. Rechts-Seiten/-Links im Template per data-ps="impressum"/"datenschutz" bzw. link-impressum/link-datenschutz markieren → Marker-Syntax. Schreibend. |
| site_domain_status({ site?, check? }) | Kundendomain-Status (verbunden/kanonisch/Zert-bis) + offene Jobs; mit check nur Live-DNS-Prüfung. Lesend. |
| site_domain_connect({ site?, domain, canonical?, action? }) | Eigene Domain verbinden (nginx + HTTPS automatisch, www/apex) oder trennen; DNS muss auf den Server zeigen; ab Starter-Plan. Schreibend. |
| site_embeds({ site? }) | Externe Einbettungen der Website: Host, Seite(n), aktuelle Einwilligungs-Kategorie (gated = Zwei-Klick | notwendig). Lesend. |
| site_embed_consent({ site?, host, page?, category, confirmed }) | Einbettung als notwendig (§ 25 Abs. 2 Nr. 2 TDDDG, Eigenverantwortung) oder wieder gated einstufen; notwendig nur mit confirmed:true (sonst 400 mit Verantwortungs-Text). Optional seiten-gebunden. Datenschutz/Cookie-Richtlinie passen sich beim nächsten Publish an. Schreibend. |
| site_widgets({ site? }) | Katalog der verwalteten Widgets: name, aktiv, optionen, schema (consent, a11y, notice/Pop-Ups, google-reviews, ps-impressum, ps-datenschutz). In jedem Plan verfügbar. Lesend. |
| site_widget_set({ site?, widget, aktiv?, optionen? }) | Widget aktivieren/deaktivieren und Optionen setzen – gleicher Schema-Sanitizer wie das Dashboard; Listen-Widgets (notice) via optionen.items[]. Greift beim nächsten Publish. Siehe Widget-Katalog. Schreibend. |
site_deploy und site_publish sind schreibende Aktionen (verändern die Live-Website). Die
Tool-Beschreibungen weisen den Assistenten an, vorher rückzufragen. Jeder Aufruf wird serverseitig auditiert.
Pflicht-Marker beim lokalen Bauen
Baust du das Template selbst, gehören drei Dinge dazu (volle Spec: Marker-Syntax):
- Rechtsseiten:
impressum/index.htmlunddatenschutz/index.htmltragen IMMER<div data-ps="impressum">bzw.<div data-ps="datenschutz">als Inhaltsbereich und eine eigene<h1>(kein handgeschriebener Rechtstext). Danachsite_legal_options({ impressum:{ showTitle:false } })setzen (eigene H1 → keine doppelte Überschrift). Beim Erst-Import mit?markers=auto/der Rechts-Automatik setzt ProntoSiteshowTitle:falseautomatisch, sobald die Rechtsseite eine eigene H1 hat. - Footer: IMMER alle vier Marker
link-impressum,link-datenschutz,cookie-einstellungen,cookie-richtlinie– sonst hängt das Consent-Widget einen ungestylten Block an den Seitenfuß (mehrsprachig je Sprach-Footer dieselben Marker, Linktext lokalisiert). - Mobile-Menü: rendert als Drawer (von rechts); der Toggle braucht
aria-controlsauf das Menü.
Arbeitsweise: ein Chat je Kunde
Für saubere Trennung: pro Kundenwebsite einen eigenen Claude-Chat. So bezieht sich der ganze Verlauf auf
genau diese Website, und Verwechslungen sind ausgeschlossen. sites_list zeigt alle Slugs – so kannst du im
Chat einfach sagen „deploye mas-monti", ohne Slugs auswendig zu kennen. (Alternativ ein Chat für alles und die
Website je Aufruf über site wählen – die getrennten Chats sind aber übersichtlicher.)
Sicherheit
- Tokens liegen nur lokal (Config/Env), werden nie geloggt und nie in Antworten zurückgegeben.
- Behandle Tokens wie Passwörter. Ein durchgesickertes Token erlaubt Deploy/Publish der betroffenen Website; im Dashboard jederzeit widerrufbar, dann ein neues erzeugen.
- Es gelten dieselben serverseitigen Grenzen wie bei der HTTP-API (Plan/Operator-Gate, Rate-Limit, Audit-Log, 100 MB ZIP, kein Server-Code).
Betreuer-Token (ein Token für ALLE betreuten Kunden)
Für Agenturen/Partner: ein Betreuer-Token deckt alle betreuten Kunden ab – ohne sites-Map. Erzeugt im
Admin/Partner-Bereich (Panel „Betreuer-Token"). Config dann einfach:
{ "token": "psk_…", "host": "app.prontosite.io" } // KEIN sites, KEIN sitesites_list liefert automatisch alle betreuten Kunden-Sites (Neukunde erscheint, sobald er dem Partner
zugeordnet ist – keine Config-Pflege). Website je Aufruf per Slug oder stabiler Site-ID angeben (kein
"active" – es sind mehrere Konten). Erst-Import: site_deploy({ site: "new", customer: "k-…" }).
Neuen Kunden anlegen (es gibt noch KEIN Konto): zuerst account_create({ name, email? }) – das Konto wird
dem Betreuer zugeordnet (Agentur-Kunden automatisch agentur-kunde). Die Antwort nennt die Konto-ID (k-…);
danach die erste Website per site_deploy({ site: "<k-id>:new", zipPath }) importieren. Also nicht site=new
raten, solange die Konto-ID unbekannt ist – erst account_create.
Sicherheit: der Zugriff wird bei JEDEM Aufruf serverseitig geprüft (assertCanManage – nur betreute Konten,
Rollenentzug wirkt sofort); nur Deploy/Status/Export/Veröffentlichen, kein Konto-/Zahlungszugriff; optionaler
Ablauf (Default 90 Tage) und optionale IP-Bindung; Widerruf sperrt alle betreuten Sites auf einmal.
Alternative bleibt die sites-Map oben (kleinere Angriffsfläche je Token, aber Pflege je Kunde).
