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.
Files changed (28) hide show
  1. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/PKG-INFO +1 -1
  2. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/pyproject.toml +1 -1
  3. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/server.json +2 -2
  4. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/src/server.py +16 -6
  5. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/package.json +1 -1
  6. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/api-client.test.ts +20 -0
  7. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/api-client.ts +9 -4
  8. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/index.ts +1 -1
  9. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/tools.ts +11 -7
  10. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/.gitignore +0 -0
  11. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/.mcp.json +0 -0
  12. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/LICENSE +0 -0
  13. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/README.md +0 -0
  14. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/aeo-icon.svg +0 -0
  15. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/scoring-methodology.md +0 -0
  16. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/src/__init__.py +0 -0
  17. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/uv.lock +0 -0
  18. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.gitignore +0 -0
  19. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.oxfmtrc.json +0 -0
  20. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/.oxlintrc.json +0 -0
  21. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/README.md +0 -0
  22. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/package-lock.json +0 -0
  23. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/prompts.ts +0 -0
  24. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/resources.ts +0 -0
  25. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/src/scoring-methodology.ts +0 -0
  26. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/tsconfig.json +0 -0
  27. {aeo_scanner-2.2.2 → aeo_scanner-2.2.3}/workers/worker-configuration.d.ts +0 -0
  28. {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.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.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.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.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(url: str, pages: int = 5, format: str = "generic") -> str:
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). Content recommendations include research citations.
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
- return await _handle_paid_request(
154
- "/api/aeo/fix",
155
- {"url": url, "pages": min(max(1, pages), 5), "format": format},
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")
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aeo-scanner-mcp",
3
- "version": "2.2.2",
3
+ "version": "2.2.3",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "deploy": "wrangler deploy",
@@ -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
- return handlePaidRequest(env, "/api/aeo/fix", {
109
- url,
109
+ const payload: Record<string, unknown> = {
110
110
  maxPages: Math.min(Math.max(1, pages), 10),
111
111
  format,
112
- }, clientPaymentHeader);
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.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 — use fix_site for that, or 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.",
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