@mentionova/mcp-server 1.0.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 (3) hide show
  1. package/README.md +85 -0
  2. package/index.js +207 -0
  3. package/package.json +38 -0
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # Mentionova MCP Server
2
+
3
+ Connect AI assistants to your [Mentionova](https://app.mentionova.com) data. Query workspaces, prompts, runs, citations, brand mentions, and more directly from Claude Code, Claude Desktop, or any MCP-compatible client.
4
+
5
+ ## Prerequisites
6
+
7
+ - A Mentionova account on a **Scale plan or higher**
8
+ - An API key (create one at Settings > API in the Mentionova dashboard)
9
+ - Node.js 18+
10
+
11
+ ## Setup
12
+
13
+ ### Claude Code
14
+
15
+ Add to your Claude Code settings (`~/.claude/settings.json` or project-level `.claude/settings.json`):
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "mentionova": {
21
+ "command": "npx",
22
+ "args": ["-y", "@mentionova/mcp-server"],
23
+ "env": {
24
+ "MENTIONOVA_API_KEY": "mn_live_your_key_here"
25
+ }
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ### Claude Desktop
32
+
33
+ Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on Mac):
34
+
35
+ ```json
36
+ {
37
+ "mcpServers": {
38
+ "mentionova": {
39
+ "command": "npx",
40
+ "args": ["-y", "@mentionova/mcp-server"],
41
+ "env": {
42
+ "MENTIONOVA_API_KEY": "mn_live_your_key_here"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ Then restart Claude Code or Claude Desktop.
50
+
51
+ ## Available Tools
52
+
53
+ | Tool | Description |
54
+ |------|-------------|
55
+ | `mentionova_list_workspaces` | List all workspaces in your organization |
56
+ | `mentionova_get_workspace` | Get details for a specific workspace |
57
+ | `mentionova_list_prompts` | List tracked prompts (search queries) in a workspace |
58
+ | `mentionova_list_runs` | List prompt executions with status and channel results |
59
+ | `mentionova_list_citations` | List URLs cited by AI engines, with filters |
60
+ | `mentionova_list_mentions` | List verified brand mentions and recommendations |
61
+ | `mentionova_list_pages` | List tracked pages from citations and GSC |
62
+ | `mentionova_list_grids` | List content grids in a workspace |
63
+ | `mentionova_list_alerts` | List notifications and alerts |
64
+ | `mentionova_list_contacts` | List enriched contacts for cited domains |
65
+
66
+ ## Example Usage
67
+
68
+ Once connected, just ask your AI assistant naturally:
69
+
70
+ - "List my Mentionova workspaces"
71
+ - "Show me the latest citations for workspace [name]"
72
+ - "Which prompts are active in [workspace]?"
73
+ - "Get all ChatGPT citations from the last 7 days"
74
+ - "Show brand mentions for the most recent run"
75
+
76
+ ## API Key Permissions
77
+
78
+ Your API key's permissions control which tools are available. Configure read/write access per resource in Settings > API in the Mentionova dashboard.
79
+
80
+ ## Environment Variables
81
+
82
+ | Variable | Required | Description |
83
+ |----------|----------|-------------|
84
+ | `MENTIONOVA_API_KEY` | Yes | Your Mentionova API key (`mn_live_...`) |
85
+ | `MENTIONOVA_BASE_URL` | No | API base URL (default: `https://app.mentionova.com`) |
package/index.js ADDED
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { z } from "zod";
6
+
7
+ const API_KEY = process.env.MENTIONOVA_API_KEY;
8
+ const BASE_URL = process.env.MENTIONOVA_BASE_URL || "https://app.mentionova.com";
9
+
10
+ if (!API_KEY) {
11
+ console.error("MENTIONOVA_API_KEY environment variable is required");
12
+ process.exit(1);
13
+ }
14
+
15
+ async function api(path, params = {}) {
16
+ const url = new URL(`/api/v1${path}`, BASE_URL);
17
+ for (const [k, v] of Object.entries(params)) {
18
+ if (v !== undefined && v !== null && v !== "") url.searchParams.set(k, String(v));
19
+ }
20
+
21
+ const res = await fetch(url.toString(), {
22
+ headers: { Authorization: `Bearer ${API_KEY}` },
23
+ });
24
+
25
+ const json = await res.json();
26
+ if (!res.ok) throw new Error(json.error || `API error ${res.status}`);
27
+ return json;
28
+ }
29
+
30
+ const server = new McpServer({
31
+ name: "mentionova",
32
+ version: "1.0.0",
33
+ });
34
+
35
+ // --- Workspaces ---
36
+
37
+ server.tool(
38
+ "mentionova_list_workspaces",
39
+ "List all workspaces in your Mentionova organization",
40
+ {
41
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
42
+ offset: z.number().optional().describe("Offset for pagination"),
43
+ },
44
+ async ({ limit, offset }) => {
45
+ const data = await api("/workspaces", { limit, offset });
46
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
47
+ }
48
+ );
49
+
50
+ server.tool(
51
+ "mentionova_get_workspace",
52
+ "Get details for a specific workspace",
53
+ {
54
+ workspace_id: z.string().describe("Workspace UUID"),
55
+ },
56
+ async ({ workspace_id }) => {
57
+ const data = await api(`/workspaces/${workspace_id}`);
58
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
59
+ }
60
+ );
61
+
62
+ // --- Prompts ---
63
+
64
+ server.tool(
65
+ "mentionova_list_prompts",
66
+ "List prompts (search queries) tracked in a workspace. These are the questions being monitored across AI engines.",
67
+ {
68
+ workspace_id: z.string().describe("Workspace UUID"),
69
+ status: z.enum(["active", "paused", "archived"]).optional().describe("Filter by status"),
70
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
71
+ offset: z.number().optional().describe("Offset for pagination"),
72
+ },
73
+ async ({ workspace_id, status, limit, offset }) => {
74
+ const data = await api(`/workspaces/${workspace_id}/prompts`, { status, limit, offset });
75
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
76
+ }
77
+ );
78
+
79
+ // --- Runs ---
80
+
81
+ server.tool(
82
+ "mentionova_list_runs",
83
+ "List prompt runs (executions). Each run queries AI engines and captures their responses, citations, and mention data.",
84
+ {
85
+ workspace_id: z.string().describe("Workspace UUID"),
86
+ status: z.enum(["pending", "running", "completed", "failed", "partial"]).optional().describe("Filter by run status"),
87
+ prompt_id: z.string().optional().describe("Filter by prompt UUID"),
88
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
89
+ offset: z.number().optional().describe("Offset for pagination"),
90
+ },
91
+ async ({ workspace_id, status, prompt_id, limit, offset }) => {
92
+ const data = await api(`/workspaces/${workspace_id}/runs`, { status, prompt_id, limit, offset });
93
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
94
+ }
95
+ );
96
+
97
+ // --- Citations ---
98
+
99
+ server.tool(
100
+ "mentionova_list_citations",
101
+ "List citations (URLs referenced by AI engines in their responses). Filter by channel, date range, competitor status, etc.",
102
+ {
103
+ workspace_id: z.string().describe("Workspace UUID"),
104
+ channel: z.enum(["chatgpt", "claude", "perplexity", "gemini", "google", "reddit"]).optional().describe("Filter by AI engine"),
105
+ prompt_id: z.string().optional().describe("Filter by prompt UUID"),
106
+ run_id: z.string().optional().describe("Filter by run UUID"),
107
+ is_competitor: z.enum(["true", "false"]).optional().describe("Filter competitor citations"),
108
+ from: z.string().optional().describe("Start date (ISO 8601)"),
109
+ to: z.string().optional().describe("End date (ISO 8601)"),
110
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
111
+ offset: z.number().optional().describe("Offset for pagination"),
112
+ },
113
+ async ({ workspace_id, channel, prompt_id, run_id, is_competitor, from, to, limit, offset }) => {
114
+ const data = await api(`/workspaces/${workspace_id}/citations`, {
115
+ channel, prompt_id, run_id, is_competitor, from, to, limit, offset,
116
+ });
117
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
118
+ }
119
+ );
120
+
121
+ // --- Verified Mentions ---
122
+
123
+ server.tool(
124
+ "mentionova_list_mentions",
125
+ "List LLM-verified brand mentions and recommendations. Each entry shows whether the brand (and competitors) were mentioned or recommended in an AI engine response.",
126
+ {
127
+ workspace_id: z.string().describe("Workspace UUID"),
128
+ channel: z.enum(["chatgpt", "claude", "perplexity", "gemini", "google", "reddit"]).optional().describe("Filter by AI engine"),
129
+ run_id: z.string().optional().describe("Filter by run UUID"),
130
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
131
+ offset: z.number().optional().describe("Offset for pagination"),
132
+ },
133
+ async ({ workspace_id, channel, run_id, limit, offset }) => {
134
+ const data = await api(`/workspaces/${workspace_id}/mentions`, { channel, run_id, limit, offset });
135
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
136
+ }
137
+ );
138
+
139
+ // --- Pages ---
140
+
141
+ server.tool(
142
+ "mentionova_list_pages",
143
+ "List tracked pages (URLs from citations and GSC) for a workspace",
144
+ {
145
+ workspace_id: z.string().describe("Workspace UUID"),
146
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
147
+ offset: z.number().optional().describe("Offset for pagination"),
148
+ },
149
+ async ({ workspace_id, limit, offset }) => {
150
+ const data = await api(`/workspaces/${workspace_id}/pages`, { limit, offset });
151
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
152
+ }
153
+ );
154
+
155
+ // --- Grids ---
156
+
157
+ server.tool(
158
+ "mentionova_list_grids",
159
+ "List content grids (AI-powered spreadsheets) in a workspace",
160
+ {
161
+ workspace_id: z.string().describe("Workspace UUID"),
162
+ status: z.enum(["active", "archived"]).optional().describe("Filter by status (default: active)"),
163
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
164
+ offset: z.number().optional().describe("Offset for pagination"),
165
+ },
166
+ async ({ workspace_id, status, limit, offset }) => {
167
+ const data = await api(`/workspaces/${workspace_id}/grids`, { status, limit, offset });
168
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
169
+ }
170
+ );
171
+
172
+ // --- Alerts ---
173
+
174
+ server.tool(
175
+ "mentionova_list_alerts",
176
+ "List alerts and notifications for a workspace (run completions, failures, Reddit mentions, etc.)",
177
+ {
178
+ workspace_id: z.string().describe("Workspace UUID"),
179
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
180
+ offset: z.number().optional().describe("Offset for pagination"),
181
+ },
182
+ async ({ workspace_id, limit, offset }) => {
183
+ const data = await api(`/workspaces/${workspace_id}/alerts`, { limit, offset });
184
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
185
+ }
186
+ );
187
+
188
+ // --- Contacts ---
189
+
190
+ server.tool(
191
+ "mentionova_list_contacts",
192
+ "List enriched contacts for domains that appear in citations. Includes org info, employee count, and contact details from Apollo.",
193
+ {
194
+ workspace_id: z.string().describe("Workspace UUID"),
195
+ domain: z.string().optional().describe("Filter by specific domain"),
196
+ limit: z.number().optional().describe("Results per page (1-100, default 50)"),
197
+ offset: z.number().optional().describe("Offset for pagination"),
198
+ },
199
+ async ({ workspace_id, domain, limit, offset }) => {
200
+ const data = await api(`/workspaces/${workspace_id}/contacts`, { domain, limit, offset });
201
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
202
+ }
203
+ );
204
+
205
+ // Start the server
206
+ const transport = new StdioServerTransport();
207
+ await server.connect(transport);
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@mentionova/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for the Mentionova API - connect AI assistants to your AI search visibility data",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "bin": {
8
+ "mentionova-mcp": "index.js"
9
+ },
10
+ "scripts": {
11
+ "start": "node index.js"
12
+ },
13
+ "keywords": [
14
+ "mcp",
15
+ "mentionova",
16
+ "ai-visibility",
17
+ "seo",
18
+ "citations",
19
+ "claude",
20
+ "model-context-protocol"
21
+ ],
22
+ "license": "MIT",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "https://github.com/Loudspeaker-2025/mentionova-mcp"
26
+ },
27
+ "homepage": "https://mentionova.com/docs",
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "files": [
32
+ "index.js",
33
+ "README.md"
34
+ ],
35
+ "dependencies": {
36
+ "@modelcontextprotocol/sdk": "^1.12.1"
37
+ }
38
+ }