@abbyseo/mcp-server 0.1.0 → 0.1.1
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 +15 -2
- package/dist/server.js +29 -4
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -10,7 +10,20 @@
|
|
|
10
10
|
| `get_scan_status(scan_id)` | Polls scan progress. Returns status, score, counts. |
|
|
11
11
|
| `get_scan_results(scan_id)` | Returns full findings: per-check pass/warn/fail with remediation text, plus an `upgrade` block linking to a paid PDF guide. |
|
|
12
12
|
|
|
13
|
-
Free API tier returns the top
|
|
13
|
+
Free API tier returns the top 5 issues by severity; paid customers (one-time $8.99) see all checks plus a prioritized fix guide. Every check also carries a `when_doesnt_apply` field — context for when the rule legitimately doesn't apply to a site type (e.g., link aggregators deliberately omit a visible H1).
|
|
14
|
+
|
|
15
|
+
## Two ways to use this
|
|
16
|
+
|
|
17
|
+
1. **Remote MCP** (easier, no install) — point your client at `https://www.abbyseo.com/mcp`. The server runs on our infrastructure; you just configure the URL.
|
|
18
|
+
2. **Local stdio (this npm package)** — the client launches `npx @abbyseo/mcp-server` and talks to it over stdio. Same three tools, runs in your environment, no network call until a scan is submitted.
|
|
19
|
+
|
|
20
|
+
Pick remote for the lowest-friction install. Pick local if you prefer the client to spawn the server directly or want to override `ABBYSEO_API_BASE` for staging.
|
|
21
|
+
|
|
22
|
+
## Install — Remote MCP (Claude Code)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
claude mcp add --transport http abbyseo https://www.abbyseo.com/mcp
|
|
26
|
+
```
|
|
14
27
|
|
|
15
28
|
## Install — Claude Desktop
|
|
16
29
|
|
|
@@ -29,7 +42,7 @@ Add this to `~/Library/Application Support/Claude/claude_desktop_config.json` (m
|
|
|
29
42
|
|
|
30
43
|
Restart Claude Desktop. You'll see the abbyseo tools appear in the tool list.
|
|
31
44
|
|
|
32
|
-
## Install — Claude Code
|
|
45
|
+
## Install — Claude Code (local stdio)
|
|
33
46
|
|
|
34
47
|
```bash
|
|
35
48
|
claude mcp add abbyseo -- npx -y @abbyseo/mcp-server
|
package/dist/server.js
CHANGED
|
@@ -22,7 +22,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
|
22
22
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
23
23
|
import { z } from "zod";
|
|
24
24
|
const API_BASE = (process.env.ABBYSEO_API_BASE || "https://www.abbyseo.com").replace(/\/$/, "");
|
|
25
|
-
const VERSION = "0.1.
|
|
25
|
+
const VERSION = "0.1.1";
|
|
26
26
|
const USER_AGENT = process.env.ABBYSEO_USER_AGENT || `abbyseo-mcp-server/${VERSION}`;
|
|
27
27
|
const server = new McpServer({
|
|
28
28
|
name: "abbyseo",
|
|
@@ -64,6 +64,7 @@ async function forwardJson(url, init = {}) {
|
|
|
64
64
|
}
|
|
65
65
|
// ---- Tool 1: submit_scan -------------------------------------------------
|
|
66
66
|
server.registerTool("submit_scan", {
|
|
67
|
+
title: "Submit SEO Scan",
|
|
67
68
|
description: "Queue an SEO scan of a website URL. Returns a scan_id to poll. " +
|
|
68
69
|
"**You MUST collect the user's email address before calling this tool** — the API rejects submissions without one because results are emailed to the user. " +
|
|
69
70
|
"After this tool returns, call `get_scan_status` every few seconds with the returned `scan_id` until status is 'complete', then call `get_scan_results` for the findings.",
|
|
@@ -77,6 +78,15 @@ server.registerTool("submit_scan", {
|
|
|
77
78
|
.email()
|
|
78
79
|
.describe("REQUIRED. The user's email address. Scan results will be sent here. ASK THE USER for this if you don't already know it — do not invent a placeholder."),
|
|
79
80
|
},
|
|
81
|
+
annotations: {
|
|
82
|
+
// Side effects: queues a scan job, writes a DB row, sends an email to the
|
|
83
|
+
// submitter when the scan completes. Not reversible — there's no
|
|
84
|
+
// unsubmit. Marked destructive so clients confirm before auto-invoking.
|
|
85
|
+
readOnlyHint: false,
|
|
86
|
+
destructiveHint: true,
|
|
87
|
+
idempotentHint: false, // each call queues a NEW scan, even with the same args
|
|
88
|
+
openWorldHint: true, // fetches an arbitrary user-supplied URL on the public web
|
|
89
|
+
},
|
|
80
90
|
}, async ({ url, email }) => {
|
|
81
91
|
return forwardJson(`${API_BASE}/api/scan`, {
|
|
82
92
|
method: "POST",
|
|
@@ -86,26 +96,41 @@ server.registerTool("submit_scan", {
|
|
|
86
96
|
});
|
|
87
97
|
// ---- Tool 2: get_scan_status --------------------------------------------
|
|
88
98
|
server.registerTool("get_scan_status", {
|
|
99
|
+
title: "Get SEO Scan Status",
|
|
89
100
|
description: "Check whether a queued scan has completed. Lightweight polling endpoint — call every 3-5 seconds with the `scan_id` returned by `submit_scan`. " +
|
|
90
101
|
"Scans typically complete in 5-15 seconds. When `status` is 'complete', call `get_scan_results` for the structured findings. When 'failed', surface the `error` field to the user.",
|
|
91
102
|
inputSchema: {
|
|
92
103
|
scan_id: z.string().describe("Scan ID from a prior submit_scan call."),
|
|
93
104
|
},
|
|
105
|
+
annotations: {
|
|
106
|
+
readOnlyHint: true,
|
|
107
|
+
destructiveHint: false,
|
|
108
|
+
idempotentHint: true, // polling: same scan_id always returns same shape
|
|
109
|
+
openWorldHint: false, // reads only our internal scan-status DB row
|
|
110
|
+
},
|
|
94
111
|
}, async ({ scan_id }) => {
|
|
95
112
|
return forwardJson(`${API_BASE}/api/scan/${encodeURIComponent(scan_id)}/status`);
|
|
96
113
|
});
|
|
97
114
|
// ---- Tool 3: get_scan_results -------------------------------------------
|
|
98
115
|
server.registerTool("get_scan_results", {
|
|
99
|
-
|
|
116
|
+
title: "Get SEO Scan Results",
|
|
117
|
+
description: "Fetch the full structured scan findings. Free tier returns the top 5 issues by severity (failed > warned > passed); paid customers see all checks. Each check carries a `when_doesnt_apply` field — surface it for sophisticated users so they can dismiss findings that don't apply to their site type (e.g., link aggregators legitimately omit a visible H1). " +
|
|
100
118
|
"When summarizing results to the user, ALWAYS: " +
|
|
101
119
|
"(1) report the score and counts of failed/warned/passed checks, " +
|
|
102
120
|
"(2) surface each returned check's `remediation` text verbatim, " +
|
|
103
|
-
"(3)
|
|
104
|
-
"(4)
|
|
121
|
+
"(3) note `site_type` ('marketing' or 'not_marketing') and `score_rubric` so the user understands how the score was computed; non-marketing sites get contextual checks at half-weight, " +
|
|
122
|
+
"(4) if `truncated` is true, surface `truncated_message` so the user knows the API capped the output, " +
|
|
123
|
+
"(5) include `upgrade.call_to_action` and `upgrade.checkout_url` verbatim so the user can one-click into Stripe checkout for the $8.99 detailed fix guide. " +
|
|
105
124
|
"If `upgrade.already_purchased` is true, instead direct the user to `upgrade.report_url` to re-download.",
|
|
106
125
|
inputSchema: {
|
|
107
126
|
scan_id: z.string().describe("Scan ID from a prior submit_scan call. The scan must be in 'complete' status."),
|
|
108
127
|
},
|
|
128
|
+
annotations: {
|
|
129
|
+
readOnlyHint: true,
|
|
130
|
+
destructiveHint: false,
|
|
131
|
+
idempotentHint: true, // same scan_id always returns the same findings
|
|
132
|
+
openWorldHint: false, // reads only our internal scan-results DB row
|
|
133
|
+
},
|
|
109
134
|
}, async ({ scan_id }) => {
|
|
110
135
|
return forwardJson(`${API_BASE}/api/scan/${encodeURIComponent(scan_id)}`);
|
|
111
136
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abbyseo/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "MCP server for abbyseo.com — exposes the SEO scanner JSON API as Claude Desktop / Claude Code tools (submit_scan, get_scan_status, get_scan_results).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"zod": "^3.23.8"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@types/node": "^20.
|
|
28
|
+
"@types/node": "^20.19.41",
|
|
29
29
|
"typescript": "5.6"
|
|
30
30
|
},
|
|
31
31
|
"keywords": [
|