mcp-scraper 0.3.0 → 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.
Files changed (52) hide show
  1. package/README.md +4 -1
  2. package/dist/bin/api-server.cjs +2047 -831
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +2 -2
  5. package/dist/bin/browser-agent-stdio-server.cjs +3 -3
  6. package/dist/bin/browser-agent-stdio-server.cjs.map +1 -1
  7. package/dist/bin/browser-agent-stdio-server.js +2 -2
  8. package/dist/bin/mcp-scraper-cli.cjs +1 -1
  9. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-cli.js +1 -1
  11. package/dist/bin/mcp-scraper-combined-stdio-server.cjs +350 -5
  12. package/dist/bin/mcp-scraper-combined-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-scraper-combined-stdio-server.js +4 -4
  14. package/dist/bin/mcp-scraper-install.cjs +3 -3
  15. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  16. package/dist/bin/mcp-scraper-install.js +2 -2
  17. package/dist/bin/mcp-stdio-server.cjs +346 -1
  18. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  19. package/dist/bin/mcp-stdio-server.js +2 -2
  20. package/dist/bin/paa-harvest.cjs +3 -1
  21. package/dist/bin/paa-harvest.cjs.map +1 -1
  22. package/dist/bin/paa-harvest.js +1 -1
  23. package/dist/{chunk-SXTXMFEQ.js → chunk-AZ5PKU4F.js} +34 -1
  24. package/dist/chunk-AZ5PKU4F.js.map +1 -0
  25. package/dist/{chunk-Q4STSM63.js → chunk-C3FGVJWH.js} +3 -3
  26. package/dist/chunk-C3FGVJWH.js.map +1 -0
  27. package/dist/{chunk-DH4H3F6S.js → chunk-HRTCMLZB.js} +4 -4
  28. package/dist/chunk-HRTCMLZB.js.map +1 -0
  29. package/dist/{chunk-SIXJ6EVS.js → chunk-KO223PSJ.js} +347 -2
  30. package/dist/chunk-KO223PSJ.js.map +1 -0
  31. package/dist/{chunk-IPW4LFOT.js → chunk-UWSG3C5J.js} +4 -2
  32. package/dist/chunk-UWSG3C5J.js.map +1 -0
  33. package/dist/chunk-VB65G7PS.js +7 -0
  34. package/dist/chunk-VB65G7PS.js.map +1 -0
  35. package/dist/index.cjs +3 -1
  36. package/dist/index.cjs.map +1 -1
  37. package/dist/index.js +1 -1
  38. package/dist/{server-MOP7NIUK.js → server-N5LM3PEO.js} +997 -253
  39. package/dist/server-N5LM3PEO.js.map +1 -0
  40. package/dist/{worker-SLQ375UG.js → worker-56IXWOQU.js} +3 -3
  41. package/docs/mcp-tool-craft-lint.generated.md +5 -2
  42. package/docs/mcp-tool-manifest.generated.json +85 -9
  43. package/package.json +1 -1
  44. package/dist/chunk-DH4H3F6S.js.map +0 -1
  45. package/dist/chunk-IPW4LFOT.js.map +0 -1
  46. package/dist/chunk-PGWJ2EJ3.js +0 -7
  47. package/dist/chunk-PGWJ2EJ3.js.map +0 -1
  48. package/dist/chunk-Q4STSM63.js.map +0 -1
  49. package/dist/chunk-SIXJ6EVS.js.map +0 -1
  50. package/dist/chunk-SXTXMFEQ.js.map +0 -1
  51. package/dist/server-MOP7NIUK.js.map +0 -1
  52. /package/dist/{worker-SLQ375UG.js.map → worker-56IXWOQU.js.map} +0 -0
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-LFATOGDF.js";
8
8
  import {
9
9
  PACKAGE_VERSION
10
- } from "./chunk-PGWJ2EJ3.js";
10
+ } from "./chunk-VB65G7PS.js";
11
11
 
12
12
  // src/harvest-timeout.ts
13
13
  var VERCEL_FUNCTION_MAX_MS = 3e5;
@@ -1478,6 +1478,216 @@ ${chunkRows}` : "",
1478
1478
  }
1479
1479
  };
1480
1480
  }
1481
+ function structuredInstagramBrowser(raw) {
1482
+ const browser = raw && typeof raw === "object" ? raw : {};
1483
+ const mode = browser.mode === "local" ? "local" : "hosted";
1484
+ const requestedMode = browser.requestedMode === "local" || browser.requestedMode === "hosted" || browser.requestedMode === "auto" ? browser.requestedMode : "auto";
1485
+ const profileSource = browser.profileSource === "managed_profile" || browser.profileSource === "direct_profile_dir" ? browser.profileSource : "hosted";
1486
+ return {
1487
+ mode,
1488
+ requestedMode,
1489
+ profileName: typeof browser.profileName === "string" ? browser.profileName : null,
1490
+ profileSource,
1491
+ profileDirConfigured: browser.profileDirConfigured === true,
1492
+ executablePathConfigured: browser.executablePathConfigured === true
1493
+ };
1494
+ }
1495
+ function structuredInstagramPagination(raw, input) {
1496
+ const pagination = raw && typeof raw === "object" ? raw : {};
1497
+ const stages = Array.isArray(pagination.stages) ? pagination.stages : [];
1498
+ const stoppedReason = typeof pagination.stoppedReason === "string" && ["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"].includes(pagination.stoppedReason) ? pagination.stoppedReason : "no_scrolls";
1499
+ return {
1500
+ maxItems: typeof pagination.maxItems === "number" ? pagination.maxItems : Number(input.maxItems ?? 50),
1501
+ maxScrolls: typeof pagination.maxScrolls === "number" ? pagination.maxScrolls : Number(input.maxScrolls ?? 10),
1502
+ attemptedScrolls: typeof pagination.attemptedScrolls === "number" ? pagination.attemptedScrolls : 0,
1503
+ stableScrolls: typeof pagination.stableScrolls === "number" ? pagination.stableScrolls : 0,
1504
+ stableScrollLimit: typeof pagination.stableScrollLimit === "number" ? pagination.stableScrollLimit : Number(input.stableScrollLimit ?? 4),
1505
+ scrollDelayMs: typeof pagination.scrollDelayMs === "number" ? pagination.scrollDelayMs : Number(input.scrollDelayMs ?? 1200),
1506
+ reachedMaxItems: pagination.reachedMaxItems === true,
1507
+ reachedReportedPostCount: pagination.reachedReportedPostCount === true,
1508
+ finalScrollHeight: typeof pagination.finalScrollHeight === "number" ? pagination.finalScrollHeight : null,
1509
+ stoppedReason,
1510
+ stages: stages.map((stage) => {
1511
+ const row = stage && typeof stage === "object" ? stage : {};
1512
+ return {
1513
+ stage: String(row.stage ?? ""),
1514
+ itemCount: typeof row.itemCount === "number" ? row.itemCount : 0,
1515
+ addedCount: typeof row.addedCount === "number" ? row.addedCount : 0,
1516
+ scrollY: typeof row.scrollY === "number" ? row.scrollY : null,
1517
+ scrollHeight: typeof row.scrollHeight === "number" ? row.scrollHeight : null
1518
+ };
1519
+ })
1520
+ };
1521
+ }
1522
+ function formatInstagramProfileContent(raw, input) {
1523
+ const parsed = parseData(raw);
1524
+ if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
1525
+ const d = parsed.data;
1526
+ const items = Array.isArray(d.items) ? d.items : [];
1527
+ const typeCounts = d.typeCounts;
1528
+ const limitations = Array.isArray(d.limitations) ? d.limitations.map(String) : [];
1529
+ const browser = structuredInstagramBrowser(d.browser);
1530
+ const pagination = structuredInstagramPagination(d.pagination, input);
1531
+ const itemRows = items.slice(0, 100).map(
1532
+ (item, i) => `| ${i + 1} | ${item.type} | \`${item.shortcode}\` | ${item.url} | ${cell(item.firstSeenStage ?? "")} |`
1533
+ ).join("\n");
1534
+ const browserLabel = browser.mode === "local" ? `local profile ${browser.profileName ? `\`${browser.profileName}\`` : "(unnamed)"}` : "hosted browser";
1535
+ const full = [
1536
+ `# Instagram Profile Content: ${d.handle ?? input.handle ?? input.url ?? "profile"}`,
1537
+ `**Collected:** ${items.length} items \xB7 posts ${typeCounts?.post ?? 0} \xB7 reels ${typeCounts?.reel ?? 0} \xB7 tv ${typeCounts?.tv ?? 0}`,
1538
+ `**Browser:** ${browserLabel}`,
1539
+ `**Pagination:** ${pagination.attemptedScrolls} scrolls \xB7 stopped: ${pagination.stoppedReason}`,
1540
+ d.reportedPostCountText ? `**Profile count:** ${d.reportedPostCountText}` : "",
1541
+ d.followerCountText ? `**Followers:** ${d.followerCountText}` : "",
1542
+ `
1543
+ ## Content Links
1544
+ | # | Type | Shortcode | URL | First Seen |
1545
+ |---|------|-----------|-----|------------|
1546
+ ${itemRows || "| \u2014 | \u2014 | \u2014 | \u2014 | \u2014 |"}`,
1547
+ limitations.length ? `
1548
+ ## Limits
1549
+ ${limitations.map((l) => `- ${l}`).join("\n")}` : "",
1550
+ `
1551
+ ---
1552
+ \u{1F4A1} Use \`instagram_media_download\` with one of these URLs to download text, image, reel tracks, and optional transcript.`
1553
+ ].filter(Boolean).join("\n");
1554
+ return {
1555
+ ...oneBlock(full),
1556
+ structuredContent: {
1557
+ handle: String(d.handle ?? input.handle ?? ""),
1558
+ profileUrl: String(d.profileUrl ?? input.url ?? ""),
1559
+ pageUrl: String(d.pageUrl ?? d.profileUrl ?? input.url ?? ""),
1560
+ browser,
1561
+ profileName: typeof d.profileName === "string" ? d.profileName : null,
1562
+ reportedPostCount: typeof d.reportedPostCount === "number" ? d.reportedPostCount : null,
1563
+ reportedPostCountText: typeof d.reportedPostCountText === "string" ? d.reportedPostCountText : null,
1564
+ followerCountText: typeof d.followerCountText === "string" ? d.followerCountText : null,
1565
+ followingCountText: typeof d.followingCountText === "string" ? d.followingCountText : null,
1566
+ collectedContentCount: items.length,
1567
+ typeCounts: {
1568
+ post: Number(typeCounts?.post ?? 0),
1569
+ reel: Number(typeCounts?.reel ?? 0),
1570
+ tv: Number(typeCounts?.tv ?? 0)
1571
+ },
1572
+ pagination,
1573
+ limited: d.limited === true,
1574
+ limitations,
1575
+ items: items.map((item) => ({
1576
+ url: String(item.url ?? ""),
1577
+ type: item.type,
1578
+ shortcode: String(item.shortcode ?? ""),
1579
+ anchorText: item.anchorText ?? null,
1580
+ firstSeenStage: String(item.firstSeenStage ?? "")
1581
+ }))
1582
+ }
1583
+ };
1584
+ }
1585
+ function structuredInstagramTrack(track) {
1586
+ if (!track) return null;
1587
+ return {
1588
+ url: String(track.url ?? ""),
1589
+ streamType: track.streamType ?? "unknown",
1590
+ bitrate: typeof track.bitrate === "number" ? track.bitrate : null,
1591
+ durationSec: typeof track.durationSec === "number" ? track.durationSec : null,
1592
+ vencodeTag: track.vencodeTag ?? null,
1593
+ width: typeof track.width === "number" ? track.width : null,
1594
+ height: typeof track.height === "number" ? track.height : null
1595
+ };
1596
+ }
1597
+ function formatInstagramMediaDownload(raw, input) {
1598
+ const parsed = parseData(raw);
1599
+ if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
1600
+ const d = parsed.data;
1601
+ const tracks = Array.isArray(d.tracks) ? d.tracks : [];
1602
+ const downloads = Array.isArray(d.downloads) ? d.downloads : [];
1603
+ const warnings = Array.isArray(d.warnings) ? d.warnings.map(String) : [];
1604
+ const limitations = Array.isArray(d.limitations) ? d.limitations.map(String) : [];
1605
+ const transcript = d.transcript;
1606
+ const transcriptText = transcript?.text ?? "";
1607
+ const chunks = transcript?.chunks ?? [];
1608
+ const browser = structuredInstagramBrowser(d.browser);
1609
+ const browserLabel = browser.mode === "local" ? `local profile ${browser.profileName ? `\`${browser.profileName}\`` : "(unnamed)"}` : "hosted browser";
1610
+ const downloadRows = downloads.map((download, i) => {
1611
+ const status = download.error ? `error: ${cell(download.error)}` : `${download.sizeBytes ?? 0} bytes`;
1612
+ return `| ${i + 1} | ${download.kind} | ${download.savedPath ? `\`${download.savedPath}\`` : "\u2014"} | ${status} |`;
1613
+ }).join("\n");
1614
+ const trackRows = tracks.slice(0, 20).map(
1615
+ (track, i) => `| ${i + 1} | ${track.streamType} | ${track.bitrate ?? "\u2014"} | ${track.durationSec ?? "\u2014"} | ${cell(track.vencodeTag ?? "")} |`
1616
+ ).join("\n");
1617
+ const full = [
1618
+ `# Instagram Media Download`,
1619
+ `**URL:** ${d.pageUrl ?? input.url}`,
1620
+ `**Browser:** ${browserLabel}`,
1621
+ d.ownerName ? `**Owner:** ${d.ownerName}` : "",
1622
+ d.shortcode ? `**Shortcode:** \`${d.shortcode}\`` : "",
1623
+ d.caption ? `
1624
+ ## Caption
1625
+ ${truncate(String(d.caption), 1200)}` : "",
1626
+ d.imageUrl ? `
1627
+ ## Image
1628
+ ${d.imageUrl}` : "",
1629
+ tracks.length ? `
1630
+ ## Media Tracks
1631
+ | # | Type | Bitrate | Duration | Tag |
1632
+ |---|------|---------|----------|-----|
1633
+ ${trackRows}` : "\n## Media Tracks\n*None captured.*",
1634
+ downloads.length ? `
1635
+ ## Downloads
1636
+ | # | Kind | File | Status |
1637
+ |---|------|------|--------|
1638
+ ${downloadRows}` : "",
1639
+ d.outputDir ? `
1640
+ **Output directory:** \`${d.outputDir}\`` : "",
1641
+ transcript ? `
1642
+ ## Transcript
1643
+ **${wordCount(transcriptText)} words** \xB7 ${chunks.length} chunks
1644
+
1645
+ ${transcriptText}` : "",
1646
+ warnings.length ? `
1647
+ ## Warnings
1648
+ ${warnings.map((w) => `- ${w}`).join("\n")}` : "",
1649
+ limitations.length ? `
1650
+ ## Limits
1651
+ ${limitations.map((l) => `- ${l}`).join("\n")}` : "",
1652
+ `
1653
+ ---
1654
+ \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.`
1655
+ ].filter(Boolean).join("\n");
1656
+ return {
1657
+ ...oneBlock(full),
1658
+ structuredContent: {
1659
+ sourceUrl: String(d.sourceUrl ?? input.url),
1660
+ pageUrl: String(d.pageUrl ?? input.url),
1661
+ browser,
1662
+ type: d.type === "post" || d.type === "reel" || d.type === "tv" ? d.type : null,
1663
+ shortcode: typeof d.shortcode === "string" ? d.shortcode : null,
1664
+ ownerName: typeof d.ownerName === "string" ? d.ownerName : null,
1665
+ caption: typeof d.caption === "string" ? d.caption : null,
1666
+ imageUrl: typeof d.imageUrl === "string" ? d.imageUrl : null,
1667
+ trackCount: tracks.length,
1668
+ selectedVideoTrack: structuredInstagramTrack(d.selectedVideoTrack),
1669
+ selectedAudioTrack: structuredInstagramTrack(d.selectedAudioTrack),
1670
+ downloads: downloads.map((download) => ({
1671
+ kind: download.kind,
1672
+ url: download.url ?? null,
1673
+ savedPath: download.savedPath ?? null,
1674
+ sizeBytes: typeof download.sizeBytes === "number" ? download.sizeBytes : null,
1675
+ mimeType: download.mimeType ?? null,
1676
+ error: download.error ?? null
1677
+ })),
1678
+ outputDir: typeof d.outputDir === "string" ? d.outputDir : null,
1679
+ warnings,
1680
+ limitations,
1681
+ transcript: transcript ? {
1682
+ wordCount: wordCount(transcriptText),
1683
+ chunkCount: chunks.length,
1684
+ durationMs: typeof transcript.durationMs === "number" ? transcript.durationMs : null,
1685
+ transcriptText,
1686
+ chunks: structuredTranscriptChunks(chunks)
1687
+ } : null
1688
+ }
1689
+ };
1690
+ }
1481
1691
  function formatCaptureSerpSnapshot(raw, input) {
1482
1692
  const parsed = parseData(raw);
1483
1693
  if ("error" in parsed) return { content: [{ type: "text", text: parsed.error }], isError: true };
@@ -1628,6 +1838,26 @@ var FacebookVideoTranscribeInputSchema = {
1628
1838
  url: 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."),
1629
1839
  quality: 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.")
1630
1840
  };
1841
+ var InstagramProfileContentInputSchema = {
1842
+ handle: 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."),
1843
+ url: z.string().url().optional().describe("Instagram profile URL, e.g. https://www.instagram.com/nasaartemis/. Provide handle or url."),
1844
+ maxItems: 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."),
1845
+ maxScrolls: 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."),
1846
+ scrollDelayMs: 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."),
1847
+ stableScrollLimit: 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."),
1848
+ browserMode: 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."),
1849
+ browserProfile: 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.")
1850
+ };
1851
+ var InstagramMediaDownloadInputSchema = {
1852
+ url: 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."),
1853
+ mediaTypes: z.array(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."),
1854
+ downloadMedia: 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."),
1855
+ downloadAllTracks: 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."),
1856
+ includeTranscript: z.boolean().default(false).describe("Transcribe the selected audio track when available. This adds transcription cost and may take longer."),
1857
+ mux: 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."),
1858
+ browserMode: 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."),
1859
+ browserProfile: 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.")
1860
+ };
1631
1861
  var MapsPlaceIntelInputSchema = {
1632
1862
  businessName: z.string().min(1).describe('Business name only. If user says "Elite Roofing Denver CO", use businessName="Elite Roofing" and location="Denver, CO".'),
1633
1863
  location: 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.'),
@@ -2024,6 +2254,101 @@ var TranscriptChunkOutput = z.object({
2024
2254
  endSec: z.number(),
2025
2255
  text: z.string()
2026
2256
  });
2257
+ var InstagramBrowserOutput = z.object({
2258
+ mode: z.enum(["hosted", "local"]),
2259
+ requestedMode: z.enum(["auto", "hosted", "local"]),
2260
+ profileName: NullableString,
2261
+ profileSource: z.enum(["hosted", "managed_profile", "direct_profile_dir"]),
2262
+ profileDirConfigured: z.boolean(),
2263
+ executablePathConfigured: z.boolean()
2264
+ });
2265
+ var InstagramPaginationOutput = z.object({
2266
+ maxItems: z.number().int().min(1).max(500),
2267
+ maxScrolls: z.number().int().min(0).max(100),
2268
+ attemptedScrolls: z.number().int().min(0),
2269
+ stableScrolls: z.number().int().min(0),
2270
+ stableScrollLimit: z.number().int().min(1).max(10),
2271
+ scrollDelayMs: z.number().int().min(250).max(5e3),
2272
+ reachedMaxItems: z.boolean(),
2273
+ reachedReportedPostCount: z.boolean(),
2274
+ finalScrollHeight: z.number().int().nullable(),
2275
+ stoppedReason: z.enum(["max_items", "reported_post_count", "stable_scrolls", "max_scrolls", "no_scrolls"]),
2276
+ stages: z.array(z.object({
2277
+ stage: z.string(),
2278
+ itemCount: z.number().int().min(0),
2279
+ addedCount: z.number().int().min(0),
2280
+ scrollY: z.number().nullable(),
2281
+ scrollHeight: z.number().nullable()
2282
+ }))
2283
+ });
2284
+ var InstagramProfileContentOutputSchema = {
2285
+ handle: z.string(),
2286
+ profileUrl: z.string().url(),
2287
+ pageUrl: z.string().url(),
2288
+ browser: InstagramBrowserOutput,
2289
+ profileName: NullableString,
2290
+ reportedPostCount: z.number().int().nullable(),
2291
+ reportedPostCountText: NullableString,
2292
+ followerCountText: NullableString,
2293
+ followingCountText: NullableString,
2294
+ collectedContentCount: z.number().int().min(0),
2295
+ typeCounts: z.object({
2296
+ post: z.number().int().min(0),
2297
+ reel: z.number().int().min(0),
2298
+ tv: z.number().int().min(0)
2299
+ }),
2300
+ pagination: InstagramPaginationOutput,
2301
+ limited: z.boolean(),
2302
+ limitations: z.array(z.string()),
2303
+ items: z.array(z.object({
2304
+ url: z.string().url(),
2305
+ type: z.enum(["post", "reel", "tv"]),
2306
+ shortcode: z.string(),
2307
+ anchorText: NullableString,
2308
+ firstSeenStage: z.string()
2309
+ }))
2310
+ };
2311
+ var InstagramMediaTrackOutput = z.object({
2312
+ url: z.string().url(),
2313
+ streamType: z.enum(["video", "audio", "unknown"]),
2314
+ bitrate: z.number().int().nullable(),
2315
+ durationSec: z.number().nullable(),
2316
+ vencodeTag: NullableString,
2317
+ width: z.number().int().nullable(),
2318
+ height: z.number().int().nullable()
2319
+ });
2320
+ var InstagramDownloadOutput = z.object({
2321
+ kind: z.enum(["text", "image", "video", "audio", "muxed_video"]),
2322
+ url: z.string().url().nullable(),
2323
+ savedPath: NullableString,
2324
+ sizeBytes: z.number().int().nullable(),
2325
+ mimeType: NullableString,
2326
+ error: NullableString
2327
+ });
2328
+ var InstagramMediaDownloadOutputSchema = {
2329
+ sourceUrl: z.string().url(),
2330
+ pageUrl: z.string().url(),
2331
+ browser: InstagramBrowserOutput,
2332
+ type: z.enum(["post", "reel", "tv"]).nullable(),
2333
+ shortcode: NullableString,
2334
+ ownerName: NullableString,
2335
+ caption: NullableString,
2336
+ imageUrl: z.string().url().nullable(),
2337
+ trackCount: z.number().int().min(0),
2338
+ selectedVideoTrack: InstagramMediaTrackOutput.nullable(),
2339
+ selectedAudioTrack: InstagramMediaTrackOutput.nullable(),
2340
+ downloads: z.array(InstagramDownloadOutput),
2341
+ outputDir: NullableString,
2342
+ warnings: z.array(z.string()),
2343
+ limitations: z.array(z.string()),
2344
+ transcript: z.object({
2345
+ wordCount: z.number().int().min(0),
2346
+ chunkCount: z.number().int().min(0),
2347
+ durationMs: z.number().nullable(),
2348
+ transcriptText: z.string(),
2349
+ chunks: z.array(TranscriptChunkOutput)
2350
+ }).nullable()
2351
+ };
2027
2352
  var YoutubeTranscribeOutputSchema = {
2028
2353
  videoId: NullableString,
2029
2354
  url: NullableString,
@@ -2673,6 +2998,20 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
2673
2998
  outputSchema: FacebookVideoTranscribeOutputSchema,
2674
2999
  annotations: liveWebToolAnnotations("Facebook Organic Video Transcription")
2675
3000
  }, async (input) => formatFacebookVideoTranscribe(await executor.facebookVideoTranscribe(input), input));
3001
+ server.registerTool("instagram_profile_content", {
3002
+ title: "Instagram Profile Content Discovery",
3003
+ 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."),
3004
+ inputSchema: InstagramProfileContentInputSchema,
3005
+ outputSchema: InstagramProfileContentOutputSchema,
3006
+ annotations: liveWebToolAnnotations("Instagram Profile Content Discovery")
3007
+ }, async (input) => formatInstagramProfileContent(await executor.instagramProfileContent(input), input));
3008
+ server.registerTool("instagram_media_download", {
3009
+ title: "Instagram Post/Reel Media Download",
3010
+ 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."),
3011
+ inputSchema: InstagramMediaDownloadInputSchema,
3012
+ outputSchema: InstagramMediaDownloadOutputSchema,
3013
+ annotations: liveWebToolAnnotations("Instagram Post/Reel Media Download")
3014
+ }, async (input) => formatInstagramMediaDownload(await executor.instagramMediaDownload(input), input));
2676
3015
  server.registerTool("maps_place_intel", {
2677
3016
  title: "Google Maps Business Profile Details",
2678
3017
  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.'),
@@ -2933,6 +3272,12 @@ var HttpMcpToolExecutor = class {
2933
3272
  facebookVideoTranscribe(input) {
2934
3273
  return this.call("/facebook/video-transcribe", input, this.httpTimeoutOverrideMs ?? 24e4);
2935
3274
  }
3275
+ instagramProfileContent(input) {
3276
+ return this.call("/instagram/profile-content", input, this.httpTimeoutOverrideMs ?? 24e4);
3277
+ }
3278
+ instagramMediaDownload(input) {
3279
+ return this.call("/instagram/media-download", input, this.httpTimeoutOverrideMs ?? 3e5);
3280
+ }
2936
3281
  mapsPlaceIntel(input) {
2937
3282
  return this.call("/maps/place", input);
2938
3283
  }
@@ -2995,4 +3340,4 @@ export {
2995
3340
  registerPaaExtractorMcpTools,
2996
3341
  HttpMcpToolExecutor
2997
3342
  };
2998
- //# sourceMappingURL=chunk-SIXJ6EVS.js.map
3343
+ //# sourceMappingURL=chunk-KO223PSJ.js.map