mcp-scraper 0.3.1 → 0.3.2
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 -1
- package/dist/bin/api-server.cjs +2047 -831
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- 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-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-combined-stdio-server.cjs +348 -3
- package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-scraper-combined-stdio-server.js +4 -4
- package/dist/bin/mcp-scraper-install.cjs +3 -3
- 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 +346 -1
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +2 -2
- package/dist/bin/paa-harvest.cjs +3 -1
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +1 -1
- package/dist/{chunk-SXTXMFEQ.js → chunk-AZ5PKU4F.js} +34 -1
- package/dist/chunk-AZ5PKU4F.js.map +1 -0
- package/dist/{chunk-Q4STSM63.js → chunk-C3FGVJWH.js} +3 -3
- package/dist/chunk-C3FGVJWH.js.map +1 -0
- package/dist/{chunk-LICHCMV6.js → chunk-HRTCMLZB.js} +2 -2
- package/dist/{chunk-55T4SRLJ.js → chunk-KO223PSJ.js} +347 -2
- package/dist/chunk-KO223PSJ.js.map +1 -0
- package/dist/{chunk-IPW4LFOT.js → chunk-UWSG3C5J.js} +4 -2
- package/dist/chunk-UWSG3C5J.js.map +1 -0
- package/dist/chunk-VB65G7PS.js +7 -0
- package/dist/chunk-VB65G7PS.js.map +1 -0
- package/dist/index.cjs +3 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/{server-AXPNL2RV.js → server-N5LM3PEO.js} +997 -253
- package/dist/server-N5LM3PEO.js.map +1 -0
- package/dist/{worker-SLQ375UG.js → worker-56IXWOQU.js} +3 -3
- package/docs/mcp-tool-craft-lint.generated.md +5 -2
- package/docs/mcp-tool-manifest.generated.json +80 -5
- package/package.json +1 -1
- package/dist/chunk-55T4SRLJ.js.map +0 -1
- package/dist/chunk-D4JDGKOV.js +0 -7
- package/dist/chunk-D4JDGKOV.js.map +0 -1
- package/dist/chunk-IPW4LFOT.js.map +0 -1
- package/dist/chunk-Q4STSM63.js.map +0 -1
- package/dist/chunk-SXTXMFEQ.js.map +0 -1
- package/dist/server-AXPNL2RV.js.map +0 -1
- /package/dist/{chunk-LICHCMV6.js.map → chunk-HRTCMLZB.js.map} +0 -0
- /package/dist/{worker-SLQ375UG.js.map → worker-56IXWOQU.js.map} +0 -0
|
@@ -2,21 +2,21 @@
|
|
|
2
2
|
import {
|
|
3
3
|
HttpMcpToolExecutor,
|
|
4
4
|
registerPaaExtractorMcpTools
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-KO223PSJ.js";
|
|
6
6
|
import "../chunk-M2S27J6Z.js";
|
|
7
7
|
import {
|
|
8
8
|
registerBrowserAgentMcpTools
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-HRTCMLZB.js";
|
|
10
10
|
import "../chunk-NXRWFOEZ.js";
|
|
11
11
|
import "../chunk-WN7PBKMV.js";
|
|
12
12
|
import {
|
|
13
13
|
renderInstallTerminal
|
|
14
|
-
} from "../chunk-
|
|
14
|
+
} from "../chunk-C3FGVJWH.js";
|
|
15
15
|
import "../chunk-LFATOGDF.js";
|
|
16
16
|
import "../chunk-DUEW4EOO.js";
|
|
17
17
|
import {
|
|
18
18
|
PACKAGE_VERSION
|
|
19
|
-
} from "../chunk-
|
|
19
|
+
} from "../chunk-VB65G7PS.js";
|
|
20
20
|
|
|
21
21
|
// bin/mcp-scraper-combined-stdio-server.ts
|
|
22
22
|
import { readFileSync } from "fs";
|
|
@@ -53,11 +53,11 @@ function renderInstallTerminal(options) {
|
|
|
53
53
|
"1/1 install surfaces ready",
|
|
54
54
|
colorize("Newest: local Chrome profile mode for browser_open, browser_profile_import/sync, and one-server MCP installs.", "lime", color),
|
|
55
55
|
"",
|
|
56
|
-
`${colorize("Tools", "cyan", color)} ${colorize("(
|
|
56
|
+
`${colorize("Tools", "cyan", color)} ${colorize("(46 MCP tools)", "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
59
|
toolRow("build", ["rank_tracker_blueprint", "cron plan", "database prompt"], color),
|
|
60
|
-
toolRow("media", ["youtube_harvest", "youtube_transcribe", "facebook_ad_search", "facebook_page_intel", "facebook_ad_transcribe", "facebook_video_transcribe"], color),
|
|
60
|
+
toolRow("media", ["youtube_harvest", "youtube_transcribe", "facebook_ad_search", "facebook_page_intel", "facebook_ad_transcribe", "facebook_video_transcribe", "instagram_profile_content", "instagram_media_download"], color),
|
|
61
61
|
toolRow("browser", ["browser_open", "browser_profile_import", "browser_profile_sync", "browser_screenshot", "browser_read", "browser_locate", "browser_replay_mark", "browser_replay_annotate"], color),
|
|
62
62
|
toolRow("account", ["credits_info", "local reports", "MCP resources"], color),
|
|
63
63
|
`${colorize("Workflows", "cyan", color)} ${colorize("(MCP + CLI + API)", "muted", color)}`,
|
|
@@ -101,7 +101,7 @@ function renderInstallTerminal(options) {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
// src/version.ts
|
|
104
|
-
var PACKAGE_VERSION = "0.3.
|
|
104
|
+
var PACKAGE_VERSION = "0.3.2";
|
|
105
105
|
|
|
106
106
|
// bin/mcp-scraper-install.ts
|
|
107
107
|
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 `MCP_SCRAPER_API_KEY=${apiKeyValue} npx -y -p mcp-scraper@latest \\\\`,\n ' mcp-scraper-cli agent install claude --apply',\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 colorize('Newest: local Chrome profile mode for browser_open, browser_profile_import/sync, and one-server MCP installs.', 'lime', color),\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 `MCP_SCRAPER_API_KEY=${apiKeyValue} npx -y -p mcp-scraper@latest \\\\`,\n ' mcp-scraper-cli agent install claude --apply',\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 colorize('Newest: local Chrome profile mode for browser_open, browser_profile_import/sync, and one-server MCP installs.', 'lime', color),\n '',\n `${colorize('Tools', 'cyan', color)} ${colorize('(46 MCP tools)', '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', 'facebook_ad_transcribe', 'facebook_video_transcribe', 'instagram_profile_content', 'instagram_media_download'], color),\n toolRow('browser', ['browser_open', 'browser_profile_import', 'browser_profile_sync', 'browser_screenshot', 'browser_read', 'browser_locate', 'browser_replay_mark', 'browser_replay_annotate'], color),\n toolRow('account', ['credits_info', 'local reports', 'MCP resources'], color),\n `${colorize('Workflows', 'cyan', color)} ${colorize('(MCP + CLI + API)', 'muted', color)}`,\n toolRow('route', ['workflow_list', 'workflow_suggest', 'workflow_run', 'workflow_step', 'workflow_status', 'workflow_artifact_read'], color),\n toolRow('seo', ['directory', 'agent-packet', 'local audit', 'map/serp comparison', 'PAA/AIO briefs', 'scheduled runs'], color),\n '',\n colorize('Usage tips:', 'amber', color),\n 'Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.',\n 'Run mcp-scraper-combined in a human terminal to print this card; MCP clients get the same command as a silent stdio server.',\n 'Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install',\n 'Local Chrome mode: mcp-scraper-cli browser import-chrome --email you@example.com --name chrome-default',\n 'Then: mcp-scraper-cli agent install claude --apply --browser-mode local --browser-profile chrome-default',\n 'Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.',\n 'For MCP clients, use mcp-scraper-combined so one install can mix SERP, Maps, browser, reports, and saved MCP resources.',\n 'If you hit the concurrency limit, add an extra slot for $5/month with mcp-scraper-cli billing concurrency checkout.',\n '',\n `${colorize('Ready.', 'lime', color)} Install the combined MCP server with one command:`,\n '',\n colorize('Setup doctor', 'amber', color),\n 'npx -y -p mcp-scraper@latest mcp-scraper-cli doctor',\n '',\n colorize('Local Chrome profile setup', 'amber', color),\n 'npx -y -p mcp-scraper@latest mcp-scraper-cli browser profiles --email you@example.com',\n 'npx -y -p mcp-scraper@latest mcp-scraper-cli browser import-chrome --email you@example.com --name chrome-default',\n '',\n colorize('Claude Code one-command setup', 'amber', color),\n claudeCommand,\n 'Then fully exit Claude Code and open a new Claude terminal. Check with: claude mcp list',\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 'mcp-scraper-combined prints this card only when stdin/stdout are an interactive TTY. In MCP clients it writes only JSON-RPC to stdout.',\n 'Use --stdio or MCP_SCRAPER_FORCE_STDIO=1 to force server mode from a terminal.',\n '',\n ].join('\\n')\n}\n","export const PACKAGE_VERSION = '0.3.2'\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 'mcp-scraper-combined prints the same card in a human terminal and runs as the MCP stdio server in clients.',\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,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
renderInstallTerminal
|
|
4
|
-
} from "../chunk-
|
|
4
|
+
} from "../chunk-C3FGVJWH.js";
|
|
5
5
|
import {
|
|
6
6
|
PACKAGE_VERSION
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-VB65G7PS.js";
|
|
8
8
|
|
|
9
9
|
// bin/mcp-scraper-install.ts
|
|
10
10
|
var noColor = process.argv.includes("--no-color") || process.env.NO_COLOR !== void 0 || process.env.FORCE_COLOR === "0" || !process.stdout.isTTY;
|
|
@@ -196,6 +196,12 @@ var HttpMcpToolExecutor = class {
|
|
|
196
196
|
facebookVideoTranscribe(input) {
|
|
197
197
|
return this.call("/facebook/video-transcribe", input, this.httpTimeoutOverrideMs ?? 24e4);
|
|
198
198
|
}
|
|
199
|
+
instagramProfileContent(input) {
|
|
200
|
+
return this.call("/instagram/profile-content", input, this.httpTimeoutOverrideMs ?? 24e4);
|
|
201
|
+
}
|
|
202
|
+
instagramMediaDownload(input) {
|
|
203
|
+
return this.call("/instagram/media-download", input, this.httpTimeoutOverrideMs ?? 3e5);
|
|
204
|
+
}
|
|
199
205
|
mapsPlaceIntel(input) {
|
|
200
206
|
return this.call("/maps/place", input);
|
|
201
207
|
}
|
|
@@ -249,7 +255,7 @@ var import_node_fs2 = require("fs");
|
|
|
249
255
|
var import_node_path2 = require("path");
|
|
250
256
|
|
|
251
257
|
// src/version.ts
|
|
252
|
-
var PACKAGE_VERSION = "0.3.
|
|
258
|
+
var PACKAGE_VERSION = "0.3.2";
|
|
253
259
|
|
|
254
260
|
// src/mcp/mcp-response-formatter.ts
|
|
255
261
|
var import_node_fs = require("fs");
|
|
@@ -1703,6 +1709,216 @@ ${chunkRows}` : "",
|
|
|
1703
1709
|
}
|
|
1704
1710
|
};
|
|
1705
1711
|
}
|
|
1712
|
+
function structuredInstagramBrowser(raw) {
|
|
1713
|
+
const browser = raw && typeof raw === "object" ? raw : {};
|
|
1714
|
+
const mode = browser.mode === "local" ? "local" : "hosted";
|
|
1715
|
+
const requestedMode = browser.requestedMode === "local" || browser.requestedMode === "hosted" || browser.requestedMode === "auto" ? browser.requestedMode : "auto";
|
|
1716
|
+
const profileSource = browser.profileSource === "managed_profile" || browser.profileSource === "direct_profile_dir" ? browser.profileSource : "hosted";
|
|
1717
|
+
return {
|
|
1718
|
+
mode,
|
|
1719
|
+
requestedMode,
|
|
1720
|
+
profileName: typeof browser.profileName === "string" ? browser.profileName : null,
|
|
1721
|
+
profileSource,
|
|
1722
|
+
profileDirConfigured: browser.profileDirConfigured === true,
|
|
1723
|
+
executablePathConfigured: browser.executablePathConfigured === true
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
function structuredInstagramPagination(raw, input) {
|
|
1727
|
+
const pagination = raw && typeof raw === "object" ? raw : {};
|
|
1728
|
+
const stages = Array.isArray(pagination.stages) ? pagination.stages : [];
|
|
1729
|
+
const stoppedReason = typeof pagination.stoppedReason === "string" && ["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"].includes(pagination.stoppedReason) ? pagination.stoppedReason : "no_scrolls";
|
|
1730
|
+
return {
|
|
1731
|
+
maxItems: typeof pagination.maxItems === "number" ? pagination.maxItems : Number(input.maxItems ?? 50),
|
|
1732
|
+
maxScrolls: typeof pagination.maxScrolls === "number" ? pagination.maxScrolls : Number(input.maxScrolls ?? 10),
|
|
1733
|
+
attemptedScrolls: typeof pagination.attemptedScrolls === "number" ? pagination.attemptedScrolls : 0,
|
|
1734
|
+
stableScrolls: typeof pagination.stableScrolls === "number" ? pagination.stableScrolls : 0,
|
|
1735
|
+
stableScrollLimit: typeof pagination.stableScrollLimit === "number" ? pagination.stableScrollLimit : Number(input.stableScrollLimit ?? 4),
|
|
1736
|
+
scrollDelayMs: typeof pagination.scrollDelayMs === "number" ? pagination.scrollDelayMs : Number(input.scrollDelayMs ?? 1200),
|
|
1737
|
+
reachedMaxItems: pagination.reachedMaxItems === true,
|
|
1738
|
+
reachedReportedPostCount: pagination.reachedReportedPostCount === true,
|
|
1739
|
+
finalScrollHeight: typeof pagination.finalScrollHeight === "number" ? pagination.finalScrollHeight : null,
|
|
1740
|
+
stoppedReason,
|
|
1741
|
+
stages: stages.map((stage) => {
|
|
1742
|
+
const row = stage && typeof stage === "object" ? stage : {};
|
|
1743
|
+
return {
|
|
1744
|
+
stage: String(row.stage ?? ""),
|
|
1745
|
+
itemCount: typeof row.itemCount === "number" ? row.itemCount : 0,
|
|
1746
|
+
addedCount: typeof row.addedCount === "number" ? row.addedCount : 0,
|
|
1747
|
+
scrollY: typeof row.scrollY === "number" ? row.scrollY : null,
|
|
1748
|
+
scrollHeight: typeof row.scrollHeight === "number" ? row.scrollHeight : null
|
|
1749
|
+
};
|
|
1750
|
+
})
|
|
1751
|
+
};
|
|
1752
|
+
}
|
|
1753
|
+
function formatInstagramProfileContent(raw, input) {
|
|
1754
|
+
const parsed = parseData(raw);
|
|
1755
|
+
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
1756
|
+
const d = parsed.data;
|
|
1757
|
+
const items = Array.isArray(d.items) ? d.items : [];
|
|
1758
|
+
const typeCounts = d.typeCounts;
|
|
1759
|
+
const limitations = Array.isArray(d.limitations) ? d.limitations.map(String) : [];
|
|
1760
|
+
const browser = structuredInstagramBrowser(d.browser);
|
|
1761
|
+
const pagination = structuredInstagramPagination(d.pagination, input);
|
|
1762
|
+
const itemRows = items.slice(0, 100).map(
|
|
1763
|
+
(item, i) => `| ${i + 1} | ${item.type} | \`${item.shortcode}\` | ${item.url} | ${cell(item.firstSeenStage ?? "")} |`
|
|
1764
|
+
).join("\n");
|
|
1765
|
+
const browserLabel = browser.mode === "local" ? `local profile ${browser.profileName ? `\`${browser.profileName}\`` : "(unnamed)"}` : "hosted browser";
|
|
1766
|
+
const full = [
|
|
1767
|
+
`# Instagram Profile Content: ${d.handle ?? input.handle ?? input.url ?? "profile"}`,
|
|
1768
|
+
`**Collected:** ${items.length} items \xB7 posts ${typeCounts?.post ?? 0} \xB7 reels ${typeCounts?.reel ?? 0} \xB7 tv ${typeCounts?.tv ?? 0}`,
|
|
1769
|
+
`**Browser:** ${browserLabel}`,
|
|
1770
|
+
`**Pagination:** ${pagination.attemptedScrolls} scrolls \xB7 stopped: ${pagination.stoppedReason}`,
|
|
1771
|
+
d.reportedPostCountText ? `**Profile count:** ${d.reportedPostCountText}` : "",
|
|
1772
|
+
d.followerCountText ? `**Followers:** ${d.followerCountText}` : "",
|
|
1773
|
+
`
|
|
1774
|
+
## Content Links
|
|
1775
|
+
| # | Type | Shortcode | URL | First Seen |
|
|
1776
|
+
|---|------|-----------|-----|------------|
|
|
1777
|
+
${itemRows || "| \u2014 | \u2014 | \u2014 | \u2014 | \u2014 |"}`,
|
|
1778
|
+
limitations.length ? `
|
|
1779
|
+
## Limits
|
|
1780
|
+
${limitations.map((l) => `- ${l}`).join("\n")}` : "",
|
|
1781
|
+
`
|
|
1782
|
+
---
|
|
1783
|
+
\u{1F4A1} Use \`instagram_media_download\` with one of these URLs to download text, image, reel tracks, and optional transcript.`
|
|
1784
|
+
].filter(Boolean).join("\n");
|
|
1785
|
+
return {
|
|
1786
|
+
...oneBlock(full),
|
|
1787
|
+
structuredContent: {
|
|
1788
|
+
handle: String(d.handle ?? input.handle ?? ""),
|
|
1789
|
+
profileUrl: String(d.profileUrl ?? input.url ?? ""),
|
|
1790
|
+
pageUrl: String(d.pageUrl ?? d.profileUrl ?? input.url ?? ""),
|
|
1791
|
+
browser,
|
|
1792
|
+
profileName: typeof d.profileName === "string" ? d.profileName : null,
|
|
1793
|
+
reportedPostCount: typeof d.reportedPostCount === "number" ? d.reportedPostCount : null,
|
|
1794
|
+
reportedPostCountText: typeof d.reportedPostCountText === "string" ? d.reportedPostCountText : null,
|
|
1795
|
+
followerCountText: typeof d.followerCountText === "string" ? d.followerCountText : null,
|
|
1796
|
+
followingCountText: typeof d.followingCountText === "string" ? d.followingCountText : null,
|
|
1797
|
+
collectedContentCount: items.length,
|
|
1798
|
+
typeCounts: {
|
|
1799
|
+
post: Number(typeCounts?.post ?? 0),
|
|
1800
|
+
reel: Number(typeCounts?.reel ?? 0),
|
|
1801
|
+
tv: Number(typeCounts?.tv ?? 0)
|
|
1802
|
+
},
|
|
1803
|
+
pagination,
|
|
1804
|
+
limited: d.limited === true,
|
|
1805
|
+
limitations,
|
|
1806
|
+
items: items.map((item) => ({
|
|
1807
|
+
url: String(item.url ?? ""),
|
|
1808
|
+
type: item.type,
|
|
1809
|
+
shortcode: String(item.shortcode ?? ""),
|
|
1810
|
+
anchorText: item.anchorText ?? null,
|
|
1811
|
+
firstSeenStage: String(item.firstSeenStage ?? "")
|
|
1812
|
+
}))
|
|
1813
|
+
}
|
|
1814
|
+
};
|
|
1815
|
+
}
|
|
1816
|
+
function structuredInstagramTrack(track) {
|
|
1817
|
+
if (!track) return null;
|
|
1818
|
+
return {
|
|
1819
|
+
url: String(track.url ?? ""),
|
|
1820
|
+
streamType: track.streamType ?? "unknown",
|
|
1821
|
+
bitrate: typeof track.bitrate === "number" ? track.bitrate : null,
|
|
1822
|
+
durationSec: typeof track.durationSec === "number" ? track.durationSec : null,
|
|
1823
|
+
vencodeTag: track.vencodeTag ?? null,
|
|
1824
|
+
width: typeof track.width === "number" ? track.width : null,
|
|
1825
|
+
height: typeof track.height === "number" ? track.height : null
|
|
1826
|
+
};
|
|
1827
|
+
}
|
|
1828
|
+
function formatInstagramMediaDownload(raw, input) {
|
|
1829
|
+
const parsed = parseData(raw);
|
|
1830
|
+
if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
|
|
1831
|
+
const d = parsed.data;
|
|
1832
|
+
const tracks = Array.isArray(d.tracks) ? d.tracks : [];
|
|
1833
|
+
const downloads = Array.isArray(d.downloads) ? d.downloads : [];
|
|
1834
|
+
const warnings = Array.isArray(d.warnings) ? d.warnings.map(String) : [];
|
|
1835
|
+
const limitations = Array.isArray(d.limitations) ? d.limitations.map(String) : [];
|
|
1836
|
+
const transcript = d.transcript;
|
|
1837
|
+
const transcriptText = transcript?.text ?? "";
|
|
1838
|
+
const chunks = transcript?.chunks ?? [];
|
|
1839
|
+
const browser = structuredInstagramBrowser(d.browser);
|
|
1840
|
+
const browserLabel = browser.mode === "local" ? `local profile ${browser.profileName ? `\`${browser.profileName}\`` : "(unnamed)"}` : "hosted browser";
|
|
1841
|
+
const downloadRows = downloads.map((download, i) => {
|
|
1842
|
+
const status = download.error ? `error: ${cell(download.error)}` : `${download.sizeBytes ?? 0} bytes`;
|
|
1843
|
+
return `| ${i + 1} | ${download.kind} | ${download.savedPath ? `\`${download.savedPath}\`` : "\u2014"} | ${status} |`;
|
|
1844
|
+
}).join("\n");
|
|
1845
|
+
const trackRows = tracks.slice(0, 20).map(
|
|
1846
|
+
(track, i) => `| ${i + 1} | ${track.streamType} | ${track.bitrate ?? "\u2014"} | ${track.durationSec ?? "\u2014"} | ${cell(track.vencodeTag ?? "")} |`
|
|
1847
|
+
).join("\n");
|
|
1848
|
+
const full = [
|
|
1849
|
+
`# Instagram Media Download`,
|
|
1850
|
+
`**URL:** ${d.pageUrl ?? input.url}`,
|
|
1851
|
+
`**Browser:** ${browserLabel}`,
|
|
1852
|
+
d.ownerName ? `**Owner:** ${d.ownerName}` : "",
|
|
1853
|
+
d.shortcode ? `**Shortcode:** \`${d.shortcode}\`` : "",
|
|
1854
|
+
d.caption ? `
|
|
1855
|
+
## Caption
|
|
1856
|
+
${truncate(String(d.caption), 1200)}` : "",
|
|
1857
|
+
d.imageUrl ? `
|
|
1858
|
+
## Image
|
|
1859
|
+
${d.imageUrl}` : "",
|
|
1860
|
+
tracks.length ? `
|
|
1861
|
+
## Media Tracks
|
|
1862
|
+
| # | Type | Bitrate | Duration | Tag |
|
|
1863
|
+
|---|------|---------|----------|-----|
|
|
1864
|
+
${trackRows}` : "\n## Media Tracks\n*None captured.*",
|
|
1865
|
+
downloads.length ? `
|
|
1866
|
+
## Downloads
|
|
1867
|
+
| # | Kind | File | Status |
|
|
1868
|
+
|---|------|------|--------|
|
|
1869
|
+
${downloadRows}` : "",
|
|
1870
|
+
d.outputDir ? `
|
|
1871
|
+
**Output directory:** \`${d.outputDir}\`` : "",
|
|
1872
|
+
transcript ? `
|
|
1873
|
+
## Transcript
|
|
1874
|
+
**${wordCount(transcriptText)} words** \xB7 ${chunks.length} chunks
|
|
1875
|
+
|
|
1876
|
+
${transcriptText}` : "",
|
|
1877
|
+
warnings.length ? `
|
|
1878
|
+
## Warnings
|
|
1879
|
+
${warnings.map((w) => `- ${w}`).join("\n")}` : "",
|
|
1880
|
+
limitations.length ? `
|
|
1881
|
+
## Limits
|
|
1882
|
+
${limitations.map((l) => `- ${l}`).join("\n")}` : "",
|
|
1883
|
+
`
|
|
1884
|
+
---
|
|
1885
|
+
\u{1F4A1} Reels may expose separate video-only and audio-only MP4 tracks. Use the muxed file when present; otherwise use the selected video/audio track URLs or saved files.`
|
|
1886
|
+
].filter(Boolean).join("\n");
|
|
1887
|
+
return {
|
|
1888
|
+
...oneBlock(full),
|
|
1889
|
+
structuredContent: {
|
|
1890
|
+
sourceUrl: String(d.sourceUrl ?? input.url),
|
|
1891
|
+
pageUrl: String(d.pageUrl ?? input.url),
|
|
1892
|
+
browser,
|
|
1893
|
+
type: d.type === "post" || d.type === "reel" || d.type === "tv" ? d.type : null,
|
|
1894
|
+
shortcode: typeof d.shortcode === "string" ? d.shortcode : null,
|
|
1895
|
+
ownerName: typeof d.ownerName === "string" ? d.ownerName : null,
|
|
1896
|
+
caption: typeof d.caption === "string" ? d.caption : null,
|
|
1897
|
+
imageUrl: typeof d.imageUrl === "string" ? d.imageUrl : null,
|
|
1898
|
+
trackCount: tracks.length,
|
|
1899
|
+
selectedVideoTrack: structuredInstagramTrack(d.selectedVideoTrack),
|
|
1900
|
+
selectedAudioTrack: structuredInstagramTrack(d.selectedAudioTrack),
|
|
1901
|
+
downloads: downloads.map((download) => ({
|
|
1902
|
+
kind: download.kind,
|
|
1903
|
+
url: download.url ?? null,
|
|
1904
|
+
savedPath: download.savedPath ?? null,
|
|
1905
|
+
sizeBytes: typeof download.sizeBytes === "number" ? download.sizeBytes : null,
|
|
1906
|
+
mimeType: download.mimeType ?? null,
|
|
1907
|
+
error: download.error ?? null
|
|
1908
|
+
})),
|
|
1909
|
+
outputDir: typeof d.outputDir === "string" ? d.outputDir : null,
|
|
1910
|
+
warnings,
|
|
1911
|
+
limitations,
|
|
1912
|
+
transcript: transcript ? {
|
|
1913
|
+
wordCount: wordCount(transcriptText),
|
|
1914
|
+
chunkCount: chunks.length,
|
|
1915
|
+
durationMs: typeof transcript.durationMs === "number" ? transcript.durationMs : null,
|
|
1916
|
+
transcriptText,
|
|
1917
|
+
chunks: structuredTranscriptChunks(chunks)
|
|
1918
|
+
} : null
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1921
|
+
}
|
|
1706
1922
|
|
|
1707
1923
|
// src/mcp/mcp-tool-schemas.ts
|
|
1708
1924
|
var import_zod2 = require("zod");
|
|
@@ -1863,6 +2079,26 @@ var FacebookVideoTranscribeInputSchema = {
|
|
|
1863
2079
|
url: import_zod2.z.string().url().describe("Organic Facebook reel, video, watch, post, or share URL from facebook.com, m.facebook.com, or fb.watch. The tool renders the page, extracts the best matching public Facebook CDN MP4 URL, then transcribes it. Use this when the user pastes a normal Facebook video page URL and asks for the transcript or downloadable MP4."),
|
|
1864
2080
|
quality: import_zod2.z.enum(["best", "hd", "sd"]).default("best").describe("Preferred progressive MP4 quality. Use best by default; hd prefers the highest HD progressive URL; sd forces the SD URL.")
|
|
1865
2081
|
};
|
|
2082
|
+
var InstagramProfileContentInputSchema = {
|
|
2083
|
+
handle: import_zod2.z.string().min(1).optional().describe("Instagram handle, with or without @. Provide handle or url. Use only public profiles unless a configured browser profile is available server-side."),
|
|
2084
|
+
url: import_zod2.z.string().url().optional().describe("Instagram profile URL, e.g. https://www.instagram.com/nasaartemis/. Provide handle or url."),
|
|
2085
|
+
maxItems: import_zod2.z.number().int().min(1).max(500).default(50).describe("Maximum profile grid post/reel/tv URLs to collect. Default 50, maximum 500. Use higher values with an authenticated browser profile when the user asks for a fuller archive."),
|
|
2086
|
+
maxScrolls: import_zod2.z.number().int().min(0).max(100).default(10).describe("Maximum pagination scroll attempts. Default 10, maximum 100. Increase when using authenticated Chromium and the profile has a long history."),
|
|
2087
|
+
scrollDelayMs: import_zod2.z.number().int().min(250).max(5e3).default(1200).describe("Delay after each pagination scroll before collecting newly loaded links. Default 1200ms. Increase to 2000-3000ms when Instagram loads slowly."),
|
|
2088
|
+
stableScrollLimit: import_zod2.z.number().int().min(1).max(10).default(4).describe("Stop after this many consecutive scrolls with no new links or scroll progress. Default 4."),
|
|
2089
|
+
browserMode: import_zod2.z.enum(["auto", "hosted", "local"]).default("auto").describe("Browser backend. auto uses the hosted browser unless local mode is configured or browserProfile is passed. local uses an imported/authenticated Chrome profile from browser_profile_import/sync. hosted forces the remote browser path."),
|
|
2090
|
+
browserProfile: import_zod2.z.string().min(1).optional().describe("Managed local browser profile name created by browser_profile_import/sync. Passing this opts the Instagram tool into local authenticated Chromium for this call.")
|
|
2091
|
+
};
|
|
2092
|
+
var InstagramMediaDownloadInputSchema = {
|
|
2093
|
+
url: import_zod2.z.string().url().describe("Instagram post, reel, or tv URL, e.g. https://www.instagram.com/reel/SHORTCODE/. The tool renders the page, extracts text, image metadata, and Instagram CDN media tracks."),
|
|
2094
|
+
mediaTypes: import_zod2.z.array(import_zod2.z.enum(["image", "video", "audio"])).default(["image", "video", "audio"]).describe("Which media types to download when downloadMedia is true. Reels commonly expose separate video-only and audio-only MP4 tracks."),
|
|
2095
|
+
downloadMedia: import_zod2.z.boolean().default(true).describe("Download extracted text/media files to the MCP Scraper output directory when the API server can write files. Always returns extracted media URLs even when false."),
|
|
2096
|
+
downloadAllTracks: import_zod2.z.boolean().default(false).describe("Download every captured Instagram MP4 track instead of only the selected best video and audio tracks. Use false by default to avoid duplicate bitrates."),
|
|
2097
|
+
includeTranscript: import_zod2.z.boolean().default(false).describe("Transcribe the selected audio track when available. This adds transcription cost and may take longer."),
|
|
2098
|
+
mux: import_zod2.z.boolean().default(true).describe("When video and audio tracks are downloaded separately, try to mux them into a single MP4 if ffmpeg is available. Returns separate tracks when muxing is unavailable."),
|
|
2099
|
+
browserMode: import_zod2.z.enum(["auto", "hosted", "local"]).default("auto").describe("Browser backend. auto uses the hosted browser unless local mode is configured or browserProfile is passed. local uses an imported/authenticated Chrome profile from browser_profile_import/sync. hosted forces the remote browser path."),
|
|
2100
|
+
browserProfile: import_zod2.z.string().min(1).optional().describe("Managed local browser profile name created by browser_profile_import/sync. Passing this opts the Instagram tool into local authenticated Chromium for this call.")
|
|
2101
|
+
};
|
|
1866
2102
|
var MapsPlaceIntelInputSchema = {
|
|
1867
2103
|
businessName: import_zod2.z.string().min(1).describe('Business name only. If user says "Elite Roofing Denver CO", use businessName="Elite Roofing" and location="Denver, CO".'),
|
|
1868
2104
|
location: import_zod2.z.string().min(1).describe('City/region/country where the business should be searched, e.g. "Denver, CO". Infer from the user request when possible.'),
|
|
@@ -2259,6 +2495,101 @@ var TranscriptChunkOutput = import_zod2.z.object({
|
|
|
2259
2495
|
endSec: import_zod2.z.number(),
|
|
2260
2496
|
text: import_zod2.z.string()
|
|
2261
2497
|
});
|
|
2498
|
+
var InstagramBrowserOutput = import_zod2.z.object({
|
|
2499
|
+
mode: import_zod2.z.enum(["hosted", "local"]),
|
|
2500
|
+
requestedMode: import_zod2.z.enum(["auto", "hosted", "local"]),
|
|
2501
|
+
profileName: NullableString,
|
|
2502
|
+
profileSource: import_zod2.z.enum(["hosted", "managed_profile", "direct_profile_dir"]),
|
|
2503
|
+
profileDirConfigured: import_zod2.z.boolean(),
|
|
2504
|
+
executablePathConfigured: import_zod2.z.boolean()
|
|
2505
|
+
});
|
|
2506
|
+
var InstagramPaginationOutput = import_zod2.z.object({
|
|
2507
|
+
maxItems: import_zod2.z.number().int().min(1).max(500),
|
|
2508
|
+
maxScrolls: import_zod2.z.number().int().min(0).max(100),
|
|
2509
|
+
attemptedScrolls: import_zod2.z.number().int().min(0),
|
|
2510
|
+
stableScrolls: import_zod2.z.number().int().min(0),
|
|
2511
|
+
stableScrollLimit: import_zod2.z.number().int().min(1).max(10),
|
|
2512
|
+
scrollDelayMs: import_zod2.z.number().int().min(250).max(5e3),
|
|
2513
|
+
reachedMaxItems: import_zod2.z.boolean(),
|
|
2514
|
+
reachedReportedPostCount: import_zod2.z.boolean(),
|
|
2515
|
+
finalScrollHeight: import_zod2.z.number().int().nullable(),
|
|
2516
|
+
stoppedReason: import_zod2.z.enum(["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"]),
|
|
2517
|
+
stages: import_zod2.z.array(import_zod2.z.object({
|
|
2518
|
+
stage: import_zod2.z.string(),
|
|
2519
|
+
itemCount: import_zod2.z.number().int().min(0),
|
|
2520
|
+
addedCount: import_zod2.z.number().int().min(0),
|
|
2521
|
+
scrollY: import_zod2.z.number().nullable(),
|
|
2522
|
+
scrollHeight: import_zod2.z.number().nullable()
|
|
2523
|
+
}))
|
|
2524
|
+
});
|
|
2525
|
+
var InstagramProfileContentOutputSchema = {
|
|
2526
|
+
handle: import_zod2.z.string(),
|
|
2527
|
+
profileUrl: import_zod2.z.string().url(),
|
|
2528
|
+
pageUrl: import_zod2.z.string().url(),
|
|
2529
|
+
browser: InstagramBrowserOutput,
|
|
2530
|
+
profileName: NullableString,
|
|
2531
|
+
reportedPostCount: import_zod2.z.number().int().nullable(),
|
|
2532
|
+
reportedPostCountText: NullableString,
|
|
2533
|
+
followerCountText: NullableString,
|
|
2534
|
+
followingCountText: NullableString,
|
|
2535
|
+
collectedContentCount: import_zod2.z.number().int().min(0),
|
|
2536
|
+
typeCounts: import_zod2.z.object({
|
|
2537
|
+
post: import_zod2.z.number().int().min(0),
|
|
2538
|
+
reel: import_zod2.z.number().int().min(0),
|
|
2539
|
+
tv: import_zod2.z.number().int().min(0)
|
|
2540
|
+
}),
|
|
2541
|
+
pagination: InstagramPaginationOutput,
|
|
2542
|
+
limited: import_zod2.z.boolean(),
|
|
2543
|
+
limitations: import_zod2.z.array(import_zod2.z.string()),
|
|
2544
|
+
items: import_zod2.z.array(import_zod2.z.object({
|
|
2545
|
+
url: import_zod2.z.string().url(),
|
|
2546
|
+
type: import_zod2.z.enum(["post", "reel", "tv"]),
|
|
2547
|
+
shortcode: import_zod2.z.string(),
|
|
2548
|
+
anchorText: NullableString,
|
|
2549
|
+
firstSeenStage: import_zod2.z.string()
|
|
2550
|
+
}))
|
|
2551
|
+
};
|
|
2552
|
+
var InstagramMediaTrackOutput = import_zod2.z.object({
|
|
2553
|
+
url: import_zod2.z.string().url(),
|
|
2554
|
+
streamType: import_zod2.z.enum(["video", "audio", "unknown"]),
|
|
2555
|
+
bitrate: import_zod2.z.number().int().nullable(),
|
|
2556
|
+
durationSec: import_zod2.z.number().nullable(),
|
|
2557
|
+
vencodeTag: NullableString,
|
|
2558
|
+
width: import_zod2.z.number().int().nullable(),
|
|
2559
|
+
height: import_zod2.z.number().int().nullable()
|
|
2560
|
+
});
|
|
2561
|
+
var InstagramDownloadOutput = import_zod2.z.object({
|
|
2562
|
+
kind: import_zod2.z.enum(["text", "image", "video", "audio", "muxed_video"]),
|
|
2563
|
+
url: import_zod2.z.string().url().nullable(),
|
|
2564
|
+
savedPath: NullableString,
|
|
2565
|
+
sizeBytes: import_zod2.z.number().int().nullable(),
|
|
2566
|
+
mimeType: NullableString,
|
|
2567
|
+
error: NullableString
|
|
2568
|
+
});
|
|
2569
|
+
var InstagramMediaDownloadOutputSchema = {
|
|
2570
|
+
sourceUrl: import_zod2.z.string().url(),
|
|
2571
|
+
pageUrl: import_zod2.z.string().url(),
|
|
2572
|
+
browser: InstagramBrowserOutput,
|
|
2573
|
+
type: import_zod2.z.enum(["post", "reel", "tv"]).nullable(),
|
|
2574
|
+
shortcode: NullableString,
|
|
2575
|
+
ownerName: NullableString,
|
|
2576
|
+
caption: NullableString,
|
|
2577
|
+
imageUrl: import_zod2.z.string().url().nullable(),
|
|
2578
|
+
trackCount: import_zod2.z.number().int().min(0),
|
|
2579
|
+
selectedVideoTrack: InstagramMediaTrackOutput.nullable(),
|
|
2580
|
+
selectedAudioTrack: InstagramMediaTrackOutput.nullable(),
|
|
2581
|
+
downloads: import_zod2.z.array(InstagramDownloadOutput),
|
|
2582
|
+
outputDir: NullableString,
|
|
2583
|
+
warnings: import_zod2.z.array(import_zod2.z.string()),
|
|
2584
|
+
limitations: import_zod2.z.array(import_zod2.z.string()),
|
|
2585
|
+
transcript: import_zod2.z.object({
|
|
2586
|
+
wordCount: import_zod2.z.number().int().min(0),
|
|
2587
|
+
chunkCount: import_zod2.z.number().int().min(0),
|
|
2588
|
+
durationMs: import_zod2.z.number().nullable(),
|
|
2589
|
+
transcriptText: import_zod2.z.string(),
|
|
2590
|
+
chunks: import_zod2.z.array(TranscriptChunkOutput)
|
|
2591
|
+
}).nullable()
|
|
2592
|
+
};
|
|
2262
2593
|
var YoutubeTranscribeOutputSchema = {
|
|
2263
2594
|
videoId: NullableString,
|
|
2264
2595
|
url: NullableString,
|
|
@@ -2908,6 +3239,20 @@ function registerPaaExtractorMcpTools(server2, executor2, options = {}) {
|
|
|
2908
3239
|
outputSchema: FacebookVideoTranscribeOutputSchema,
|
|
2909
3240
|
annotations: liveWebToolAnnotations("Facebook Organic Video Transcription")
|
|
2910
3241
|
}, async (input) => formatFacebookVideoTranscribe(await executor2.facebookVideoTranscribe(input), input));
|
|
3242
|
+
server2.registerTool("instagram_profile_content", {
|
|
3243
|
+
title: "Instagram Profile Content Discovery",
|
|
3244
|
+
description: withReportNote("Discover Instagram profile grid content links for a handle or profile URL. Use this when the user wants a person or brand account content inventory before selecting posts/reels to download. Returns profile stats, collected post/reel/tv URLs, shortcodes, type counts, browser mode, pagination attempts, stop reason, and limitations. For authenticated collection, first use browser_profile_import/sync, then pass browserProfile and raise maxItems/maxScrolls for longer profile pagination."),
|
|
3245
|
+
inputSchema: InstagramProfileContentInputSchema,
|
|
3246
|
+
outputSchema: InstagramProfileContentOutputSchema,
|
|
3247
|
+
annotations: liveWebToolAnnotations("Instagram Profile Content Discovery")
|
|
3248
|
+
}, async (input) => formatInstagramProfileContent(await executor2.instagramProfileContent(input), input));
|
|
3249
|
+
server2.registerTool("instagram_media_download", {
|
|
3250
|
+
title: "Instagram Post/Reel Media Download",
|
|
3251
|
+
description: withReportNote("Extract and download media from one Instagram post, reel, or tv URL. Use after instagram_profile_content or when the user gives a specific Instagram URL and wants the image, caption/text, reel audio/video tracks, optional muxed MP4, or optional transcript. Reels commonly expose separate video-only and audio-only MP4 tracks; this tool selects the best video and audio tracks and attempts muxing when ffmpeg is available. Pass browserProfile from browser_profile_import/sync when the media is login-gated."),
|
|
3252
|
+
inputSchema: InstagramMediaDownloadInputSchema,
|
|
3253
|
+
outputSchema: InstagramMediaDownloadOutputSchema,
|
|
3254
|
+
annotations: liveWebToolAnnotations("Instagram Post/Reel Media Download")
|
|
3255
|
+
}, async (input) => formatInstagramMediaDownload(await executor2.instagramMediaDownload(input), input));
|
|
2911
3256
|
server2.registerTool("maps_place_intel", {
|
|
2912
3257
|
title: "Google Maps Business Profile Details",
|
|
2913
3258
|
description: withReportNote('Extract Google Maps business intelligence for one known/named business: rating, review count, category, address, phone, website, hours, booking URL, review histogram, review topics, about attributes, entity IDs, and optional review cards. Do not use this for category searches, local market prospect lists, or requests for multiple GMB/GBP profiles; use maps_search first for those. Split business name from location (e.g. "Elite Roofing Denver CO" => businessName "Elite Roofing", location "Denver, CO"). Pass includeReviews true when the user asks for reviews/customer pain.'),
|