@prontosite/mcp 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +1 -0
- package/api.mjs +15 -5
- package/package.json +1 -1
- package/tools.mjs +31 -22
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,20 @@
|
|
|
3
3
|
Alle nennenswerten Änderungen am MCP-Server für ProntoSite. Der Server ist ein dünner Client um die
|
|
4
4
|
ProntoSite Deploy-API; die eigentliche Logik lebt serverseitig.
|
|
5
5
|
|
|
6
|
+
## 0.18.0 – 2026-11-06
|
|
7
|
+
|
|
8
|
+
- Neu: `site_badge_set` (`aktiv`, `variant` = auto | light | dark | mono) blendet das Badge „Made with ProntoSite" für die ganze Website aus oder ein und
|
|
9
|
+
setzt die Variante, auf allen Tarifen. Normale Entwurfsänderung mit einem Rückgängig-Schritt, Auto-Publish-Regeln gelten. Ohne eingebautes Badge liefert die
|
|
10
|
+
Antwort `warnung` und `snippet`.
|
|
11
|
+
- `site_status`: neues Feld `badge` (`aktiv`, `variant`, `eingebaut`, `seiten`, `sichtbar`). Instructions 2d: Ausblenden nur über `site_badge_set`, nie per CSS oder HTML.
|
|
12
|
+
|
|
13
|
+
## 0.17.0 – 2026-11-05
|
|
14
|
+
|
|
15
|
+
- JS-Freigabe-Pflicht für Änderungen entfällt (Entscheidung 05.11.): Auf Websites mit JavaScript-Freigabe wirkt jede JS-Änderung sofort wie HTML/CSS,
|
|
16
|
+
auch Umbenennen. `jsReview` in Antworten und `site_status` entfällt, neu ist `jsExtern` bei neuer externer Adresse im Skript
|
|
17
|
+
(„Externe Einbindung erkannt, Datenschutzerklärung prüfen").
|
|
18
|
+
- `site_js_review` zeigt nur noch den Verlauf (lesend, Betreuer-Token); Parameter `path`, `action`, `note` entfallen. Instructions 2e angepasst.
|
|
19
|
+
|
|
6
20
|
## 0.16.0 – 2026-11-03
|
|
7
21
|
|
|
8
22
|
- Formular-Anfragen per MCP (Scope `anfragen` bzw. `anfragen:schreiben`, beim Verbinden ein eigener, nie vorausgewählter Punkt;
|
package/README.md
CHANGED
|
@@ -101,6 +101,7 @@ sichern: `cp ~/.prontosite.json ~/.prontosite.json.bak`).
|
|
|
101
101
|
| `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.** |
|
|
102
102
|
| `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.** |
|
|
103
103
|
| `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](https://prontosite.io/docs/widget-katalog). **Schreibend.** |
|
|
104
|
+
| `site_badge_set({ site?, aktiv?, variant? })` | Badge „Made with ProntoSite" für die ganze Website aus-/einblenden und Variante setzen (`auto` \| `light` \| `dark` \| `mono`), auf allen Tarifen. Stand steht in `site_status.badge`. |
|
|
104
105
|
|
|
105
106
|
`site_deploy` und `site_publish` sind **schreibende** Aktionen (verändern die Live-Website). Die
|
|
106
107
|
Tool-Beschreibungen weisen den Assistenten an, vorher rückzufragen. Jeder Aufruf wird serverseitig auditiert.
|
package/api.mjs
CHANGED
|
@@ -303,6 +303,18 @@ export async function apiWidgetSet(cfg, { site, widget, aktiv, optionen } = {},
|
|
|
303
303
|
return asJson(res);
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
/** PUT /api/badge/<site> {aktiv?, variant?} – Badge ein-/ausblenden, Variante setzen (dieselbe Op wie das Dashboard). */
|
|
307
|
+
export async function apiBadgeSet(cfg, { site, aktiv, variant } = {}, fetchImpl = fetch) {
|
|
308
|
+
if (aktiv === undefined && variant === undefined) throw new Error("aktiv oder variant erwartet.");
|
|
309
|
+
const { token, slug } = resolveTarget(cfg, site);
|
|
310
|
+
const body = {};
|
|
311
|
+
if (aktiv !== undefined) body.aktiv = !!aktiv;
|
|
312
|
+
if (variant !== undefined) body.variant = variant;
|
|
313
|
+
const res = await fetchImpl(`${baseUrl(cfg)}/badge/${encodeURIComponent(slug)}`, {
|
|
314
|
+
method: "PUT", headers: { ...authHeaders(token, cfg), "content-type": "application/json" }, body: JSON.stringify(body) });
|
|
315
|
+
return asJson(res);
|
|
316
|
+
}
|
|
317
|
+
|
|
306
318
|
/** GET/PUT /api/legal-options/<site> – Anzeige-Optionen der Rechtstext-Widgets. Ohne impressum/datenschutz
|
|
307
319
|
* nur LESEN; sonst Teil-Update (nur echte Booleans wirken). */
|
|
308
320
|
export async function apiLegalOptions(cfg, { site, impressum, datenschutz } = {}, fetchImpl = fetch) {
|
|
@@ -600,12 +612,10 @@ export async function apiLock(cfg, { site, action = null, note = null } = {}, fe
|
|
|
600
612
|
return asJsonOr409(await fetchImpl(url, { method: "POST", headers: { ...authHeaders(token, cfg), "content-type": "application/json" }, body: JSON.stringify({ action, note }) }));
|
|
601
613
|
}
|
|
602
614
|
|
|
603
|
-
/** GET
|
|
604
|
-
export async function apiJsReview(cfg, { site
|
|
615
|
+
/** GET /api/js-review/<site> – Verlauf der JS-Änderungen (nur lesen, nur Betreuer-Token). */
|
|
616
|
+
export async function apiJsReview(cfg, { site } = {}, fetchImpl = fetch) {
|
|
605
617
|
const { token, slug } = resolveTarget(cfg, site);
|
|
606
|
-
|
|
607
|
-
if (!action) return asJson(await fetchImpl(url, { headers: authHeaders(token, cfg) }));
|
|
608
|
-
return asJson(await fetchImpl(url, { method: "POST", headers: { ...authHeaders(token, cfg), "content-type": "application/json" }, body: JSON.stringify({ path: rel, action, note }) }));
|
|
618
|
+
return asJson(await fetchImpl(`${baseUrl(cfg)}/js-review/${encodeURIComponent(slug)}`, { headers: authHeaders(token, cfg) }));
|
|
609
619
|
}
|
|
610
620
|
|
|
611
621
|
/** GET /api/inbox/<site> – Formular-Anfragen: Liste (Filter), eine Anfrage (id) oder Statistik (stats). */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prontosite/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/tools.mjs
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* site_domain_connect nur mit Betreuer-Token (Entscheidung 9a).
|
|
10
10
|
* `z` wird vom Aufrufer übergeben (dieselbe zod-Instanz wie sein MCP-SDK).
|
|
11
11
|
*/
|
|
12
|
-
import { apiEditText, apiEditHtml, apiPageTexts, apiPageTextsSet, apiPageCopy, apiMediaUploadBegin, apiMediaUploadFile, apiMediaCommit, apiMediaList, apiImageSet, apiUndo, apiMediaDelete, apiMediaRestore, apiFormsGet, apiFormsSet, apiMediaSearch, apiMediaImport, apiPreviewScreenshot, apiStatus, apiExport, apiExportFetch, apiDeploy, apiPublish, sitesList, apiAccountCreate, apiCompanyGet, apiCompanySet, apiLegalOptions, apiDomainStatus, apiDomainConnect, apiEmbeds, apiEmbedConsent, apiWidgets, apiWidgetSet, apiFiles, apiFileGet, apiFilePut, apiFileDelete, apiFileRename, apiLock, apiJsReview, apiInboxGet, apiInboxPost } from "./api.mjs";
|
|
12
|
+
import { apiEditText, apiEditHtml, apiPageTexts, apiPageTextsSet, apiPageCopy, apiMediaUploadBegin, apiMediaUploadFile, apiMediaCommit, apiMediaList, apiImageSet, apiUndo, apiMediaDelete, apiMediaRestore, apiFormsGet, apiFormsSet, apiMediaSearch, apiMediaImport, apiPreviewScreenshot, apiStatus, apiExport, apiExportFetch, apiDeploy, apiPublish, sitesList, apiAccountCreate, apiCompanyGet, apiCompanySet, apiLegalOptions, apiDomainStatus, apiDomainConnect, apiEmbeds, apiEmbedConsent, apiWidgets, apiWidgetSet, apiBadgeSet, apiFiles, apiFileGet, apiFilePut, apiFileDelete, apiFileRename, apiLock, apiJsReview, apiInboxGet, apiInboxPost } from "./api.mjs";
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Arbeitsweise (MCP-`instructions` beim Initialize – lokal UND /mcp): Weg B ist der Standard (Nick 19.10.).
|
|
@@ -29,18 +29,19 @@ const instructionLines = mode => [
|
|
|
29
29
|
"2a. Für Text-, Link- und Kontaktdaten-Änderungen (Telefonnummer, E-Mail, Adresse, Öffnungszeiten) IMMER site_edit_text mit "
|
|
30
30
|
+ "scope:\"all\" (bei Bedarf region:\"footer\"/\"header\") – EIN Aufruf für alle Seiten, inkl. tel:/mailto:-Links. NIE Seite für Seite per "
|
|
31
31
|
+ "site_file_put. Meldet die Antwort company, zusätzlich site_company_set für die Firmendaten (Impressum/Datenschutz/Kontakt).",
|
|
32
|
-
"2e. Preise, Texte und Zahlen
|
|
33
|
-
+ "nur in Texten/Zahlen/Kommentaren, nie im Code
|
|
34
|
-
+ "
|
|
35
|
-
+ "
|
|
36
|
-
+ "
|
|
32
|
+
"2e. Skriptdateien (.js): Preise, Texte und Zahlen darin (z. B. Preisrechner) ändert site_edit_text mit scope:\"all\" mit – ersetzt wird dort "
|
|
33
|
+
+ "nur in Texten/Zahlen/Kommentaren, nie im Code; für Code-Änderungen site_file_get/site_file_put. Bei JavaScript-Freigabe der Website wirkt "
|
|
34
|
+
+ "jede Änderung sofort wie HTML/CSS, es gibt keine Prüfung und keine Wartezeit. Meldet eine Antwort jsExtern (\"Externe Einbindung erkannt, "
|
|
35
|
+
+ "Datenschutzerklärung prüfen\"), dem Nutzer das sagen und die genannten Adressen nennen: die Änderung ist gespeichert, die Datenschutzerklärung "
|
|
36
|
+
+ "muss er selbst prüfen. Ohne JavaScript-Freigabe der Website kommt 403: dem Nutzer sagen, dass der Betreuer JavaScript für die Website einmalig freigeben muss.",
|
|
37
37
|
"2c. Für Markup über alle Seiten (z. B. Footer-HTML) site_edit_html mit scope:\"all\" (ggf. region:\"footer\"), nie Seite für Seite per site_file_put. "
|
|
38
38
|
+ "Entwurfs-Limit je Website: 300 Änderungen je Stunde, davon 30 direkt hintereinander (Kunden und Betreuer gleich) – dieselbe Änderung auf vielen Seiten ist EIN Aufruf (site_edit_text scope:\"all\" bzw. site_edit_html). Bei 429 (rateLimited) NICHT aufgeben: retryAfter Sekunden warten, dann weitermachen; bisherige Änderungen bleiben gespeichert.",
|
|
39
39
|
"2d. Badge „Made with ProntoSite\" NUR als dieses Snippet einbauen (Footer, letzte Zeile, bündig mit dem Copyright), nie manuell stylen: "
|
|
40
40
|
+ "<a data-ps=\"badge\" data-ps-variant=\"auto\" href=\"https://prontosite.io/?ref=badge&site=<slug>\" rel=\"noopener noreferrer\">Made with ProntoSite</a> "
|
|
41
41
|
+ "(Variante auto | light für dunkle Footer | dark für helle Flächen | mono). Der Server ersetzt beim Ausliefern alles außer der Variante "
|
|
42
42
|
+ "(Schrift, Größe, Farbe, Icon). Ein vorhandenes Badge nie im HTML ändern, nachbauen oder entfernen (site_edit_text/site_edit_html/"
|
|
43
|
-
+ "site_file_put lehnen das ab; erlaubt ist nur das Wiederherstellen des Original-Markers)."
|
|
43
|
+
+ "site_file_put lehnen das ab; erlaubt ist nur das Wiederherstellen des Original-Markers). Badge ausblenden nur über site_badge_set, nie per CSS oder HTML; "
|
|
44
|
+
+ "dasselbe Tool ändert die Variante für die ganze Website. Stand: badge in site_status.",
|
|
44
45
|
"2b. Für Übersetzungen und Textüberarbeitung: site_page_texts → Texte übersetzen/überarbeiten → site_page_texts_set, JE SEITE ein Aufruf "
|
|
45
46
|
+ "(neue Sprachfassung vorher mit site_page_copy, z. B. index.html → en/index.html). NIE HTML über site_file_put umschreiben. "
|
|
46
47
|
+ "Rechtstext-Seiten (Impressum/Datenschutz) sind ausgenommen.",
|
|
@@ -82,7 +83,7 @@ export const SERVER_INSTRUCTIONS = instructionsFor("remote");
|
|
|
82
83
|
// Tool-Annotationen (MCP ToolAnnotations): ChatGPT & Co. fragen sonst bei JEDEM Aufruf nach. readOnly = ändert nichts;
|
|
83
84
|
// destructive = live/kundenwirksam, ersetzt Bestand oder nimmt zurück (Bestätigung sinnvoll). Entwurfs-Änderungen sind
|
|
84
85
|
// rückgängig machbar und daher nicht destruktiv. openWorld = wirkt nach außen (öffentliche Website/DNS).
|
|
85
|
-
const READ_ONLY = new Set(["sites_list", "site_status", "site_forms_get", "media_search", "site_page_texts", "site_media_list", "site_preview_screenshot", "site_company_get",
|
|
86
|
+
const READ_ONLY = new Set(["site_js_review", "sites_list", "site_status", "site_forms_get", "media_search", "site_page_texts", "site_media_list", "site_preview_screenshot", "site_company_get",
|
|
86
87
|
"site_domain_status", "site_embeds", "site_widgets", "site_files", "site_file_get", "site_inbox_list", "site_inbox_get", "site_inbox_stats"]);
|
|
87
88
|
const DESTRUCTIVE = new Set(["site_publish", "site_deploy", "deploy_commit", "site_file_delete", "site_media_delete", "site_inbox_delete", "site_undo", "site_redo", "site_domain_connect"]);
|
|
88
89
|
const OPEN_WORLD = new Set(["site_publish", "site_deploy", "deploy_commit", "site_domain_connect", "media_search", "media_import"]);
|
|
@@ -203,7 +204,7 @@ export function registerTools(server0, { z, cfg, mode = "local", remote = null }
|
|
|
203
204
|
+ "scope:\"all\" = alle Fundstellen auf allen Seiten sofort ersetzen (für Kontaktdaten im Kopf-/Fußbereich: plus region:\"footer\" bzw. "
|
|
204
205
|
+ "\"header\"); ohne scope ändert der Server bei mehr als einer Fundstelle NICHTS und liefert nur die Liste (oder pages:[…]). "
|
|
205
206
|
+ "Mit scope:\"all\" auch in Skriptdateien (.js, z. B. Preisrechner) – dort nur in Texten/Zahlen/Kommentaren (skripte = Fundstellen); "
|
|
206
|
-
+ "
|
|
207
|
+
+ "jsExtern = neue externe Adresse im Skript (dem Nutzer sagen: Datenschutzerklärung prüfen). "
|
|
207
208
|
+ "Telefonnummern werden unabhängig von Schreibweise gefunden (Leerzeichen, „/“, „-“, Klammern, geschütztes Leerzeichen); ersetzt "
|
|
208
209
|
+ "wird wörtlich durch `replace`. Antwort: treffer = getrennt nach text/linktext/linkziel/attribut; linktextNichtGefunden = tel:-Ziel "
|
|
209
210
|
+ "geändert, sichtbarer Linktext aber nicht (dem Nutzer sagen). pages = je Seite gefunden/geändert. Rechtstexte und geschützte Bereiche bleiben unberührt (skipped); steht der Wert in "
|
|
@@ -628,19 +629,14 @@ export function registerTools(server0, { z, cfg, mode = "local", remote = null }
|
|
|
628
629
|
}
|
|
629
630
|
);
|
|
630
631
|
}
|
|
631
|
-
// JS-
|
|
632
|
+
// JS-Verlauf lesen (nur Betreuer-Token; der Server prüft die Rolle zusätzlich).
|
|
632
633
|
if (mode === "local" || remote?.isManager) {
|
|
633
634
|
server.tool(
|
|
634
635
|
"site_js_review",
|
|
635
|
-
"NUR BETREUER-TOKEN:
|
|
636
|
-
+ "
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
{ site: z.string().optional().describe(SITE_DESC),
|
|
640
|
-
path: z.string().optional().describe("Datei (z. B. 'js/rechner.js') – für approve/reject Pflicht."),
|
|
641
|
-
action: z.enum(["approve", "reject"]).optional().describe("Leer = nur ansehen."),
|
|
642
|
-
note: z.string().optional().describe("Notiz/Grund (bei reject sinnvoll).") },
|
|
643
|
-
async ({ site, path, action, note }) => { try { return asText(await apiJsReview(cfg, { site, path, action, note })); } catch (e) { return asError(e); } }
|
|
636
|
+
"LESEND, NUR BETREUER-TOKEN: Verlauf der Änderungen an Skriptdateien (JS) einer Website – Zeit, Datei, von wem, Art (werte | code | neu) "
|
|
637
|
+
+ "und neu eingebundene externe Adressen (extern). Reine Information: Änderungen wirken sofort, es gibt nichts freizugeben.",
|
|
638
|
+
{ site: z.string().optional().describe(SITE_DESC) },
|
|
639
|
+
async ({ site }) => { try { return asText(await apiJsReview(cfg, { site })); } catch (e) { return asError(e); } }
|
|
644
640
|
);
|
|
645
641
|
}
|
|
646
642
|
server.tool(
|
|
@@ -698,12 +694,25 @@ export function registerTools(server0, { z, cfg, mode = "local", remote = null }
|
|
|
698
694
|
}
|
|
699
695
|
);
|
|
700
696
|
|
|
697
|
+
server.tool(
|
|
698
|
+
"site_badge_set",
|
|
699
|
+
"SCHREIBEND (normale Entwurfsänderung, ein Rückgängig-Schritt, Auto-Publish-Regeln gelten): Badge „Made with ProntoSite\" für die ganze Website "
|
|
700
|
+
+ "ein-/ausblenden und/oder die Variante setzen. Auf allen Tarifen möglich. DER einzige Weg zum Ausblenden: nie per CSS oder HTML. Beim Ausblenden bleibt "
|
|
701
|
+
+ "der Marker im Quelltext, ausgeliefert wird ein verstecktes leeres Element; einen eigenen Trennstrich davor im Footer entfernt das nicht. "
|
|
702
|
+
+ "Einbauen kann dieses Tool nicht: Meldet die Antwort eingebaut:false, das gelieferte snippet mit site_edit_html in die letzte Footer-Zeile setzen.",
|
|
703
|
+
{ site: z.string().optional().describe(SITE_DESC),
|
|
704
|
+
aktiv: z.boolean().optional().describe("true = einblenden, false = ausblenden. Weglassen = unverändert."),
|
|
705
|
+
variant: z.enum(["auto", "light", "dark", "mono"]).optional().describe("Variante für alle Seiten (übersteuert data-ps-variant): auto = Textfarbe des Footers, light für dunkle Footer, dark für helle Flächen, mono = Icon einfarbig. Weglassen = unverändert.") },
|
|
706
|
+
async ({ site, aktiv, variant }) => {
|
|
707
|
+
try { return asText(await apiBadgeSet(cfg, { site, aktiv, variant })); } catch (e) { return asError(e); }
|
|
708
|
+
}
|
|
709
|
+
);
|
|
710
|
+
|
|
701
711
|
// ---- Datei-API: kleine Änderungen am Entwurf direkt auf dem Server (Konzept §7) ----
|
|
702
712
|
const FILE_SMALL = "STANDARDWEG: Änderungen direkt am Server-Entwurf (für reine Textänderungen am einfachsten site_edit_text); "
|
|
703
713
|
+ "Export + Deploy nur als Ausnahme für größere Umbauten oder auf ausdrücklichen Wunsch. "
|
|
704
|
-
+ "Skriptdateien (JavaScript) nur bei JavaScript-Freigabe der Website;
|
|
705
|
-
+ "
|
|
706
|
-
+ "dem Nutzer so sagen). Preise/Texte in Skripten besser mit site_edit_text scope:\"all\". ";
|
|
714
|
+
+ "Skriptdateien (JavaScript) nur bei JavaScript-Freigabe der Website; dann wirkt jede Änderung sofort wie HTML/CSS. Neue externe Adresse im "
|
|
715
|
+
+ "Skript → Antwort jsExtern (dem Nutzer sagen: Datenschutzerklärung prüfen). Preise/Texte in Skripten besser mit site_edit_text scope:\"all\". ";
|
|
707
716
|
server.tool(
|
|
708
717
|
"site_files",
|
|
709
718
|
"LESEND: Listet die Dateien des Entwurfs einer Website (Pfad, Größe, Typ, ob bearbeitbar) und die aktuelle draftRev. "
|