mcp-scraper 0.21.2 → 0.21.4
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 +1 -1
- package/dist/bin/api-server.cjs +1061 -308
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +3 -3
- package/dist/bin/mcp-scraper-cli.cjs +1 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +1 -1
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +101 -34
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +5 -5
- package/dist/bin/paa-harvest.cjs +22 -0
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +3 -3
- package/dist/{chunk-ZJDANZTQ.js → chunk-E5J4HJBO.js} +3 -2
- package/dist/chunk-E5J4HJBO.js.map +1 -0
- package/dist/{chunk-DZBGULWW.js → chunk-ICT7DDHL.js} +399 -3
- package/dist/chunk-ICT7DDHL.js.map +1 -0
- package/dist/{chunk-2FF4GBQ4.js → chunk-JHI373VB.js} +49 -7
- package/dist/chunk-JHI373VB.js.map +1 -0
- package/dist/{chunk-GMZFQRH2.js → chunk-MTSBI7ZH.js} +23 -6
- package/dist/chunk-MTSBI7ZH.js.map +1 -0
- package/dist/{chunk-ZNNYPE2U.js → chunk-N4JHXPW6.js} +89 -27
- package/dist/chunk-N4JHXPW6.js.map +1 -0
- package/dist/{chunk-X3NIXHHG.js → chunk-PNBYYAEK.js} +3 -3
- package/dist/{chunk-JBME5WJR.js → chunk-SDHPQTFM.js} +2 -2
- package/dist/chunk-WQI7JIIN.js +7 -0
- package/dist/chunk-WQI7JIIN.js.map +1 -0
- package/dist/{db-EONGTNJM.js → db-WRILVOFY.js} +6 -2
- package/dist/{extract-bundle-HMCYUVBJ.js → extract-bundle-NFFVMUMT.js} +2 -2
- package/dist/index.cjs +22 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +3 -3
- package/dist/{server-CHTX6YQA.js → server-OLOOFN5W.js} +499 -271
- package/dist/server-OLOOFN5W.js.map +1 -0
- package/dist/{site-extract-repository-5V5EEQ72.js → site-extract-repository-2QQSL2QC.js} +4 -4
- package/dist/{worker-GE5JMHE6.js → worker-RV2TYXE3.js} +15 -8
- package/dist/worker-RV2TYXE3.js.map +1 -0
- package/docs/mcp-tool-manifest.generated.json +90 -11
- package/docs/specs/oauth-mcp-spec.md +2 -2
- package/package.json +1 -1
- package/dist/chunk-2FF4GBQ4.js.map +0 -1
- package/dist/chunk-DZBGULWW.js.map +0 -1
- package/dist/chunk-GMZFQRH2.js.map +0 -1
- package/dist/chunk-NBF4F4UT.js +0 -7
- package/dist/chunk-NBF4F4UT.js.map +0 -1
- package/dist/chunk-ZJDANZTQ.js.map +0 -1
- package/dist/chunk-ZNNYPE2U.js.map +0 -1
- package/dist/server-CHTX6YQA.js.map +0 -1
- package/dist/worker-GE5JMHE6.js.map +0 -1
- /package/dist/{chunk-X3NIXHHG.js.map → chunk-PNBYYAEK.js.map} +0 -0
- /package/dist/{chunk-JBME5WJR.js.map → chunk-SDHPQTFM.js.map} +0 -0
- /package/dist/{db-EONGTNJM.js.map → db-WRILVOFY.js.map} +0 -0
- /package/dist/{extract-bundle-HMCYUVBJ.js.map → extract-bundle-NFFVMUMT.js.map} +0 -0
- /package/dist/{site-extract-repository-5V5EEQ72.js.map → site-extract-repository-2QQSL2QC.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/browser-service-env.ts","../src/api/cost-context.ts","../src/api/cost-rates.ts","../src/api/cost-telemetry.ts"],"sourcesContent":["export function browserServiceApiKey(): string | undefined {\n const value = (process.env.BROWSER_SERVICE_API_KEY ?? process.env.KERNEL_API_KEY)?.trim()\n return value || undefined\n}\n\nexport function browserServiceProxyId(): string | undefined {\n return undefined\n}\n\nexport function browserServiceProfileName(): string | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_NAME ??\n process.env.BROWSER_SERVICE_PROFILE_NAME ??\n process.env.KERNEL_BROWSER_PROFILE_NAME ??\n process.env.KERNEL_PROFILE_NAME\n )?.trim()\n return value || undefined\n}\n\nexport function browserServiceProfileSaveChanges(): boolean | undefined {\n const value = (\n process.env.BROWSER_AGENT_PROFILE_SAVE_CHANGES ??\n process.env.BROWSER_SERVICE_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_BROWSER_PROFILE_SAVE_CHANGES ??\n process.env.KERNEL_PROFILE_SAVE_CHANGES\n )?.trim().toLowerCase()\n if (!value) return undefined\n if (['1', 'true', 'yes', 'on'].includes(value)) return true\n if (['0', 'false', 'no', 'off'].includes(value)) return false\n return undefined\n}\n","import { AsyncLocalStorage } from 'node:async_hooks'\n\nexport interface CostContext {\n op: string\n probeRunId?: string | null\n userId?: number | null\n forceHeadless?: boolean\n forceHeadful?: boolean\n subOp?: string | null\n headlessSentOut?: { value: boolean | null }\n}\n\nconst storage = new AsyncLocalStorage<CostContext>()\n\nexport function runWithCostContext<T>(ctx: CostContext, fn: () => T): T {\n return storage.run(ctx, fn)\n}\n\nexport function currentCostContext(): CostContext | undefined {\n return storage.getStore()\n}\n","export const KERNEL_HEADLESS_USD_PER_SEC = 0.0000166667\nexport const KERNEL_HEADFUL_USD_PER_SEC = 0.0001333336\n\nexport const HEADLESS_OPS = new Set<string>(['serp', 'maps_search', 'yt_channel', 'yt_transcription', 'fb_search', 'fb_ad', 'instagram'])\n\nexport const FAL_WIZPER_USD_PER_COMPUTE_SEC = 0.00111\nexport const FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR = 4 // calibrated from 2 real Fal invoices (4.36x, 6.18x wall-clock vs actual)\nexport const DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS = 0.0004\n\nexport function kernelCostUsd(ms: number, headful: boolean): number {\n const sec = Math.max(0, ms) / 1000\n return sec * (headful ? KERNEL_HEADFUL_USD_PER_SEC : KERNEL_HEADLESS_USD_PER_SEC)\n}\n\nexport function vendorCostUsd(vendor: string, units: number): number {\n if (vendor === 'fal_wizper') {\n const estimatedComputeSec = Math.max(0, units) / FAL_WIZPER_WALLCLOCK_TO_COMPUTE_SEC_FACTOR\n return estimatedComputeSec * FAL_WIZPER_USD_PER_COMPUTE_SEC\n }\n if (vendor === 'deepinfra_qwen') return (Math.max(0, units) / 1000) * DEEPINFRA_QWEN_USD_PER_1K_OUT_TOKENS\n if (vendor === 'openrouter') return Math.max(0, units) // units IS the real USD cost OpenRouter reported, not a rate-multiplied estimate\n if (vendor === 'mcp_memory_video') return Math.max(0, units) // units IS the real costUsd mcp-memory's video pipeline reported (OpenRouter + transcription)\n if (vendor === 'mcp_memory_ai') return Math.max(0, units) // units IS the real costUsd mcp-memory reported via /ai-debit\n return 0\n}\n","import { randomUUID } from 'node:crypto'\nimport { getDb } from './db.js'\nimport { currentCostContext } from './cost-context.js'\nimport { kernelCostUsd, vendorCostUsd } from './cost-rates.js'\n\nlet _ready = false\nlet _migrationPromise: Promise<void> | null = null\n\nexport async function migrateCostTelemetry(): Promise<void> {\n if (_ready) return\n if (_migrationPromise) return _migrationPromise\n _migrationPromise = runCostTelemetryMigration().finally(() => {\n _migrationPromise = null\n })\n return _migrationPromise\n}\n\nasync function runCostTelemetryMigration(): Promise<void> {\n const db = getDb()\n const existing = await db.execute(`\n SELECT\n (SELECT COUNT(*) FROM sqlite_master WHERE type = 'table' AND name IN ('kernel_session_log', 'vendor_usage_log', 'cost_probe_runs')) = 3\n AND (SELECT COUNT(*) FROM pragma_table_info('kernel_session_log') WHERE name IN ('proxy_source', 'proxy_type', 'method')) = 3\n AND (SELECT COUNT(*) FROM pragma_table_info('vendor_usage_log') WHERE name = 'method') = 1\n AND (SELECT COUNT(*) FROM pragma_table_info('cost_probe_runs') WHERE name IN ('units', 'unit_type', 'mode')) = 3\n AS ready\n `)\n if (Number(existing.rows[0]?.ready ?? 0) === 1) {\n _ready = true\n return\n }\n\n await db.execute(`\n CREATE TABLE IF NOT EXISTS kernel_session_log (\n id TEXT PRIMARY KEY,\n kernel_session_id TEXT,\n op TEXT,\n source TEXT NOT NULL,\n probe_run_id TEXT,\n user_id INTEGER,\n stealth INTEGER,\n headless_sent INTEGER,\n proxy_used INTEGER,\n fallback INTEGER NOT NULL DEFAULT 0,\n opened_at TEXT,\n closed_at TEXT,\n duration_ms INTEGER NOT NULL DEFAULT 0,\n est_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_cost_usd_headful REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_op ON kernel_session_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_probe ON kernel_session_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS kernel_session_log_created ON kernel_session_log(created_at)`)\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_source TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN proxy_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE kernel_session_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS vendor_usage_log (\n id TEXT PRIMARY KEY,\n op TEXT,\n probe_run_id TEXT,\n user_id INTEGER,\n vendor TEXT NOT NULL,\n model TEXT,\n units REAL NOT NULL DEFAULT 0,\n unit_type TEXT,\n est_cost_usd REAL NOT NULL DEFAULT 0,\n error TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_op ON vendor_usage_log(op)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_probe ON vendor_usage_log(probe_run_id)`)\n await db.execute(`CREATE INDEX IF NOT EXISTS vendor_usage_log_created ON vendor_usage_log(created_at)`)\n try { await db.execute(`ALTER TABLE vendor_usage_log ADD COLUMN method TEXT`) } catch { void 0 }\n await db.execute(`\n CREATE TABLE IF NOT EXISTS cost_probe_runs (\n id TEXT PRIMARY KEY,\n tool TEXT NOT NULL,\n target TEXT,\n started_at TEXT NOT NULL DEFAULT (datetime('now')),\n wall_ms INTEGER NOT NULL DEFAULT 0,\n success INTEGER NOT NULL DEFAULT 0,\n error TEXT,\n http_only INTEGER NOT NULL DEFAULT 0,\n kernel_used INTEGER NOT NULL DEFAULT 0,\n kernel_sessions INTEGER NOT NULL DEFAULT 0,\n kernel_seconds_total REAL NOT NULL DEFAULT 0,\n kernel_tier_observed TEXT,\n est_kernel_cost_usd_headless REAL NOT NULL DEFAULT 0,\n est_kernel_cost_usd_headful REAL NOT NULL DEFAULT 0,\n vendor_cost_usd REAL NOT NULL DEFAULT 0,\n charged_credits REAL NOT NULL DEFAULT 0,\n margin_usd_headless_starter REAL NOT NULL DEFAULT 0,\n margin_usd_headful_starter REAL NOT NULL DEFAULT 0,\n notes TEXT\n )\n `)\n await db.execute(`CREATE INDEX IF NOT EXISTS cost_probe_runs_tool ON cost_probe_runs(tool)`)\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN units REAL`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN unit_type TEXT`) } catch { void 0 }\n try { await db.execute(`ALTER TABLE cost_probe_runs ADD COLUMN mode TEXT`) } catch { void 0 }\n _ready = true\n}\n\nexport interface KernelSessionRecord {\n kernelSessionId?: string | null\n source: string\n stealth?: boolean | null\n headlessSent?: boolean | null\n proxyUsed?: boolean | null\n proxySource?: string | null\n proxyType?: string | null\n fallback?: boolean\n openedAtMs: number\n closedAtMs: number\n error?: string | null\n}\n\nexport async function recordKernelSession(r: KernelSessionRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const durationMs = Math.max(0, r.closedAtMs - r.openedAtMs)\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO kernel_session_log\n (id, kernel_session_id, op, source, probe_run_id, user_id, stealth, headless_sent, proxy_used, proxy_source, proxy_type, fallback, opened_at, closed_at, duration_ms, est_cost_usd_headless, est_cost_usd_headful, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n r.kernelSessionId ?? null,\n ctx?.op ?? null,\n r.source,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n boolToInt(r.stealth),\n boolToInt(r.headlessSent),\n boolToInt(r.proxyUsed),\n r.proxySource ?? null,\n r.proxyType ?? null,\n r.fallback ? 1 : 0,\n new Date(r.openedAtMs).toISOString(),\n new Date(r.closedAtMs).toISOString(),\n durationMs,\n kernelCostUsd(durationMs, false),\n kernelCostUsd(durationMs, true),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordKernelSession failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface VendorUsageRecord {\n vendor: string\n model?: string | null\n units: number\n unitType: string\n error?: string | null\n}\n\nexport async function recordVendorUsage(r: VendorUsageRecord): Promise<void> {\n try {\n await migrateCostTelemetry()\n const ctx = currentCostContext()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO vendor_usage_log\n (id, op, probe_run_id, user_id, vendor, model, units, unit_type, est_cost_usd, error, method)\n VALUES (?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n randomUUID(),\n ctx?.op ?? null,\n ctx?.probeRunId ?? null,\n ctx?.userId ?? null,\n r.vendor,\n r.model ?? null,\n r.units,\n r.unitType,\n vendorCostUsd(r.vendor, r.units),\n r.error ?? null,\n ctx?.subOp ?? null,\n ],\n })\n } catch (err) {\n console.warn('[cost-telemetry] recordVendorUsage failed:', err instanceof Error ? err.message : String(err))\n }\n}\n\nexport interface ProbeRunRecord {\n id: string\n tool: string\n target?: string | null\n wallMs: number\n success: boolean\n error?: string | null\n httpOnly: boolean\n kernelUsed: boolean\n kernelSessions: number\n kernelSecondsTotal: number\n kernelTierObserved?: string | null\n estKernelCostUsdHeadless: number\n estKernelCostUsdHeadful: number\n vendorCostUsd: number\n chargedCredits: number\n marginUsdHeadlessStarter: number\n marginUsdHeadfulStarter: number\n units?: number | null\n unitType?: string | null\n mode?: string | null\n notes?: string | null\n}\n\nexport async function recordProbeRun(r: ProbeRunRecord): Promise<void> {\n await migrateCostTelemetry()\n const db = getDb()\n await db.execute({\n sql: `INSERT INTO cost_probe_runs\n (id, tool, target, wall_ms, success, error, http_only, kernel_used, kernel_sessions, kernel_seconds_total, kernel_tier_observed, est_kernel_cost_usd_headless, est_kernel_cost_usd_headful, vendor_cost_usd, charged_credits, margin_usd_headless_starter, margin_usd_headful_starter, units, unit_type, mode, notes)\n VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,\n args: [\n r.id, r.tool, r.target ?? null, r.wallMs, r.success ? 1 : 0, r.error ?? null,\n r.httpOnly ? 1 : 0, r.kernelUsed ? 1 : 0, r.kernelSessions, r.kernelSecondsTotal,\n r.kernelTierObserved ?? null, r.estKernelCostUsdHeadless, r.estKernelCostUsdHeadful,\n r.vendorCostUsd, r.chargedCredits, r.marginUsdHeadlessStarter, r.marginUsdHeadfulStarter,\n r.units ?? null, r.unitType ?? null, r.mode ?? null, r.notes ?? null,\n ],\n })\n}\n\nfunction boolToInt(v: boolean | null | undefined): number | null {\n if (v === null || v === undefined) return null\n return v ? 1 : 0\n}\n"],"mappings":"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","names":[]}
|
|
@@ -12,17 +12,17 @@ import {
|
|
|
12
12
|
browserServiceProfileSaveChanges,
|
|
13
13
|
recordVendorUsage,
|
|
14
14
|
vendorCostUsd
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-MTSBI7ZH.js";
|
|
16
16
|
import {
|
|
17
17
|
DEFAULT_MAPS_PROXY_MODE,
|
|
18
18
|
DEFAULT_PROXY_MODE
|
|
19
19
|
} from "./chunk-XGIPATLV.js";
|
|
20
20
|
import {
|
|
21
21
|
PACKAGE_VERSION
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-WQI7JIIN.js";
|
|
23
23
|
import {
|
|
24
24
|
MC_PER_CREDIT
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-JHI373VB.js";
|
|
26
26
|
import {
|
|
27
27
|
sanitizeVendorName
|
|
28
28
|
} from "./chunk-M2S27J6Z.js";
|
|
@@ -3076,21 +3076,33 @@ function formatCaptureSerpSnapshot(raw, input) {
|
|
|
3076
3076
|
const parsed = parseData(raw);
|
|
3077
3077
|
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
3078
3078
|
const d = parsed.data;
|
|
3079
|
+
const harvestResult = d.harvestResult && typeof d.harvestResult === "object" ? d.harvestResult : d;
|
|
3079
3080
|
const providerPayload = d;
|
|
3080
|
-
const organic = Array.isArray(
|
|
3081
|
-
const localPack = Array.isArray(
|
|
3082
|
-
const artifacts = Array.isArray(d.artifacts) ? d.artifacts : [];
|
|
3083
|
-
const
|
|
3084
|
-
const
|
|
3085
|
-
const
|
|
3086
|
-
const
|
|
3081
|
+
const organic = Array.isArray(harvestResult.organicResults) ? harvestResult.organicResults : Array.isArray(harvestResult.organic) ? harvestResult.organic : [];
|
|
3082
|
+
const localPack = Array.isArray(harvestResult.localPack) ? harvestResult.localPack : [];
|
|
3083
|
+
const artifacts = Array.isArray(d.pageSnapshotArtifacts) ? d.pageSnapshotArtifacts : Array.isArray(d.artifacts) ? d.artifacts : [];
|
|
3084
|
+
const attempts = Array.isArray(d.attempts) ? d.attempts : [];
|
|
3085
|
+
const diagnostics = harvestResult.diagnostics && typeof harvestResult.diagnostics === "object" ? harvestResult.diagnostics : d.diagnostics && typeof d.diagnostics === "object" ? d.diagnostics : null;
|
|
3086
|
+
const completionStatus = diagnostics && typeof diagnostics.completionStatus === "string" ? diagnostics.completionStatus : null;
|
|
3087
|
+
const status = String(d.status ?? d.captureStatus ?? completionStatus ?? "captured");
|
|
3088
|
+
const query = typeof harvestResult.seed === "string" ? harvestResult.seed : typeof harvestResult.query === "string" ? harvestResult.query : typeof input.query === "string" ? input.query : null;
|
|
3089
|
+
const location = typeof harvestResult.location === "string" ? harvestResult.location : typeof input.location === "string" ? input.location : null;
|
|
3090
|
+
const capturedAt = typeof harvestResult.extractedAt === "string" ? harvestResult.extractedAt : typeof harvestResult.capturedAt === "string" ? harvestResult.capturedAt : null;
|
|
3087
3091
|
const resultCount = organic.length + localPack.length;
|
|
3092
|
+
const pageSnapshotFailedCount = artifacts.filter((artifact) => artifact.status === "failed" || Boolean(artifact.error)).length;
|
|
3093
|
+
const rawBilling = d.billing && typeof d.billing === "object" ? d.billing : null;
|
|
3094
|
+
const billing = rawBilling ? {
|
|
3095
|
+
creditsUsed: typeof rawBilling.creditsUsed === "number" ? rawBilling.creditsUsed : null,
|
|
3096
|
+
requestId: typeof rawBilling.requestId === "string" ? rawBilling.requestId : null,
|
|
3097
|
+
jobId: typeof rawBilling.jobId === "string" ? rawBilling.jobId : null
|
|
3098
|
+
} : null;
|
|
3088
3099
|
const full = [
|
|
3089
3100
|
`# SERP Intelligence Snapshot: ${query ?? "query"}`,
|
|
3090
3101
|
`**Status:** ${status}`,
|
|
3091
3102
|
location ? `**Location:** ${location}` : "",
|
|
3092
|
-
`**
|
|
3093
|
-
|
|
3103
|
+
`**SERP results:** ${resultCount} (${organic.length} organic, ${localPack.length} local pack)`,
|
|
3104
|
+
`**Page snapshots:** ${artifacts.length} (${pageSnapshotFailedCount} failed)`,
|
|
3105
|
+
billing?.creditsUsed !== null && billing?.creditsUsed !== void 0 ? `**Credits used:** ${billing.creditsUsed}` : "",
|
|
3094
3106
|
"",
|
|
3095
3107
|
"Use `capture_serp_page_snapshots` when you need page-level evidence for ranking URLs."
|
|
3096
3108
|
].filter(Boolean).join("\n");
|
|
@@ -3103,6 +3115,10 @@ function formatCaptureSerpSnapshot(raw, input) {
|
|
|
3103
3115
|
location,
|
|
3104
3116
|
capturedAt,
|
|
3105
3117
|
resultCount,
|
|
3118
|
+
organicResultCount: organic.length,
|
|
3119
|
+
localPackResultCount: localPack.length,
|
|
3120
|
+
pageSnapshotCount: artifacts.length,
|
|
3121
|
+
pageSnapshotFailedCount,
|
|
3106
3122
|
snapshotId: typeof d.snapshotId === "string" ? d.snapshotId : typeof d.snapshot_id === "string" ? d.snapshot_id : typeof d.id === "string" ? d.id : null,
|
|
3107
3123
|
resolvedInputs: {
|
|
3108
3124
|
query: input.query ?? null,
|
|
@@ -3115,7 +3131,9 @@ function formatCaptureSerpSnapshot(raw, input) {
|
|
|
3115
3131
|
pages: input.pages ?? null
|
|
3116
3132
|
},
|
|
3117
3133
|
artifacts,
|
|
3118
|
-
|
|
3134
|
+
attempts,
|
|
3135
|
+
billing,
|
|
3136
|
+
diagnostics,
|
|
3119
3137
|
providerPayload
|
|
3120
3138
|
}
|
|
3121
3139
|
};
|
|
@@ -3124,9 +3142,13 @@ function formatCaptureSerpPageSnapshots(raw, input) {
|
|
|
3124
3142
|
const parsed = parseData(raw);
|
|
3125
3143
|
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
3126
3144
|
const d = parsed.data;
|
|
3127
|
-
const captures = Array.isArray(d.captures) ? d.captures : Array.isArray(d.results) ? d.results : [];
|
|
3145
|
+
const captures = Array.isArray(d.pageSnapshotArtifacts) ? d.pageSnapshotArtifacts : Array.isArray(d.captures) ? d.captures : Array.isArray(d.results) ? d.results : [];
|
|
3128
3146
|
const failedCount = captures.filter((c) => c.status === "failed" || c.error).length;
|
|
3129
|
-
const
|
|
3147
|
+
const capturedCount = captures.filter((c) => c.status === "captured" || c.status === "ok").length;
|
|
3148
|
+
const skippedCount = captures.filter((c) => c.status === "skipped").length;
|
|
3149
|
+
const attempts = Array.isArray(d.attempts) ? d.attempts : [];
|
|
3150
|
+
const inferredStatus = captures.length === 0 ? "empty" : failedCount === captures.length ? "failed" : failedCount > 0 || skippedCount > 0 ? "partial" : "captured";
|
|
3151
|
+
const status = String(d.status ?? inferredStatus);
|
|
3130
3152
|
const rows = captures.slice(0, 25).map((capture, i) => {
|
|
3131
3153
|
const url = typeof capture.url === "string" ? capture.url : "";
|
|
3132
3154
|
const sourceKind = typeof capture.sourceKind === "string" ? capture.sourceKind : typeof capture.source_kind === "string" ? capture.source_kind : "configured_target";
|
|
@@ -3135,8 +3157,10 @@ function formatCaptureSerpPageSnapshots(raw, input) {
|
|
|
3135
3157
|
const full = [
|
|
3136
3158
|
"# SERP Intelligence Page Snapshots",
|
|
3137
3159
|
`**Status:** ${status}`,
|
|
3138
|
-
`**
|
|
3160
|
+
`**Attempted:** ${captures.length}`,
|
|
3161
|
+
`**Captured:** ${capturedCount}`,
|
|
3139
3162
|
`**Failed:** ${failedCount}`,
|
|
3163
|
+
skippedCount ? `**Skipped:** ${skippedCount}` : "",
|
|
3140
3164
|
captures.length ? `
|
|
3141
3165
|
| # | URL | Source | Status |
|
|
3142
3166
|
|---|-----|--------|--------|
|
|
@@ -3148,8 +3172,11 @@ ${rows}` : ""
|
|
|
3148
3172
|
schemaVersion: "serp-intelligence.page-snapshots.v1",
|
|
3149
3173
|
status,
|
|
3150
3174
|
count: captures.length,
|
|
3175
|
+
capturedCount,
|
|
3151
3176
|
failedCount,
|
|
3177
|
+
skippedCount,
|
|
3152
3178
|
captures,
|
|
3179
|
+
attempts,
|
|
3153
3180
|
resolvedInputs: {
|
|
3154
3181
|
urls: input.urls ?? null,
|
|
3155
3182
|
targets: input.targets ?? null,
|
|
@@ -4268,9 +4295,19 @@ var CaptureSerpSnapshotOutputSchema = {
|
|
|
4268
4295
|
location: NullableString,
|
|
4269
4296
|
capturedAt: NullableString,
|
|
4270
4297
|
resultCount: z.number().int().min(0).nullable(),
|
|
4298
|
+
organicResultCount: z.number().int().min(0),
|
|
4299
|
+
localPackResultCount: z.number().int().min(0),
|
|
4300
|
+
pageSnapshotCount: z.number().int().min(0),
|
|
4301
|
+
pageSnapshotFailedCount: z.number().int().min(0),
|
|
4271
4302
|
snapshotId: NullableString,
|
|
4272
4303
|
resolvedInputs: z.record(z.unknown()),
|
|
4273
4304
|
artifacts: z.array(z.record(z.unknown())),
|
|
4305
|
+
attempts: z.array(z.record(z.unknown())),
|
|
4306
|
+
billing: z.object({
|
|
4307
|
+
creditsUsed: z.number().min(0).nullable(),
|
|
4308
|
+
requestId: NullableString,
|
|
4309
|
+
jobId: NullableString
|
|
4310
|
+
}).nullable(),
|
|
4274
4311
|
diagnostics: z.record(z.unknown()).nullable(),
|
|
4275
4312
|
providerPayload: z.record(z.unknown())
|
|
4276
4313
|
};
|
|
@@ -4278,8 +4315,11 @@ var CaptureSerpPageSnapshotsOutputSchema = {
|
|
|
4278
4315
|
schemaVersion: z.literal("serp-intelligence.page-snapshots.v1"),
|
|
4279
4316
|
status: z.string(),
|
|
4280
4317
|
count: z.number().int().min(0),
|
|
4318
|
+
capturedCount: z.number().int().min(0),
|
|
4281
4319
|
failedCount: z.number().int().min(0),
|
|
4320
|
+
skippedCount: z.number().int().min(0),
|
|
4282
4321
|
captures: z.array(z.record(z.unknown())),
|
|
4322
|
+
attempts: z.array(z.record(z.unknown())),
|
|
4283
4323
|
resolvedInputs: z.record(z.unknown()),
|
|
4284
4324
|
diagnostics: z.record(z.unknown()).nullable(),
|
|
4285
4325
|
providerPayload: z.record(z.unknown())
|
|
@@ -4404,8 +4444,8 @@ var CaptureSerpSnapshotInputSchema = {
|
|
|
4404
4444
|
proxyZip: z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location".'),
|
|
4405
4445
|
pages: z.number().int().min(1).max(2).default(1).describe("Google result pages to capture. Use 2 only for deeper ranking evidence."),
|
|
4406
4446
|
debug: z.boolean().default(false).describe("Include sanitized browser/proxy/location diagnostics."),
|
|
4407
|
-
includePageSnapshots: z.boolean().default(false).describe("Also capture ranking-page snapshots for selected SERP URLs."),
|
|
4408
|
-
pageSnapshotLimit: z.number().int().min(0).max(10).default(0).describe("Maximum ranking-page snapshots when includePageSnapshots is true.")
|
|
4447
|
+
includePageSnapshots: z.boolean().default(false).describe("Also capture ranking-page snapshots for selected SERP URLs. Each attempted snapshot adds 1 Credit."),
|
|
4448
|
+
pageSnapshotLimit: z.number().int().min(0).max(10).default(0).describe("Maximum ranking-page snapshots when includePageSnapshots is true. This capacity is held up front and unused capacity is refunded.")
|
|
4409
4449
|
};
|
|
4410
4450
|
var ScreenshotInputSchema = {
|
|
4411
4451
|
url: z.string().url().describe("URL to capture as a full-page screenshot. Use http or https. Pass allowLocal: true to capture localhost or private-network URLs during development."),
|
|
@@ -4413,12 +4453,12 @@ var ScreenshotInputSchema = {
|
|
|
4413
4453
|
allowLocal: z.boolean().default(false).describe("Allow localhost and private-network URLs (127.x, 192.168.x, 10.x, etc.). For local development only \u2014 not for production use.")
|
|
4414
4454
|
};
|
|
4415
4455
|
var CaptureSerpPageSnapshotsInputSchema = {
|
|
4416
|
-
urls: z.array(z.string().url()).min(1).max(25).describe("Public HTTP/HTTPS URLs to capture. Do not pass localhost, private IPs, file URLs, or internal admin URLs."),
|
|
4456
|
+
urls: z.array(z.string().url()).min(1).max(25).optional().describe("Public HTTP/HTTPS URLs to capture. Provide exactly one of urls or targets. Do not pass localhost, private IPs, file URLs, or internal admin URLs."),
|
|
4417
4457
|
targets: z.array(z.object({
|
|
4418
4458
|
url: z.string().url().describe("Public HTTP/HTTPS URL to capture."),
|
|
4419
4459
|
sourceKind: z.enum(["organic", "ai_citation", "local_pack_website", "configured_target", "site_subject"]).default("configured_target").describe("Why this page is being captured."),
|
|
4420
4460
|
sourcePosition: z.number().int().min(1).optional().describe("Ranking or citation position when the page came from SERP evidence.")
|
|
4421
|
-
}).strict()).min(1).max(25).optional().describe("Structured targets.
|
|
4461
|
+
}).strict()).min(1).max(25).optional().describe("Structured targets. Provide exactly one of targets or urls; use targets when source kind or position should be preserved."),
|
|
4422
4462
|
maxConcurrency: z.number().int().min(1).max(5).default(2).describe("Parallel page captures."),
|
|
4423
4463
|
timeoutMs: z.number().int().min(1e3).max(6e4).default(15e3).describe("Per-page capture timeout in milliseconds; timeouts return as structured capture failures."),
|
|
4424
4464
|
debug: z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics.")
|
|
@@ -5060,14 +5100,14 @@ function liveWebToolAnnotations(title) {
|
|
|
5060
5100
|
function registerSerpIntelligenceCaptureTools(server, executor) {
|
|
5061
5101
|
server.registerTool("capture_serp_snapshot", {
|
|
5062
5102
|
title: "SERP Intelligence Snapshot",
|
|
5063
|
-
description: "Capture a structured SERP Intelligence snapshot of a Google query \u2014 the persistent evidence format used by rank-tracking and comparison pipelines. Split query from location; leave proxyMode unset.",
|
|
5103
|
+
description: "Capture a structured SERP Intelligence snapshot of a Google query \u2014 the persistent evidence format used by rank-tracking and comparison pipelines. Split query from location; leave proxyMode unset. Costs 4 Credits when headless or 14 if anti-bot escalation requires headful mode; the 14-Credit hold is settled to the mode used. Optional page snapshots add 1 Credit per attempted URL.",
|
|
5064
5104
|
inputSchema: CaptureSerpSnapshotInputSchema,
|
|
5065
5105
|
outputSchema: recordOutputSchema("capture_serp_snapshot", CaptureSerpSnapshotOutputSchema),
|
|
5066
5106
|
annotations: liveWebToolAnnotations("SERP Intelligence Snapshot")
|
|
5067
5107
|
}, async (input) => formatCaptureSerpSnapshot(await executor.captureSerpSnapshot(input), input));
|
|
5068
5108
|
server.registerTool("capture_serp_page_snapshots", {
|
|
5069
5109
|
title: "SERP Intelligence Page Snapshots",
|
|
5070
|
-
description: "Capture public ranking pages as SERP Intelligence page snapshots \u2014 persistent page evidence linked to a captured SERP. Provide urls
|
|
5110
|
+
description: "Capture public ranking pages as SERP Intelligence page snapshots \u2014 persistent page evidence linked to a captured SERP. Provide exactly one of urls or targets; use targets to preserve source metadata. Private IPs, localhost, file, and internal URLs are rejected. Costs 1 Credit per attempted URL.",
|
|
5071
5111
|
inputSchema: CaptureSerpPageSnapshotsInputSchema,
|
|
5072
5112
|
outputSchema: recordOutputSchema("capture_serp_page_snapshots", CaptureSerpPageSnapshotsOutputSchema),
|
|
5073
5113
|
annotations: liveWebToolAnnotations("SERP Intelligence Page Snapshots")
|
|
@@ -5492,6 +5532,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
5492
5532
|
}
|
|
5493
5533
|
|
|
5494
5534
|
// src/mcp/http-mcp-tool-executor.ts
|
|
5535
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
5495
5536
|
function youtubeVideoIdFromUrl(url) {
|
|
5496
5537
|
if (!url) return null;
|
|
5497
5538
|
try {
|
|
@@ -5554,6 +5595,7 @@ var HttpMcpToolExecutor = class {
|
|
|
5554
5595
|
timeoutMs;
|
|
5555
5596
|
httpTimeoutOverrideMs;
|
|
5556
5597
|
serpIntelligenceTimeoutMs;
|
|
5598
|
+
pendingSerpCaptureBillingKeys = /* @__PURE__ */ new Map();
|
|
5557
5599
|
constructor(baseUrl, apiKey) {
|
|
5558
5600
|
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
5559
5601
|
this.apiKey = apiKey;
|
|
@@ -5564,13 +5606,14 @@ var HttpMcpToolExecutor = class {
|
|
|
5564
5606
|
const configuredSerpIntelligenceTimeoutMs = Number(process.env.MCP_SCRAPER_SERP_INTELLIGENCE_HTTP_TIMEOUT_MS ?? this.timeoutMs);
|
|
5565
5607
|
this.serpIntelligenceTimeoutMs = Number.isFinite(configuredSerpIntelligenceTimeoutMs) && configuredSerpIntelligenceTimeoutMs > 0 ? configuredSerpIntelligenceTimeoutMs : this.timeoutMs;
|
|
5566
5608
|
}
|
|
5567
|
-
async call(path, body, timeoutMs = this.timeoutMs, method = "POST") {
|
|
5609
|
+
async call(path, body, timeoutMs = this.timeoutMs, method = "POST", requestHeaders = {}) {
|
|
5568
5610
|
try {
|
|
5569
5611
|
const res = await fetch(`${this.baseUrl}${path}`, {
|
|
5570
5612
|
method,
|
|
5571
5613
|
headers: {
|
|
5572
5614
|
"Content-Type": "application/json",
|
|
5573
|
-
"x-api-key": this.apiKey
|
|
5615
|
+
"x-api-key": this.apiKey,
|
|
5616
|
+
...requestHeaders
|
|
5574
5617
|
},
|
|
5575
5618
|
body: JSON.stringify(body),
|
|
5576
5619
|
signal: AbortSignal.timeout(timeoutMs)
|
|
@@ -5818,8 +5861,27 @@ var HttpMcpToolExecutor = class {
|
|
|
5818
5861
|
connections: input.connections
|
|
5819
5862
|
}, void 0, "PUT");
|
|
5820
5863
|
}
|
|
5821
|
-
captureSerpSnapshot(input) {
|
|
5822
|
-
|
|
5864
|
+
async captureSerpSnapshot(input) {
|
|
5865
|
+
const fingerprint = createHash3("sha256").update(JSON.stringify(input)).digest("hex");
|
|
5866
|
+
const now = Date.now();
|
|
5867
|
+
for (const [pendingFingerprint, pendingEntry] of this.pendingSerpCaptureBillingKeys) {
|
|
5868
|
+
if (pendingEntry.expiresAt <= now) this.pendingSerpCaptureBillingKeys.delete(pendingFingerprint);
|
|
5869
|
+
}
|
|
5870
|
+
const pending = this.pendingSerpCaptureBillingKeys.get(fingerprint);
|
|
5871
|
+
const idempotencyKey = pending && pending.expiresAt > now ? pending.key : randomUUID2();
|
|
5872
|
+
this.pendingSerpCaptureBillingKeys.set(fingerprint, {
|
|
5873
|
+
key: idempotencyKey,
|
|
5874
|
+
expiresAt: now + 15 * 6e4
|
|
5875
|
+
});
|
|
5876
|
+
const result = await this.call(
|
|
5877
|
+
"/serp-intelligence/capture",
|
|
5878
|
+
input,
|
|
5879
|
+
this.serpIntelligenceTimeoutMs,
|
|
5880
|
+
"POST",
|
|
5881
|
+
{ "Idempotency-Key": idempotencyKey }
|
|
5882
|
+
);
|
|
5883
|
+
if (!result.isError) this.pendingSerpCaptureBillingKeys.delete(fingerprint);
|
|
5884
|
+
return result;
|
|
5823
5885
|
}
|
|
5824
5886
|
captureSerpPageSnapshots(input) {
|
|
5825
5887
|
return this.call("/serp-intelligence/page-snapshots", input, this.serpIntelligenceTimeoutMs);
|
|
@@ -9786,4 +9848,4 @@ export {
|
|
|
9786
9848
|
registerMemoryMcpTools,
|
|
9787
9849
|
MemoryMcpToolExecutor
|
|
9788
9850
|
};
|
|
9789
|
-
//# sourceMappingURL=chunk-
|
|
9851
|
+
//# sourceMappingURL=chunk-N4JHXPW6.js.map
|