@mentionova/mcp-server 1.1.0 → 1.3.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 +663 -0
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -249,6 +249,60 @@ server.tool(
249
249
  }
250
250
  );
251
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
+
252
306
  // --- Write: Prompts ---
253
307
 
254
308
  server.tool(
@@ -315,6 +369,615 @@ server.tool(
315
369
  }
316
370
  );
317
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
+
476
+ // --- Workflows ---
477
+
478
+ server.tool(
479
+ "mentionova_list_workflows",
480
+ "List automation workflows in a workspace",
481
+ {
482
+ workspace_id: z.string().describe("Workspace UUID"),
483
+ status: z.enum(["draft", "active", "paused", "archived"]).optional().describe("Filter by status"),
484
+ limit: z.number().optional(),
485
+ offset: z.number().optional(),
486
+ },
487
+ async ({ workspace_id, status, limit, offset }) => {
488
+ const data = await api(`/workspaces/${workspace_id}/workflows`, { status, limit, offset });
489
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
490
+ }
491
+ );
492
+
493
+ server.tool(
494
+ "mentionova_create_workflow",
495
+ "Create a new automation workflow",
496
+ {
497
+ workspace_id: z.string().describe("Workspace UUID"),
498
+ name: z.string().describe("Workflow name"),
499
+ description: z.string().optional(),
500
+ status: z.enum(["draft", "active", "paused"]).optional(),
501
+ graph: z.object({ steps: z.array(z.any()), edges: z.array(z.any()) }).optional().describe("DAG definition"),
502
+ schedule_cron: z.string().optional().describe("Cron expression for scheduled runs"),
503
+ },
504
+ async ({ workspace_id, ...body }) => {
505
+ const data = await apiPost(`/workspaces/${workspace_id}/workflows`, body);
506
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
507
+ }
508
+ );
509
+
510
+ server.tool(
511
+ "mentionova_get_workflow",
512
+ "Get a specific workflow by ID",
513
+ {
514
+ workspace_id: z.string().describe("Workspace UUID"),
515
+ workflow_id: z.string().describe("Workflow UUID"),
516
+ },
517
+ async ({ workspace_id, workflow_id }) => {
518
+ const data = await api(`/workspaces/${workspace_id}/workflows/${workflow_id}`);
519
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
520
+ }
521
+ );
522
+
523
+ server.tool(
524
+ "mentionova_update_workflow",
525
+ "Update a workflow's name, status, graph, or schedule",
526
+ {
527
+ workspace_id: z.string().describe("Workspace UUID"),
528
+ workflow_id: z.string().describe("Workflow UUID"),
529
+ name: z.string().optional(),
530
+ description: z.string().optional(),
531
+ status: z.enum(["draft", "active", "paused", "archived"]).optional(),
532
+ graph: z.object({ steps: z.array(z.any()), edges: z.array(z.any()) }).optional(),
533
+ schedule_cron: z.string().optional(),
534
+ },
535
+ async ({ workspace_id, workflow_id, ...body }) => {
536
+ const data = await apiPatch(`/workspaces/${workspace_id}/workflows/${workflow_id}`, body);
537
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
538
+ }
539
+ );
540
+
541
+ server.tool(
542
+ "mentionova_delete_workflow",
543
+ "Delete a workflow",
544
+ {
545
+ workspace_id: z.string().describe("Workspace UUID"),
546
+ workflow_id: z.string().describe("Workflow UUID"),
547
+ },
548
+ async ({ workspace_id, workflow_id }) => {
549
+ const data = await apiDelete(`/workspaces/${workspace_id}/workflows/${workflow_id}`);
550
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
551
+ }
552
+ );
553
+
554
+ server.tool(
555
+ "mentionova_list_workflow_runs",
556
+ "List runs for a specific workflow",
557
+ {
558
+ workspace_id: z.string().describe("Workspace UUID"),
559
+ workflow_id: z.string().describe("Workflow UUID"),
560
+ status: z.enum(["pending", "running", "completed", "partial", "failed", "cancelled"]).optional(),
561
+ limit: z.number().optional(),
562
+ offset: z.number().optional(),
563
+ },
564
+ async ({ workspace_id, workflow_id, status, limit, offset }) => {
565
+ const data = await api(`/workspaces/${workspace_id}/workflows/${workflow_id}/runs`, { status, limit, offset });
566
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
567
+ }
568
+ );
569
+
570
+ server.tool(
571
+ "mentionova_trigger_workflow",
572
+ "Trigger a workflow run via the API",
573
+ {
574
+ workspace_id: z.string().describe("Workspace UUID"),
575
+ workflow_id: z.string().describe("Workflow UUID"),
576
+ input: z.record(z.any()).optional().describe("Input payload for the run"),
577
+ },
578
+ async ({ workspace_id, workflow_id, input }) => {
579
+ const data = await apiPost(`/workspaces/${workspace_id}/workflows/${workflow_id}/runs`, { input });
580
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
581
+ }
582
+ );
583
+
584
+ // --- Reddit Engagement ---
585
+
586
+ server.tool(
587
+ "mentionova_list_reddit_comments",
588
+ "List Reddit comment drafts (engagement queue) for a workspace",
589
+ {
590
+ workspace_id: z.string().describe("Workspace UUID"),
591
+ status: z.enum(["draft", "approved", "posted", "skipped"]).optional(),
592
+ subreddit: z.string().optional().describe("Filter by subreddit"),
593
+ limit: z.number().optional(),
594
+ offset: z.number().optional(),
595
+ },
596
+ async ({ workspace_id, status, subreddit, limit, offset }) => {
597
+ const data = await api(`/workspaces/${workspace_id}/reddit`, { status, subreddit, limit, offset });
598
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
599
+ }
600
+ );
601
+
602
+ server.tool(
603
+ "mentionova_update_reddit_comment",
604
+ "Update a Reddit comment draft (edit text, change status, assign)",
605
+ {
606
+ workspace_id: z.string().describe("Workspace UUID"),
607
+ comment_id: z.string().describe("Comment UUID"),
608
+ status: z.enum(["draft", "approved", "posted", "skipped"]).optional(),
609
+ edited_comment: z.string().optional().describe("Edited comment text"),
610
+ assigned_to: z.string().optional().describe("User UUID to assign to"),
611
+ },
612
+ async ({ workspace_id, comment_id, ...body }) => {
613
+ const data = await apiPatch(`/workspaces/${workspace_id}/reddit`, { comment_id, ...body });
614
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
615
+ }
616
+ );
617
+
618
+ server.tool(
619
+ "mentionova_delete_reddit_comment",
620
+ "Delete a Reddit comment draft",
621
+ {
622
+ workspace_id: z.string().describe("Workspace UUID"),
623
+ comment_id: z.string().describe("Comment UUID"),
624
+ },
625
+ async ({ workspace_id, comment_id }) => {
626
+ const data = await apiDelete(`/workspaces/${workspace_id}/reddit?comment_id=${comment_id}`);
627
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
628
+ }
629
+ );
630
+
631
+ // --- Reports ---
632
+
633
+ server.tool(
634
+ "mentionova_list_shared_reports",
635
+ "List shared report links for a workspace",
636
+ {
637
+ workspace_id: z.string().describe("Workspace UUID"),
638
+ include_revoked: z.enum(["true", "false"]).optional(),
639
+ limit: z.number().optional(),
640
+ offset: z.number().optional(),
641
+ },
642
+ async ({ workspace_id, include_revoked, limit, offset }) => {
643
+ const data = await api(`/workspaces/${workspace_id}/reports`, { include_revoked, limit, offset });
644
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
645
+ }
646
+ );
647
+
648
+ server.tool(
649
+ "mentionova_create_shared_report",
650
+ "Create a shareable report link for a workspace",
651
+ {
652
+ workspace_id: z.string().describe("Workspace UUID"),
653
+ channel: z.string().optional().describe("Filter report to a specific AI engine channel"),
654
+ expires_at: z.string().optional().describe("Expiration date (ISO 8601)"),
655
+ },
656
+ async ({ workspace_id, channel, expires_at }) => {
657
+ const data = await apiPost(`/workspaces/${workspace_id}/reports`, { channel, expires_at });
658
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
659
+ }
660
+ );
661
+
662
+ server.tool(
663
+ "mentionova_revoke_shared_report",
664
+ "Revoke a shared report link",
665
+ {
666
+ workspace_id: z.string().describe("Workspace UUID"),
667
+ report_id: z.string().describe("Shared report UUID"),
668
+ },
669
+ async ({ workspace_id, report_id }) => {
670
+ const data = await apiDelete(`/workspaces/${workspace_id}/reports?report_id=${report_id}`);
671
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
672
+ }
673
+ );
674
+
675
+ server.tool(
676
+ "mentionova_list_geo_reports",
677
+ "List GEO (weekly AI visibility) reports for a workspace",
678
+ {
679
+ workspace_id: z.string().describe("Workspace UUID"),
680
+ status: z.enum(["pending", "generating", "ready", "failed"]).optional(),
681
+ limit: z.number().optional(),
682
+ offset: z.number().optional(),
683
+ },
684
+ async ({ workspace_id, status, limit, offset }) => {
685
+ const data = await api(`/workspaces/${workspace_id}/reports/geo`, { status, limit, offset });
686
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
687
+ }
688
+ );
689
+
690
+ server.tool(
691
+ "mentionova_get_geo_report",
692
+ "Get a GEO report with its content plays",
693
+ {
694
+ workspace_id: z.string().describe("Workspace UUID"),
695
+ report_id: z.string().describe("GEO report UUID"),
696
+ },
697
+ async ({ workspace_id, report_id }) => {
698
+ const data = await api(`/workspaces/${workspace_id}/reports/geo/${report_id}`);
699
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
700
+ }
701
+ );
702
+
703
+ // --- Grid Columns ---
704
+
705
+ server.tool(
706
+ "mentionova_list_grid_columns",
707
+ "List columns in a content grid",
708
+ {
709
+ workspace_id: z.string().describe("Workspace UUID"),
710
+ grid_id: z.string().describe("Grid UUID"),
711
+ },
712
+ async ({ workspace_id, grid_id }) => {
713
+ const data = await api(`/workspaces/${workspace_id}/grids/${grid_id}/columns`);
714
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
715
+ }
716
+ );
717
+
718
+ server.tool(
719
+ "mentionova_create_grid_column",
720
+ "Add a column to a content grid",
721
+ {
722
+ workspace_id: z.string().describe("Workspace UUID"),
723
+ grid_id: z.string().describe("Grid UUID"),
724
+ key: z.string().describe("Column key (unique within grid)"),
725
+ display_name: z.string().describe("Column display name"),
726
+ column_type: z.string().describe("Column type (e.g. text, url, ai_generate)"),
727
+ config: z.record(z.any()).optional().describe("Column configuration"),
728
+ position: z.number().optional().describe("Position (auto-assigned if omitted)"),
729
+ depends_on: z.array(z.string()).optional().describe("Keys of columns this depends on"),
730
+ is_output: z.boolean().optional(),
731
+ },
732
+ async ({ workspace_id, grid_id, ...body }) => {
733
+ const data = await apiPost(`/workspaces/${workspace_id}/grids/${grid_id}/columns`, body);
734
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
735
+ }
736
+ );
737
+
738
+ server.tool(
739
+ "mentionova_update_grid_column",
740
+ "Update a grid column's name, type, config, or position",
741
+ {
742
+ workspace_id: z.string().describe("Workspace UUID"),
743
+ grid_id: z.string().describe("Grid UUID"),
744
+ column_id: z.string().describe("Column UUID"),
745
+ display_name: z.string().optional(),
746
+ column_type: z.string().optional(),
747
+ config: z.record(z.any()).optional(),
748
+ depends_on: z.array(z.string()).optional(),
749
+ is_output: z.boolean().optional(),
750
+ position: z.number().optional(),
751
+ },
752
+ async ({ workspace_id, grid_id, column_id, ...body }) => {
753
+ const data = await apiPatch(`/workspaces/${workspace_id}/grids/${grid_id}/columns/${column_id}`, body);
754
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
755
+ }
756
+ );
757
+
758
+ server.tool(
759
+ "mentionova_delete_grid_column",
760
+ "Delete a grid column and its cells",
761
+ {
762
+ workspace_id: z.string().describe("Workspace UUID"),
763
+ grid_id: z.string().describe("Grid UUID"),
764
+ column_id: z.string().describe("Column UUID"),
765
+ },
766
+ async ({ workspace_id, grid_id, column_id }) => {
767
+ const data = await apiDelete(`/workspaces/${workspace_id}/grids/${grid_id}/columns/${column_id}`);
768
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
769
+ }
770
+ );
771
+
772
+ // --- Grid Rows ---
773
+
774
+ server.tool(
775
+ "mentionova_list_grid_rows",
776
+ "List rows in a content grid",
777
+ {
778
+ workspace_id: z.string().describe("Workspace UUID"),
779
+ grid_id: z.string().describe("Grid UUID"),
780
+ limit: z.number().optional(),
781
+ offset: z.number().optional(),
782
+ },
783
+ async ({ workspace_id, grid_id, limit, offset }) => {
784
+ const data = await api(`/workspaces/${workspace_id}/grids/${grid_id}/rows`, { limit, offset });
785
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
786
+ }
787
+ );
788
+
789
+ server.tool(
790
+ "mentionova_create_grid_row",
791
+ "Add a row to a content grid",
792
+ {
793
+ workspace_id: z.string().describe("Workspace UUID"),
794
+ grid_id: z.string().describe("Grid UUID"),
795
+ source: z.enum(["manual", "csv", "webhook"]).optional().describe("Row source (default: manual)"),
796
+ source_ref: z.record(z.any()).optional(),
797
+ position: z.number().optional(),
798
+ },
799
+ async ({ workspace_id, grid_id, ...body }) => {
800
+ const data = await apiPost(`/workspaces/${workspace_id}/grids/${grid_id}/rows`, body);
801
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
802
+ }
803
+ );
804
+
805
+ server.tool(
806
+ "mentionova_get_grid_row",
807
+ "Get a grid row with all its cell values",
808
+ {
809
+ workspace_id: z.string().describe("Workspace UUID"),
810
+ grid_id: z.string().describe("Grid UUID"),
811
+ row_id: z.string().describe("Row UUID"),
812
+ },
813
+ async ({ workspace_id, grid_id, row_id }) => {
814
+ const data = await api(`/workspaces/${workspace_id}/grids/${grid_id}/rows/${row_id}`);
815
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
816
+ }
817
+ );
818
+
819
+ server.tool(
820
+ "mentionova_update_grid_row",
821
+ "Update a grid row's position or source reference",
822
+ {
823
+ workspace_id: z.string().describe("Workspace UUID"),
824
+ grid_id: z.string().describe("Grid UUID"),
825
+ row_id: z.string().describe("Row UUID"),
826
+ position: z.number().optional(),
827
+ source_ref: z.record(z.any()).optional(),
828
+ },
829
+ async ({ workspace_id, grid_id, row_id, ...body }) => {
830
+ const data = await apiPatch(`/workspaces/${workspace_id}/grids/${grid_id}/rows/${row_id}`, body);
831
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
832
+ }
833
+ );
834
+
835
+ server.tool(
836
+ "mentionova_delete_grid_row",
837
+ "Delete a grid row and its cells",
838
+ {
839
+ workspace_id: z.string().describe("Workspace UUID"),
840
+ grid_id: z.string().describe("Grid UUID"),
841
+ row_id: z.string().describe("Row UUID"),
842
+ },
843
+ async ({ workspace_id, grid_id, row_id }) => {
844
+ const data = await apiDelete(`/workspaces/${workspace_id}/grids/${grid_id}/rows/${row_id}`);
845
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
846
+ }
847
+ );
848
+
849
+ // --- Grid Cells ---
850
+
851
+ server.tool(
852
+ "mentionova_list_grid_cells",
853
+ "List all cells in a content grid",
854
+ {
855
+ workspace_id: z.string().describe("Workspace UUID"),
856
+ grid_id: z.string().describe("Grid UUID"),
857
+ limit: z.number().optional(),
858
+ offset: z.number().optional(),
859
+ },
860
+ async ({ workspace_id, grid_id, limit, offset }) => {
861
+ const data = await api(`/workspaces/${workspace_id}/grids/${grid_id}/cells`, { limit, offset });
862
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
863
+ }
864
+ );
865
+
866
+ server.tool(
867
+ "mentionova_update_grid_cell",
868
+ "Update (or create) a cell value in a grid",
869
+ {
870
+ workspace_id: z.string().describe("Workspace UUID"),
871
+ grid_id: z.string().describe("Grid UUID"),
872
+ row_id: z.string().describe("Row UUID"),
873
+ column_id: z.string().describe("Column UUID"),
874
+ value_text: z.string().optional(),
875
+ value_json: z.record(z.any()).optional(),
876
+ value_number: z.number().optional(),
877
+ },
878
+ async ({ workspace_id, grid_id, ...body }) => {
879
+ const data = await apiPatch(`/workspaces/${workspace_id}/grids/${grid_id}/cells`, body);
880
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
881
+ }
882
+ );
883
+
884
+ // --- Marketplace ---
885
+
886
+ server.tool(
887
+ "mentionova_list_marketplace_profiles",
888
+ "Browse marketplace profiles for collaboration opportunities",
889
+ {
890
+ status: z.enum(["live", "hidden"]).optional(),
891
+ industry: z.string().optional(),
892
+ limit: z.number().optional(),
893
+ offset: z.number().optional(),
894
+ },
895
+ async ({ status, industry, limit, offset }) => {
896
+ const data = await api("/marketplace/profiles", { status, industry, limit, offset });
897
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
898
+ }
899
+ );
900
+
901
+ server.tool(
902
+ "mentionova_get_marketplace_profile",
903
+ "Get a specific marketplace profile",
904
+ {
905
+ profile_id: z.string().describe("Profile UUID"),
906
+ },
907
+ async ({ profile_id }) => {
908
+ const data = await api(`/marketplace/profiles/${profile_id}`);
909
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
910
+ }
911
+ );
912
+
913
+ server.tool(
914
+ "mentionova_create_marketplace_profile",
915
+ "Create a marketplace profile for one of your workspaces",
916
+ {
917
+ workspace_id: z.string().describe("Workspace UUID to create profile for"),
918
+ display_name: z.string().describe("Display name"),
919
+ tagline: z.string().optional(),
920
+ description: z.string().optional(),
921
+ industry: z.string().optional(),
922
+ website_url: z.string().optional(),
923
+ collab_types: z.array(z.enum(["newsletter_swap", "social_cross_post", "co_content", "bundle", "event"])).optional(),
924
+ looking_for: z.string().optional(),
925
+ show_stats: z.boolean().optional(),
926
+ },
927
+ async (body) => {
928
+ const data = await apiPost("/marketplace/profiles", body);
929
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
930
+ }
931
+ );
932
+
933
+ server.tool(
934
+ "mentionova_update_marketplace_profile",
935
+ "Update your marketplace profile",
936
+ {
937
+ profile_id: z.string().describe("Profile UUID"),
938
+ display_name: z.string().optional(),
939
+ tagline: z.string().optional(),
940
+ description: z.string().optional(),
941
+ industry: z.string().optional(),
942
+ website_url: z.string().optional(),
943
+ collab_types: z.array(z.enum(["newsletter_swap", "social_cross_post", "co_content", "bundle", "event"])).optional(),
944
+ looking_for: z.string().optional(),
945
+ show_stats: z.boolean().optional(),
946
+ status: z.enum(["live", "hidden"]).optional(),
947
+ },
948
+ async ({ profile_id, ...body }) => {
949
+ const data = await apiPatch(`/marketplace/profiles/${profile_id}`, body);
950
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
951
+ }
952
+ );
953
+
954
+ server.tool(
955
+ "mentionova_express_interest",
956
+ "Express interest in collaborating with a marketplace profile",
957
+ {
958
+ to_profile: z.string().describe("Target profile UUID"),
959
+ type: z.enum(["interest", "reachout", "pass"]).describe("Type of interest"),
960
+ message: z.string().optional().describe("Message to include"),
961
+ },
962
+ async (body) => {
963
+ const data = await apiPost("/marketplace/interests", body);
964
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
965
+ }
966
+ );
967
+
968
+ server.tool(
969
+ "mentionova_list_marketplace_matches",
970
+ "List your marketplace matches (mutual interests / accepted reachouts)",
971
+ {
972
+ limit: z.number().optional(),
973
+ offset: z.number().optional(),
974
+ },
975
+ async ({ limit, offset }) => {
976
+ const data = await api("/marketplace/matches", { limit, offset });
977
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
978
+ }
979
+ );
980
+
318
981
  // Start the server
319
982
  const transport = new StdioServerTransport();
320
983
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentionova/mcp-server",
3
- "version": "1.1.0",
3
+ "version": "1.3.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",