@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 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 3 issues by severity; paid customers (one-time $8.99) see all checks plus a prioritized fix guide.
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.0";
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
- description: "Fetch the full structured scan findings. Free tier returns the top 3 issues by severity (failed > warned > passed); paid customers see all checks. " +
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) if `truncated` is true, surface `truncated_message` so the user knows the API capped the output, " +
104
- "(4) 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. " +
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.0",
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.14.10",
28
+ "@types/node": "^20.19.41",
29
29
  "typescript": "5.6"
30
30
  },
31
31
  "keywords": [