@prontosite/mcp 0.7.0 → 0.8.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 +10 -0
- package/README.md +2 -0
- package/api.mjs +19 -0
- package/index.mjs +29 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
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.8.0 – 2026-09-23
|
|
7
|
+
|
|
8
|
+
- **Neu: `site_embeds`** – listet alle externen Einbettungen (Host, Seite(n), Kategorie `gated`/`notwendig`). Lesend.
|
|
9
|
+
- **Neu: `site_embed_consent`** – stuft eine Einbettung als `notwendig` (§ 25 Abs. 2 Nr. 2 TDDDG,
|
|
10
|
+
Kunden-Eigenverantwortung) oder wieder als `gated` (Zwei-Klick) ein. `notwendig` nur mit `confirmed:true`;
|
|
11
|
+
ohne Bestätigung antwortet der Server 400 mit dem Verantwortungs-Text, den der Assistent dem Nutzer
|
|
12
|
+
vorlegen muss. Optional seiten-gebunden (`page`) – so bleibt der Dienst nur dort einwilligungsfrei, wo die
|
|
13
|
+
Funktion gebraucht wird. Datenschutz-Text + Cookie-Richtlinie werden beim nächsten Publish automatisch
|
|
14
|
+
angepasst (technisch erforderlicher Dienst statt Einwilligung). Betreuer-Token gilt für betreute Kunden.
|
|
15
|
+
|
|
6
16
|
## 0.7.0 – 2026-09-23
|
|
7
17
|
|
|
8
18
|
- **Ambige Config erkannt:** Liegt ein Top-Level-Token (env `PRONTOSITE_TOKEN` bzw. `token`) NEBEN einer
|
package/README.md
CHANGED
|
@@ -91,6 +91,8 @@ sichern: `cp ~/.prontosite.json ~/.prontosite.json.bak`).
|
|
|
91
91
|
| `site_legal_options({ site?, impressum?, datenschutz? })` | Anzeige-Optionen der Rechtstexte (showTitle, showDate, draftNotice); ohne Rolle nur lesen. **Schreibend.** |
|
|
92
92
|
| `site_domain_status({ site?, check? })` | Kundendomain-Status (verbunden/kanonisch/Zert-bis) + offene Jobs; mit `check` nur Live-DNS-Prüfung. **Lesend.** |
|
|
93
93
|
| `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.** |
|
|
94
|
+
| `site_embeds({ site? })` | Externe Einbettungen der Website: Host, Seite(n), aktuelle Einwilligungs-Kategorie (`gated` = Zwei-Klick \| `notwendig`). **Lesend.** |
|
|
95
|
+
| `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.** |
|
|
94
96
|
|
|
95
97
|
`site_deploy` und `site_publish` sind **schreibende** Aktionen (verändern die Live-Website). Die
|
|
96
98
|
Tool-Beschreibungen weisen den Assistenten an, vorher rückzufragen. Jeder Aufruf wird serverseitig auditiert.
|
package/api.mjs
CHANGED
|
@@ -189,6 +189,25 @@ export async function apiDomainConnect(cfg, { site, domain, canonical = "www", a
|
|
|
189
189
|
return asJson(res);
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
+
/** GET /api/embeds/<site> – erkannte Embeds (Host, Seite(n), aktuelle Kategorie gated|notwendig). LESEND. */
|
|
193
|
+
export async function apiEmbeds(cfg, { site } = {}, fetchImpl = fetch) {
|
|
194
|
+
const { token, slug } = resolveTarget(cfg, site);
|
|
195
|
+
const res = await fetchImpl(`${baseUrl(cfg)}/embeds/${encodeURIComponent(slug)}`, { headers: authHeaders(token) });
|
|
196
|
+
return asJson(res);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** PUT /api/embeds/<site> – SCHREIBEND: ein Embed als „notwendig" (technisch erforderlich, § 25 Abs. 2 Nr. 2
|
|
200
|
+
* TDDDG) oder zurück „gated" einstufen. „notwendig" NUR mit confirmed:true – sonst 400 mit dem
|
|
201
|
+
* Verantwortungs-Text. Wirkt beim nächsten Veröffentlichen; Datenschutz-Text passt sich automatisch an. */
|
|
202
|
+
export async function apiEmbedConsent(cfg, { site, host, page, category = "notwendig", confirmed = false } = {}, fetchImpl = fetch) {
|
|
203
|
+
if (!host) throw new Error("host erwartet.");
|
|
204
|
+
const { token, slug } = resolveTarget(cfg, site);
|
|
205
|
+
const res = await fetchImpl(`${baseUrl(cfg)}/embeds/${encodeURIComponent(slug)}`, {
|
|
206
|
+
method: "PUT", headers: { ...authHeaders(token), "content-type": "application/json" },
|
|
207
|
+
body: JSON.stringify({ host, page: page || null, category, confirmed: !!confirmed }) });
|
|
208
|
+
return asJson(res);
|
|
209
|
+
}
|
|
210
|
+
|
|
192
211
|
/** GET/PUT /api/legal-options/<site> – Anzeige-Optionen der Rechtstext-Widgets. Ohne impressum/datenschutz
|
|
193
212
|
* nur LESEN; sonst Teil-Update (nur echte Booleans wirken). */
|
|
194
213
|
export async function apiLegalOptions(cfg, { site, impressum, datenschutz } = {}, fetchImpl = fetch) {
|
package/index.mjs
CHANGED
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
12
12
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
13
13
|
import { z } from "zod";
|
|
14
|
-
import { loadConfig, apiStatus, apiExport, apiDeploy, apiPublish, sitesList, apiCompanyGet, apiCompanySet, apiLegalOptions, apiDomainStatus, apiDomainConnect } from "./api.mjs";
|
|
14
|
+
import { loadConfig, apiStatus, apiExport, apiDeploy, apiPublish, sitesList, apiCompanyGet, apiCompanySet, apiLegalOptions, apiDomainStatus, apiDomainConnect, apiEmbeds, apiEmbedConsent } from "./api.mjs";
|
|
15
15
|
|
|
16
16
|
const cfg = loadConfig();
|
|
17
17
|
// Deutliche Startwarnung bei ambiger Konfiguration (Top-Level-Token NEBEN sites-Map). Nach stderr, damit
|
|
18
18
|
// es im MCP-Log/Terminal auffällt; die endgültige Auflösung (Betreuer-Token-Vorrang vs. Map) klärt sites_list.
|
|
19
19
|
for (const w of (cfg.warnings || [])) process.stderr.write("[prontosite-mcp] ⚠ " + w + "\n");
|
|
20
|
-
const server = new McpServer({ name: "prontosite", version: "0.
|
|
20
|
+
const server = new McpServer({ name: "prontosite", version: "0.8.0" });
|
|
21
21
|
const asText = obj => ({ content: [{ type: "text", text: JSON.stringify(obj, null, 2) }] });
|
|
22
22
|
const asError = e => ({ isError: true, content: [{ type: "text", text: "Fehler: " + (e?.message || String(e)) }] });
|
|
23
23
|
const SITE_DESC = "Website-Slug (z. B. 'mas-monti'). Ohne Angabe die Standard-Site der Config. Bei Betreuer-"
|
|
@@ -176,5 +176,32 @@ server.tool(
|
|
|
176
176
|
}
|
|
177
177
|
);
|
|
178
178
|
|
|
179
|
+
server.tool(
|
|
180
|
+
"site_embeds",
|
|
181
|
+
"LESEND: erkannte eingebettete Inhalte Dritter (iframes) einer Website – je Embed Host, Seite(n) und "
|
|
182
|
+
+ "aktuelle Consent-Kategorie (`gated` = lädt erst nach Einwilligung / Zwei-Klick, `notwendig` = technisch "
|
|
183
|
+
+ "erforderlich, lädt ohne Einwilligung). Basis für site_embed_consent.",
|
|
184
|
+
{ site: z.string().optional().describe(SITE_DESC) },
|
|
185
|
+
async ({ site }) => { try { return asText(await apiEmbeds(cfg, { site })); } catch (e) { return asError(e); } }
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
server.tool(
|
|
189
|
+
"site_embed_consent",
|
|
190
|
+
"SCHREIBEND: ein Embed als `notwendig` (technisch erforderlich, § 25 Abs. 2 Nr. 2 TDDDG) oder zurück auf "
|
|
191
|
+
+ "`gated` einstufen. Bei `notwendig` erklärt der Kunde/Betreuer, dass der Dienst für die vom Besucher "
|
|
192
|
+
+ "gewünschte Funktion (z. B. Reservierung) UNBEDINGT ERFORDERLICH ist und übernimmt die Verantwortung – "
|
|
193
|
+
+ "das MUSS mit dem Nutzer bestätigt werden (confirmed:true; sonst lehnt der Server mit dem Verantwortungs-"
|
|
194
|
+
+ "Text ab). Dann lädt das Embed OHNE Einwilligung, aber nur auf der angegebenen Seite; der Datenschutz-Text "
|
|
195
|
+
+ "passt sich automatisch an. Greift beim nächsten Veröffentlichen. Betreuer-Token gilt für betreute Kunden.",
|
|
196
|
+
{ site: z.string().optional().describe(SITE_DESC),
|
|
197
|
+
host: z.string().describe("Embed-Host/Key aus site_embeds (z. B. 'resmio', 'youtube' oder ein Hostname)."),
|
|
198
|
+
page: z.string().optional().describe("Seiten-Datei, auf die die Einstufung beschränkt ist (z. B. 'reservierung.html'); leer = alle Seiten mit diesem Embed."),
|
|
199
|
+
category: z.enum(["notwendig", "gated"]).default("notwendig").describe("notwendig = technisch erforderlich (ohne Einwilligung); gated = zurück hinter das Consent-/Zwei-Klick-Gate."),
|
|
200
|
+
confirmed: z.boolean().default(false).describe("MUSS true sein, um 'notwendig' zu setzen (Verantwortungs-Bestätigung). Vorher den Nutzer explizit fragen.") },
|
|
201
|
+
async ({ site, host, page, category, confirmed }) => {
|
|
202
|
+
try { return asText(await apiEmbedConsent(cfg, { site, host, page, category, confirmed })); } catch (e) { return asError(e); }
|
|
203
|
+
}
|
|
204
|
+
);
|
|
205
|
+
|
|
179
206
|
const transport = new StdioServerTransport();
|
|
180
207
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prontosite/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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": {
|