mcp-scraper 0.33.7 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/bin/api-server.cjs +7100 -7023
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +2 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +2 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +2 -2
- package/dist/bin/mcp-stdio-server.cjs +43 -37
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +6 -6
- 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-V36LS5YV.js → chunk-4ZB3X6BQ.js} +4 -3
- package/dist/chunk-4ZB3X6BQ.js.map +1 -0
- package/dist/{chunk-SUOHUXQS.js → chunk-5PZ6N2QM.js} +2 -2
- package/dist/{chunk-H6QECE2U.js → chunk-6OPHG76G.js} +30 -27
- package/dist/chunk-6OPHG76G.js.map +1 -0
- package/dist/{chunk-2EDFOQD7.js → chunk-7AYRWAEK.js} +2 -2
- package/dist/{chunk-2EDFOQD7.js.map → chunk-7AYRWAEK.js.map} +1 -1
- package/dist/chunk-7N2KYL4U.js +7 -0
- package/dist/chunk-7N2KYL4U.js.map +1 -0
- package/dist/{chunk-JBSGBSGT.js → chunk-BWXLTWF7.js} +21 -16
- package/dist/chunk-BWXLTWF7.js.map +1 -0
- package/dist/{chunk-V73MPRU6.js → chunk-CB5C3BPB.js} +17 -1
- package/dist/chunk-CB5C3BPB.js.map +1 -0
- package/dist/{chunk-XVCETVYY.js → chunk-XVVNKASZ.js} +12 -4
- package/dist/chunk-XVVNKASZ.js.map +1 -0
- package/dist/{chunk-AT2PFWHW.js → chunk-ZID3WQID.js} +2 -2
- package/dist/index.cjs +22 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -3
- package/dist/{server-B35CQJB3.js → server-IWDHTES2.js} +185 -139
- package/dist/server-IWDHTES2.js.map +1 -0
- package/dist/{site-extract-repository-JHMVHENZ.js → site-extract-repository-OLVWMOU2.js} +3 -3
- package/dist/{worker-3LYNVGLF.js → worker-645BZPEK.js} +5 -5
- package/docs/mcp-tool-craft-lint.generated.md +171 -49
- package/docs/mcp-tool-manifest.generated.json +46 -11
- package/docs/specs/query-fanout-transport-contract-fix.md +37 -0
- package/package.json +1 -1
- package/dist/chunk-H6QECE2U.js.map +0 -1
- package/dist/chunk-HAMN42SP.js +0 -7
- package/dist/chunk-HAMN42SP.js.map +0 -1
- package/dist/chunk-JBSGBSGT.js.map +0 -1
- package/dist/chunk-V36LS5YV.js.map +0 -1
- package/dist/chunk-V73MPRU6.js.map +0 -1
- package/dist/chunk-XVCETVYY.js.map +0 -1
- package/dist/server-B35CQJB3.js.map +0 -1
- /package/dist/{chunk-SUOHUXQS.js.map → chunk-5PZ6N2QM.js.map} +0 -0
- /package/dist/{chunk-AT2PFWHW.js.map → chunk-ZID3WQID.js.map} +0 -0
- /package/dist/{site-extract-repository-JHMVHENZ.js.map → site-extract-repository-OLVWMOU2.js.map} +0 -0
- /package/dist/{worker-3LYNVGLF.js.map → worker-645BZPEK.js.map} +0 -0
package/dist/bin/paa-harvest.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
harvest
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-XVVNKASZ.js";
|
|
5
5
|
import {
|
|
6
6
|
browserServiceApiKey
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-4ZB3X6BQ.js";
|
|
8
8
|
import "../chunk-K443GQY5.js";
|
|
9
|
-
import "../chunk-
|
|
9
|
+
import "../chunk-CB5C3BPB.js";
|
|
10
10
|
import "../chunk-M2S27J6Z.js";
|
|
11
11
|
import "../chunk-62DQAWPF.js";
|
|
12
12
|
|
|
@@ -32,6 +32,9 @@ function currentCostContext() {
|
|
|
32
32
|
return storage.getStore();
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// src/api/cost-telemetry.ts
|
|
36
|
+
import { randomUUID } from "crypto";
|
|
37
|
+
|
|
35
38
|
// src/api/cost-rates.ts
|
|
36
39
|
var KERNEL_HEADLESS_USD_PER_SEC = 166667e-10;
|
|
37
40
|
var KERNEL_HEADFUL_USD_PER_SEC = 1333336e-10;
|
|
@@ -56,7 +59,6 @@ function vendorCostUsd(vendor, units) {
|
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
// src/api/cost-telemetry.ts
|
|
59
|
-
import { randomUUID } from "crypto";
|
|
60
62
|
var _ready = false;
|
|
61
63
|
var _migrationPromise = null;
|
|
62
64
|
async function migrateCostTelemetry() {
|
|
@@ -253,9 +255,8 @@ export {
|
|
|
253
255
|
runWithCostContext,
|
|
254
256
|
currentCostContext,
|
|
255
257
|
HEADLESS_OPS,
|
|
256
|
-
kernelCostUsd,
|
|
257
258
|
vendorCostUsd,
|
|
258
259
|
recordKernelSession,
|
|
259
260
|
recordVendorUsage
|
|
260
261
|
};
|
|
261
|
-
//# sourceMappingURL=chunk-
|
|
262
|
+
//# sourceMappingURL=chunk-4ZB3X6BQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/browser-service-env.ts","../src/api/cost-context.ts","../src/api/cost-telemetry.ts","../src/api/cost-rates.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","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","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"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
LedgerOperation
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-BWXLTWF7.js";
|
|
4
4
|
import {
|
|
5
5
|
sanitizeVendorName
|
|
6
6
|
} from "./chunk-M2S27J6Z.js";
|
|
@@ -127,4 +127,4 @@ export {
|
|
|
127
127
|
failExtractJob,
|
|
128
128
|
settleExtractJob
|
|
129
129
|
};
|
|
130
|
-
//# sourceMappingURL=chunk-
|
|
130
|
+
//# sourceMappingURL=chunk-5PZ6N2QM.js.map
|
|
@@ -12,17 +12,17 @@ import {
|
|
|
12
12
|
browserServiceProfileSaveChanges,
|
|
13
13
|
recordVendorUsage,
|
|
14
14
|
vendorCostUsd
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-4ZB3X6BQ.js";
|
|
16
16
|
import {
|
|
17
17
|
DEFAULT_MAPS_PROXY_MODE,
|
|
18
18
|
DEFAULT_PROXY_MODE
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-CB5C3BPB.js";
|
|
20
20
|
import {
|
|
21
21
|
PACKAGE_VERSION
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-7N2KYL4U.js";
|
|
23
23
|
import {
|
|
24
24
|
MC_PER_CREDIT
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-BWXLTWF7.js";
|
|
26
26
|
import {
|
|
27
27
|
sanitizeVendorName
|
|
28
28
|
} from "./chunk-M2S27J6Z.js";
|
|
@@ -1982,7 +1982,7 @@ ${t.topQuestions.map((q) => `- ${q}`).join("\n")}` : ""
|
|
|
1982
1982
|
${q.threadUrl}` : ""}`).join("\n");
|
|
1983
1983
|
const full = [
|
|
1984
1984
|
`# Reddit Trending: "${d.topic || input.topic}"${subreddit ? ` in r/${subreddit}` : ""}`,
|
|
1985
|
-
`**${totals.threads} threads \xB7 ${totals.upvotes} upvotes \xB7 ${totals.comments} comments** \xB7 last
|
|
1985
|
+
`**${totals.threads} threads \xB7 ${totals.upvotes} upvotes \xB7 ${totals.comments} comments** \xB7 last ${d.window === "7d" ? "week" : "month"} \xB7 ${d.threadsScraped ?? 0} of ${d.candidatesFound ?? threads.length} discovered scraped${d.partial ? " (partial \u2014 hit the time limit)" : ""}`,
|
|
1986
1986
|
`
|
|
1987
1987
|
## Ranked threads
|
|
1988
1988
|
${threadBlocks || "_No threads found._"}`,
|
|
@@ -2012,7 +2012,9 @@ ${questionList || "_No questions extracted._"}`,
|
|
|
2012
2012
|
})),
|
|
2013
2013
|
questions: questions.map((q) => ({ question: q.question ?? "", threadUrl: q.threadUrl ?? "" })),
|
|
2014
2014
|
threadsScraped: Number(d.threadsScraped ?? 0),
|
|
2015
|
-
|
|
2015
|
+
candidatesFound: Number(d.candidatesFound ?? threads.length),
|
|
2016
|
+
partial: Boolean(d.partial),
|
|
2017
|
+
searchQuery: d.searchQuery ?? ""
|
|
2016
2018
|
}
|
|
2017
2019
|
};
|
|
2018
2020
|
}
|
|
@@ -3616,8 +3618,9 @@ var RedditThreadInputSchema = {
|
|
|
3616
3618
|
var RedditTrendingInputSchema = {
|
|
3617
3619
|
topic: z.string().min(1).describe('Topic to scan, in plain words (e.g. "crm for small business"). Not a URL \u2014 pass a known thread URL to reddit_thread instead.'),
|
|
3618
3620
|
subreddit: z.string().min(1).optional().describe('Bare subreddit name to scope the scan to one community, e.g. "SEO" (no r/ prefix, no URL). Omit to scan all of Reddit.'),
|
|
3619
|
-
|
|
3620
|
-
|
|
3621
|
+
window: z.enum(["week", "month"]).default("month").describe('How recent the threads must be: "week" or "month" (default). Applied via a Google time filter over reddit.com, so it reflects genuine recency.'),
|
|
3622
|
+
maxThreads: z.number().int().min(1).max(40).default(20).describe("How many discovered threads to scrape and rank. Default 20 (scrape-all). Each scraped thread is billed like reddit_thread + its comments, so lower this to cap cost; raise toward 40 for a wider sweep. Scraping runs in parallel and stops early if it nears the request time limit (partial:true in the response)."),
|
|
3623
|
+
includeComments: z.boolean().default(true).describe("Scrape each discovered thread for real upvotes, comments, and the questions people asked, then rank by engagement. Set false for a fast, cheap discovery-only sweep \u2014 returns the discovered threads (title + url) in relevance order with NO engagement stats and NO per-thread billing, so you can then call reddit_thread on the ones you want."),
|
|
3621
3624
|
maxCommentsPerThread: z.number().int().min(1).max(200).default(50).describe("Comments captured per scraped thread when includeComments is true. Default 50. Billed per captured comment.")
|
|
3622
3625
|
};
|
|
3623
3626
|
var VideoFrameAnalysisInputSchema = {
|
|
@@ -4231,7 +4234,9 @@ var RedditTrendingOutputSchema = {
|
|
|
4231
4234
|
threadUrl: z.string()
|
|
4232
4235
|
})),
|
|
4233
4236
|
threadsScraped: z.number().int().min(0),
|
|
4234
|
-
|
|
4237
|
+
candidatesFound: z.number().int().min(0),
|
|
4238
|
+
partial: z.boolean(),
|
|
4239
|
+
searchQuery: z.string()
|
|
4235
4240
|
};
|
|
4236
4241
|
var FacebookPageIntelOutputSchema = {
|
|
4237
4242
|
advertiserName: NullableString,
|
|
@@ -4603,7 +4608,8 @@ var SearchSerpInputSchema = {
|
|
|
4603
4608
|
proxyMode: z.enum(["configured", "none"]).default(DEFAULT_PROXY_MODE).describe("Leave unset for the default route. Country/region localization comes from gl/hl plus the city or region in the query."),
|
|
4604
4609
|
proxyZip: z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override."),
|
|
4605
4610
|
debug: z.boolean().default(false).describe("Include sanitized diagnostics for debugging."),
|
|
4606
|
-
pages: z.number().int().min(1).max(2).default(1).describe("Number of result pages to fetch (1\u20132).")
|
|
4611
|
+
pages: z.number().int().min(1).max(2).default(1).describe("Number of result pages to fetch (1\u20132)."),
|
|
4612
|
+
recency: z.enum(["day", "week", "month", "year"]).optional().describe('Restrict results to a recent time window (Google "past day/week/month/year" filter). Omit for all-time. Useful for "what is being said this week" style queries; pairs well with a site: operator in the query.')
|
|
4607
4613
|
};
|
|
4608
4614
|
var CaptureSerpSnapshotInputSchema = {
|
|
4609
4615
|
query: z.string().min(1).describe('Search query to capture. KEEP the place in the query text for localized captures (e.g. "botox clinic austin tx") and also set location.'),
|
|
@@ -5533,7 +5539,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
5533
5539
|
}, async (input) => formatRedditThread(await executor.redditThread(input), input));
|
|
5534
5540
|
server.registerTool("reddit_trending", {
|
|
5535
5541
|
title: "Reddit Trending",
|
|
5536
|
-
description: "Discover the top Reddit conversations about a topic from the last
|
|
5542
|
+
description: "Discover the top Reddit conversations about a topic from the last week or month: finds relevant recent threads via a Google site:reddit.com search (optionally scoped to one subreddit), scrapes them for real upvotes, comments, and the questions people asked, and ranks by engagement (upvotes + 2x comments). Scraping runs in parallel across the discovered threads; set includeComments:false for a fast, cheap discovery-only sweep (relevant thread list, no engagement stats, no per-thread billing) and then read the ones you want with reddit_thread. Not for reading one known thread URL \u2014 use reddit_thread for that.",
|
|
5537
5543
|
inputSchema: RedditTrendingInputSchema,
|
|
5538
5544
|
outputSchema: recordOutputSchema("reddit_trending", RedditTrendingOutputSchema),
|
|
5539
5545
|
annotations: liveWebToolAnnotations("Reddit Trending")
|
|
@@ -6479,7 +6485,7 @@ var BrowserCaptureFanoutInputSchema = {
|
|
|
6479
6485
|
wait_ms: z2.number().int().min(0).max(18e4).optional().describe("How long to wait for the answer stream to finish. Defaults to 90000 when a prompt is sent, 8000 for passive capture."),
|
|
6480
6486
|
first_party_domain: z2.string().optional().describe("The brand/site being researched, e.g. example.com \u2014 sources on this domain are tagged First-party/vendor."),
|
|
6481
6487
|
reset: z2.boolean().default(false).describe("Clear any previously buffered stream for this page before capturing."),
|
|
6482
|
-
export: z2.boolean().default(false).describe("
|
|
6488
|
+
export: z2.boolean().default(false).describe("When using the installed local MCP server, write JSON/CSV/TSV/HTML exports to MCP_SCRAPER_OUTPUT_DIR/fanout. Hosted clients such as ChatGPT always receive the complete structured result inline and leave exports null.")
|
|
6483
6489
|
};
|
|
6484
6490
|
var FanoutSourceOutput = z2.object({
|
|
6485
6491
|
url: z2.string(),
|
|
@@ -6520,6 +6526,7 @@ var BrowserCaptureFanoutOutputSchema = {
|
|
|
6520
6526
|
byCategory: z2.record(z2.number().int())
|
|
6521
6527
|
}).describe("Objective aggregates: top sourced sites by frequency, citation order, and URL-category counts."),
|
|
6522
6528
|
first_party_domain: z2.string().nullable(),
|
|
6529
|
+
export_error: z2.string().nullable().optional().describe("Non-fatal local export failure. The inline capture remains complete when this is present."),
|
|
6523
6530
|
exports: z2.object({
|
|
6524
6531
|
relativeTo: z2.string(),
|
|
6525
6532
|
dir: z2.string(),
|
|
@@ -7081,6 +7088,7 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
7081
7088
|
const baseUrl = opts.baseUrl.replace(/\/$/, "");
|
|
7082
7089
|
const consoleBase = (opts.consoleBaseUrl ?? opts.baseUrl).replace(/\/$/, "");
|
|
7083
7090
|
const timeoutMs = opts.timeoutMs ?? 9e4;
|
|
7091
|
+
const savesReportsLocally = opts.savesReportsLocally !== false;
|
|
7084
7092
|
async function req(method, path, body, requestTimeoutMs = timeoutMs) {
|
|
7085
7093
|
try {
|
|
7086
7094
|
const res = await fetch(`${baseUrl}${path}`, {
|
|
@@ -7732,13 +7740,13 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
7732
7740
|
"query_fanout_workflow",
|
|
7733
7741
|
{
|
|
7734
7742
|
title: "Capture AI Search Fan-Out",
|
|
7735
|
-
description: "Capture the query fan-out behind a ChatGPT or Claude web-search answer for AEO: sub-queries issued, every researched URL split into cited vs browsed-only, and top sourced sites.
|
|
7743
|
+
description: "Capture the query fan-out behind a ChatGPT or Claude web-search answer for AEO: sub-queries issued, every researched URL split into cited vs browsed-only, and top sourced sites. Complete structured data is always returned inline for analysis. export=true additionally writes JSON/CSV/TSV/HTML only from an installed local MCP server; hosted OAuth/HTTP clients receive exports=null and use the inline data. A local export failure does not discard a successful capture. WRITE NOTE: passing prompt submits a real message in the user's logged-in account \u2014 only send when the user wants that; omit it to capture a prompt the user just ran. The session must already be open on chatgpt.com or claude.ai (see browser_profile_connect) while the prompt streams. NOT for Google AI Overview \u2014 use harvest_paa for that.",
|
|
7736
7744
|
inputSchema: BrowserCaptureFanoutInputSchema,
|
|
7737
7745
|
outputSchema: recordOutputSchema("query_fanout_workflow", BrowserCaptureFanoutOutputSchema),
|
|
7738
7746
|
annotations: annotations("Capture AI Search Fan-Out")
|
|
7739
7747
|
},
|
|
7740
7748
|
async (input) => {
|
|
7741
|
-
const emit = (result, exports2) => structuredResult({
|
|
7749
|
+
const emit = (result, exports2, exportError2 = null) => structuredResult({
|
|
7742
7750
|
ok: true,
|
|
7743
7751
|
tool: "query_fanout_workflow",
|
|
7744
7752
|
session_id: input.session_id,
|
|
@@ -7755,6 +7763,7 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
7755
7763
|
aggregates: result.aggregates,
|
|
7756
7764
|
first_party_domain: result.firstPartyDomain,
|
|
7757
7765
|
exports: exports2 ?? null,
|
|
7766
|
+
export_error: exportError2,
|
|
7758
7767
|
...result.debug ? { debug: result.debug } : {}
|
|
7759
7768
|
});
|
|
7760
7769
|
const res = await req("POST", `/agent/sessions/${input.session_id}/capture-fanout`, {
|
|
@@ -7762,26 +7771,20 @@ function registerBrowserAgentMcpTools(server, opts) {
|
|
|
7762
7771
|
wait_ms: input.wait_ms,
|
|
7763
7772
|
first_party_domain: input.first_party_domain,
|
|
7764
7773
|
reset: input.reset,
|
|
7765
|
-
export:
|
|
7774
|
+
export: false
|
|
7766
7775
|
}, Math.max(timeoutMs, (input.wait_ms ?? (input.prompt ? 9e4 : 8e3)) + 3e4));
|
|
7767
7776
|
if (!res.ok) return errorResult("query_fanout_workflow", res.data, input.session_id);
|
|
7768
7777
|
const hosted = res.data?.result ?? res.data;
|
|
7769
|
-
let exports =
|
|
7770
|
-
|
|
7778
|
+
let exports = null;
|
|
7779
|
+
let exportError = null;
|
|
7780
|
+
if (input.export && savesReportsLocally && isEnrichedFanout(hosted)) {
|
|
7771
7781
|
try {
|
|
7772
7782
|
exports = exportFanout(hosted);
|
|
7773
7783
|
} catch (err) {
|
|
7774
|
-
|
|
7775
|
-
"query_fanout_workflow",
|
|
7776
|
-
{
|
|
7777
|
-
error: `Fan-out captured but local export failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
7778
|
-
result: hosted
|
|
7779
|
-
},
|
|
7780
|
-
input.session_id
|
|
7781
|
-
);
|
|
7784
|
+
exportError = `Fan-out captured successfully, but local export failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
7782
7785
|
}
|
|
7783
7786
|
}
|
|
7784
|
-
return emit(hosted, exports);
|
|
7787
|
+
return emit(hosted, exports, exportError);
|
|
7785
7788
|
}
|
|
7786
7789
|
);
|
|
7787
7790
|
}
|
|
@@ -10256,4 +10259,4 @@ export {
|
|
|
10256
10259
|
MEMORY_TOOL_SCHEMAS,
|
|
10257
10260
|
registerMemoryMcpTools
|
|
10258
10261
|
};
|
|
10259
|
-
//# sourceMappingURL=chunk-
|
|
10262
|
+
//# sourceMappingURL=chunk-6OPHG76G.js.map
|