mcp-scraper 0.2.5 → 0.2.6
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 +6 -5
- package/dist/bin/api-server.cjs +399 -2
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs +1 -1
- package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
- package/dist/bin/browser-agent-stdio-server.js +2 -2
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs +391 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +3 -2
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +3 -2
- package/dist/bin/mcp-scraper-install.js.map +1 -1
- package/dist/bin/mcp-stdio-server.cjs +391 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/{chunk-ENI4DM3S.js → chunk-7WB2W6FO.js} +392 -2
- package/dist/chunk-7WB2W6FO.js.map +1 -0
- package/dist/chunk-T6SIPPOQ.js +7 -0
- package/dist/chunk-T6SIPPOQ.js.map +1 -0
- package/dist/{chunk-O36HHUKX.js → chunk-XL4V7VKD.js} +2 -2
- package/dist/{server-Q3WHIS63.js → server-MKCU3M7Y.js} +3 -3
- package/package.json +1 -1
- package/dist/chunk-ENI4DM3S.js.map +0 -1
- package/dist/chunk-JDX57SEC.js +0 -7
- package/dist/chunk-JDX57SEC.js.map +0 -1
- /package/dist/{chunk-O36HHUKX.js.map → chunk-XL4V7VKD.js.map} +0 -0
- /package/dist/{server-Q3WHIS63.js.map → server-MKCU3M7Y.js.map} +0 -0
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
HttpMcpToolExecutor,
|
|
4
4
|
registerPaaExtractorMcpTools
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-7WB2W6FO.js";
|
|
6
6
|
import "../chunk-M2S27J6Z.js";
|
|
7
7
|
import {
|
|
8
8
|
registerBrowserAgentMcpTools
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-XL4V7VKD.js";
|
|
10
10
|
import {
|
|
11
11
|
PACKAGE_VERSION
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-T6SIPPOQ.js";
|
|
13
13
|
|
|
14
14
|
// bin/mcp-scraper-combined-stdio-server.ts
|
|
15
15
|
import { readFileSync } from "fs";
|
|
@@ -53,9 +53,10 @@ function renderInstallTerminal(options) {
|
|
|
53
53
|
`${colorize("MCP Scraper Agent", "cyan", color)} . v${options.version} . mcpscraper.dev`,
|
|
54
54
|
"1/1 install surfaces ready",
|
|
55
55
|
"",
|
|
56
|
-
`${colorize("Tools", "cyan", color)} ${colorize("(
|
|
56
|
+
`${colorize("Tools", "cyan", color)} ${colorize("(29 loaded)", "muted", color)}`,
|
|
57
57
|
toolRow("search", ["harvest_paa", "search_serp", "maps_search", "maps_place_intel"], color),
|
|
58
58
|
toolRow("extract", ["extract_url", "map_site_urls", "extract_site", "directory_workflow"], color),
|
|
59
|
+
toolRow("build", ["rank_tracker_blueprint", "cron plan", "database prompt"], color),
|
|
59
60
|
toolRow("media", ["youtube_harvest", "youtube_transcribe", "facebook_ad_search", "facebook_page_intel"], color),
|
|
60
61
|
toolRow("browser", ["browser_open", "browser_screenshot", "browser_click", "browser_replay_download"], color),
|
|
61
62
|
toolRow("account", ["credits_info", "local reports", "MCP resources"], color),
|
|
@@ -78,7 +79,7 @@ function renderInstallTerminal(options) {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
// src/version.ts
|
|
81
|
-
var PACKAGE_VERSION = "0.2.
|
|
82
|
+
var PACKAGE_VERSION = "0.2.6";
|
|
82
83
|
|
|
83
84
|
// bin/mcp-scraper-install.ts
|
|
84
85
|
var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/install-terminal.ts","../../src/version.ts","../../bin/mcp-scraper-install.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n 'claude mcp add mcp-scraper --scope user',\n ` --env MCP_SCRAPER_API_KEY=${apiKeyValue}`,\n ' -- npx -y -p mcp-scraper@latest mcp-scraper-combined',\n ].join(' \\\\\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper-combined\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(
|
|
1
|
+
{"version":3,"sources":["../../src/install-terminal.ts","../../src/version.ts","../../bin/mcp-scraper-install.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n 'claude mcp add mcp-scraper --scope user',\n ` --env MCP_SCRAPER_API_KEY=${apiKeyValue}`,\n ' -- npx -y -p mcp-scraper@latest mcp-scraper-combined',\n ].join(' \\\\\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper-combined\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(29 loaded)', 'muted', color)}`,\n toolRow('search', ['harvest_paa', 'search_serp', 'maps_search', 'maps_place_intel'], color),\n toolRow('extract', ['extract_url', 'map_site_urls', 'extract_site', 'directory_workflow'], color),\n toolRow('build', ['rank_tracker_blueprint', 'cron plan', 'database prompt'], color),\n toolRow('media', ['youtube_harvest', 'youtube_transcribe', 'facebook_ad_search', 'facebook_page_intel'], color),\n toolRow('browser', ['browser_open', 'browser_screenshot', 'browser_click', 'browser_replay_download'], color),\n toolRow('account', ['credits_info', 'local reports', 'MCP resources'], color),\n '',\n `${colorize('Ready.', 'lime', color)} Install the combined MCP server with one of these paths:`,\n '',\n colorize('Claude Code', 'amber', color),\n claudeCommand,\n '',\n colorize('Codex config', 'amber', color),\n codexConfig,\n '',\n colorize('Claude Desktop Extension', 'amber', color),\n 'Download: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n '',\n colorize('Safety note:', 'muted', color),\n 'This installer can print terminal UI. MCP server commands stay silent so stdio JSON-RPC is not corrupted.',\n '',\n ].join('\\n')\n}\n","export const PACKAGE_VERSION = '0.2.6'\n","#!/usr/bin/env node\nimport { renderInstallTerminal } from '../src/install-terminal.js'\nimport { PACKAGE_VERSION } from '../src/version.js'\n\nconst noColor =\n process.argv.includes('--no-color') ||\n process.env.NO_COLOR !== undefined ||\n process.env.FORCE_COLOR === '0' ||\n !process.stdout.isTTY\n\nconst help = process.argv.includes('--help') || process.argv.includes('-h')\nif (help) {\n process.stdout.write([\n 'Usage: mcp-scraper-install [--no-color]',\n '',\n 'Prints the branded MCP Scraper terminal install card and copyable install commands.',\n 'Use mcp-scraper-combined, mcp-scraper, and browser-agent only as MCP stdio servers.',\n '',\n ].join('\\n'))\n process.exit(0)\n}\n\nprocess.stdout.write(renderInstallTerminal({\n version: PACKAGE_VERSION,\n color: !noColor,\n apiKeyConfigured: Boolean(process.env.MCP_SCRAPER_API_KEY?.trim()),\n}))\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
PACKAGE_VERSION
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-T6SIPPOQ.js";
|
|
5
5
|
|
|
6
6
|
// src/install-terminal.ts
|
|
7
7
|
var CODES = {
|
|
@@ -55,9 +55,10 @@ function renderInstallTerminal(options) {
|
|
|
55
55
|
`${colorize("MCP Scraper Agent", "cyan", color)} . v${options.version} . mcpscraper.dev`,
|
|
56
56
|
"1/1 install surfaces ready",
|
|
57
57
|
"",
|
|
58
|
-
`${colorize("Tools", "cyan", color)} ${colorize("(
|
|
58
|
+
`${colorize("Tools", "cyan", color)} ${colorize("(29 loaded)", "muted", color)}`,
|
|
59
59
|
toolRow("search", ["harvest_paa", "search_serp", "maps_search", "maps_place_intel"], color),
|
|
60
60
|
toolRow("extract", ["extract_url", "map_site_urls", "extract_site", "directory_workflow"], color),
|
|
61
|
+
toolRow("build", ["rank_tracker_blueprint", "cron plan", "database prompt"], color),
|
|
61
62
|
toolRow("media", ["youtube_harvest", "youtube_transcribe", "facebook_ad_search", "facebook_page_intel"], color),
|
|
62
63
|
toolRow("browser", ["browser_open", "browser_screenshot", "browser_click", "browser_replay_download"], color),
|
|
63
64
|
toolRow("account", ["credits_info", "local reports", "MCP resources"], color),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/install-terminal.ts","../../bin/mcp-scraper-install.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n 'claude mcp add mcp-scraper --scope user',\n ` --env MCP_SCRAPER_API_KEY=${apiKeyValue}`,\n ' -- npx -y -p mcp-scraper@latest mcp-scraper-combined',\n ].join(' \\\\\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper-combined\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(
|
|
1
|
+
{"version":3,"sources":["../../src/install-terminal.ts","../../bin/mcp-scraper-install.ts"],"sourcesContent":["export interface InstallTerminalOptions {\n color?: boolean\n version: string\n apiKeyConfigured?: boolean\n}\n\ntype Tone = 'cyan' | 'lime' | 'amber' | 'red' | 'muted' | 'bold'\n\nconst CODES: Record<Tone | 'reset', string> = {\n reset: '\\x1b[0m',\n cyan: '\\x1b[36m',\n lime: '\\x1b[32m',\n amber: '\\x1b[33m',\n red: '\\x1b[31m',\n muted: '\\x1b[90m',\n bold: '\\x1b[1m',\n}\n\nfunction colorize(value: string, tone: Tone, enabled: boolean): string {\n if (!enabled) return value\n return `${CODES[tone]}${value}${CODES.reset}`\n}\n\nfunction toolRow(label: string, tools: string[], enabled: boolean): string {\n const padded = label.padEnd(9, ' ')\n return ` ${colorize(padded, 'muted', enabled)} ${tools.join(colorize(' . ', 'muted', enabled))}`\n}\n\nexport function renderInstallTerminal(options: InstallTerminalOptions): string {\n const color = options.color ?? true\n const apiKeyValue = options.apiKeyConfigured ? '$MCP_SCRAPER_API_KEY' : 'sk_live_your_key'\n const ascii = String.raw`\n __ __ ____ ____ \n| \\/ |/ ___| _ \\\n| |\\/| | | | |_) |\n| | | | |___| __/\n|_| |_|\\____|_|\n\n ____ ____ ____ _ ____ _____ ____\n/ ___| / ___| _ \\ / \\ | _ \\| ____| _ \\\n\\___ \\| | | |_) | / _ \\ | |_) | _| | |_) |\n ___) | |___| _ < / ___ \\| __/| |___| _ <\n|____/ \\____|_| \\_\\/_/ \\_\\_| |_____|_| \\_\\\n`\n\n const claudeCommand = [\n 'claude mcp add mcp-scraper --scope user',\n ` --env MCP_SCRAPER_API_KEY=${apiKeyValue}`,\n ' -- npx -y -p mcp-scraper@latest mcp-scraper-combined',\n ].join(' \\\\\\n')\n\n const codexConfig = [\n '[mcp_servers.mcp-scraper]',\n 'command = \"npx\"',\n 'args = [\"-y\", \"-p\", \"mcp-scraper@latest\", \"mcp-scraper-combined\"]',\n `env = { MCP_SCRAPER_API_KEY = \"${apiKeyValue}\" }`,\n ].join('\\n')\n\n return [\n colorize(`mcp-scraper v${options.version}`, 'bold', color),\n colorize('> mcp-scraper-install', 'muted', color),\n colorize(ascii, 'amber', color),\n `${colorize('MCP Scraper Agent', 'cyan', color)} . v${options.version} . mcpscraper.dev`,\n '1/1 install surfaces ready',\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(29 loaded)', 'muted', color)}`,\n toolRow('search', ['harvest_paa', 'search_serp', 'maps_search', 'maps_place_intel'], color),\n toolRow('extract', ['extract_url', 'map_site_urls', 'extract_site', 'directory_workflow'], color),\n toolRow('build', ['rank_tracker_blueprint', 'cron plan', 'database prompt'], color),\n toolRow('media', ['youtube_harvest', 'youtube_transcribe', 'facebook_ad_search', 'facebook_page_intel'], color),\n toolRow('browser', ['browser_open', 'browser_screenshot', 'browser_click', 'browser_replay_download'], color),\n toolRow('account', ['credits_info', 'local reports', 'MCP resources'], color),\n '',\n `${colorize('Ready.', 'lime', color)} Install the combined MCP server with one of these paths:`,\n '',\n colorize('Claude Code', 'amber', color),\n claudeCommand,\n '',\n colorize('Codex config', 'amber', color),\n codexConfig,\n '',\n colorize('Claude Desktop Extension', 'amber', color),\n 'Download: https://mcpscraper.dev/downloads/mcp-scraper.mcpb',\n '',\n colorize('Safety note:', 'muted', color),\n 'This installer can print terminal UI. MCP server commands stay silent so stdio JSON-RPC is not corrupted.',\n '',\n ].join('\\n')\n}\n","#!/usr/bin/env node\nimport { renderInstallTerminal } from '../src/install-terminal.js'\nimport { PACKAGE_VERSION } from '../src/version.js'\n\nconst noColor =\n process.argv.includes('--no-color') ||\n process.env.NO_COLOR !== undefined ||\n process.env.FORCE_COLOR === '0' ||\n !process.stdout.isTTY\n\nconst help = process.argv.includes('--help') || process.argv.includes('-h')\nif (help) {\n process.stdout.write([\n 'Usage: mcp-scraper-install [--no-color]',\n '',\n 'Prints the branded MCP Scraper terminal install card and copyable install commands.',\n 'Use mcp-scraper-combined, mcp-scraper, and browser-agent only as MCP stdio servers.',\n '',\n ].join('\\n'))\n process.exit(0)\n}\n\nprocess.stdout.write(renderInstallTerminal({\n version: PACKAGE_VERSION,\n color: !noColor,\n apiKeyConfigured: Boolean(process.env.MCP_SCRAPER_API_KEY?.trim()),\n}))\n"],"mappings":"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","names":[]}
|
|
@@ -136,7 +136,7 @@ var import_node_fs2 = require("fs");
|
|
|
136
136
|
var import_node_path2 = require("path");
|
|
137
137
|
|
|
138
138
|
// src/version.ts
|
|
139
|
-
var PACKAGE_VERSION = "0.2.
|
|
139
|
+
var PACKAGE_VERSION = "0.2.6";
|
|
140
140
|
|
|
141
141
|
// src/mcp/mcp-response-formatter.ts
|
|
142
142
|
var import_node_fs = require("fs");
|
|
@@ -1166,6 +1166,24 @@ var DirectoryWorkflowInputSchema = {
|
|
|
1166
1166
|
proxyZip: import_zod.z.string().regex(/^\d{5}$/).optional().describe("Optional ZIP override for proxy targeting. Normally omit it so each city can use its Lead Magician ZIP group or city/state location."),
|
|
1167
1167
|
debug: import_zod.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics in each Maps browser session when supported.")
|
|
1168
1168
|
};
|
|
1169
|
+
var RankTrackerModeSchema = import_zod.z.enum(["maps", "organic", "ai_overview", "paa"]);
|
|
1170
|
+
var RankTrackerBlueprintInputSchema = {
|
|
1171
|
+
projectName: import_zod.z.string().min(1).optional().describe("Optional name for the rank tracker project, client, or campaign."),
|
|
1172
|
+
targetDomain: import_zod.z.string().min(1).optional().describe("Primary domain to track in organic results, AI Overview citations, and PAA sources, e.g. example.com."),
|
|
1173
|
+
targetBusinessName: import_zod.z.string().min(1).optional().describe("Primary Google Business Profile or brand/business name to match in Maps results. Required for reliable Maps rank tracking."),
|
|
1174
|
+
trackingModes: import_zod.z.array(RankTrackerModeSchema).min(1).max(4).default(["maps", "organic", "ai_overview", "paa"]).describe("Rank tracker surfaces to build. maps uses directory_workflow/maps_search. organic uses search_serp. ai_overview uses search_serp/harvest_paa. paa uses harvest_paa source presence."),
|
|
1175
|
+
keywords: import_zod.z.array(import_zod.z.string().min(1)).max(200).default([]).describe("Seed keywords or service queries to track. Leave empty when the downstream AI should create the keyword table from user input."),
|
|
1176
|
+
locations: import_zod.z.array(import_zod.z.string().min(1)).max(100).default([]).describe("Markets, cities, ZIPs, or service areas to track. Use city/state strings like Denver, CO for localized SERP and Maps checks."),
|
|
1177
|
+
competitors: import_zod.z.array(import_zod.z.string().min(1)).max(100).default([]).describe("Optional competitor domains or business names to persist as comparison targets."),
|
|
1178
|
+
database: import_zod.z.enum(["postgres", "neon", "supabase", "sqlite", "mysql"]).default("postgres").describe("Database family the downstream AI should target when generating migrations."),
|
|
1179
|
+
scheduleCadence: import_zod.z.enum(["daily", "weekly", "monthly", "custom"]).default("weekly").describe("Default recurring rank check cadence for the generated cron/heartbeat plan."),
|
|
1180
|
+
customCron: import_zod.z.string().min(1).optional().describe("Cron expression to use when scheduleCadence is custom."),
|
|
1181
|
+
timezone: import_zod.z.string().min(1).default("UTC").describe("IANA timezone for scheduled rank checks, e.g. America/Denver."),
|
|
1182
|
+
includeCron: import_zod.z.boolean().default(true).describe("Include a cron or heartbeat worker plan. Keep true for production rank trackers."),
|
|
1183
|
+
includeDashboard: import_zod.z.boolean().default(true).describe("Include dashboard/reporting requirements in the generated prompt."),
|
|
1184
|
+
includeAlerts: import_zod.z.boolean().default(true).describe("Include alert rules for rank movement and SERP feature gains/losses."),
|
|
1185
|
+
notes: import_zod.z.string().max(4e3).optional().describe("Extra product, client, stack, or hosting requirements to include in the implementation prompt.")
|
|
1186
|
+
};
|
|
1169
1187
|
var NullableString = import_zod.z.string().nullable();
|
|
1170
1188
|
var MapsSearchOutputSchema = {
|
|
1171
1189
|
query: import_zod.z.string(),
|
|
@@ -1241,6 +1259,39 @@ var DirectoryWorkflowOutputSchema = {
|
|
|
1241
1259
|
})),
|
|
1242
1260
|
durationMs: import_zod.z.number().int().min(0)
|
|
1243
1261
|
};
|
|
1262
|
+
var RankTrackerToolPlanOutput = import_zod.z.object({
|
|
1263
|
+
tool: import_zod.z.string(),
|
|
1264
|
+
purpose: import_zod.z.string()
|
|
1265
|
+
});
|
|
1266
|
+
var RankTrackerTableOutput = import_zod.z.object({
|
|
1267
|
+
name: import_zod.z.string(),
|
|
1268
|
+
purpose: import_zod.z.string(),
|
|
1269
|
+
keyColumns: import_zod.z.array(import_zod.z.string())
|
|
1270
|
+
});
|
|
1271
|
+
var RankTrackerCronJobOutput = import_zod.z.object({
|
|
1272
|
+
name: import_zod.z.string(),
|
|
1273
|
+
purpose: import_zod.z.string(),
|
|
1274
|
+
modes: import_zod.z.array(RankTrackerModeSchema),
|
|
1275
|
+
recommendedTools: import_zod.z.array(import_zod.z.string())
|
|
1276
|
+
});
|
|
1277
|
+
var RankTrackerBlueprintOutputSchema = {
|
|
1278
|
+
projectName: import_zod.z.string(),
|
|
1279
|
+
targetDomain: NullableString,
|
|
1280
|
+
targetBusinessName: NullableString,
|
|
1281
|
+
trackingModes: import_zod.z.array(RankTrackerModeSchema),
|
|
1282
|
+
database: import_zod.z.string(),
|
|
1283
|
+
recommendedTools: import_zod.z.array(RankTrackerToolPlanOutput),
|
|
1284
|
+
tables: import_zod.z.array(RankTrackerTableOutput),
|
|
1285
|
+
cron: import_zod.z.object({
|
|
1286
|
+
enabled: import_zod.z.boolean(),
|
|
1287
|
+
cadence: import_zod.z.string(),
|
|
1288
|
+
expression: import_zod.z.string(),
|
|
1289
|
+
timezone: import_zod.z.string(),
|
|
1290
|
+
jobs: import_zod.z.array(RankTrackerCronJobOutput)
|
|
1291
|
+
}),
|
|
1292
|
+
metrics: import_zod.z.array(import_zod.z.string()),
|
|
1293
|
+
implementationPrompt: import_zod.z.string()
|
|
1294
|
+
};
|
|
1244
1295
|
var OrganicResultOutput = import_zod.z.object({
|
|
1245
1296
|
position: import_zod.z.number().int(),
|
|
1246
1297
|
title: import_zod.z.string(),
|
|
@@ -1455,6 +1506,329 @@ var CaptureSerpPageSnapshotsInputSchema = {
|
|
|
1455
1506
|
debug: import_zod.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics for page snapshot debugging. Use true for capture, network, or proxy troubleshooting.")
|
|
1456
1507
|
};
|
|
1457
1508
|
|
|
1509
|
+
// src/mcp/rank-tracker-blueprint.ts
|
|
1510
|
+
var DEFAULT_MODES = ["maps", "organic", "ai_overview", "paa"];
|
|
1511
|
+
function normalizeDomain(value) {
|
|
1512
|
+
const trimmed = value?.trim();
|
|
1513
|
+
if (!trimmed) return null;
|
|
1514
|
+
try {
|
|
1515
|
+
const url = new URL(trimmed.includes("://") ? trimmed : `https://${trimmed}`);
|
|
1516
|
+
return url.hostname.replace(/^www\./, "").toLowerCase();
|
|
1517
|
+
} catch {
|
|
1518
|
+
return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").split("/")[0]?.toLowerCase() || trimmed;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
function uniqueModes(input) {
|
|
1522
|
+
const modes = input?.length ? input : DEFAULT_MODES;
|
|
1523
|
+
return [...new Set(modes)];
|
|
1524
|
+
}
|
|
1525
|
+
function cronExpression(cadence, customCron) {
|
|
1526
|
+
if (cadence === "daily") return "15 6 * * *";
|
|
1527
|
+
if (cadence === "monthly") return "15 6 1 * *";
|
|
1528
|
+
if (cadence === "custom") return customCron?.trim() || "CUSTOM_CRON_EXPRESSION_REQUIRED";
|
|
1529
|
+
return "15 6 * * 1";
|
|
1530
|
+
}
|
|
1531
|
+
function includes(modes, mode) {
|
|
1532
|
+
return modes.includes(mode);
|
|
1533
|
+
}
|
|
1534
|
+
function buildToolPlan(modes) {
|
|
1535
|
+
const plans = [];
|
|
1536
|
+
const push = (tool, purpose) => {
|
|
1537
|
+
if (!plans.some((plan) => plan.tool === tool)) plans.push({ tool, purpose });
|
|
1538
|
+
};
|
|
1539
|
+
push("credits_info", "Check account balance and rates before scheduling recurring rank checks.");
|
|
1540
|
+
if (includes(modes, "maps")) {
|
|
1541
|
+
push("directory_workflow", "Seed or refresh city-by-city Maps datasets when building local market coverage.");
|
|
1542
|
+
push("maps_search", "Run recurring Google Maps category checks for each keyword and location.");
|
|
1543
|
+
push("maps_place_intel", "Hydrate selected target or competitor GBP details when profile-level evidence is needed.");
|
|
1544
|
+
}
|
|
1545
|
+
if (includes(modes, "organic")) {
|
|
1546
|
+
push("search_serp", "Capture localized organic rankings, local pack data, and AI Overview status without PAA expansion.");
|
|
1547
|
+
}
|
|
1548
|
+
if (includes(modes, "ai_overview")) {
|
|
1549
|
+
push("search_serp", "Capture quick AI Overview detection and organic context for each tracked query.");
|
|
1550
|
+
push("harvest_paa", "Use when AI Overview text, PAA context, or source-level evidence needs deeper capture.");
|
|
1551
|
+
}
|
|
1552
|
+
if (includes(modes, "paa")) {
|
|
1553
|
+
push("harvest_paa", "Capture People Also Ask questions, answers, and source sites for PAA presence tracking.");
|
|
1554
|
+
}
|
|
1555
|
+
return plans;
|
|
1556
|
+
}
|
|
1557
|
+
function buildTables(modes, includeDashboard, includeAlerts, hasCompetitors) {
|
|
1558
|
+
const tables = [
|
|
1559
|
+
{
|
|
1560
|
+
name: "rank_tracker_projects",
|
|
1561
|
+
purpose: "One row per client, campaign, or tracked property.",
|
|
1562
|
+
keyColumns: ["id", "name", "target_domain", "target_business_name", "database_mode", "timezone", "created_at"]
|
|
1563
|
+
},
|
|
1564
|
+
{
|
|
1565
|
+
name: "rank_tracker_targets",
|
|
1566
|
+
purpose: "Normalized target identities and match rules for domains, URLs, business names, CIDs, and competitors.",
|
|
1567
|
+
keyColumns: ["id", "project_id", "kind", "value", "display_name", "match_rules_json", "active"]
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
name: "rank_tracker_keywords",
|
|
1571
|
+
purpose: "Tracked keywords or service queries, separated from location so calls can localize correctly.",
|
|
1572
|
+
keyColumns: ["id", "project_id", "keyword", "intent", "tags_json", "active"]
|
|
1573
|
+
},
|
|
1574
|
+
{
|
|
1575
|
+
name: "rank_tracker_locations",
|
|
1576
|
+
purpose: "Markets, cities, ZIPs, country/language settings, and proxy targeting hints.",
|
|
1577
|
+
keyColumns: ["id", "project_id", "label", "gl", "hl", "proxy_zip", "device", "active"]
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
name: "rank_tracker_runs",
|
|
1581
|
+
purpose: "Heartbeat table for every scheduled or manual rank check batch.",
|
|
1582
|
+
keyColumns: ["id", "project_id", "scheduled_for", "started_at", "completed_at", "status", "idempotency_key", "error_message"]
|
|
1583
|
+
}
|
|
1584
|
+
];
|
|
1585
|
+
if (includes(modes, "organic")) {
|
|
1586
|
+
tables.push({
|
|
1587
|
+
name: "rank_tracker_organic_results",
|
|
1588
|
+
purpose: "SERP organic result rows from search_serp, including target-domain matches and competitor rows.",
|
|
1589
|
+
keyColumns: ["id", "run_id", "keyword_id", "location_id", "device", "position", "title", "url", "domain", "is_target"]
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
if (includes(modes, "maps")) {
|
|
1593
|
+
tables.push({
|
|
1594
|
+
name: "rank_tracker_maps_results",
|
|
1595
|
+
purpose: "Google Maps result rows from maps_search and directory_workflow, including GBP identity fields.",
|
|
1596
|
+
keyColumns: ["id", "run_id", "keyword_id", "location_id", "position", "business_name", "place_url", "cid", "website_url", "rating", "review_count", "is_target"]
|
|
1597
|
+
});
|
|
1598
|
+
tables.push({
|
|
1599
|
+
name: "rank_tracker_market_seeds",
|
|
1600
|
+
purpose: "Directory workflow city, population, ZIP-group, and market seed records used to build local tracking coverage.",
|
|
1601
|
+
keyColumns: ["id", "project_id", "query", "city", "state", "population", "zip_group_json", "last_seeded_run_id"]
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
if (includes(modes, "ai_overview")) {
|
|
1605
|
+
tables.push({
|
|
1606
|
+
name: "rank_tracker_ai_overviews",
|
|
1607
|
+
purpose: "AI Overview detection, text snapshot, citation domains, and target citation status per query/location.",
|
|
1608
|
+
keyColumns: ["id", "run_id", "keyword_id", "location_id", "detected", "target_cited", "cited_domains_json", "overview_text"]
|
|
1609
|
+
});
|
|
1610
|
+
}
|
|
1611
|
+
if (includes(modes, "paa")) {
|
|
1612
|
+
tables.push({
|
|
1613
|
+
name: "rank_tracker_paa_sources",
|
|
1614
|
+
purpose: "People Also Ask questions, answers, and source sites, with target source presence flags.",
|
|
1615
|
+
keyColumns: ["id", "run_id", "keyword_id", "location_id", "question", "answer", "source_title", "source_site", "target_present"]
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
if (hasCompetitors) {
|
|
1619
|
+
tables.push({
|
|
1620
|
+
name: "rank_tracker_competitor_snapshots",
|
|
1621
|
+
purpose: "Per-run competitor visibility summaries across organic, Maps, AI Overview, and PAA surfaces.",
|
|
1622
|
+
keyColumns: ["id", "run_id", "target_id", "surface", "best_position", "presence_count", "share_of_surface"]
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1625
|
+
if (includeDashboard) {
|
|
1626
|
+
tables.push({
|
|
1627
|
+
name: "rank_tracker_daily_metrics",
|
|
1628
|
+
purpose: "Rollup table for dashboard charts, trend lines, and share-of-visibility summaries.",
|
|
1629
|
+
keyColumns: ["id", "project_id", "metric_date", "keyword_id", "location_id", "surface", "metric_name", "metric_value"]
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
if (includeAlerts) {
|
|
1633
|
+
tables.push({
|
|
1634
|
+
name: "rank_tracker_alert_events",
|
|
1635
|
+
purpose: "Deduplicated gain/loss events for rank movement, Maps top 3, AI Overview citations, and PAA source presence.",
|
|
1636
|
+
keyColumns: ["id", "project_id", "run_id", "surface", "severity", "event_key", "message", "created_at", "acknowledged_at"]
|
|
1637
|
+
});
|
|
1638
|
+
}
|
|
1639
|
+
return tables;
|
|
1640
|
+
}
|
|
1641
|
+
function buildCronJobs(modes, includeDashboard, includeAlerts) {
|
|
1642
|
+
const jobs = [
|
|
1643
|
+
{
|
|
1644
|
+
name: "rank-tracker-dispatch",
|
|
1645
|
+
purpose: "Find due keyword/location/mode combinations, create a rank_tracker_runs row, and enqueue idempotent work items.",
|
|
1646
|
+
modes,
|
|
1647
|
+
recommendedTools: ["credits_info"]
|
|
1648
|
+
}
|
|
1649
|
+
];
|
|
1650
|
+
if (includes(modes, "maps")) {
|
|
1651
|
+
jobs.push({
|
|
1652
|
+
name: "maps-rank-check",
|
|
1653
|
+
purpose: "Run maps_search per keyword/location and optionally directory_workflow for market seed refreshes.",
|
|
1654
|
+
modes: ["maps"],
|
|
1655
|
+
recommendedTools: ["maps_search", "directory_workflow", "maps_place_intel"]
|
|
1656
|
+
});
|
|
1657
|
+
}
|
|
1658
|
+
if (includes(modes, "organic") || includes(modes, "ai_overview")) {
|
|
1659
|
+
jobs.push({
|
|
1660
|
+
name: "serp-rank-check",
|
|
1661
|
+
purpose: "Run search_serp per keyword/location/device and persist organic ranks, local pack, and AI Overview status.",
|
|
1662
|
+
modes: modes.filter((mode) => mode === "organic" || mode === "ai_overview"),
|
|
1663
|
+
recommendedTools: ["search_serp"]
|
|
1664
|
+
});
|
|
1665
|
+
}
|
|
1666
|
+
if (includes(modes, "paa") || includes(modes, "ai_overview")) {
|
|
1667
|
+
jobs.push({
|
|
1668
|
+
name: "paa-ai-evidence-check",
|
|
1669
|
+
purpose: "Run harvest_paa for PAA source presence and deeper AI Overview/PAA evidence where needed.",
|
|
1670
|
+
modes: modes.filter((mode) => mode === "paa" || mode === "ai_overview"),
|
|
1671
|
+
recommendedTools: ["harvest_paa"]
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1674
|
+
if (includeDashboard) {
|
|
1675
|
+
jobs.push({
|
|
1676
|
+
name: "rank-tracker-rollups",
|
|
1677
|
+
purpose: "Aggregate raw rows into daily metrics for charts, comparison tables, and trend lines.",
|
|
1678
|
+
modes,
|
|
1679
|
+
recommendedTools: []
|
|
1680
|
+
});
|
|
1681
|
+
}
|
|
1682
|
+
if (includeAlerts) {
|
|
1683
|
+
jobs.push({
|
|
1684
|
+
name: "rank-tracker-alerts",
|
|
1685
|
+
purpose: "Compare latest run against prior snapshots and emit deduplicated visibility gain/loss events.",
|
|
1686
|
+
modes,
|
|
1687
|
+
recommendedTools: []
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
return jobs;
|
|
1691
|
+
}
|
|
1692
|
+
function buildMetrics(modes, includeDashboard, includeAlerts) {
|
|
1693
|
+
const metrics = ["run_success_rate", "last_successful_run_at", "stale_keyword_location_count"];
|
|
1694
|
+
if (includes(modes, "maps")) {
|
|
1695
|
+
metrics.push("maps_best_position", "maps_top_3_presence", "maps_target_found", "maps_competitor_count_above_target");
|
|
1696
|
+
}
|
|
1697
|
+
if (includes(modes, "organic")) {
|
|
1698
|
+
metrics.push("organic_best_position", "organic_top_3_presence", "organic_top_10_presence", "organic_best_url");
|
|
1699
|
+
}
|
|
1700
|
+
if (includes(modes, "ai_overview")) {
|
|
1701
|
+
metrics.push("ai_overview_detected", "target_ai_overview_cited", "ai_overview_citation_domain_count");
|
|
1702
|
+
}
|
|
1703
|
+
if (includes(modes, "paa")) {
|
|
1704
|
+
metrics.push("paa_question_count", "target_paa_source_count", "paa_presence_rate", "paa_source_domains");
|
|
1705
|
+
}
|
|
1706
|
+
if (includeDashboard) metrics.push("share_of_visibility", "position_delta_7d", "position_delta_30d");
|
|
1707
|
+
if (includeAlerts) metrics.push("visibility_gain_events", "visibility_loss_events");
|
|
1708
|
+
return metrics;
|
|
1709
|
+
}
|
|
1710
|
+
function listOrPlaceholder(values, fallback) {
|
|
1711
|
+
const clean = values?.map((value) => value.trim()).filter(Boolean) ?? [];
|
|
1712
|
+
if (!clean.length) return fallback;
|
|
1713
|
+
return clean.map((value) => `- ${value}`).join("\n");
|
|
1714
|
+
}
|
|
1715
|
+
function buildPrompt(input, modes, tools, tables, jobs, metrics, expression, targetDomain, targetBusinessName) {
|
|
1716
|
+
const keywords = listOrPlaceholder(input.keywords, "- TODO: add tracked keywords");
|
|
1717
|
+
const locations = listOrPlaceholder(input.locations, "- TODO: add tracked markets/locations");
|
|
1718
|
+
const competitors = listOrPlaceholder(input.competitors, "- Optional: add competitor domains or GBP names");
|
|
1719
|
+
const notes = input.notes?.trim() || "No extra implementation notes.";
|
|
1720
|
+
return [
|
|
1721
|
+
"You are building a production rank tracker powered by MCP Scraper. Create the database migrations, scheduled worker, ingestion functions, and dashboard/query layer described below.",
|
|
1722
|
+
"",
|
|
1723
|
+
`Project: ${input.projectName || "MCP Scraper Rank Tracker"}`,
|
|
1724
|
+
`Target domain: ${targetDomain || "TODO_TARGET_DOMAIN"}`,
|
|
1725
|
+
`Target business/GBP name: ${targetBusinessName || "TODO_TARGET_BUSINESS_NAME"}`,
|
|
1726
|
+
`Database target: ${input.database || "postgres"}`,
|
|
1727
|
+
`Tracking modes: ${modes.join(", ")}`,
|
|
1728
|
+
"",
|
|
1729
|
+
"Seed keywords:",
|
|
1730
|
+
keywords,
|
|
1731
|
+
"",
|
|
1732
|
+
"Seed locations:",
|
|
1733
|
+
locations,
|
|
1734
|
+
"",
|
|
1735
|
+
"Competitors:",
|
|
1736
|
+
competitors,
|
|
1737
|
+
"",
|
|
1738
|
+
"MCP Scraper calls to use:",
|
|
1739
|
+
tools.map((tool) => `- ${tool.tool}: ${tool.purpose}`).join("\n"),
|
|
1740
|
+
"",
|
|
1741
|
+
"Database tables to create:",
|
|
1742
|
+
tables.map((table) => `- ${table.name}: ${table.keyColumns.join(", ")}`).join("\n"),
|
|
1743
|
+
"",
|
|
1744
|
+
"Scheduler and heartbeat requirements:",
|
|
1745
|
+
`- Use cron expression "${expression}" in timezone "${input.timezone || "UTC"}" unless the user changes cadence.`,
|
|
1746
|
+
"- Every scheduled batch must insert or update rank_tracker_runs before calling MCP tools.",
|
|
1747
|
+
"- Use idempotency_key = project_id + keyword_id + location_id + mode + device + scheduled_date.",
|
|
1748
|
+
"- Mark runs as running, succeeded, failed, or skipped; persist error_message on failures.",
|
|
1749
|
+
"- Run MCP calls sequentially by default because accounts have one concurrency slot unless the user bought more.",
|
|
1750
|
+
"- Retry retryable upstream failures with backoff, but do not duplicate rows for the same idempotency key.",
|
|
1751
|
+
"",
|
|
1752
|
+
"Mode-specific ingestion rules:",
|
|
1753
|
+
"- maps: Use directory_workflow to seed/refresh market coverage and maps_search for recurring keyword/location rank checks. Match the target by targetBusinessName, website domain, CID, and place URL when available.",
|
|
1754
|
+
"- organic: Use search_serp and persist every organic result row. Compute the best targetDomain position and best ranking URL per keyword/location/device.",
|
|
1755
|
+
"- ai_overview: Use search_serp for quick detection and harvest_paa when deeper text/source evidence is needed. Track detected, overview_text, cited domains, and whether targetDomain is cited.",
|
|
1756
|
+
"- paa: Use harvest_paa and persist each question/source pair. Track whether sourceSite or answer/source evidence matches targetDomain, then compute PAA presence rate.",
|
|
1757
|
+
"",
|
|
1758
|
+
"Metrics to expose:",
|
|
1759
|
+
metrics.map((metric) => `- ${metric}`).join("\n"),
|
|
1760
|
+
"",
|
|
1761
|
+
"Alert requirements:",
|
|
1762
|
+
input.includeAlerts ? "- Emit deduplicated alert_events when target gains/loses Maps top 3, organic top 10, AI Overview citation, or PAA source presence." : "- Alerts are out of scope for this build unless the user asks for them.",
|
|
1763
|
+
"",
|
|
1764
|
+
"Dashboard requirements:",
|
|
1765
|
+
input.includeDashboard ? "- Build views for latest position by keyword/location, trend deltas, competitors above target, AI Overview citations, and PAA source wins/losses." : "- Dashboard is out of scope for this build unless the user asks for it.",
|
|
1766
|
+
"",
|
|
1767
|
+
"Extra notes:",
|
|
1768
|
+
notes
|
|
1769
|
+
].join("\n");
|
|
1770
|
+
}
|
|
1771
|
+
function buildRankTrackerBlueprint(input) {
|
|
1772
|
+
const trackingModes = uniqueModes(input.trackingModes);
|
|
1773
|
+
const targetDomain = normalizeDomain(input.targetDomain);
|
|
1774
|
+
const targetBusinessName = input.targetBusinessName?.trim() || null;
|
|
1775
|
+
const projectName = input.projectName?.trim() || "MCP Scraper Rank Tracker";
|
|
1776
|
+
const database = input.database || "postgres";
|
|
1777
|
+
const expression = cronExpression(input.scheduleCadence || "weekly", input.customCron);
|
|
1778
|
+
const tools = buildToolPlan(trackingModes);
|
|
1779
|
+
const tables = buildTables(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false, Boolean(input.competitors?.length));
|
|
1780
|
+
const jobs = input.includeCron === false ? [] : buildCronJobs(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false);
|
|
1781
|
+
const metrics = buildMetrics(trackingModes, input.includeDashboard !== false, input.includeAlerts !== false);
|
|
1782
|
+
const implementationPrompt = buildPrompt(input, trackingModes, tools, tables, jobs, metrics, expression, targetDomain, targetBusinessName);
|
|
1783
|
+
const blueprint = {
|
|
1784
|
+
projectName,
|
|
1785
|
+
targetDomain,
|
|
1786
|
+
targetBusinessName,
|
|
1787
|
+
trackingModes,
|
|
1788
|
+
database,
|
|
1789
|
+
recommendedTools: tools,
|
|
1790
|
+
tables,
|
|
1791
|
+
cron: {
|
|
1792
|
+
enabled: input.includeCron !== false,
|
|
1793
|
+
cadence: input.scheduleCadence || "weekly",
|
|
1794
|
+
expression: input.includeCron === false ? "disabled" : expression,
|
|
1795
|
+
timezone: input.timezone || "UTC",
|
|
1796
|
+
jobs
|
|
1797
|
+
},
|
|
1798
|
+
metrics,
|
|
1799
|
+
implementationPrompt
|
|
1800
|
+
};
|
|
1801
|
+
const text = [
|
|
1802
|
+
`# ${projectName}`,
|
|
1803
|
+
"",
|
|
1804
|
+
"Rank tracker build blueprint generated from MCP Scraper tool capabilities.",
|
|
1805
|
+
"",
|
|
1806
|
+
"## Modes",
|
|
1807
|
+
trackingModes.map((mode) => `- ${mode}`).join("\n"),
|
|
1808
|
+
"",
|
|
1809
|
+
"## Recommended MCP Tools",
|
|
1810
|
+
tools.map((tool) => `- \`${tool.tool}\` - ${tool.purpose}`).join("\n"),
|
|
1811
|
+
"",
|
|
1812
|
+
"## Database Tables",
|
|
1813
|
+
tables.map((table) => `- \`${table.name}\` - ${table.purpose}`).join("\n"),
|
|
1814
|
+
"",
|
|
1815
|
+
"## Cron / Heartbeat",
|
|
1816
|
+
blueprint.cron.enabled ? `- Cadence: ${blueprint.cron.cadence}
|
|
1817
|
+
- Cron: \`${blueprint.cron.expression}\`
|
|
1818
|
+
- Timezone: ${blueprint.cron.timezone}
|
|
1819
|
+
- Jobs: ${jobs.map((job) => job.name).join(", ")}` : "- Disabled by input. Still create rank_tracker_runs for manual runs.",
|
|
1820
|
+
"",
|
|
1821
|
+
"## Implementation Prompt",
|
|
1822
|
+
"```text",
|
|
1823
|
+
implementationPrompt,
|
|
1824
|
+
"```"
|
|
1825
|
+
].join("\n");
|
|
1826
|
+
return {
|
|
1827
|
+
content: [{ type: "text", text }],
|
|
1828
|
+
structuredContent: blueprint
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1458
1832
|
// src/mcp/paa-mcp-server.ts
|
|
1459
1833
|
function liveWebToolAnnotations(title) {
|
|
1460
1834
|
return {
|
|
@@ -1465,6 +1839,15 @@ function liveWebToolAnnotations(title) {
|
|
|
1465
1839
|
openWorldHint: true
|
|
1466
1840
|
};
|
|
1467
1841
|
}
|
|
1842
|
+
function localPlanningToolAnnotations(title) {
|
|
1843
|
+
return {
|
|
1844
|
+
title,
|
|
1845
|
+
readOnlyHint: true,
|
|
1846
|
+
destructiveHint: false,
|
|
1847
|
+
idempotentHint: true,
|
|
1848
|
+
openWorldHint: false
|
|
1849
|
+
};
|
|
1850
|
+
}
|
|
1468
1851
|
function listSavedReports() {
|
|
1469
1852
|
try {
|
|
1470
1853
|
const dir = outputBaseDir();
|
|
@@ -1598,6 +1981,13 @@ function registerPaaExtractorMcpTools(server2, executor2, options = {}) {
|
|
|
1598
1981
|
outputSchema: DirectoryWorkflowOutputSchema,
|
|
1599
1982
|
annotations: liveWebToolAnnotations("Directory Workflow: Markets + Maps")
|
|
1600
1983
|
}, async (input) => formatDirectoryWorkflow(await executor2.directoryWorkflow(input), input));
|
|
1984
|
+
server2.registerTool("rank_tracker_blueprint", {
|
|
1985
|
+
title: "Rank Tracker Blueprint Builder",
|
|
1986
|
+
description: "Generate a build-ready database, cron/heartbeat, ingestion, metrics, and AI implementation prompt for a rank tracker powered by MCP Scraper. Supports Maps rankings through directory_workflow/maps_search, organic rankings through search_serp, AI Overview citation tracking, and People Also Ask source presence tracking. This tool is local planning only; it does not call the web or spend credits.",
|
|
1987
|
+
inputSchema: RankTrackerBlueprintInputSchema,
|
|
1988
|
+
outputSchema: RankTrackerBlueprintOutputSchema,
|
|
1989
|
+
annotations: localPlanningToolAnnotations("Rank Tracker Blueprint Builder")
|
|
1990
|
+
}, async (input) => buildRankTrackerBlueprint(input));
|
|
1601
1991
|
server2.registerTool("credits_info", {
|
|
1602
1992
|
title: "MCP Scraper Credits & Costs",
|
|
1603
1993
|
description: "Answer questions about MCP Scraper credits: current credit balance, what a specific tool/action costs, the full cost table, and optionally recent credit ledger entries. Does not expose payment methods or credit card information.",
|