@clicbase/mcp 0.3.0 → 0.3.2
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 +2 -0
- package/clicbase-mcp.mjs +50 -3
- package/package.json +1 -1
- package/portee.mjs +8 -0
- package/savoir.mjs +5 -1
package/README.md
CHANGED
|
@@ -18,6 +18,8 @@ Outils :
|
|
|
18
18
|
- `enable_realtime` — active le temps réel sur une table.
|
|
19
19
|
- `set_oauth_provider` — configure Google OAuth.
|
|
20
20
|
- `set_email_smtp` — configure un SMTP (sinon SMTP interne Clicbase par défaut).
|
|
21
|
+
- `list_sites` — les sites heberges : c'est ICI qu'on prend le `site_id`.
|
|
22
|
+
- `list_projects` — les projets (bases) visibles par la cle.
|
|
21
23
|
- `list_site_files` — liste les fichiers d'un site heberge (nom, taille, date).
|
|
22
24
|
- `read_site_file` — rend le contenu d'UN fichier, en base64 cote API, decode cote outil.
|
|
23
25
|
- `clicbase_conventions` — les regles de la plateforme : policies RLS, droits, PostgREST.
|
package/clicbase-mcp.mjs
CHANGED
|
@@ -75,10 +75,19 @@ async function lireEchec(res) {
|
|
|
75
75
|
const via = res.headers.get("cf-ray")
|
|
76
76
|
? `Cloudflare (cf-ray ${res.headers.get("cf-ray")})`
|
|
77
77
|
: (res.headers.get("server") ?? "origine inconnue");
|
|
78
|
+
// ⚠️ UN CORPS NON-JSON INTERDIT D'EXPLIQUER LE STATUT. `expliquer(403)` dit
|
|
79
|
+
// « hors du perimetre de cette cle » : c'est ce que NOTRE 403 signifie, et
|
|
80
|
+
// cette reponse ne vient pas de nous. Le 2026-09-18 une session a lu
|
|
81
|
+
// « hors du perimetre » alors que son bac a sable bloquait la sortie reseau
|
|
82
|
+
// vers clicbase.com — le vrai motif etait dans le corps, sous une phrase qui
|
|
83
|
+
// le contredisait. Affirmer une cause qu'on ne connait pas est exactement le
|
|
84
|
+
// defaut que ce fichier corrige ailleurs.
|
|
78
85
|
return {
|
|
79
86
|
json,
|
|
80
87
|
// ⚠️ UN CORPS NON-JSON EST LA SIGNATURE D'UN REFUS EN AMONT. On le dit en
|
|
81
88
|
// clair au lieu de rendre un objet vide qui ressemble a une reponse.
|
|
89
|
+
// Vrai seulement quand la reponse vient bien de l'application.
|
|
90
|
+
denotre: json !== null,
|
|
82
91
|
detail: json
|
|
83
92
|
? JSON.stringify(json)
|
|
84
93
|
: brut.trim()
|
|
@@ -113,7 +122,11 @@ async function trouver(name) {
|
|
|
113
122
|
});
|
|
114
123
|
if (!res.ok) {
|
|
115
124
|
const e = await lireEchec(res);
|
|
116
|
-
throw new Error(
|
|
125
|
+
throw new Error(
|
|
126
|
+
e.denotre
|
|
127
|
+
? `Clicbase ${res.status} — ${expliquer(res.status)} ${e.detail}`
|
|
128
|
+
: `Clicbase ${res.status} — ${e.detail}`,
|
|
129
|
+
);
|
|
117
130
|
}
|
|
118
131
|
const data = await res.json().catch(() => ({}));
|
|
119
132
|
const liste = Array.isArray(data.projects) ? data.projects : [];
|
|
@@ -155,7 +168,11 @@ async function resolve(name, domain, { creer = true } = {}) {
|
|
|
155
168
|
});
|
|
156
169
|
if (!res.ok) {
|
|
157
170
|
const e = await lireEchec(res);
|
|
158
|
-
throw new Error(
|
|
171
|
+
throw new Error(
|
|
172
|
+
e.denotre
|
|
173
|
+
? `Clicbase ${res.status} — ${expliquer(res.status)} ${e.detail}`
|
|
174
|
+
: `Clicbase ${res.status} — ${e.detail}`,
|
|
175
|
+
);
|
|
159
176
|
}
|
|
160
177
|
const data = await res.json().catch(() => ({}));
|
|
161
178
|
const info = {
|
|
@@ -284,11 +301,41 @@ async function admin(chemin, methode = "GET") {
|
|
|
284
301
|
});
|
|
285
302
|
if (!res.ok) {
|
|
286
303
|
const e = await lireEchec(res);
|
|
287
|
-
throw new Error(
|
|
304
|
+
throw new Error(
|
|
305
|
+
e.denotre
|
|
306
|
+
? `Clicbase ${res.status} — ${expliquer(res.status)} ${e.detail}`
|
|
307
|
+
: `Clicbase ${res.status} — ${e.detail}`,
|
|
308
|
+
);
|
|
288
309
|
}
|
|
289
310
|
return res.json();
|
|
290
311
|
}
|
|
291
312
|
|
|
313
|
+
outils.tool(
|
|
314
|
+
"list_sites",
|
|
315
|
+
"Liste les sites heberges visibles par cette cle : identifiant, slug, domaine, mode de deploiement. C'est ICI qu'on prend le `site_id` des autres outils : ce n'est ni le domaine ni le slug.",
|
|
316
|
+
{},
|
|
317
|
+
async () => {
|
|
318
|
+
try {
|
|
319
|
+
return out(await admin("/sites"));
|
|
320
|
+
} catch (e) {
|
|
321
|
+
return fail(e);
|
|
322
|
+
}
|
|
323
|
+
},
|
|
324
|
+
);
|
|
325
|
+
|
|
326
|
+
outils.tool(
|
|
327
|
+
"list_projects",
|
|
328
|
+
"Liste les projets (bases) visibles par cette cle : identifiant, nom, slug. Utile pour savoir sur quoi on peut agir avant de nommer quoi que ce soit.",
|
|
329
|
+
{},
|
|
330
|
+
async () => {
|
|
331
|
+
try {
|
|
332
|
+
return out(await admin("/projects"));
|
|
333
|
+
} catch (e) {
|
|
334
|
+
return fail(e);
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
);
|
|
338
|
+
|
|
292
339
|
outils.tool(
|
|
293
340
|
"list_site_files",
|
|
294
341
|
"Liste les fichiers d'un site heberge (nom, dossier ou non, taille, date). `dossier` pour descendre d'un niveau. L'id du site vient de GET /sites.",
|
package/package.json
CHANGED
package/portee.mjs
CHANGED
|
@@ -48,6 +48,14 @@ export const OUTILS = {
|
|
|
48
48
|
// restreint qui en a le plus besoin, puisqu'il ne reste alors que trois
|
|
49
49
|
// outils et qu'un assistant doit deviner le reste.
|
|
50
50
|
clicbase_conventions: "lecture",
|
|
51
|
+
// --- de quoi savoir sur quoi agir ---
|
|
52
|
+
// ⚠️ SANS EUX, LES OUTILS QUI PRENNENT UN `site_id` SONT INUTILISABLES. Le
|
|
53
|
+
// 2026-09-18, un assistant a essaye le domaine puis le slug, recolte deux
|
|
54
|
+
// 404, et fini par demander l'identifiant a son utilisateur. L'API le
|
|
55
|
+
// publiait depuis toujours ; c'est l'outil qui manquait. Livrer une action
|
|
56
|
+
// sans le moyen de decouvrir sa cible, c'est livrer une porte sans poignee.
|
|
57
|
+
list_sites: "lecture",
|
|
58
|
+
list_projects: "lecture",
|
|
51
59
|
// --- fichiers d'un site heberge ---
|
|
52
60
|
// ⚠️ LISTER EST UNE LECTURE, LIRE EST UN SECRET. Le nom et la taille d'un
|
|
53
61
|
// fichier revelent une structure ; son CONTENU peut porter des identifiants,
|
package/savoir.mjs
CHANGED
|
@@ -35,7 +35,11 @@ SIX PIÈGES QUI NE LÈVENT AUCUNE ERREUR. Ils répondent tous « 200 OK ».
|
|
|
35
35
|
5. Une fonction Edge renvoie \`{ status, body }\`, jamais \`new Response(...)\`.
|
|
36
36
|
6. Deux authentifications sans rapport coexistent. Celle du PROJET (tes utilisateurs finaux) vit dans le schéma \`auth\` de cette base et alimente \`auth.uid()\` dans les policies. Celle de la PLATEFORME (le compte Clicbase) ne s'écrit jamais dans une policy.
|
|
37
37
|
|
|
38
|
-
CE QUI N'EXISTE PAS, ET QUE
|
|
38
|
+
CE QUI N'EXISTE PAS, ET QUE DES ASSISTANTS ONT DEJA INVENTE. Aucun registre Docker : ni \`docker login\`, ni \`docker pull\`, ni \`registry.*.clicbase.com\`. Ne devine aucun nom d'hote.
|
|
39
|
+
|
|
40
|
+
COMMENCE PAR \`list_sites\`. Le \`site_id\` des autres outils est un identifiant technique : ni le domaine, ni le slug.
|
|
41
|
+
|
|
42
|
+
FICHIERS D'UN SITE : \`list_site_files\` et \`read_site_file\` pour lire, POST /sites/<id>/files pour ecrire. Les fichiers caches sont refuses a tout niveau, \`.env\` compris. Ne reclame JAMAIS le mot de passe SFTP principal : c'est l'identite du site, elle ouvre tout et ne se revoque pas. \`create_sftp_account\` fabrique un compte DEDIE, a supprimer des que tu as fini.
|
|
39
43
|
|
|
40
44
|
APPELS REST : en-têtes \`apikey\` ET \`Authorization: Bearer\`, la même clé dans les deux. Filtres dans l'URL, façon PostgREST : \`?select=id,title&status=eq.published&order=created_at.desc\`.
|
|
41
45
|
|