@fil-technology/appmate-mcp 0.3.0 → 0.4.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/README.md +8 -0
- package/dist/tools.js +185 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,14 @@ staging or self-hosted instances.
|
|
|
68
68
|
| `publish_waitlist_flow` | Promote the waitlist draft live. |
|
|
69
69
|
| `list_waitlist_signups` | Paginated list (cursor + nextCursor). |
|
|
70
70
|
| `export_waitlist_csv` | Return the full waitlist as a CSV string. |
|
|
71
|
+
| `get_feedback_flow` | Read published + draft feedback config. |
|
|
72
|
+
| `update_feedback_draft` | Replace the feedback draft. |
|
|
73
|
+
| `publish_feedback_flow` | Promote the feedback draft live. |
|
|
74
|
+
| `list_feedback_submissions` | Paginated list of feedback rows (rating + message + email). |
|
|
75
|
+
| `get_report_flow` | Read published + draft report config. |
|
|
76
|
+
| `update_report_draft` | Replace the report draft (categorised). |
|
|
77
|
+
| `publish_report_flow` | Promote the report draft live. |
|
|
78
|
+
| `list_report_submissions` | Paginated, optional `category` filter. |
|
|
71
79
|
|
|
72
80
|
Tools that accept an app reference (`get_app`, `update_cancel_draft`,
|
|
73
81
|
etc.) accept either the cuid `id` or the human-readable `slug` — use
|
package/dist/tools.js
CHANGED
|
@@ -125,22 +125,50 @@ export const updateWaitlistDraft = {
|
|
|
125
125
|
description: [
|
|
126
126
|
"Replace the draft waitlist config. Body MUST be a full waitlist config object (type: 'waitlist').",
|
|
127
127
|
"",
|
|
128
|
-
"
|
|
128
|
+
"The public URL at signup.appmate.cloud/{slug} renders a FULL landing",
|
|
129
|
+
"page — not just a form. The `hero` block drives the visual treatment;",
|
|
130
|
+
"omit it for the minimal/legacy look.",
|
|
131
|
+
"",
|
|
132
|
+
"Full shape:",
|
|
129
133
|
" {",
|
|
130
134
|
" type: 'waitlist',",
|
|
131
135
|
" intro: {",
|
|
132
|
-
" title,
|
|
133
|
-
"
|
|
134
|
-
"
|
|
136
|
+
" title, // h1 on the landing",
|
|
137
|
+
" subtitle, // lede paragraph",
|
|
138
|
+
" emailPlaceholder, // input placeholder, e.g. 'you@example.com'",
|
|
139
|
+
" submitLabel, // button text, e.g. 'Notify me'",
|
|
140
|
+
" legal? // small print under the form (optional)",
|
|
135
141
|
" },",
|
|
136
142
|
" success: {",
|
|
137
|
-
" title, body,",
|
|
138
|
-
" ctaLabel?, ctaUrl?
|
|
139
|
-
" }",
|
|
143
|
+
" title, body, // shown after signup",
|
|
144
|
+
" ctaLabel?, ctaUrl? // both-or-neither — partial pair renders nothing",
|
|
145
|
+
" },",
|
|
146
|
+
" hero?: { // ALL fields optional; omit `hero` entirely for minimal",
|
|
147
|
+
" theme?: 'minimal' | 'gradient' | 'dark' | 'side_by_side',",
|
|
148
|
+
" eyebrow?: string, // short chip above title, e.g. 'Coming soon · Q1 2026'",
|
|
149
|
+
" accentColor?: string, // hex '#rrggbb'; tints button + chip + gradient blob",
|
|
150
|
+
" bullets?: [ // 0–5 value-prop cards under the form",
|
|
151
|
+
" { icon?: '✨', title: 'Fast', body?: 'Sub-second responses' }",
|
|
152
|
+
" ],",
|
|
153
|
+
" showCount?: boolean, // renders '{N} on the waitlist' pill (hides if <3 signups)",
|
|
154
|
+
" heroImage?: string, // optional URL of a hero image",
|
|
155
|
+
" },",
|
|
156
|
+
" templateId?: string // analytics tag if seeded from a template",
|
|
140
157
|
" }",
|
|
141
158
|
"",
|
|
159
|
+
"Theme picker guide — pick from intent:",
|
|
160
|
+
" - minimal → no brand, conservative B2B. Default.",
|
|
161
|
+
" - gradient → marketing-launch energy. Pastel blobs + accent color.",
|
|
162
|
+
" - dark → premium / product-reveal vibe. Dark hero + accent glow.",
|
|
163
|
+
" - side_by_side → desktop-first 2-column (story left, form right).",
|
|
164
|
+
" Collapses to minimal on phone — fine for landing-pageiness.",
|
|
165
|
+
"",
|
|
166
|
+
"Starter templates available (see /examples?kind=waitlist):",
|
|
167
|
+
" minimal_email_only, feature_tease, launching_soon, pro_upsell,",
|
|
168
|
+
" private_beta, early_access_referral.",
|
|
169
|
+
"",
|
|
142
170
|
"Server returns { ok:true, warnings: [...] } — check warnings before publishing.",
|
|
143
|
-
"Common: partial_cta (label without url, or vice versa).",
|
|
171
|
+
"Common warnings: partial_cta (label without url, or vice versa).",
|
|
144
172
|
].join("\n"),
|
|
145
173
|
inputSchema: z.object({
|
|
146
174
|
appIdOrSlug: z.string().min(1),
|
|
@@ -182,17 +210,166 @@ export const exportWaitlistCsv = {
|
|
|
182
210
|
return { csv };
|
|
183
211
|
},
|
|
184
212
|
};
|
|
213
|
+
// ─── Feedback flow ──────────────────────────────────────────────────────────
|
|
214
|
+
export const getFeedbackFlow = {
|
|
215
|
+
name: "get_feedback_flow",
|
|
216
|
+
description: "Read the published and draft feedback flow configs for an app. Feedback flows host an open-ended message form (optional 1–5 star rating + optional reply email) at appmate.cloud/feedback/{appSlug}.",
|
|
217
|
+
inputSchema: z.object({ appIdOrSlug: z.string().min(1) }),
|
|
218
|
+
handler: (input, cfg) => apiFetch(cfg, "GET", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/feedback`),
|
|
219
|
+
};
|
|
220
|
+
export const updateFeedbackDraft = {
|
|
221
|
+
name: "update_feedback_draft",
|
|
222
|
+
description: [
|
|
223
|
+
"Replace the draft feedback config. Body MUST be a full feedback config object (type: 'feedback').",
|
|
224
|
+
"",
|
|
225
|
+
"Shape:",
|
|
226
|
+
" {",
|
|
227
|
+
" type: 'feedback',",
|
|
228
|
+
" intro: {",
|
|
229
|
+
" title, subtitle,",
|
|
230
|
+
" messagePlaceholder, // textarea placeholder",
|
|
231
|
+
" submitLabel,",
|
|
232
|
+
" legal? // small print under the form (optional)",
|
|
233
|
+
" },",
|
|
234
|
+
" rating?: { // OPTIONAL 1–5 star widget",
|
|
235
|
+
" enabled: true,",
|
|
236
|
+
" prompt?: 'How would you rate your experience?',",
|
|
237
|
+
" required?: false // when true, blocks submit until picked",
|
|
238
|
+
" },",
|
|
239
|
+
" emailField?: { // OPTIONAL reply-to email field",
|
|
240
|
+
" enabled: true,",
|
|
241
|
+
" placeholder?: 'you@example.com (optional)',",
|
|
242
|
+
" required?: false",
|
|
243
|
+
" },",
|
|
244
|
+
" success: {",
|
|
245
|
+
" title, body,",
|
|
246
|
+
" ctaLabel?, ctaUrl? // both-or-neither follow-up CTA",
|
|
247
|
+
" },",
|
|
248
|
+
" hero?: { // visual treatment, matches waitlist hero",
|
|
249
|
+
" theme?: 'minimal' | 'gradient' | 'dark' | 'side_by_side',",
|
|
250
|
+
" eyebrow?, accentColor?, titleFont?",
|
|
251
|
+
" }",
|
|
252
|
+
" }",
|
|
253
|
+
"",
|
|
254
|
+
"Server returns { ok:true, warnings: [] }. Warning rules will be added later — for now treat any non-empty array as advisory.",
|
|
255
|
+
].join("\n"),
|
|
256
|
+
inputSchema: z.object({
|
|
257
|
+
appIdOrSlug: z.string().min(1),
|
|
258
|
+
config: z.unknown(),
|
|
259
|
+
}),
|
|
260
|
+
handler: (input, cfg) => apiFetch(cfg, "PUT", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/feedback`, input.config),
|
|
261
|
+
};
|
|
262
|
+
export const publishFeedbackFlow = {
|
|
263
|
+
name: "publish_feedback_flow",
|
|
264
|
+
description: "Promote the draft feedback config to the live published version. Visitors at appmate.cloud/feedback/{appSlug} see the new version immediately.",
|
|
265
|
+
inputSchema: z.object({ appIdOrSlug: z.string().min(1) }),
|
|
266
|
+
handler: (input, cfg) => apiFetch(cfg, "POST", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/feedback/publish`),
|
|
267
|
+
};
|
|
268
|
+
export const listFeedbackSubmissions = {
|
|
269
|
+
name: "list_feedback_submissions",
|
|
270
|
+
description: "Paginated list of feedback submissions for an app. Each row: { id, message, rating, email, source, createdAt }. limit max 200, default 50; pass nextCursor back for the next page.",
|
|
271
|
+
inputSchema: z.object({
|
|
272
|
+
appIdOrSlug: z.string().min(1),
|
|
273
|
+
limit: z.number().int().min(1).max(200).optional(),
|
|
274
|
+
cursor: z.string().optional(),
|
|
275
|
+
}),
|
|
276
|
+
handler: (input, cfg) => {
|
|
277
|
+
const qs = new URLSearchParams();
|
|
278
|
+
if (input.limit !== undefined)
|
|
279
|
+
qs.set("limit", String(input.limit));
|
|
280
|
+
if (input.cursor)
|
|
281
|
+
qs.set("cursor", input.cursor);
|
|
282
|
+
const tail = qs.toString() ? `?${qs.toString()}` : "";
|
|
283
|
+
return apiFetch(cfg, "GET", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/feedback/submissions${tail}`);
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
// ─── Report flow ────────────────────────────────────────────────────────────
|
|
287
|
+
export const getReportFlow = {
|
|
288
|
+
name: "get_report_flow",
|
|
289
|
+
description: "Read the published and draft report flow configs for an app. Report flows host a categorised bug/abuse/spam form (required category picker + message + optional reply email) at appmate.cloud/report/{appSlug}.",
|
|
290
|
+
inputSchema: z.object({ appIdOrSlug: z.string().min(1) }),
|
|
291
|
+
handler: (input, cfg) => apiFetch(cfg, "GET", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/report`),
|
|
292
|
+
};
|
|
293
|
+
export const updateReportDraft = {
|
|
294
|
+
name: "update_report_draft",
|
|
295
|
+
description: [
|
|
296
|
+
"Replace the draft report config. Body MUST be a full report config object (type: 'report').",
|
|
297
|
+
"",
|
|
298
|
+
"Shape:",
|
|
299
|
+
" {",
|
|
300
|
+
" type: 'report',",
|
|
301
|
+
" intro: {",
|
|
302
|
+
" title, subtitle,",
|
|
303
|
+
" messagePlaceholder, // textarea placeholder",
|
|
304
|
+
" submitLabel,",
|
|
305
|
+
" legal? // optional small print",
|
|
306
|
+
" },",
|
|
307
|
+
" categories: [ // REQUIRED 1–10 entries",
|
|
308
|
+
" { id: 'bug', label: 'Bug or crash', emoji?: '🐞', hint?: '…' },",
|
|
309
|
+
" { id: 'abuse', label: 'Harassment or abuse', emoji?: '🚫' },",
|
|
310
|
+
" { id: 'spam', label: 'Spam', emoji?: '🧹' },",
|
|
311
|
+
" { id: 'privacy', label: 'Privacy concern', emoji?: '🔒' },",
|
|
312
|
+
" { id: 'other', label: 'Something else', emoji?: '💬' }",
|
|
313
|
+
" ],",
|
|
314
|
+
" emailField?: { enabled, placeholder?, required? },",
|
|
315
|
+
" success: { title, body, ctaLabel?, ctaUrl? },",
|
|
316
|
+
" hero?: { theme?, eyebrow?, accentColor?, titleFont? }",
|
|
317
|
+
" }",
|
|
318
|
+
"",
|
|
319
|
+
"Category ids must be snake_case ([a-z][a-z0-9_]*). The public submit endpoint validates posted category against this list — unknown ids return 422.",
|
|
320
|
+
].join("\n"),
|
|
321
|
+
inputSchema: z.object({
|
|
322
|
+
appIdOrSlug: z.string().min(1),
|
|
323
|
+
config: z.unknown(),
|
|
324
|
+
}),
|
|
325
|
+
handler: (input, cfg) => apiFetch(cfg, "PUT", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/report`, input.config),
|
|
326
|
+
};
|
|
327
|
+
export const publishReportFlow = {
|
|
328
|
+
name: "publish_report_flow",
|
|
329
|
+
description: "Promote the draft report config to the live published version. Visitors at appmate.cloud/report/{appSlug} see the new version immediately.",
|
|
330
|
+
inputSchema: z.object({ appIdOrSlug: z.string().min(1) }),
|
|
331
|
+
handler: (input, cfg) => apiFetch(cfg, "POST", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/flows/report/publish`),
|
|
332
|
+
};
|
|
333
|
+
export const listReportSubmissions = {
|
|
334
|
+
name: "list_report_submissions",
|
|
335
|
+
description: "Paginated list of report submissions for an app. Each row: { id, message, category, email, source, createdAt }. Pass `category` to scope to one bucket (e.g. 'bug') for triage.",
|
|
336
|
+
inputSchema: z.object({
|
|
337
|
+
appIdOrSlug: z.string().min(1),
|
|
338
|
+
limit: z.number().int().min(1).max(200).optional(),
|
|
339
|
+
cursor: z.string().optional(),
|
|
340
|
+
category: z.string().optional(),
|
|
341
|
+
}),
|
|
342
|
+
handler: (input, cfg) => {
|
|
343
|
+
const qs = new URLSearchParams();
|
|
344
|
+
if (input.limit !== undefined)
|
|
345
|
+
qs.set("limit", String(input.limit));
|
|
346
|
+
if (input.cursor)
|
|
347
|
+
qs.set("cursor", input.cursor);
|
|
348
|
+
if (input.category)
|
|
349
|
+
qs.set("category", input.category);
|
|
350
|
+
const tail = qs.toString() ? `?${qs.toString()}` : "";
|
|
351
|
+
return apiFetch(cfg, "GET", `/api/v1/apps/${encodeURIComponent(input.appIdOrSlug)}/report/submissions${tail}`);
|
|
352
|
+
},
|
|
353
|
+
};
|
|
185
354
|
// Registered alphabetically so `list_tools` reads predictably.
|
|
186
355
|
export const ALL_TOOLS = [
|
|
187
356
|
createApp,
|
|
188
357
|
exportWaitlistCsv,
|
|
189
358
|
getApp,
|
|
190
359
|
getCancelFlow,
|
|
360
|
+
getFeedbackFlow,
|
|
361
|
+
getReportFlow,
|
|
191
362
|
getWaitlistFlow,
|
|
192
363
|
listApps,
|
|
364
|
+
listFeedbackSubmissions,
|
|
365
|
+
listReportSubmissions,
|
|
193
366
|
listWaitlistSignups,
|
|
194
367
|
publishCancelFlow,
|
|
368
|
+
publishFeedbackFlow,
|
|
369
|
+
publishReportFlow,
|
|
195
370
|
publishWaitlistFlow,
|
|
196
371
|
updateCancelDraft,
|
|
372
|
+
updateFeedbackDraft,
|
|
373
|
+
updateReportDraft,
|
|
197
374
|
updateWaitlistDraft,
|
|
198
375
|
];
|
package/package.json
CHANGED