@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.
Files changed (2) hide show
  1. package/index.js +271 -0
  2. 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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentionova/mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "MCP server for the Mentionova API - connect AI assistants to your AI search visibility data",
5
5
  "type": "module",
6
6
  "main": "index.js",