@automatelab/ai-seo-mcp 0.1.1 → 0.1.3
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 +61 -141
- package/dist/index.js +213 -40
- package/dist/index.js.map +1 -1
- package/dist/lib/config.js +1 -1
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/scorecard-html.d.ts +21 -0
- package/dist/lib/scorecard-html.d.ts.map +1 -0
- package/dist/lib/scorecard-html.js +167 -0
- package/dist/lib/scorecard-html.js.map +1 -0
- package/dist/tools/audit-canonical.d.ts.map +1 -1
- package/dist/tools/audit-canonical.js +9 -2
- package/dist/tools/audit-canonical.js.map +1 -1
- package/dist/tools/audit-page.d.ts +15 -0
- package/dist/tools/audit-page.d.ts.map +1 -1
- package/dist/tools/audit-page.js +54 -3
- package/dist/tools/audit-page.js.map +1 -1
- package/dist/tools/check-robots.d.ts.map +1 -1
- package/dist/tools/check-robots.js +4 -1
- package/dist/tools/check-robots.js.map +1 -1
- package/dist/tools/check-sitemap.d.ts.map +1 -1
- package/dist/tools/check-sitemap.js +12 -2
- package/dist/tools/check-sitemap.js.map +1 -1
- package/dist/tools/check-technical.d.ts.map +1 -1
- package/dist/tools/check-technical.js +9 -2
- package/dist/tools/check-technical.js.map +1 -1
- package/dist/tools/diff-pages.d.ts +58 -0
- package/dist/tools/diff-pages.d.ts.map +1 -0
- package/dist/tools/diff-pages.js +120 -0
- package/dist/tools/diff-pages.js.map +1 -0
- package/dist/tools/generate-llms-txt.d.ts.map +1 -1
- package/dist/tools/generate-llms-txt.js +25 -5
- package/dist/tools/generate-llms-txt.js.map +1 -1
- package/dist/tools/score-ai-overview-eligibility.d.ts.map +1 -1
- package/dist/tools/score-ai-overview-eligibility.js +9 -2
- package/dist/tools/score-ai-overview-eligibility.js.map +1 -1
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -1,36 +1,67 @@
|
|
|
1
1
|
# @automatelab/ai-seo-mcp
|
|
2
2
|
|
|
3
|
+
> AI Citation Toolkit for the Model Context Protocol
|
|
4
|
+
|
|
3
5
|
[](https://www.npmjs.com/package/@automatelab/ai-seo-mcp)
|
|
4
6
|
[](./LICENSE)
|
|
5
7
|
[](https://nodejs.org)
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
**Audit why AI systems do or do not cite your pages.** MCP server. No API keys.
|
|
8
10
|
|
|
9
|
-
Works
|
|
11
|
+
Works inside Claude, Cursor, Windsurf, Codex, and any MCP client that speaks stdio.
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
---
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
## What it checks
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
- **AI crawler access** - GPTBot, OAI-SearchBot, ClaudeBot, and PerplexityBot allowed or blocked in `robots.txt`
|
|
18
|
+
- **`llms.txt`** - present, spec-compliant, links alive
|
|
19
|
+
- **Structured answer extraction** - FAQ headings, BLUF paragraphs, answer-ready blocks
|
|
20
|
+
- **Schema completeness** - FAQPage, Article, Organization, Person; flags deprecated patterns
|
|
21
|
+
- **Entity clarity** - named entity density and `sameAs` coverage that help AI systems identify the subject
|
|
22
|
+
- **Citation formatting** - canonical URL hygiene, `og:url`, `hreflang`, noindex traps
|
|
23
|
+
- **Sitemap freshness** - `lastmod` signals that tell crawlers the page is current
|
|
16
24
|
|
|
17
|
-
|
|
25
|
+
---
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
## Run an audit. Get a list of citation-blockers, ranked.
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
> **You:** Run an AI-SEO audit on `https://automatelab.tech/how-to-connect-zapier-to-notion`.
|
|
22
30
|
|
|
23
|
-
|
|
31
|
+
Result (truncated):
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"url": "https://automatelab.tech/how-to-connect-zapier-to-notion",
|
|
36
|
+
"score": 61,
|
|
37
|
+
"grade": "C",
|
|
38
|
+
"dimension_scores": {
|
|
39
|
+
"schema": 45, "technical": 80, "structure": 40,
|
|
40
|
+
"robots": 90, "freshness": 85, "authority": 40,
|
|
41
|
+
"entity_density": 21, "sitemap": 100
|
|
42
|
+
},
|
|
43
|
+
"findings": [
|
|
44
|
+
{
|
|
45
|
+
"severity": "critical",
|
|
46
|
+
"category": "structure",
|
|
47
|
+
"message": "No FAQ structure found (no FAQPage schema or H3 question headings).",
|
|
48
|
+
"fix": "Add FAQ H3 headings ending in '?' with answer paragraphs, and a FAQPage JSON-LD block.",
|
|
49
|
+
"estimated_impact": "high"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"severity": "warning",
|
|
53
|
+
"category": "authority",
|
|
54
|
+
"message": "Low authority signals - missing Organization or author Person schema.",
|
|
55
|
+
"fix": "Add Organization JSON-LD and Article.author as a Person node with sameAs links.",
|
|
56
|
+
"estimated_impact": "high"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
}
|
|
60
|
+
```
|
|
26
61
|
|
|
27
|
-
|
|
28
|
-
- What schema is missing, malformed, or deprecated?
|
|
29
|
-
- Are GPTBot, ClaudeBot, OAI-SearchBot, and PerplexityBot allowed by `robots.txt`?
|
|
30
|
-
- Does the page have a chance at the Answer Engine slot for a given query?
|
|
31
|
-
- Rewrite this passage into a citation-ready answer block.
|
|
62
|
+
Each finding names the exact fix. No opaque scores, no guesswork.
|
|
32
63
|
|
|
33
|
-
|
|
64
|
+
---
|
|
34
65
|
|
|
35
66
|
## Install
|
|
36
67
|
|
|
@@ -38,11 +69,11 @@ This MCP gives any AI client a toolkit to inspect a URL and answer questions lik
|
|
|
38
69
|
npx -y @automatelab/ai-seo-mcp
|
|
39
70
|
```
|
|
40
71
|
|
|
41
|
-
Requires Node 20 or later.
|
|
72
|
+
Requires Node 20 or later.
|
|
42
73
|
|
|
43
74
|
### Claude Desktop
|
|
44
75
|
|
|
45
|
-
Add to `%APPDATA%\Claude\claude_desktop_config.json`
|
|
76
|
+
Add to `%APPDATA%\Claude\claude_desktop_config.json` (Windows) or `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):
|
|
46
77
|
|
|
47
78
|
```json
|
|
48
79
|
{
|
|
@@ -55,57 +86,18 @@ Add to `%APPDATA%\Claude\claude_desktop_config.json` on Windows, or `~/Library/A
|
|
|
55
86
|
}
|
|
56
87
|
```
|
|
57
88
|
|
|
58
|
-
Restart Claude Desktop.
|
|
59
|
-
|
|
60
|
-
### Cursor
|
|
61
|
-
|
|
62
|
-
Add to `.cursor/mcp.json` in the project root or `~/.cursor/mcp.json` globally:
|
|
63
|
-
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"mcpServers": {
|
|
67
|
-
"ai-seo": {
|
|
68
|
-
"command": "npx",
|
|
69
|
-
"args": ["-y", "@automatelab/ai-seo-mcp"]
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### Cline
|
|
76
|
-
|
|
77
|
-
Add to VS Code settings or `.cline/mcp_settings.json`:
|
|
78
|
-
|
|
79
|
-
```json
|
|
80
|
-
{
|
|
81
|
-
"mcpServers": {
|
|
82
|
-
"ai-seo": {
|
|
83
|
-
"command": "npx",
|
|
84
|
-
"args": ["-y", "@automatelab/ai-seo-mcp"],
|
|
85
|
-
"disabled": false,
|
|
86
|
-
"autoApprove": []
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
### Windsurf, Continue, VS Code Copilot
|
|
93
|
-
|
|
94
|
-
Use the same `command` / `args` pattern. Any MCP client that supports stdio transport works.
|
|
89
|
+
Restart Claude Desktop. Any MCP client that supports stdio transport works - same `command` / `args` pattern.
|
|
95
90
|
|
|
96
|
-
|
|
91
|
+
---
|
|
97
92
|
|
|
98
|
-
|
|
93
|
+
## Further reading
|
|
99
94
|
|
|
100
|
-
-
|
|
101
|
-
- *"Check which AI crawlers my site allows in `robots.txt` for `https://yourdomain.com`."* - calls `check_robots` and lists per-crawler allow/disallow.
|
|
102
|
-
- *"Score how citation-worthy this blog post is for Perplexity and ChatGPT: `https://...`."* - calls `score_citation_worthiness`.
|
|
103
|
-
- *"Generate an `llms.txt` for `https://yourdomain.com` from its sitemap."* - calls `generate_llms_txt`.
|
|
104
|
-
- *"Rewrite this passage for Answer Engine Optimization: [paste passage]."* - calls `rewrite_for_aeo` (uses MCP sampling if your client supports it).
|
|
95
|
+
- [automatelab.tech](https://automatelab.tech/products/mcp/ai-seo/) - teardowns and case studies
|
|
105
96
|
|
|
106
|
-
|
|
97
|
+
---
|
|
107
98
|
|
|
108
|
-
|
|
99
|
+
<details>
|
|
100
|
+
<summary>All 14 tools</summary>
|
|
109
101
|
|
|
110
102
|
| Tool | Purpose |
|
|
111
103
|
|------|---------|
|
|
@@ -122,81 +114,13 @@ No API keys. No accounts. The first call may take a few seconds while `npx` down
|
|
|
122
114
|
| `rewrite_for_aeo` | Rewrite content for Answer Engine Optimization (BLUF structure, FAQ format, schema additions). |
|
|
123
115
|
| `rewrite_for_geo` | Rewrite content for Generative Engine Optimization (entity definitions, comparison tables, synthesis-ready structure). |
|
|
124
116
|
| `extract_entities` | Extract named entities, `sameAs` links, and citation-density score from a page's content and structured data. |
|
|
117
|
+
| `diff_pages` | Compare two URLs for AI citation-worthiness: side-by-side dimension scores, gap analysis, and prioritized fix recommendations for url_a. |
|
|
125
118
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
In Claude Desktop, after wiring the server above:
|
|
129
|
-
|
|
130
|
-
> **You:** Run an AI-SEO audit on `https://automatelab.tech/how-to-connect-zapier-to-notion`.
|
|
131
|
-
|
|
132
|
-
Claude calls `audit_page`. Result (truncated):
|
|
133
|
-
|
|
134
|
-
```json
|
|
135
|
-
{
|
|
136
|
-
"url": "https://automatelab.tech/how-to-connect-zapier-to-notion",
|
|
137
|
-
"fetched_at": "2026-05-15T10:32:00Z",
|
|
138
|
-
"score": 61,
|
|
139
|
-
"grade": "C",
|
|
140
|
-
"dimension_scores": {
|
|
141
|
-
"schema": 45, "technical": 80, "structure": 40,
|
|
142
|
-
"robots": 90, "freshness": 85, "authority": 40,
|
|
143
|
-
"entity_density": 21, "sitemap": 100
|
|
144
|
-
},
|
|
145
|
-
"findings": [
|
|
146
|
-
{
|
|
147
|
-
"severity": "critical",
|
|
148
|
-
"category": "structure",
|
|
149
|
-
"where": "<body>",
|
|
150
|
-
"message": "No FAQ structure found (no FAQPage schema or H3 question headings).",
|
|
151
|
-
"fix": "Add FAQ H3 headings ending in '?' with answer paragraphs, and a FAQPage JSON-LD block.",
|
|
152
|
-
"estimated_impact": "high"
|
|
153
|
-
},
|
|
154
|
-
{
|
|
155
|
-
"severity": "warning",
|
|
156
|
-
"category": "authority",
|
|
157
|
-
"where": "page-level",
|
|
158
|
-
"message": "Low authority signals - missing Organization or author Person schema.",
|
|
159
|
-
"fix": "Add Organization JSON-LD and Article.author as a Person node with sameAs links.",
|
|
160
|
-
"estimated_impact": "high"
|
|
161
|
-
}
|
|
162
|
-
]
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
Claude then summarizes the findings and proposes fixes. For rewrite tools, the host model (Claude / GPT / etc.) does the rewriting via MCP sampling.
|
|
167
|
-
|
|
168
|
-
## Environment variables
|
|
169
|
-
|
|
170
|
-
All variables are optional. Set them in the MCP client config under `"env"`.
|
|
171
|
-
|
|
172
|
-
| Variable | Default | Description |
|
|
173
|
-
|----------|---------|-------------|
|
|
174
|
-
| `USER_AGENT` | `automatelab-ai-seo-mcp/0.1.0 (+https://github.com/AutomateLab-tech/ai-seo)` | HTTP User-Agent on all fetches. |
|
|
175
|
-
| `FETCH_TIMEOUT_MS` | `15000` | Per-request timeout in milliseconds. |
|
|
176
|
-
| `MAX_BYTES` | `5242880` | Maximum response body size in bytes (5 MB). |
|
|
177
|
-
| `RESPECT_ROBOTS` | `true` | Global default for robots.txt compliance. Set `"false"` to disable. |
|
|
178
|
-
| `INTER_REQUEST_DELAY_MS` | `1500` | Minimum delay between requests to the same host within a tool call. |
|
|
119
|
+
Environment variables: see [ENV.md](./ENV.md).
|
|
179
120
|
|
|
180
|
-
|
|
121
|
+
</details>
|
|
181
122
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
- Respects `robots.txt` for the configured User-Agent (override with `RESPECT_ROBOTS=false`).
|
|
185
|
-
- Identifies itself honestly via `User-Agent` (no spoofing as a browser).
|
|
186
|
-
- Sleeps `INTER_REQUEST_DELAY_MS` between requests to the same host within a tool call.
|
|
187
|
-
- Times out at `FETCH_TIMEOUT_MS` per request.
|
|
188
|
-
- Caps response body at `MAX_BYTES` and refuses non-HTML / non-XML payloads where inappropriate.
|
|
189
|
-
|
|
190
|
-
This MCP is not a scraper. It audits public pages the way Lighthouse or Screaming Frog do, one URL at a time.
|
|
191
|
-
|
|
192
|
-
## What it does not do
|
|
193
|
-
|
|
194
|
-
- No JavaScript-rendered scraping. Only static HTML is fetched. SPAs that render content client-side will produce incomplete audits.
|
|
195
|
-
- No paid-API integrations (Search Console, Ahrefs, Semrush). Bring those signals manually if you need them.
|
|
196
|
-
- No site-wide crawling. Tools that need multiple URLs read from the public sitemap.
|
|
197
|
-
- No live SERP checks. AI Overview eligibility is a deterministic heuristic, not a guarantee.
|
|
198
|
-
- English-language tuning. Technical checks (schema, robots, canonical) are language-agnostic; content scoring assumes English.
|
|
199
|
-
- Entity extraction is regex-based (title-case phrases, acronyms, CamelCase). False positives and misses are expected on v0.1.
|
|
123
|
+
---
|
|
200
124
|
|
|
201
125
|
## Contributing
|
|
202
126
|
|
|
@@ -210,8 +134,4 @@ To report a vulnerability, see [SECURITY.md](./SECURITY.md).
|
|
|
210
134
|
|
|
211
135
|
MIT - see [LICENSE](./LICENSE).
|
|
212
136
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
Built by [automatelab.tech](https://automatelab.tech/products/mcp/ai-seo/)
|
|
216
|
-
|
|
217
|
-
Schema.org, `robots.txt`, and `llms.txt` are open standards. Crawler user-agent data is sourced from Anthropic, OpenAI, Google, Perplexity, and Cloudflare documentation. The MCP itself is built on the [Model Context Protocol](https://modelcontextprotocol.io) by Anthropic.
|
|
137
|
+
Built by [automatelab.tech](https://automatelab.tech)
|
package/dist/index.js
CHANGED
|
@@ -17,10 +17,11 @@ import { scoreCitationWorthiness } from "./tools/score-citation-worthiness.js";
|
|
|
17
17
|
import { rewriteForAeo } from "./tools/rewrite-for-aeo.js";
|
|
18
18
|
import { rewriteForGeo } from "./tools/rewrite-for-geo.js";
|
|
19
19
|
import { extractEntities } from "./tools/extract-entities.js";
|
|
20
|
+
import { diffPages, diffPagesInputSchema } from "./tools/diff-pages.js";
|
|
20
21
|
import { ToolFetchError } from "./lib/fetch.js";
|
|
21
22
|
const server = new McpServer({
|
|
22
23
|
name: "@automatelab/ai-seo-mcp",
|
|
23
|
-
version: "0.1.
|
|
24
|
+
version: "0.1.2",
|
|
24
25
|
});
|
|
25
26
|
/** Serialize a ToolError to MCP error content. */
|
|
26
27
|
function toolError(err) {
|
|
@@ -45,36 +46,104 @@ function wrapHandler(handler) {
|
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
48
|
// --- Tool 1: audit_page ---
|
|
48
|
-
server.tool("audit_page",
|
|
49
|
+
server.tool("audit_page", [
|
|
50
|
+
"Full AI-SEO audit of a single URL: returns categorized findings (info/warning/error) with severity, fix instructions, and a 0-100 composite score plus per-dimension subscores.",
|
|
51
|
+
"Read-only. Fetches the URL once and runs every sub-audit (schema, robots, technical, sitemap, AI-Overview eligibility) against the response. No writes, no third-party APIs, no auth required, no rate limits beyond polite per-host throttling.",
|
|
52
|
+
"Deterministic, rule-based scoring; no LLM calls. Same URL + same input flags returns the same score.",
|
|
53
|
+
"When to use: the default entry point for `audit any page`. Use this instead of calling check_technical / audit_schema / check_robots / check_sitemap / score_ai_overview_eligibility individually unless you specifically need only one dimension - this tool composes all of them.",
|
|
54
|
+
].join("\n\n"), auditPageInputSchema.shape, async (input) => wrapHandler(() => auditPage(input)));
|
|
49
55
|
// --- Tool 2: audit_schema ---
|
|
50
|
-
server.tool("audit_schema",
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
server.tool("audit_schema", [
|
|
57
|
+
"Validate JSON-LD structured data against Schema.org rules and AI-citation best practices. Accepts either a URL (fetched) or a raw JSON string (parsed directly).",
|
|
58
|
+
"Read-only when given `url` (one HTTP GET). Zero network when given `schema_json`. No writes.",
|
|
59
|
+
"Deterministic, rule-based; no LLM. Validates required/recommended properties, @context correctness, sameAs links, and AI-search-friendly patterns.",
|
|
60
|
+
"When to use: focused JSON-LD audits, or to validate a schema block you're about to ship. For a full page audit that includes schema + everything else, use `audit_page` instead.",
|
|
61
|
+
"Either `url` or `schema_json` must be provided (not both). If both are provided, `schema_json` wins and no fetch happens.",
|
|
62
|
+
].join("\n\n"), {
|
|
63
|
+
url: z
|
|
64
|
+
.string()
|
|
65
|
+
.url()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Public URL to fetch and audit. Either this OR `schema_json` is required. Read-only HTTP GET."),
|
|
68
|
+
schema_json: z
|
|
69
|
+
.string()
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Raw JSON-LD as a string (the contents of a `<script type=\"application/ld+json\">` block). Use this to validate a schema block offline without fetching a URL. Either this OR `url` is required."),
|
|
72
|
+
respect_robots: z
|
|
73
|
+
.boolean()
|
|
74
|
+
.optional()
|
|
75
|
+
.default(true)
|
|
76
|
+
.describe("If true (default), respect robots.txt before fetching `url`. Ignored when `schema_json` is used."),
|
|
54
77
|
}, async (input) => {
|
|
55
|
-
// Manual refinement check (zod .refine not supported in tool shape directly)
|
|
56
78
|
if (!input.url && !input.schema_json) {
|
|
57
79
|
return toolError({ type: "invalid_url", message: "One of url or schema_json is required" });
|
|
58
80
|
}
|
|
59
81
|
return wrapHandler(() => auditSchema(input));
|
|
60
82
|
});
|
|
61
83
|
// --- Tool 3: audit_canonical ---
|
|
62
|
-
server.tool("audit_canonical",
|
|
84
|
+
server.tool("audit_canonical", [
|
|
85
|
+
"Audit a page's canonical link integrity: presence, self-reference, cross-domain mismatches, trailing-slash hygiene, and og:url consistency.",
|
|
86
|
+
"Read-only. One HTTP GET to fetch the HEAD section.",
|
|
87
|
+
"Deterministic, rule-based; no LLM.",
|
|
88
|
+
"When to use: a focused canonical-only audit (e.g. debugging a duplicate-content issue). For a full HEAD audit including OpenGraph, hreflang, noindex, title, use `check_technical`. For everything-on-a-page, use `audit_page`.",
|
|
89
|
+
].join("\n\n"), auditCanonicalInputSchema.shape, async (input) => wrapHandler(() => auditCanonical(input)));
|
|
63
90
|
// --- Tool 4: check_robots ---
|
|
64
|
-
server.tool("check_robots",
|
|
91
|
+
server.tool("check_robots", [
|
|
92
|
+
"Fetch and parse a domain's robots.txt; report per-crawler allow/disallow posture for every known AI training crawler (GPTBot, CCBot, Anthropic-AI, Google-Extended, etc.), AI search crawlers (ChatGPT-User, PerplexityBot, OAI-SearchBot), and user-triggered fetchers.",
|
|
93
|
+
"Read-only. One HTTP GET to /robots.txt. No auth, no rate limits applied.",
|
|
94
|
+
"Deterministic, rule-based; no LLM. Returns structured findings with per-crawler status.",
|
|
95
|
+
"When to use: figuring out which AI crawlers a site blocks vs allows. Combine with `check_sitemap` for a full pre-crawl audit. Distinct from `audit_page` which evaluates a single URL; this evaluates a whole-domain policy.",
|
|
96
|
+
].join("\n\n"), checkRobotsInputSchema.shape, async (input) => wrapHandler(() => checkRobots(input)));
|
|
65
97
|
// --- Tool 5: check_sitemap ---
|
|
66
|
-
server.tool("check_sitemap",
|
|
98
|
+
server.tool("check_sitemap", [
|
|
99
|
+
"Validate a domain's XML sitemap: presence, accessibility, URL count, lastmod freshness, sitemap-index handling, and image/video sitemap extensions.",
|
|
100
|
+
"Read-only. Issues N+1 HTTP GETs: one for robots.txt + sitemap, then up to `max_urls_to_check` HEADs against sampled URLs.",
|
|
101
|
+
"Deterministic, rule-based; no LLM.",
|
|
102
|
+
"When to use: site-wide indexing audits. Pair with `check_robots` for a full pre-crawl picture. For per-page checks, use `audit_page` or `check_technical` instead.",
|
|
103
|
+
].join("\n\n"), checkSitemapInputSchema.shape, async (input) => wrapHandler(() => checkSitemap(input)));
|
|
67
104
|
// --- Tool 6: check_technical ---
|
|
68
|
-
server.tool("check_technical",
|
|
105
|
+
server.tool("check_technical", [
|
|
106
|
+
"Audit a page's HEAD section for technical signals relevant to AI crawlers: HTTPS, canonical, OpenGraph, Twitter Card, hreflang, noindex, and title-vs-H1 hygiene.",
|
|
107
|
+
"Read-only. One HTTP GET, inspects HEAD only (body is not parsed).",
|
|
108
|
+
"Deterministic, rule-based; no LLM.",
|
|
109
|
+
"When to use: when you specifically need HEAD-tag audit findings. For the full page including schema and AI-Overview scoring, use `audit_page`. For canonical-only, use `audit_canonical`.",
|
|
110
|
+
].join("\n\n"), checkTechnicalInputSchema.shape, async (input) => wrapHandler(() => checkTechnical(input)));
|
|
69
111
|
// --- Tool 7: score_ai_overview_eligibility ---
|
|
70
|
-
server.tool("score_ai_overview_eligibility",
|
|
112
|
+
server.tool("score_ai_overview_eligibility", [
|
|
113
|
+
"Score a page's probability of appearing in Google AI Overviews. Returns an overall 0-100 score plus six factor subscores: semantic completeness, structured data, E-E-A-T signals, entity density, freshness, and technical hygiene.",
|
|
114
|
+
"Read-only. One HTTP GET.",
|
|
115
|
+
"Deterministic, rule-based scoring derived from published 2025-2026 AI-Overview correlation studies. No LLM calls. Same URL returns the same score on repeated runs.",
|
|
116
|
+
"When to use: AI-Overview-specific prioritization. For a multi-dimensional audit that includes this scoring plus everything else, use `audit_page`. For citation-worthiness of a specific text passage (rather than a URL ranking probability), use `score_citation_worthiness`.",
|
|
117
|
+
].join("\n\n"), scoreAiOverviewEligibilityInputSchema.shape, async (input) => wrapHandler(() => scoreAiOverviewEligibility(input)));
|
|
71
118
|
// --- Tool 8: generate_llms_txt ---
|
|
72
|
-
server.tool("generate_llms_txt",
|
|
119
|
+
server.tool("generate_llms_txt", [
|
|
120
|
+
"Generate a spec-compliant llms.txt (and optionally llms-full.txt) for a domain by reading its sitemap, sampling up to `max_pages` pages, and synthesizing a grouped, sectioned summary.",
|
|
121
|
+
"Read-only. Issues one HTTP GET for the sitemap then one per sampled page.",
|
|
122
|
+
"Deterministic; no LLM. Output is the file content as a string - this tool does NOT write to disk or upload anywhere. The caller is responsible for hosting the resulting file at `https://<domain>/llms.txt`.",
|
|
123
|
+
"When to use: bootstrapping llms.txt for a site you own. To check an existing llms.txt, use `validate_llms_txt` instead.",
|
|
124
|
+
].join("\n\n"), generateLlmsTxtInputSchema.shape, async (input) => wrapHandler(() => generateLlmsTxtTool(input)));
|
|
73
125
|
// --- Tool 9: validate_llms_txt ---
|
|
74
|
-
server.tool("validate_llms_txt",
|
|
75
|
-
|
|
76
|
-
content
|
|
77
|
-
|
|
126
|
+
server.tool("validate_llms_txt", [
|
|
127
|
+
"Validate an existing llms.txt or llms-full.txt against the spec: structure, section ordering, link format, and (optionally) broken-link detection.",
|
|
128
|
+
"Read-only. One HTTP GET when given `url`; zero network when given `content`. Optional link-check issues HEAD requests against each link if `check_links` is true.",
|
|
129
|
+
"Deterministic; no LLM.",
|
|
130
|
+
"When to use: auditing an llms.txt you already have. To generate one from scratch, use `generate_llms_txt`.",
|
|
131
|
+
"Either `url` or `content` must be provided.",
|
|
132
|
+
].join("\n\n"), {
|
|
133
|
+
url: z
|
|
134
|
+
.string()
|
|
135
|
+
.url()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe("Public URL of an existing llms.txt or llms-full.txt to validate (e.g. `https://example.com/llms.txt`). Either this OR `content` is required."),
|
|
138
|
+
content: z
|
|
139
|
+
.string()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe("Raw llms.txt content as a string. Use this to validate a file offline without fetching. Either this OR `url` is required."),
|
|
142
|
+
check_links: z
|
|
143
|
+
.boolean()
|
|
144
|
+
.optional()
|
|
145
|
+
.default(true)
|
|
146
|
+
.describe("If true (default), HEAD each linked URL to detect broken links. Set false to skip link checks for faster, network-light validation of just the structural rules."),
|
|
78
147
|
}, async (input) => {
|
|
79
148
|
if (!input.url && !input.content) {
|
|
80
149
|
return toolError({ type: "invalid_url", message: "One of url or content is required" });
|
|
@@ -82,11 +151,31 @@ server.tool("validate_llms_txt", "Validate an existing llms.txt or llms-full.txt
|
|
|
82
151
|
return wrapHandler(() => validateLlmsTxt(input));
|
|
83
152
|
});
|
|
84
153
|
// --- Tool 10: score_citation_worthiness ---
|
|
85
|
-
server.tool("score_citation_worthiness",
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
154
|
+
server.tool("score_citation_worthiness", [
|
|
155
|
+
"Score how citable a page or text block is for AI engines (ChatGPT, Claude, Perplexity, Google AI Overviews). Evaluates BLUF (bottom-line-up-front) opening, FAQ patterns, statistic density, entity clarity, and answer-shape fit for the optional `target_query`.",
|
|
156
|
+
"Read-only when given `url` (one HTTP GET). Zero network when given `text`. No writes.",
|
|
157
|
+
"Deterministic, rule-based; no LLM calls. Returns reproducible scores.",
|
|
158
|
+
"When to use: pre-publish content QA, or to triage which existing pages are worth optimizing for AI citation first. Distinct from `score_ai_overview_eligibility` which scores Google-AI-Overview ranking probability for a URL; this scores the inherent citability of a text passage regardless of host.",
|
|
159
|
+
"Either `url` or `text` must be provided.",
|
|
160
|
+
].join("\n\n"), {
|
|
161
|
+
url: z
|
|
162
|
+
.string()
|
|
163
|
+
.url()
|
|
164
|
+
.optional()
|
|
165
|
+
.describe("Public URL to fetch and score. Either this OR `text` is required."),
|
|
166
|
+
text: z
|
|
167
|
+
.string()
|
|
168
|
+
.optional()
|
|
169
|
+
.describe("Raw text/markdown/HTML to score directly without fetching. Either this OR `url` is required."),
|
|
170
|
+
target_query: z
|
|
171
|
+
.string()
|
|
172
|
+
.optional()
|
|
173
|
+
.describe("Optional target search query the content is supposed to answer (e.g. `how to fix CORS errors in Next.js`). When provided, scoring weights answer-shape fit and query-term coverage. Omit if you want a query-agnostic citability score."),
|
|
174
|
+
respect_robots: z
|
|
175
|
+
.boolean()
|
|
176
|
+
.optional()
|
|
177
|
+
.default(true)
|
|
178
|
+
.describe("If true (default), respect robots.txt when fetching `url`. Ignored when `text` is used."),
|
|
90
179
|
}, async (input) => {
|
|
91
180
|
if (!input.url && !input.text) {
|
|
92
181
|
return toolError({ type: "invalid_url", message: "One of url or text is required" });
|
|
@@ -94,13 +183,42 @@ server.tool("score_citation_worthiness", "Score how citable a page or text block
|
|
|
94
183
|
return wrapHandler(() => scoreCitationWorthiness(input));
|
|
95
184
|
});
|
|
96
185
|
// --- Tool 11: rewrite_for_aeo ---
|
|
97
|
-
server.tool("rewrite_for_aeo",
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
186
|
+
server.tool("rewrite_for_aeo", [
|
|
187
|
+
"Rewrite a content block for Answer Engine Optimization. Adds a BLUF opening, FAQ structure, schema additions, and concise question-shaped headings tuned for ChatGPT / Perplexity / Google AI Overviews.",
|
|
188
|
+
"Read-only when given `url` (one HTTP GET). Zero network when given `text`. The tool does NOT write back to the URL - it only returns the rewritten content as a string. No side effects on the source.",
|
|
189
|
+
"This tool delegates the actual rewrite to the calling LLM via MCP sampling - it does not call any external API itself. The MCP host's model produces the rewrite. Same input may produce different output across runs (model-dependent).",
|
|
190
|
+
"When to use: optimizing content for direct-answer surfaces (definitions, how-tos, FAQs). For Generative Engine Optimization (entity-rich, comparison-ready synthesis), use `rewrite_for_geo` instead.",
|
|
191
|
+
"Either `url` or `text` must be provided. `target_query` is required.",
|
|
192
|
+
].join("\n\n"), {
|
|
193
|
+
url: z
|
|
194
|
+
.string()
|
|
195
|
+
.url()
|
|
196
|
+
.optional()
|
|
197
|
+
.describe("Public URL whose content should be fetched and rewritten. Either this OR `text` is required."),
|
|
198
|
+
text: z
|
|
199
|
+
.string()
|
|
200
|
+
.optional()
|
|
201
|
+
.describe("Raw content (markdown or HTML) to rewrite directly. Either this OR `url` is required."),
|
|
202
|
+
target_query: z
|
|
203
|
+
.string()
|
|
204
|
+
.describe("The user query the rewrite should answer (e.g. `what is RAG`, `how to deploy Ghost to Docker`). Required - drives heading shape and BLUF wording."),
|
|
205
|
+
format: z
|
|
206
|
+
.enum(["article", "faq", "howto", "comparison"])
|
|
207
|
+
.default("article")
|
|
208
|
+
.describe("Output shape. `article` for prose-with-headings. `faq` for Q&A list. `howto` for numbered-step procedural content with HowTo schema hints. `comparison` for X-vs-Y tables. Default `article`."),
|
|
209
|
+
max_words: z
|
|
210
|
+
.number()
|
|
211
|
+
.int()
|
|
212
|
+
.min(100)
|
|
213
|
+
.max(5000)
|
|
214
|
+
.optional()
|
|
215
|
+
.default(1500)
|
|
216
|
+
.describe("Soft word budget for the rewrite. Default 1500. Range 100-5000. The rewrite tries to stay under this; very small budgets may force truncation."),
|
|
217
|
+
respect_robots: z
|
|
218
|
+
.boolean()
|
|
219
|
+
.optional()
|
|
220
|
+
.default(true)
|
|
221
|
+
.describe("If true (default), respect robots.txt when fetching `url`. Ignored when `text` is used."),
|
|
104
222
|
}, async (input) => {
|
|
105
223
|
if (!input.url && !input.text) {
|
|
106
224
|
return toolError({ type: "invalid_url", message: "One of url or text is required" });
|
|
@@ -108,13 +226,43 @@ server.tool("rewrite_for_aeo", "Rewrite a content block for Answer Engine Optimi
|
|
|
108
226
|
return wrapHandler(() => rewriteForAeo(input, undefined, undefined, server));
|
|
109
227
|
});
|
|
110
228
|
// --- Tool 12: rewrite_for_geo ---
|
|
111
|
-
server.tool("rewrite_for_geo",
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
229
|
+
server.tool("rewrite_for_geo", [
|
|
230
|
+
"Rewrite a content block for Generative Engine Optimization: entity-rich, comparison-ready, synthesis-friendly. Tuned for surfaces that summarize across sources (Perplexity, Google AI Mode, Claude search).",
|
|
231
|
+
"Read-only on input. Does NOT write back to the source URL - returns the rewritten content as a string.",
|
|
232
|
+
"This tool delegates the actual rewrite to the calling LLM via MCP sampling - it does not call any external API itself. The MCP host's model produces the rewrite. Output may vary across runs (model-dependent).",
|
|
233
|
+
"When to use: optimizing for synthesis-style answers across multiple sources. For direct-answer (BLUF + FAQ) optimization on a single page, use `rewrite_for_aeo` instead.",
|
|
234
|
+
"Either `url` or `text` must be provided. `target_query` is required.",
|
|
235
|
+
].join("\n\n"), {
|
|
236
|
+
url: z
|
|
237
|
+
.string()
|
|
238
|
+
.url()
|
|
239
|
+
.optional()
|
|
240
|
+
.describe("Public URL whose content should be fetched and rewritten. Either this OR `text` is required."),
|
|
241
|
+
text: z
|
|
242
|
+
.string()
|
|
243
|
+
.optional()
|
|
244
|
+
.describe("Raw content to rewrite directly. Either this OR `url` is required."),
|
|
245
|
+
target_query: z
|
|
246
|
+
.string()
|
|
247
|
+
.describe("The user query the rewrite should answer. Required - drives entity selection and comparison framing."),
|
|
248
|
+
add_comparison_table: z
|
|
249
|
+
.boolean()
|
|
250
|
+
.optional()
|
|
251
|
+
.default(false)
|
|
252
|
+
.describe("If true, inject an explicit X-vs-Y comparison table into the rewrite (useful for `X vs Y` queries). Default false."),
|
|
253
|
+
max_words: z
|
|
254
|
+
.number()
|
|
255
|
+
.int()
|
|
256
|
+
.min(100)
|
|
257
|
+
.max(5000)
|
|
258
|
+
.optional()
|
|
259
|
+
.default(1500)
|
|
260
|
+
.describe("Soft word budget. Default 1500. Range 100-5000."),
|
|
261
|
+
respect_robots: z
|
|
262
|
+
.boolean()
|
|
263
|
+
.optional()
|
|
264
|
+
.default(true)
|
|
265
|
+
.describe("If true (default), respect robots.txt when fetching `url`. Ignored when `text` is used."),
|
|
118
266
|
}, async (input) => {
|
|
119
267
|
if (!input.url && !input.text) {
|
|
120
268
|
return toolError({ type: "invalid_url", message: "One of url or text is required" });
|
|
@@ -122,16 +270,41 @@ server.tool("rewrite_for_geo", "Rewrite a content block for Generative Engine Op
|
|
|
122
270
|
return wrapHandler(() => rewriteForGeo(input, undefined, undefined, server));
|
|
123
271
|
});
|
|
124
272
|
// --- Tool 13: extract_entities ---
|
|
125
|
-
server.tool("extract_entities",
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
273
|
+
server.tool("extract_entities", [
|
|
274
|
+
"Extract named entities, linked concepts, and sameAs graph nodes from a page's content and structured data. Combines body-text NER heuristics with JSON-LD `@type` / `sameAs` walking.",
|
|
275
|
+
"Read-only when given `url` (one HTTP GET). Zero network when given `text`.",
|
|
276
|
+
"Deterministic, rule-based; no LLM. Output is a list of entities with type, confidence, and any sameAs URIs found in structured data.",
|
|
277
|
+
"When to use: building an entity map for schema generation, or auditing whether a page's entities match its target topic. To validate the JSON-LD itself, use `audit_schema`.",
|
|
278
|
+
"Either `url` or `text` must be provided.",
|
|
279
|
+
].join("\n\n"), {
|
|
280
|
+
url: z
|
|
281
|
+
.string()
|
|
282
|
+
.url()
|
|
283
|
+
.optional()
|
|
284
|
+
.describe("Public URL to fetch and analyze. Either this OR `text` is required."),
|
|
285
|
+
text: z
|
|
286
|
+
.string()
|
|
287
|
+
.optional()
|
|
288
|
+
.describe("Raw text/HTML to analyze directly. Either this OR `url` is required."),
|
|
289
|
+
respect_robots: z
|
|
290
|
+
.boolean()
|
|
291
|
+
.optional()
|
|
292
|
+
.default(true)
|
|
293
|
+
.describe("If true (default), respect robots.txt when fetching `url`. Ignored when `text` is used."),
|
|
129
294
|
}, async (input) => {
|
|
130
295
|
if (!input.url && !input.text) {
|
|
131
296
|
return toolError({ type: "invalid_url", message: "One of url or text is required" });
|
|
132
297
|
}
|
|
133
298
|
return wrapHandler(() => extractEntities(input));
|
|
134
299
|
});
|
|
300
|
+
// --- Tool 14: diff_pages ---
|
|
301
|
+
server.tool("diff_pages", [
|
|
302
|
+
"Compare two URLs for AI citation-worthiness and return a structured breakdown of which page is more likely to be cited and why. Typical use: your page (url_a) vs a competitor's page (url_b).",
|
|
303
|
+
"Read-only. Runs audit_page on both URLs in parallel (2 HTTP fetches per URL), then diffs dimension_scores and findings. No new fetch logic beyond what audit_page already does.",
|
|
304
|
+
"Deterministic, rule-based; no LLM calls. Same two URLs return the same comparison on repeated runs.",
|
|
305
|
+
"When to use: competitive gap analysis - understand exactly which dimensions (schema, structure, robots, entity density, freshness, technical, authority, sitemap) put a competitor ahead, and get prioritized fix_recommendations_for_a to close the gap. For a single-URL audit, use audit_page. For overall scoring of one page, use score_citation_worthiness.",
|
|
306
|
+
"Capped at 2 URLs per call. Heuristic verdict - does not claim to know what AI assistants actually cite; verdict matches audit_page's existing rubric.",
|
|
307
|
+
].join("\n\n"), diffPagesInputSchema.shape, async (input) => wrapHandler(() => diffPages(input)));
|
|
135
308
|
// --- Start server ---
|
|
136
309
|
async function main() {
|
|
137
310
|
const transport = new StdioServerTransport();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,kCAAkC;AAClC,yEAAyE;AAEzE,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|