aeo-scanner 2.2.2__tar.gz → 2.2.3__tar.gz
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.
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/PKG-INFO +1 -1
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/pyproject.toml +1 -1
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/server.json +2 -2
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/src/server.py +16 -6
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/package.json +1 -1
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/api-client.test.ts +20 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/api-client.ts +9 -4
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/index.ts +1 -1
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/tools.ts +11 -7
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/.gitignore +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/.mcp.json +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/LICENSE +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/README.md +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/aeo-icon.svg +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/scoring-methodology.md +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/src/__init__.py +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/uv.lock +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.gitignore +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.oxfmtrc.json +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.oxlintrc.json +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/README.md +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/package-lock.json +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/prompts.ts +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/resources.ts +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/scoring-methodology.ts +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/tsconfig.json +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/worker-configuration.d.ts +0 -0
- {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/wrangler.jsonc +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: aeo-scanner
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.3
|
|
4
4
|
Summary: MCP server for AI search visibility auditing. Triple scoring: AEO (search findability), GEO (citation readiness), Agent Readiness (agent interaction). Plus AI Identity Card and business profile detection.
|
|
5
5
|
Author-email: Convrgent <hello@convrgent.ai>
|
|
6
6
|
License: MIT
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "aeo-scanner"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.3"
|
|
4
4
|
description = "MCP server for AI search visibility auditing. Triple scoring: AEO (search findability), GEO (citation readiness), Agent Readiness (agent interaction). Plus AI Identity Card and business profile detection."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = {text = "MIT"}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"url": "https://github.com/Convrgent/aeo-saas",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
|
-
"version": "2.2.
|
|
10
|
+
"version": "2.2.3",
|
|
11
11
|
"remotes": [
|
|
12
12
|
{
|
|
13
13
|
"type": "streamable-http",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
{
|
|
19
19
|
"registryType": "pypi",
|
|
20
20
|
"identifier": "aeo-scanner",
|
|
21
|
-
"version": "2.2.
|
|
21
|
+
"version": "2.2.3",
|
|
22
22
|
"transport": {
|
|
23
23
|
"type": "stdio"
|
|
24
24
|
}
|
|
@@ -119,6 +119,8 @@ async def audit_site(
|
|
|
119
119
|
authority signals, entity definition), and Agent Readiness (machine
|
|
120
120
|
identity, API discoverability, structured actions, programmatic access).
|
|
121
121
|
Returns AI Identity Card with mention readiness and detected competitors.
|
|
122
|
+
TIP: the response's id can be passed as scan_id to fix_site within
|
|
123
|
+
1 hour to get fix code without a re-crawl.
|
|
122
124
|
Pay per call ($1.00) via x402 — USDC on Base or Solana."""
|
|
123
125
|
payload: dict = {"url": url, "pages": min(max(1, pages), 5)}
|
|
124
126
|
if categories:
|
|
@@ -142,18 +144,26 @@ async def compare_sites(url: str, competitor_url: str, pages: int = 5) -> str:
|
|
|
142
144
|
|
|
143
145
|
|
|
144
146
|
@mcp.tool()
|
|
145
|
-
async def fix_site(
|
|
147
|
+
async def fix_site(
|
|
148
|
+
url: str = "", pages: int = 5, format: str = "generic", scan_id: str = ""
|
|
149
|
+
) -> str:
|
|
146
150
|
"""Generate complete fix code for all AI visibility issues across
|
|
147
151
|
AEO, GEO, and Agent Readiness. Returns working code that coding
|
|
148
152
|
agents can apply directly. Includes two-tier score projections:
|
|
149
153
|
quick wins (critical + high fixes only) and full implementation
|
|
150
|
-
ceiling (all fixes).
|
|
154
|
+
ceiling (all fixes). TIP: pass scan_id from a fresh audit_site result
|
|
155
|
+
(kept 1 hour) to skip the re-crawl — instant response, same price.
|
|
156
|
+
Content recommendations include research citations.
|
|
151
157
|
Set format to 'claude_code' for Claude Code optimized output.
|
|
152
158
|
Pay per call ($5.00) via x402 — USDC on Base or Solana."""
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
# Backend reads maxPages (not pages) — this also fixes a latent drift
|
|
160
|
+
# where the old payload key was silently ignored and the default applied.
|
|
161
|
+
payload: dict = {"maxPages": min(max(1, pages), 10), "format": format}
|
|
162
|
+
if url:
|
|
163
|
+
payload["url"] = url
|
|
164
|
+
if scan_id:
|
|
165
|
+
payload["scanId"] = scan_id
|
|
166
|
+
return await _handle_paid_request("/api/aeo/fix", payload)
|
|
157
167
|
|
|
158
168
|
|
|
159
169
|
@mcp.resource("aeo://reference/scoring-methodology")
|
|
@@ -150,6 +150,26 @@ describe("paid tools — payment proxy behavior", () => {
|
|
|
150
150
|
expect(sentBody(fetchCalls[0]).format).toBe("claude_code");
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
+
it("callFix passes scan_id through as scanId and omits url when absent", async () => {
|
|
154
|
+
mockFetchResponse(200, "{}");
|
|
155
|
+
|
|
156
|
+
await callFix(env, undefined, 5, "generic", null, "scan_1_abc123");
|
|
157
|
+
|
|
158
|
+
const body = sentBody(fetchCalls[0]);
|
|
159
|
+
expect(body.scanId).toBe("scan_1_abc123");
|
|
160
|
+
expect(body.url).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("callFix sends both url and scanId when both provided", async () => {
|
|
164
|
+
mockFetchResponse(200, "{}");
|
|
165
|
+
|
|
166
|
+
await callFix(env, "https://example.com", 5, "generic", null, "scan_1_abc123");
|
|
167
|
+
|
|
168
|
+
const body = sentBody(fetchCalls[0]);
|
|
169
|
+
expect(body.url).toBe("https://example.com");
|
|
170
|
+
expect(body.scanId).toBe("scan_1_abc123");
|
|
171
|
+
});
|
|
172
|
+
|
|
153
173
|
it("callCompare sends both URLs, clamps maxPages to 5, uses compare_sites pricing", async () => {
|
|
154
174
|
mockFetchResponse(402, "{}");
|
|
155
175
|
|
|
@@ -100,16 +100,21 @@ export async function callAudit(
|
|
|
100
100
|
|
|
101
101
|
export async function callFix(
|
|
102
102
|
env: Env,
|
|
103
|
-
url: string,
|
|
103
|
+
url: string | undefined,
|
|
104
104
|
pages: number,
|
|
105
105
|
format: string,
|
|
106
106
|
clientPaymentHeader: string | null,
|
|
107
|
+
scanId?: string,
|
|
107
108
|
): Promise<ApiResult> {
|
|
108
|
-
|
|
109
|
-
url,
|
|
109
|
+
const payload: Record<string, unknown> = {
|
|
110
110
|
maxPages: Math.min(Math.max(1, pages), 10),
|
|
111
111
|
format,
|
|
112
|
-
}
|
|
112
|
+
};
|
|
113
|
+
if (url) payload.url = url;
|
|
114
|
+
// scanId reuses a recent audit's crawl server-side (1h TTL) — same price,
|
|
115
|
+
// instant response. Backend contract: url OR scanId required.
|
|
116
|
+
if (scanId) payload.scanId = scanId;
|
|
117
|
+
return handlePaidRequest(env, "/api/aeo/fix", payload, clientPaymentHeader);
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
export async function callCompare(
|
|
@@ -6,7 +6,7 @@ import { registerPrompts } from "./prompts";
|
|
|
6
6
|
|
|
7
7
|
export class AeoScannerMcp extends McpAgent<Env> {
|
|
8
8
|
server = new McpServer(
|
|
9
|
-
{ name: "aeo-scanner", version: "2.2.
|
|
9
|
+
{ name: "aeo-scanner", version: "2.2.3" },
|
|
10
10
|
{
|
|
11
11
|
instructions:
|
|
12
12
|
"AI search visibility audit for any website. Returns three scores (AEO, GEO, Agent Readiness), AI Identity Card with mention readiness and detected competitors, and business profile. Use scan_site first (free), then audit_site for details, fix_site for fix code, or compare_sites to benchmark against a competitor. The optimize_site prompt guides the full workflow.",
|
|
@@ -37,7 +37,7 @@ export function registerTools(server: McpServer, env: Env) {
|
|
|
37
37
|
|
|
38
38
|
server.tool(
|
|
39
39
|
"audit_site",
|
|
40
|
-
"Full AI visibility audit across 67+ checks in 12 categories (4 AEO + 4 GEO + 4 Agent Readiness). Returns detailed per-check scores with specific issues and recommendations, AI Identity Card with mention readiness and detected competitors, and business profile. GEO checks include 3 research-backed citation signals: factual density, answer frontloading, and source citations. Agent Readiness covers emerging agent-discovery standards Cloudflare's isitagentready.com evaluates: RFC 9727 api-catalog, SEP-1649 MCP Server Card, and IETF Content-Signal (draft-romm-aipref). Does NOT generate fix code —
|
|
40
|
+
"Full AI visibility audit across 67+ checks in 12 categories (4 AEO + 4 GEO + 4 Agent Readiness). Returns detailed per-check scores with specific issues and recommendations, AI Identity Card with mention readiness and detected competitors, and business profile. GEO checks include 3 research-backed citation signals: factual density, answer frontloading, and source citations. Agent Readiness covers emerging agent-discovery standards Cloudflare's isitagentready.com evaluates: RFC 9727 api-catalog, SEP-1649 MCP Server Card, and IETF Content-Signal (draft-romm-aipref). Does NOT generate fix code — pass this response's id as scan_id to fix_site (within 1 hour) to get fixes WITHOUT a re-crawl, or use compare_sites to benchmark against a competitor. Pay per call ($1.00) via x402 — USDC on Base or Solana. Machine payment via signed X-PAYMENT header; see https://www.x402.org/. On payment_required, the response includes the full x402 payload with payTo/amount/asset.",
|
|
41
41
|
{
|
|
42
42
|
url: z.string().describe("Full URL to audit"),
|
|
43
43
|
pages: z
|
|
@@ -63,25 +63,29 @@ export function registerTools(server: McpServer, env: Env) {
|
|
|
63
63
|
|
|
64
64
|
server.tool(
|
|
65
65
|
"fix_site",
|
|
66
|
-
"Generate complete fix code for all AI visibility issues across AEO, GEO, and Agent Readiness. Returns working code you can apply directly — schema generation, robots.txt, sitemap, llms.txt, meta tags, structured data, citation signals, entity markup. Also returns two-tier score projections: quick wins (critical + high fixes only) and full implementation ceiling (all fixes). Content recommendations include research citations. Run scan_site first to see which issues exist. Pay per call ($5.00) via x402 — USDC on Base or Solana. On payment_required, the response includes the full x402 payload with payTo/amount/asset.",
|
|
66
|
+
"Generate complete fix code for all AI visibility issues across AEO, GEO, and Agent Readiness. Returns working code you can apply directly — schema generation, robots.txt, sitemap, llms.txt, meta tags, structured data, citation signals, entity markup. Also returns two-tier score projections: quick wins (critical + high fixes only) and full implementation ceiling (all fixes). TIP: pass scan_id from a fresh audit_site result (kept 1 hour) to skip the re-crawl — instant response, same price. Content recommendations include research citations. Run scan_site first to see which issues exist. Pay per call ($5.00) via x402 — USDC on Base or Solana. On payment_required, the response includes the full x402 payload with payTo/amount/asset.",
|
|
67
67
|
{
|
|
68
|
-
url: z.string().describe("Full URL to generate fixes for"),
|
|
68
|
+
url: z.string().optional().describe("Full URL to generate fixes for (required unless scan_id is given)"),
|
|
69
|
+
scan_id: z
|
|
70
|
+
.string()
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("id from a recent audit_site response — reuses that crawl (1h TTL), instant response"),
|
|
69
73
|
pages: z
|
|
70
74
|
.number()
|
|
71
75
|
.int()
|
|
72
76
|
.min(1)
|
|
73
77
|
.max(10)
|
|
74
78
|
.default(5)
|
|
75
|
-
.describe("Number of pages to analyze (1-10)"),
|
|
79
|
+
.describe("Number of pages to analyze (1-10); ignored when scan_id is used"),
|
|
76
80
|
format: z
|
|
77
81
|
.enum(["generic", "claude_code"])
|
|
78
82
|
.default("generic")
|
|
79
83
|
.describe("Output format: generic or claude_code (optimized for Claude Code)"),
|
|
80
84
|
},
|
|
81
85
|
{ openWorldHint: true },
|
|
82
|
-
async ({ url, pages, format }) => {
|
|
83
|
-
console.log(`[TOOL] fix_site | url=${url} | pages=${pages} | format=${format}`);
|
|
84
|
-
return toToolResult(await callFix(env, url, pages, format, null));
|
|
86
|
+
async ({ url, scan_id, pages, format }) => {
|
|
87
|
+
console.log(`[TOOL] fix_site | url=${url ?? "-"} | scan_id=${scan_id ?? "-"} | pages=${pages} | format=${format}`);
|
|
88
|
+
return toToolResult(await callFix(env, url, pages, format, null, scan_id));
|
|
85
89
|
},
|
|
86
90
|
);
|
|
87
91
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|