@prontosite/mcp 0.2.1 → 0.3.1
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/README.md +8 -1
- package/api.mjs +20 -1
- package/index.mjs +12 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -62,9 +62,16 @@ bzw. die Einzel-Site. So verwaltest du mit **einem** Claude Desktop beliebig vie
|
|
|
62
62
|
Zuordnung bricht nicht, wenn ein Kunde seine Domain/Adresse ändert.
|
|
63
63
|
|
|
64
64
|
- `site` – **Site-ID** (`s-…`, empfohlen) oder `"active"`; ein Slug wird zwar noch akzeptiert, kann aber
|
|
65
|
-
veralten.
|
|
65
|
+
veralten.
|
|
66
66
|
- `host` – Standard `app.prontosite.io`.
|
|
67
67
|
|
|
68
|
+
**Erst-Import (neue Website):** In der Einzel-Config `site:"new"`. In einer `sites`-Map ist `"new"` ein
|
|
69
|
+
**reserviertes Schlüsselwort** (kein Profil-Label) – adressiere den Erst-Import als **`site:"<label>:new"`**
|
|
70
|
+
(z. B. `site:"rtk-kanzlei:new"`); ProntoSite legt dann mit dem Token dieses Labels eine neue Website an. Ein
|
|
71
|
+
frisches Konto-Profil trägt zunächst `"site":"active"`; der erste `site_deploy` darauf legt die Website
|
|
72
|
+
automatisch an (solange das Konto noch keine hat). *(Hinweis: `"new"` ohne Label ist in der Map mehrdeutig –
|
|
73
|
+
der Server nennt dann das richtige `<label>:new`.)*
|
|
74
|
+
|
|
68
75
|
**Datei anlegen/erweitern:** Existiert `~/.prontosite.json` noch nicht, lege sie mit obigem Inhalt an
|
|
69
76
|
(z. B. `cat > ~/.prontosite.json <<'JSON' … JSON` – ⚠ **überschreibt** eine vorhandene Datei!). Ist sie schon
|
|
70
77
|
da, NICHT überschreiben: die Datei öffnen und unter `"sites"` einen weiteren Eintrag ergänzen (vorher
|
package/api.mjs
CHANGED
|
@@ -47,6 +47,24 @@ const needToken = (token, ref) => {
|
|
|
47
47
|
* bzw. den Schlüssel. Sonst der Einzel-Token mit dem übergebenen Bezeichner (ID/„active"). */
|
|
48
48
|
export function resolveTarget(cfg, site) {
|
|
49
49
|
const want = site || cfg.defaultSite || cfg.site || "active";
|
|
50
|
+
// "new" (Erst-Import) ist ein RESERVIERTES Schlüsselwort, KEIN Profil-Label. Sonst wäre der Erst-Import
|
|
51
|
+
// über eine sites-Map unerreichbar (Befund rtk-kanzlei: „new" wurde als Label gesucht → „kein Profil").
|
|
52
|
+
// Einzel-Config: site="new" → mit dem Einzel-Token anlegen.
|
|
53
|
+
// Multi-Config: site="<label>:new" → mit dem Token DES LABELS anlegen (Erst-Import in dessen Konto).
|
|
54
|
+
// Multi + bare "new" ist mehrdeutig (welches Token/Konto?) → klare Anleitung statt stillem Fehlgriff.
|
|
55
|
+
const newMatch = /^(.+):new$/i.exec(String(want));
|
|
56
|
+
if (newMatch || String(want).toLowerCase() === "new") {
|
|
57
|
+
if (cfg.sites) {
|
|
58
|
+
const keys = Object.keys(cfg.sites);
|
|
59
|
+
if (!newMatch) throw new Error(`Erst-Import in einer Multi-Site-Config als „<label>:new" adressieren `
|
|
60
|
+
+ `(z. B. „${keys[0] || "kunde"}:new") – so ist klar, welches Token/Konto den Erst-Import bekommt. sites_list zeigt die Labels.`);
|
|
61
|
+
const label = newMatch[1];
|
|
62
|
+
const key = (cfg.sites[label] && label) || keys.find(k => k.toLowerCase() === label.toLowerCase());
|
|
63
|
+
if (!key) throw new Error(`„${label}" ist kein Profil in deiner sites-Map. Verfügbar: ${keys.join(", ")}.`);
|
|
64
|
+
return { token: needToken(cfg.sites[key].token, key), slug: "new" };
|
|
65
|
+
}
|
|
66
|
+
return { token: needToken(cfg.token, "new"), slug: "new" };
|
|
67
|
+
}
|
|
50
68
|
if (cfg.sites) {
|
|
51
69
|
const keys = Object.keys(cfg.sites);
|
|
52
70
|
const lc = String(want).toLowerCase();
|
|
@@ -99,7 +117,7 @@ export async function apiExport(cfg, { site, which = "published", outDir = "." }
|
|
|
99
117
|
}
|
|
100
118
|
|
|
101
119
|
/** POST /api/deploy/<site> – ZIP übergeben (+ optional publish/resetOverlay/legal). site="new" = anlegen. */
|
|
102
|
-
export async function apiDeploy(cfg, { site, customer = null, zipPath, publish = false, resetOverlay = false, legal = null } = {}, fetchImpl = fetch) {
|
|
120
|
+
export async function apiDeploy(cfg, { site, customer = null, slug: wishSlug = null, zipPath, publish = false, resetOverlay = false, legal = null } = {}, fetchImpl = fetch) {
|
|
103
121
|
if (!zipPath || !fs.existsSync(zipPath)) throw new Error(`ZIP nicht gefunden: ${zipPath}`);
|
|
104
122
|
const { token, slug } = resolveTarget(cfg, site);
|
|
105
123
|
const q = new URLSearchParams();
|
|
@@ -108,6 +126,7 @@ export async function apiDeploy(cfg, { site, customer = null, zipPath, publish =
|
|
|
108
126
|
if (legal === true) q.set("legal", "1");
|
|
109
127
|
if (legal === false) q.set("legal", "0");
|
|
110
128
|
if (customer) q.set("customer", customer); // Betreuer-Token + site="new": Ziel-Konto für den Erst-Import
|
|
129
|
+
if (wishSlug) q.set("slug", String(wishSlug)); // Erst-Import: Wunsch-Adresse (sonst wird sie abgeleitet)
|
|
111
130
|
const qs = q.toString() ? `?${q}` : "";
|
|
112
131
|
const res = await fetchImpl(`${baseUrl(cfg)}/deploy/${encodeURIComponent(slug)}${qs}`, {
|
|
113
132
|
method: "POST", headers: { ...authHeaders(token), "content-type": "application/zip" }, body: fs.readFileSync(zipPath) });
|
package/index.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import { z } from "zod";
|
|
|
14
14
|
import { loadConfig, apiStatus, apiExport, apiDeploy, apiPublish, sitesList } from "./api.mjs";
|
|
15
15
|
|
|
16
16
|
const cfg = loadConfig();
|
|
17
|
-
const server = new McpServer({ name: "prontosite", version: "0.
|
|
17
|
+
const server = new McpServer({ name: "prontosite", version: "0.3.1" });
|
|
18
18
|
const asText = obj => ({ content: [{ type: "text", text: JSON.stringify(obj, null, 2) }] });
|
|
19
19
|
const asError = e => ({ isError: true, content: [{ type: "text", text: "Fehler: " + (e?.message || String(e)) }] });
|
|
20
20
|
const SITE_DESC = "Website-Slug (z. B. 'mas-monti'). Ohne Angabe die Standard-Site der Config. Bei Betreuer-"
|
|
@@ -49,16 +49,21 @@ server.tool(
|
|
|
49
49
|
server.tool(
|
|
50
50
|
"site_deploy",
|
|
51
51
|
"SCHREIBEND: Übergibt eine lokale ZIP-Datei an ProntoSite (Import). Mit publish=true wird die Website "
|
|
52
|
-
+ "DIREKT LIVE geschaltet und der bestehende Live-Stand überschrieben.
|
|
53
|
-
+ "
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
+ "DIREKT LIVE geschaltet und der bestehende Live-Stand überschrieben. ERST-IMPORT (neue Website): "
|
|
53
|
+
+ "Einzel-Config site='new'; Multi-Site/Betreuer site='<label>:new' (legt im Konto DES LABELS an). "
|
|
54
|
+
+ "WICHTIG beim ERST-IMPORT: Frag den Nutzer VOR dem Deploy nach der gewünschten Adresse "
|
|
55
|
+
+ "(„Unter welcher Adresse soll die Website laufen?“, z. B. 'wuerttemberg' → wuerttemberg.prontosite.io) "
|
|
56
|
+
+ "und übergib sie als slug – ohne slug wird die Adresse nur aus Konto-/Seitenname ABGELEITET (die Antwort "
|
|
57
|
+
+ "nennt dann die abgeleitete Adresse; sie ist später änderbar). Bitte VOR dem Aufruf bestätigen lassen.",
|
|
58
|
+
{ site: z.string().optional().describe(SITE_DESC + " Erst-Import: 'new' (Einzel) bzw. '<label>:new' (Multi-Site)."),
|
|
59
|
+
slug: z.string().optional().describe("Erst-Import: gewünschte Web-Adresse (Subdomain-Label, z. B. 'wuerttemberg' → wuerttemberg.prontosite.io). Beim Erst-Import den Nutzer danach FRAGEN; wird sie weggelassen, leitet ProntoSite eine Adresse ab. Bei Updates ignoriert."),
|
|
60
|
+
customer: z.string().optional().describe("Nur Betreuer-Token + Erst-Import mit EINEM Manager-Token: Ziel-Konto-ID (k-…). Bei per-Konto-Token in der sites-Map genügt '<label>:new'."),
|
|
56
61
|
zipPath: z.string().describe("Pfad zur ZIP-Datei der Website (lokal)."),
|
|
57
62
|
publish: z.boolean().default(false).describe("true = nach dem Import direkt veröffentlichen (LIVE)."),
|
|
58
63
|
resetOverlay: z.boolean().default(false).describe("true = bisherige Dashboard-Änderungen verwerfen."),
|
|
59
64
|
legal: z.boolean().optional().describe("Rechts-Automatik (Impressum/Datenschutz): true erzwingt, false schaltet ab.") },
|
|
60
|
-
async ({ site, customer, zipPath, publish, resetOverlay, legal }) => {
|
|
61
|
-
try { return asText(await apiDeploy(cfg, { site, customer, zipPath, publish, resetOverlay, legal })); } catch (e) { return asError(e); }
|
|
65
|
+
async ({ site, slug, customer, zipPath, publish, resetOverlay, legal }) => {
|
|
66
|
+
try { return asText(await apiDeploy(cfg, { site, slug, customer, zipPath, publish, resetOverlay, legal })); } catch (e) { return asError(e); }
|
|
62
67
|
}
|
|
63
68
|
);
|
|
64
69
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prontosite/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
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": { "prontosite-mcp": "index.mjs" },
|