@mentionova/mcp-server 1.0.0 → 1.2.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/index.js +271 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -27,6 +27,53 @@ async function api(path, params = {}) {
|
|
|
27
27
|
return json;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
async function apiPost(path, body = {}) {
|
|
31
|
+
const url = new URL(`/api/v1${path}`, BASE_URL);
|
|
32
|
+
|
|
33
|
+
const res = await fetch(url.toString(), {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: {
|
|
36
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify(body),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const json = await res.json();
|
|
43
|
+
if (!res.ok) throw new Error(json.error || `API error ${res.status}`);
|
|
44
|
+
return json;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async function apiPatch(path, body = {}) {
|
|
48
|
+
const url = new URL(`/api/v1${path}`, BASE_URL);
|
|
49
|
+
|
|
50
|
+
const res = await fetch(url.toString(), {
|
|
51
|
+
method: "PATCH",
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
},
|
|
56
|
+
body: JSON.stringify(body),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const json = await res.json();
|
|
60
|
+
if (!res.ok) throw new Error(json.error || `API error ${res.status}`);
|
|
61
|
+
return json;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async function apiDelete(path) {
|
|
65
|
+
const url = new URL(`/api/v1${path}`, BASE_URL);
|
|
66
|
+
|
|
67
|
+
const res = await fetch(url.toString(), {
|
|
68
|
+
method: "DELETE",
|
|
69
|
+
headers: { Authorization: `Bearer ${API_KEY}` },
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const json = await res.json();
|
|
73
|
+
if (!res.ok) throw new Error(json.error || `API error ${res.status}`);
|
|
74
|
+
return json;
|
|
75
|
+
}
|
|
76
|
+
|
|
30
77
|
const server = new McpServer({
|
|
31
78
|
name: "mentionova",
|
|
32
79
|
version: "1.0.0",
|
|
@@ -202,6 +249,230 @@ server.tool(
|
|
|
202
249
|
}
|
|
203
250
|
);
|
|
204
251
|
|
|
252
|
+
// --- Write: Workspaces ---
|
|
253
|
+
|
|
254
|
+
server.tool(
|
|
255
|
+
"mentionova_create_workspace",
|
|
256
|
+
"Create a new workspace to track a brand's AI search visibility",
|
|
257
|
+
{
|
|
258
|
+
name: z.string().describe("Workspace name (e.g. brand or client name)"),
|
|
259
|
+
description: z.string().optional().describe("Description"),
|
|
260
|
+
website_url: z.string().optional().describe("Brand website URL"),
|
|
261
|
+
industry: z.string().optional().describe("Industry"),
|
|
262
|
+
competitor_domains: z.array(z.string()).optional().describe("Competitor website domains"),
|
|
263
|
+
competitor_names: z.array(z.string()).optional().describe("Competitor brand names"),
|
|
264
|
+
seed_keywords: z.array(z.string()).optional().describe("Initial keywords to track"),
|
|
265
|
+
brand_aliases: z.array(z.string()).optional().describe("Alternative brand names"),
|
|
266
|
+
},
|
|
267
|
+
async (params) => {
|
|
268
|
+
const data = await apiPost("/workspaces", params);
|
|
269
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
270
|
+
}
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
server.tool(
|
|
274
|
+
"mentionova_update_workspace",
|
|
275
|
+
"Update a workspace's name, competitors, keywords, or other settings",
|
|
276
|
+
{
|
|
277
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
278
|
+
name: z.string().optional().describe("New name"),
|
|
279
|
+
description: z.string().optional().describe("New description"),
|
|
280
|
+
website_url: z.string().optional().describe("New website URL"),
|
|
281
|
+
industry: z.string().optional().describe("New industry"),
|
|
282
|
+
competitor_domains: z.array(z.string()).optional().describe("New competitor domains"),
|
|
283
|
+
competitor_names: z.array(z.string()).optional().describe("New competitor names"),
|
|
284
|
+
seed_keywords: z.array(z.string()).optional().describe("New keywords"),
|
|
285
|
+
brand_aliases: z.array(z.string()).optional().describe("New brand aliases"),
|
|
286
|
+
client_context: z.string().optional().describe("Client context/brief"),
|
|
287
|
+
},
|
|
288
|
+
async ({ workspace_id, ...body }) => {
|
|
289
|
+
const data = await apiPatch(`/workspaces/${workspace_id}`, body);
|
|
290
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
server.tool(
|
|
295
|
+
"mentionova_delete_workspace",
|
|
296
|
+
"Delete a workspace and all its prompts, runs, citations, and data",
|
|
297
|
+
{
|
|
298
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
299
|
+
},
|
|
300
|
+
async ({ workspace_id }) => {
|
|
301
|
+
const data = await apiDelete(`/workspaces/${workspace_id}`);
|
|
302
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
// --- Write: Prompts ---
|
|
307
|
+
|
|
308
|
+
server.tool(
|
|
309
|
+
"mentionova_create_prompt",
|
|
310
|
+
"Create one or more prompts (search queries) to track in a workspace. These will be monitored across AI engines on a schedule.",
|
|
311
|
+
{
|
|
312
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
313
|
+
prompt_text: z.string().optional().describe("Single prompt text"),
|
|
314
|
+
prompt_texts: z.array(z.string()).optional().describe("Multiple prompt texts"),
|
|
315
|
+
status: z.enum(["active", "paused"]).optional().describe("Initial status (default: active)"),
|
|
316
|
+
schedule_frequency: z.enum(["daily", "weekly", "biweekly", "monthly"]).optional().describe("Run frequency (default: weekly)"),
|
|
317
|
+
},
|
|
318
|
+
async ({ workspace_id, prompt_text, prompt_texts, status, schedule_frequency }) => {
|
|
319
|
+
const body = { prompt_text, prompt_texts, status, schedule_frequency };
|
|
320
|
+
const data = await apiPost(`/workspaces/${workspace_id}/prompts`, body);
|
|
321
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
server.tool(
|
|
326
|
+
"mentionova_update_prompt",
|
|
327
|
+
"Update a prompt's text, status, schedule, or channels",
|
|
328
|
+
{
|
|
329
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
330
|
+
prompt_id: z.string().describe("Prompt UUID"),
|
|
331
|
+
prompt_text: z.string().optional().describe("New prompt text"),
|
|
332
|
+
status: z.enum(["active", "paused", "archived"]).optional().describe("New status"),
|
|
333
|
+
schedule_frequency: z.enum(["daily", "weekly", "biweekly", "monthly"]).optional().describe("New schedule"),
|
|
334
|
+
channels: z.array(z.string()).optional().describe("AI engine channels to run on"),
|
|
335
|
+
},
|
|
336
|
+
async ({ workspace_id, prompt_id, prompt_text, status, schedule_frequency, channels }) => {
|
|
337
|
+
const body = { prompt_text, status, schedule_frequency, channels };
|
|
338
|
+
const data = await apiPatch(`/workspaces/${workspace_id}/prompts/${prompt_id}`, body);
|
|
339
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
340
|
+
}
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
server.tool(
|
|
344
|
+
"mentionova_delete_prompt",
|
|
345
|
+
"Delete a prompt and all its associated runs and citations",
|
|
346
|
+
{
|
|
347
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
348
|
+
prompt_id: z.string().describe("Prompt UUID"),
|
|
349
|
+
},
|
|
350
|
+
async ({ workspace_id, prompt_id }) => {
|
|
351
|
+
const data = await apiDelete(`/workspaces/${workspace_id}/prompts/${prompt_id}`);
|
|
352
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
353
|
+
}
|
|
354
|
+
);
|
|
355
|
+
|
|
356
|
+
// --- Write: Runs ---
|
|
357
|
+
|
|
358
|
+
server.tool(
|
|
359
|
+
"mentionova_trigger_run",
|
|
360
|
+
"Trigger a new run for a prompt. Executes the prompt across AI engines and captures citations and mentions. Returns 202 (accepted) immediately; the run processes in the background.",
|
|
361
|
+
{
|
|
362
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
363
|
+
prompt_id: z.string().describe("Prompt UUID to run"),
|
|
364
|
+
channels: z.array(z.enum(["perplexity", "claude", "chatgpt", "gemini", "google", "reddit"])).optional().describe("Specific channels to run (default: all)"),
|
|
365
|
+
},
|
|
366
|
+
async ({ workspace_id, prompt_id, channels }) => {
|
|
367
|
+
const data = await apiPost(`/workspaces/${workspace_id}/prompts/${prompt_id}/run`, { channels });
|
|
368
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
369
|
+
}
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// --- Write: Runs ---
|
|
373
|
+
|
|
374
|
+
server.tool(
|
|
375
|
+
"mentionova_delete_run",
|
|
376
|
+
"Delete a specific run and its associated data",
|
|
377
|
+
{
|
|
378
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
379
|
+
run_id: z.string().describe("Run UUID to delete"),
|
|
380
|
+
},
|
|
381
|
+
async ({ workspace_id, run_id }) => {
|
|
382
|
+
const data = await apiDelete(`/workspaces/${workspace_id}/runs?run_id=${run_id}`);
|
|
383
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
384
|
+
}
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
// --- Write: Citations ---
|
|
388
|
+
|
|
389
|
+
server.tool(
|
|
390
|
+
"mentionova_delete_citation",
|
|
391
|
+
"Delete a specific citation",
|
|
392
|
+
{
|
|
393
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
394
|
+
citation_id: z.string().describe("Citation UUID to delete"),
|
|
395
|
+
},
|
|
396
|
+
async ({ workspace_id, citation_id }) => {
|
|
397
|
+
const data = await apiDelete(`/workspaces/${workspace_id}/citations?citation_id=${citation_id}`);
|
|
398
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
399
|
+
}
|
|
400
|
+
);
|
|
401
|
+
|
|
402
|
+
// --- Write: Grids ---
|
|
403
|
+
|
|
404
|
+
server.tool(
|
|
405
|
+
"mentionova_create_grid",
|
|
406
|
+
"Create a new content grid in a workspace",
|
|
407
|
+
{
|
|
408
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
409
|
+
name: z.string().describe("Grid name"),
|
|
410
|
+
description: z.string().optional().describe("Grid description"),
|
|
411
|
+
template_id: z.string().optional().describe("Template UUID to base grid on"),
|
|
412
|
+
},
|
|
413
|
+
async ({ workspace_id, ...body }) => {
|
|
414
|
+
const data = await apiPost(`/workspaces/${workspace_id}/grids`, body);
|
|
415
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
416
|
+
}
|
|
417
|
+
);
|
|
418
|
+
|
|
419
|
+
server.tool(
|
|
420
|
+
"mentionova_update_grid",
|
|
421
|
+
"Update a grid's name, description, or status",
|
|
422
|
+
{
|
|
423
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
424
|
+
grid_id: z.string().describe("Grid UUID"),
|
|
425
|
+
name: z.string().optional().describe("New name"),
|
|
426
|
+
description: z.string().optional().describe("New description"),
|
|
427
|
+
status: z.enum(["active", "archived"]).optional().describe("New status"),
|
|
428
|
+
},
|
|
429
|
+
async ({ workspace_id, ...body }) => {
|
|
430
|
+
const data = await apiPatch(`/workspaces/${workspace_id}/grids`, body);
|
|
431
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
432
|
+
}
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
server.tool(
|
|
436
|
+
"mentionova_delete_grid",
|
|
437
|
+
"Delete a grid",
|
|
438
|
+
{
|
|
439
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
440
|
+
grid_id: z.string().describe("Grid UUID to delete"),
|
|
441
|
+
},
|
|
442
|
+
async ({ workspace_id, grid_id }) => {
|
|
443
|
+
const data = await apiDelete(`/workspaces/${workspace_id}/grids?grid_id=${grid_id}`);
|
|
444
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
445
|
+
}
|
|
446
|
+
);
|
|
447
|
+
|
|
448
|
+
// --- Write: Alerts ---
|
|
449
|
+
|
|
450
|
+
server.tool(
|
|
451
|
+
"mentionova_mark_alert_read",
|
|
452
|
+
"Mark an alert/notification as read",
|
|
453
|
+
{
|
|
454
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
455
|
+
alert_id: z.string().describe("Alert UUID"),
|
|
456
|
+
},
|
|
457
|
+
async ({ workspace_id, alert_id }) => {
|
|
458
|
+
const data = await apiPatch(`/workspaces/${workspace_id}/alerts`, { alert_id });
|
|
459
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
server.tool(
|
|
464
|
+
"mentionova_delete_alert",
|
|
465
|
+
"Delete an alert/notification",
|
|
466
|
+
{
|
|
467
|
+
workspace_id: z.string().describe("Workspace UUID"),
|
|
468
|
+
alert_id: z.string().describe("Alert UUID to delete"),
|
|
469
|
+
},
|
|
470
|
+
async ({ workspace_id, alert_id }) => {
|
|
471
|
+
const data = await apiDelete(`/workspaces/${workspace_id}/alerts?alert_id=${alert_id}`);
|
|
472
|
+
return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
|
|
473
|
+
}
|
|
474
|
+
);
|
|
475
|
+
|
|
205
476
|
// Start the server
|
|
206
477
|
const transport = new StdioServerTransport();
|
|
207
478
|
await server.connect(transport);
|