mentionwell-mcp-account 0.1.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 ADDED
@@ -0,0 +1,38 @@
1
+ # mentionwell-mcp-account
2
+
3
+ MCP server for managing your Mentionwell account from any AI assistant — Claude, Cursor, ChatGPT, Codex.
4
+
5
+ ## Quick install
6
+
7
+ ```json
8
+ {
9
+ "mcpServers": {
10
+ "mentionwell": {
11
+ "command": "npx",
12
+ "args": ["-y", "mentionwell-mcp-account"],
13
+ "env": { "MENTIONWELL_TOKEN": "mw_pat_..." }
14
+ }
15
+ }
16
+ }
17
+ ```
18
+
19
+ Get a token at [app.mentionwell.com/settings/tokens](https://app.mentionwell.com/settings/tokens).
20
+
21
+ ## Tools
22
+
23
+ | Tool | What it does |
24
+ |---|---|
25
+ | `list_sites` | All sites on the account |
26
+ | `get_site_status` | Connection state, post count, last activity |
27
+ | `get_brand_context` | Audience / voice / CTA profile |
28
+ | `update_brand_context` | Patch fields on the brand profile |
29
+ | `probe_site` | Read-only stack/blog/webhook detection for any URL |
30
+ | `start_connect` | Begin a Connect flow (probe + first question) |
31
+ | `advance_connect` | Answer a Connect question |
32
+ | `get_connect` | Current state of a Connect session |
33
+ | `verify_webhook` | Signed test ping to a destination URL |
34
+ | `import_posts` | Pull existing posts from RSS / wp-json / Ghost as drafts |
35
+
36
+ ## Why this exists
37
+
38
+ Connecting a SaaS to your site usually means: open dashboard, copy keys, paste into env, edit code, deploy, debug. With this MCP your AI assistant does all of that for you in chat — and with [`mentionwell-cli`](https://www.npmjs.com/package/mentionwell-cli) installed, it can also write the route handler in your repo.
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Mentionwell account MCP server.
4
+ *
5
+ * Lets an AI assistant read and act on the user's Mentionwell account:
6
+ * - list_sites
7
+ * - get_site_status(slug)
8
+ * - get_brand_context(slug)
9
+ * - update_brand_context(slug, fields)
10
+ * - probe_site(url) → preview Connect output without committing
11
+ * - start_connect(slug, url) → begin a Connect session
12
+ * - advance_connect(sessionId, answer, text?)
13
+ * - get_connect(sessionId)
14
+ * - verify_webhook(slug, siteUrl)
15
+ * - import_posts(slug, feedUrl)
16
+ *
17
+ * Auth: bearer token. Pass `MENTIONWELL_TOKEN` (a personal access token
18
+ * from app.mentionwell.com/settings/tokens) when launching the server.
19
+ * The token is sent as `Authorization: Bearer …` to the Mentionwell API.
20
+ */
21
+ export {};
package/dist/server.js ADDED
@@ -0,0 +1,265 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * Mentionwell account MCP server.
5
+ *
6
+ * Lets an AI assistant read and act on the user's Mentionwell account:
7
+ * - list_sites
8
+ * - get_site_status(slug)
9
+ * - get_brand_context(slug)
10
+ * - update_brand_context(slug, fields)
11
+ * - probe_site(url) → preview Connect output without committing
12
+ * - start_connect(slug, url) → begin a Connect session
13
+ * - advance_connect(sessionId, answer, text?)
14
+ * - get_connect(sessionId)
15
+ * - verify_webhook(slug, siteUrl)
16
+ * - import_posts(slug, feedUrl)
17
+ *
18
+ * Auth: bearer token. Pass `MENTIONWELL_TOKEN` (a personal access token
19
+ * from app.mentionwell.com/settings/tokens) when launching the server.
20
+ * The token is sent as `Authorization: Bearer …` to the Mentionwell API.
21
+ */
22
+ Object.defineProperty(exports, "__esModule", { value: true });
23
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
24
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
25
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
26
+ const API_BASE = (process.env.MENTIONWELL_API_URL ?? "https://app.mentionwell.com").replace(/\/+$/, "");
27
+ const TOKEN = process.env.MENTIONWELL_TOKEN;
28
+ if (!TOKEN) {
29
+ console.error("MENTIONWELL_TOKEN is not set. Get one at app.mentionwell.com/settings/tokens.");
30
+ process.exit(1);
31
+ }
32
+ async function call(path, init) {
33
+ const res = await fetch(`${API_BASE}${path}`, {
34
+ ...init,
35
+ headers: {
36
+ "content-type": "application/json",
37
+ authorization: `Bearer ${TOKEN}`,
38
+ accept: "application/json",
39
+ ...(init?.headers ?? {})
40
+ }
41
+ });
42
+ if (!res.ok) {
43
+ const body = await res.text();
44
+ throw new Error(`${res.status} ${path}: ${body.slice(0, 240)}`);
45
+ }
46
+ return (await res.json());
47
+ }
48
+ const server = new index_js_1.Server({ name: "mentionwell-account", version: "0.1.0" }, { capabilities: { tools: {} } });
49
+ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({
50
+ tools: [
51
+ {
52
+ name: "list_sites",
53
+ description: "List all Mentionwell sites in the authenticated account.",
54
+ inputSchema: { type: "object", properties: {}, additionalProperties: false }
55
+ },
56
+ {
57
+ name: "get_site_status",
58
+ description: "Connection state, post count, and last activity for a site.",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: { siteSlug: { type: "string" } },
62
+ required: ["siteSlug"],
63
+ additionalProperties: false
64
+ }
65
+ },
66
+ {
67
+ name: "get_brand_context",
68
+ description: "Read the brand profile (audience, voice, CTA pattern) for a site.",
69
+ inputSchema: {
70
+ type: "object",
71
+ properties: { siteSlug: { type: "string" } },
72
+ required: ["siteSlug"],
73
+ additionalProperties: false
74
+ }
75
+ },
76
+ {
77
+ name: "update_brand_context",
78
+ description: "Patch fields on a site's brand profile. Only sends fields that are provided.",
79
+ inputSchema: {
80
+ type: "object",
81
+ properties: {
82
+ siteSlug: { type: "string" },
83
+ audience: { type: "string" },
84
+ voice: { type: "string" },
85
+ ctaPattern: { type: "string" },
86
+ summary: { type: "string" }
87
+ },
88
+ required: ["siteSlug"],
89
+ additionalProperties: false
90
+ }
91
+ },
92
+ {
93
+ name: "probe_site",
94
+ description: "Read-only probe: detect CMS, framework, host, existing blog, and viable webhook recipe for a URL.",
95
+ inputSchema: {
96
+ type: "object",
97
+ properties: { url: { type: "string" } },
98
+ required: ["url"],
99
+ additionalProperties: false
100
+ }
101
+ },
102
+ {
103
+ name: "start_connect",
104
+ description: "Begin a Connect session for a site. Runs the probe and returns the first question.",
105
+ inputSchema: {
106
+ type: "object",
107
+ properties: { siteSlug: { type: "string" }, url: { type: "string" } },
108
+ required: ["siteSlug", "url"],
109
+ additionalProperties: false
110
+ }
111
+ },
112
+ {
113
+ name: "advance_connect",
114
+ description: "Advance a Connect session by answering its current question.",
115
+ inputSchema: {
116
+ type: "object",
117
+ properties: {
118
+ sessionId: { type: "string" },
119
+ answer: { type: "string", description: "Option id from the question (e.g. 'confirm', 'all', 'skip')" },
120
+ text: { type: "string", description: "Free-text input when the option requires it" }
121
+ },
122
+ required: ["sessionId", "answer"],
123
+ additionalProperties: false
124
+ }
125
+ },
126
+ {
127
+ name: "get_connect",
128
+ description: "Fetch the current state of a Connect session.",
129
+ inputSchema: {
130
+ type: "object",
131
+ properties: { sessionId: { type: "string" } },
132
+ required: ["sessionId"],
133
+ additionalProperties: false
134
+ }
135
+ },
136
+ {
137
+ name: "verify_webhook",
138
+ description: "Send a signed test ping to the user's site to confirm the webhook is wired correctly.",
139
+ inputSchema: {
140
+ type: "object",
141
+ properties: { siteSlug: { type: "string" }, siteUrl: { type: "string" } },
142
+ required: ["siteSlug", "siteUrl"],
143
+ additionalProperties: false
144
+ }
145
+ },
146
+ {
147
+ name: "import_posts",
148
+ description: "Pull existing posts from an RSS / wp-json / Ghost feed into Mentionwell as drafts.",
149
+ inputSchema: {
150
+ type: "object",
151
+ properties: {
152
+ siteSlug: { type: "string" },
153
+ feedUrl: { type: "string", description: "RSS feed, /wp-json/wp/v2/posts, or /ghost/api/content/posts/?key=public" }
154
+ },
155
+ required: ["siteSlug", "feedUrl"],
156
+ additionalProperties: false
157
+ }
158
+ }
159
+ ]
160
+ }));
161
+ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
162
+ const { name, arguments: args = {} } = request.params;
163
+ const a = args;
164
+ try {
165
+ let result;
166
+ switch (name) {
167
+ case "list_sites":
168
+ result = await call("/api/dashboard");
169
+ break;
170
+ case "get_site_status":
171
+ if (!a.siteSlug)
172
+ throw new Error("siteSlug is required");
173
+ result = await call(`/api/sites/${encodeURIComponent(a.siteSlug)}`);
174
+ break;
175
+ case "get_brand_context":
176
+ if (!a.siteSlug)
177
+ throw new Error("siteSlug is required");
178
+ result = await call(`/api/sites/${encodeURIComponent(a.siteSlug)}/integration`);
179
+ break;
180
+ case "update_brand_context": {
181
+ if (!a.siteSlug)
182
+ throw new Error("siteSlug is required");
183
+ const body = {};
184
+ if (a.audience)
185
+ body.audience = a.audience;
186
+ if (a.voice)
187
+ body.voice = a.voice;
188
+ if (a.ctaPattern)
189
+ body.ctaPattern = a.ctaPattern;
190
+ if (a.summary)
191
+ body.summary = a.summary;
192
+ result = await call(`/api/sites/${encodeURIComponent(a.siteSlug)}`, {
193
+ method: "PATCH",
194
+ body: JSON.stringify(body)
195
+ });
196
+ break;
197
+ }
198
+ case "probe_site": {
199
+ if (!a.url)
200
+ throw new Error("url is required");
201
+ // Probe-only path — runs the same lib/integration/probe code via a
202
+ // helper endpoint. Falls back to start_connect for the same data.
203
+ result = await call(`/api/connect/probe`, {
204
+ method: "POST",
205
+ body: JSON.stringify({ url: a.url })
206
+ }).catch(async () => {
207
+ // Older deployments may not have /api/connect/probe — fall back.
208
+ throw new Error("This Mentionwell instance hasn't enabled probe_site yet. Use start_connect instead.");
209
+ });
210
+ break;
211
+ }
212
+ case "start_connect":
213
+ if (!a.siteSlug || !a.url)
214
+ throw new Error("siteSlug and url are required");
215
+ result = await call("/api/connect/start", {
216
+ method: "POST",
217
+ body: JSON.stringify({ siteSlug: a.siteSlug, url: a.url })
218
+ });
219
+ break;
220
+ case "advance_connect":
221
+ if (!a.sessionId || !a.answer)
222
+ throw new Error("sessionId and answer are required");
223
+ result = await call(`/api/connect/${encodeURIComponent(a.sessionId)}/advance`, {
224
+ method: "POST",
225
+ body: JSON.stringify({ answer: a.answer, text: a.text })
226
+ });
227
+ break;
228
+ case "get_connect":
229
+ if (!a.sessionId)
230
+ throw new Error("sessionId is required");
231
+ result = await call(`/api/connect/${encodeURIComponent(a.sessionId)}`);
232
+ break;
233
+ case "verify_webhook":
234
+ if (!a.siteSlug || !a.siteUrl)
235
+ throw new Error("siteSlug and siteUrl are required");
236
+ result = await call(`/api/sites/${encodeURIComponent(a.siteSlug)}/verify-webhook`, {
237
+ method: "POST",
238
+ body: JSON.stringify({ siteUrl: a.siteUrl })
239
+ });
240
+ break;
241
+ case "import_posts":
242
+ if (!a.siteSlug || !a.feedUrl)
243
+ throw new Error("siteSlug and feedUrl are required");
244
+ result = await call(`/api/sites/${encodeURIComponent(a.siteSlug)}/import`, {
245
+ method: "POST",
246
+ body: JSON.stringify({ feedUrl: a.feedUrl })
247
+ });
248
+ break;
249
+ default:
250
+ throw new Error(`Unknown tool: ${name}`);
251
+ }
252
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
253
+ }
254
+ catch (e) {
255
+ return {
256
+ content: [{ type: "text", text: e instanceof Error ? e.message : String(e) }],
257
+ isError: true
258
+ };
259
+ }
260
+ });
261
+ const transport = new stdio_js_1.StdioServerTransport();
262
+ server.connect(transport).catch((e) => {
263
+ console.error("Mentionwell account MCP failed to start:", e);
264
+ process.exit(1);
265
+ });
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "mentionwell-mcp-account",
3
+ "version": "0.1.0",
4
+ "description": "Mentionwell account MCP server — manage your sites, posts, and connect flow from your AI assistant.",
5
+ "bin": {
6
+ "mentionwell-mcp-account": "dist/server.js"
7
+ },
8
+ "main": "./dist/server.js",
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc -p tsconfig.json"
15
+ },
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.29.0"
22
+ },
23
+ "publishConfig": {
24
+ "access": "public"
25
+ }
26
+ }