mcp-scraper 0.3.9 → 0.3.10

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 (36) hide show
  1. package/README.md +4 -3
  2. package/dist/bin/api-server.cjs +109 -1
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +1 -1
  5. package/dist/bin/browser-agent-stdio-server.cjs +97 -25
  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 +103 -31
  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 +7 -7
  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 +1 -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/{chunk-KDKQ5Y7V.js → chunk-CED7X4WB.js} +2 -2
  21. package/dist/{chunk-ELI6NDEG.js → chunk-KPXMPAJ3.js} +7 -7
  22. package/dist/chunk-KPXMPAJ3.js.map +1 -0
  23. package/dist/chunk-NEGW2ZEJ.js +7 -0
  24. package/dist/chunk-NEGW2ZEJ.js.map +1 -0
  25. package/dist/{chunk-BRUVQRJK.js → chunk-QPFF3V2R.js} +98 -26
  26. package/dist/chunk-QPFF3V2R.js.map +1 -0
  27. package/dist/{server-ZSHE4R5Z.js → server-QTV2EUKA.js} +111 -3
  28. package/dist/{server-ZSHE4R5Z.js.map → server-QTV2EUKA.js.map} +1 -1
  29. package/docs/mcp-tool-craft-lint.generated.md +3 -2
  30. package/docs/mcp-tool-manifest.generated.json +43 -13
  31. package/package.json +1 -1
  32. package/dist/chunk-7VNTN4Q7.js +0 -7
  33. package/dist/chunk-7VNTN4Q7.js.map +0 -1
  34. package/dist/chunk-BRUVQRJK.js.map +0 -1
  35. package/dist/chunk-ELI6NDEG.js.map +0 -1
  36. /package/dist/{chunk-KDKQ5Y7V.js.map → chunk-CED7X4WB.js.map} +0 -0
@@ -10,7 +10,7 @@ import {
10
10
  import "../chunk-LFATOGDF.js";
11
11
  import {
12
12
  PACKAGE_VERSION
13
- } from "../chunk-7VNTN4Q7.js";
13
+ } from "../chunk-NEGW2ZEJ.js";
14
14
 
15
15
  // src/cli/human-cli.ts
16
16
  import { Command } from "commander";
@@ -270,7 +270,7 @@ function browserServiceProfileSaveChanges() {
270
270
  }
271
271
 
272
272
  // src/version.ts
273
- var PACKAGE_VERSION = "0.3.9";
273
+ var PACKAGE_VERSION = "0.3.10";
274
274
 
275
275
  // src/mcp/browser-agent-tool-schemas.ts
276
276
  var import_zod = require("zod");
@@ -296,10 +296,17 @@ var BrowserOpenInputSchema = {
296
296
  var BrowserProfileOnboardInputSchema = {
297
297
  email: import_zod.z.string().optional().describe("Optional account email used to derive a stable MCP Scraper profile name. This does not import cookies or browser state."),
298
298
  profile: import_zod.z.string().optional().describe("Optional saved MCP Scraper hosted browser profile name to create or load. If omitted, email is used to derive one."),
299
- url: import_zod.z.string().url().optional().describe("Setup URL to open after creating the direct no-proxy browser. Defaults to https://google.com/ so the user can click Sign in."),
299
+ domain: import_zod.z.string().optional().describe("Authenticated site domain to connect to the profile. Defaults to chatgpt.com for AI visibility fan-out tracking."),
300
+ login_url: import_zod.z.string().url().optional().describe("Optional login URL for the target domain. Defaults to https://chatgpt.com/ when domain is omitted."),
301
+ url: import_zod.z.string().url().optional().describe("Deprecated alias for login_url. Use login_url for the target site login page."),
300
302
  label: import_zod.z.string().optional().describe("Optional human label for this setup session."),
301
303
  timeout_seconds: import_zod.z.number().int().min(60).max(259200).optional().describe("How long the direct no-proxy setup session may live before auto-termination. Defaults to 600.")
302
304
  };
305
+ var BrowserProfileStatusInputSchema = {
306
+ connection_id: import_zod.z.string().optional().describe("Auth connection id returned by browser_profile_onboard. Prefer this when available."),
307
+ profile: import_zod.z.string().optional().describe("Saved hosted profile name to check when connection_id is unavailable."),
308
+ domain: import_zod.z.string().optional().describe("Authenticated site domain to check with profile. Defaults to chatgpt.com when omitted.")
309
+ };
303
310
  var BrowserSessionInputSchema = {
304
311
  session_id: import_zod.z.string().describe("The session id returned by browser_open or browser_list_sessions. Use only a returned session_id; do not construct one yourself.")
305
312
  };
@@ -471,15 +478,36 @@ var BrowserOpenOutputSchema = {
471
478
  var BrowserProfileOnboardOutputSchema = {
472
479
  ok: import_zod.z.boolean(),
473
480
  tool: import_zod.z.literal("browser_profile_onboard"),
474
- session_id: import_zod.z.string(),
481
+ session_id: NullableString,
482
+ auth_connection_id: import_zod.z.string(),
475
483
  watch_url: import_zod.z.string(),
476
484
  live_view_url: NullableString,
477
485
  profile: import_zod.z.string(),
486
+ domain: import_zod.z.string(),
478
487
  setup_url: import_zod.z.string(),
479
488
  account_email: NullableString,
489
+ status: import_zod.z.string(),
490
+ flow_status: NullableString,
491
+ flow_step: NullableString,
492
+ flow_expires_at: NullableString,
493
+ post_login_url: NullableString,
480
494
  next_steps: import_zod.z.array(import_zod.z.string()),
481
495
  raw: BrowserRawObject.optional()
482
496
  };
497
+ var BrowserProfileStatusOutputSchema = {
498
+ ok: import_zod.z.boolean(),
499
+ tool: import_zod.z.literal("browser_profile_status"),
500
+ session_id: NullableString,
501
+ auth_connection_id: import_zod.z.string(),
502
+ profile: import_zod.z.string(),
503
+ domain: import_zod.z.string(),
504
+ status: import_zod.z.string(),
505
+ flow_status: NullableString,
506
+ flow_step: NullableString,
507
+ flow_expires_at: NullableString,
508
+ post_login_url: NullableString,
509
+ raw: BrowserRawObject.optional()
510
+ };
483
511
  var BrowserScreenshotOutputSchema = {
484
512
  ...BrowserBaseOutput,
485
513
  tool: import_zod.z.literal("browser_screenshot"),
@@ -886,10 +914,16 @@ function replayFilePath(sessionId, replayId, filename) {
886
914
  const name = requested ? safeFilePart(requested).replace(/\.mp4$/i, "") : `${stamp}-${safeFilePart(sessionId)}-${safeFilePart(replayId)}`;
887
915
  return (0, import_node_path2.join)(outputBaseDir(), "browser-replays", `${name}.mp4`);
888
916
  }
889
- function savedProfileNameFromEmail(email) {
890
- const value = email?.trim().toLowerCase();
917
+ function slugPart(value) {
918
+ const trimmed = value?.trim().toLowerCase();
919
+ if (!trimmed) return null;
920
+ return trimmed.replace(/^https?:\/\//, "").replace(/^www\./, "").replace(/\/.*$/, "").replace(/[^a-z0-9._-]+/g, "-").replace(/[._-]+/g, "-").replace(/^-+|-+$/g, "");
921
+ }
922
+ function savedProfileNameFromEmail(email, domain) {
923
+ const value = slugPart(email);
891
924
  if (!value) return null;
892
- return value.replace(/[^a-z0-9._-]+/g, "-").replace(/[._-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || null;
925
+ const domainPart = slugPart(domain);
926
+ return `${value}${domainPart ? `-${domainPart}` : ""}`.slice(0, 80) || null;
893
927
  }
894
928
  function annotatedReplayFilePath(sessionId, replayId, filename) {
895
929
  const requested = filename?.trim();
@@ -975,45 +1009,83 @@ function registerBrowserAgentMcpTools(server2, opts) {
975
1009
  "browser_profile_onboard",
976
1010
  {
977
1011
  title: "Connect Hosted Browser Profile",
978
- description: "Create or load a saved MCP Scraper hosted browser profile and open a direct no-proxy setup browser with profile saving enabled. This is the customer auth setup and reconnect flow: open Google, give the user the watch_url, have them click Sign in and complete login, then call browser_close to save cookies and storage. If a saved profile later shows login controls, run this same setup flow again.",
1012
+ description: "Create or load a saved MCP Scraper hosted browser profile auth connection and return a user takeover login URL. This is the customer auth setup and reconnect flow for AI visibility tracking: give the user the watch_url, let them complete login for the target domain, then call browser_profile_status until status is AUTHENTICATED. If a saved profile later shows login controls, run this same setup flow again.",
979
1013
  inputSchema: BrowserProfileOnboardInputSchema,
980
1014
  outputSchema: BrowserProfileOnboardOutputSchema,
981
1015
  annotations: annotations("Connect Hosted Browser Profile")
982
1016
  },
983
1017
  async (input) => {
984
- const profile = input.profile?.trim() || savedProfileNameFromEmail(input.email) || browserServiceProfileName();
1018
+ const domain = slugPart(input.domain) || "chatgpt.com";
1019
+ const setupUrl = input.login_url ?? input.url ?? (domain === "chatgpt.com" ? "https://chatgpt.com/" : `https://${domain}/`);
1020
+ const profile = input.profile?.trim() || savedProfileNameFromEmail(input.email, domain) || browserServiceProfileName();
985
1021
  if (!profile) {
986
1022
  return errorResult("browser_profile_onboard", {
987
1023
  error: "profile or email is required when BROWSER_AGENT_PROFILE_NAME is not available"
988
1024
  });
989
1025
  }
990
- const setupUrl = input.url ?? "https://google.com/";
991
- const open = await req("POST", "/agent/sessions", {
1026
+ const open = await req("POST", "/agent/profiles/onboard", {
992
1027
  label: input.label ?? `Profile setup: ${profile}`,
993
1028
  profile,
994
- save_profile_changes: true,
995
- disable_default_proxy: true,
996
- timeout_seconds: input.timeout_seconds,
997
- url: setupUrl
1029
+ domain,
1030
+ login_url: setupUrl
998
1031
  });
999
1032
  if (!open.ok) return errorResult("browser_profile_onboard", open.data);
1000
- const session = open.data;
1001
1033
  return structuredResult({
1002
1034
  ok: true,
1003
1035
  tool: "browser_profile_onboard",
1004
- session_id: session.session_id,
1005
- watch_url: `${consoleBase}/console/${session.session_id}`,
1006
- live_view_url: session.live_view_url ?? null,
1036
+ session_id: null,
1037
+ auth_connection_id: open.data.connection_id,
1038
+ watch_url: open.data.hosted_url,
1039
+ live_view_url: open.data.live_view_url ?? null,
1007
1040
  profile,
1041
+ domain,
1008
1042
  setup_url: setupUrl,
1009
1043
  account_email: input.email?.trim() || null,
1044
+ status: open.data.status ?? null,
1045
+ flow_status: open.data.flow_status ?? null,
1046
+ flow_step: open.data.flow_step ?? null,
1047
+ flow_expires_at: open.data.flow_expires_at ?? null,
1048
+ post_login_url: open.data.post_login_url ?? null,
1010
1049
  next_steps: [
1011
- "Open the watch_url and let the user click Sign in on Google.",
1012
- "After the user confirms login is complete, call browser_close with this session_id to persist cookies and storage to the saved profile.",
1013
- "If the saved profile later shows login controls or disconnects, repeat browser_profile_onboard and close the setup session again.",
1014
- "Use BROWSER_AGENT_PROFILE_NAME or browser_open.profile with this profile name for future authenticated sessions."
1050
+ "Open the watch_url and let the user complete login for the target domain.",
1051
+ "Call browser_profile_status with auth_connection_id until status is AUTHENTICATED.",
1052
+ "After authentication, call browser_open with this profile name and the target site URL.",
1053
+ "If the saved profile later shows login controls or disconnects, repeat browser_profile_onboard."
1015
1054
  ],
1016
- raw: session
1055
+ raw: open.data
1056
+ });
1057
+ }
1058
+ );
1059
+ server2.registerTool(
1060
+ "browser_profile_status",
1061
+ {
1062
+ title: "Check Browser Profile Auth Status",
1063
+ description: "Check whether a hosted browser profile auth connection is authenticated after browser_profile_onboard. Use auth_connection_id when available. Once status is AUTHENTICATED, use browser_open with the returned profile.",
1064
+ inputSchema: BrowserProfileStatusInputSchema,
1065
+ outputSchema: BrowserProfileStatusOutputSchema,
1066
+ annotations: annotations("Check Browser Profile Auth Status", true)
1067
+ },
1068
+ async (input) => {
1069
+ const domain = slugPart(input.domain) || "chatgpt.com";
1070
+ const res = await req("POST", "/agent/profiles/status", {
1071
+ ...input.connection_id ? { connection_id: input.connection_id } : {},
1072
+ ...input.profile ? { profile: input.profile } : {},
1073
+ domain
1074
+ });
1075
+ if (!res.ok) return errorResult("browser_profile_status", res.data);
1076
+ return structuredResult({
1077
+ ok: true,
1078
+ tool: "browser_profile_status",
1079
+ session_id: null,
1080
+ auth_connection_id: res.data.connection_id,
1081
+ profile: res.data.profile,
1082
+ domain: res.data.domain,
1083
+ status: res.data.status,
1084
+ flow_status: res.data.flow_status ?? null,
1085
+ flow_step: res.data.flow_step ?? null,
1086
+ flow_expires_at: res.data.flow_expires_at ?? null,
1087
+ post_login_url: res.data.post_login_url ?? null,
1088
+ raw: res.data
1017
1089
  });
1018
1090
  }
1019
1091
  );
@@ -1021,7 +1093,7 @@ function registerBrowserAgentMcpTools(server2, opts) {
1021
1093
  "browser_open",
1022
1094
  {
1023
1095
  title: "Open Browser Session",
1024
- description: "Open a direct no-proxy hosted browser session you can drive. Pass a saved profile name to load an authenticated session for a site. For customer login setup or reconnects, use browser_profile_onboard first so the user signs in through a watch_url, then call browser_close to save the profile. Returns a session_id used by all other browser_* tools.",
1096
+ description: "Open a direct no-proxy hosted browser session you can drive. Pass a saved profile name to load an authenticated session for a site. For customer login setup or reconnects, use browser_profile_onboard first, then call browser_profile_status until status is AUTHENTICATED. Returns a session_id used by all other browser_* tools.",
1025
1097
  inputSchema: BrowserOpenInputSchema,
1026
1098
  outputSchema: BrowserOpenOutputSchema,
1027
1099
  annotations: annotations("Open Browser Session")
@@ -1443,7 +1515,7 @@ function registerBrowserAgentMcpTools(server2, opts) {
1443
1515
  "browser_capture_fanout",
1444
1516
  {
1445
1517
  title: "Capture AI Search Fan-Out",
1446
- description: `Capture the query fan-out behind a ChatGPT or Claude web-search answer for Answer Engine Optimization (AEO): the exact sub-queries the model issued, every researched URL split into cited vs browsed-only (with citation frequency and snippet), each source tagged by category (First-party/vendor, News/media, Reddit, Social/video, Encyclopedia, Review site, Docs, Blog), plus top sourced sites and citation order. This returns the raw structured data; YOU analyze it \u2014 classify each sub-query by funnel stage (Problem-aware, Solution-aware, Decision-aware, Retention) and type (BoFu, Branded, Comparison, How-to, Search operator), name the brands the model researched, and give AEO insights. Sample asks: "capture the fan-out for this ChatGPT answer", "what did Claude search and cite for best CRM", "show the sub-queries and sources behind this AI answer". WRITE NOTE: passing prompt submits a real message in the user's logged-in account (a new conversation turn) \u2014 only send when the user wants that; omit prompt to capture a prompt the user just ran. Setup, if not already connected or if the profile disconnected: call browser_profile_onboard, give the user the watch_url, let them click Sign in on Google, then call browser_close after they confirm login. After that, browser_open the saved direct no-proxy profile and go to chatgpt.com or claude.ai. Fan-out is captured only as it streams, so the session must be open when the prompt runs. NOT for Google AI Overview citations \u2014 use harvest_paa for those; this tool is ChatGPT and Claude only.`,
1518
+ description: `Capture the query fan-out behind a ChatGPT or Claude web-search answer for Answer Engine Optimization (AEO): the exact sub-queries the model issued, every researched URL split into cited vs browsed-only (with citation frequency and snippet), each source tagged by category (First-party/vendor, News/media, Reddit, Social/video, Encyclopedia, Review site, Docs, Blog), plus top sourced sites and citation order. This returns the raw structured data; YOU analyze it \u2014 classify each sub-query by funnel stage (Problem-aware, Solution-aware, Decision-aware, Retention) and type (BoFu, Branded, Comparison, How-to, Search operator), name the brands the model researched, and give AEO insights. Sample asks: "capture the fan-out for this ChatGPT answer", "what did Claude search and cite for best CRM", "show the sub-queries and sources behind this AI answer". WRITE NOTE: passing prompt submits a real message in the user's logged-in account (a new conversation turn) \u2014 only send when the user wants that; omit prompt to capture a prompt the user just ran. Setup, if not already connected or if the profile disconnected: call browser_profile_onboard, give the user the watch_url, let them complete login, then call browser_profile_status until status is AUTHENTICATED. After that, browser_open the saved direct no-proxy profile and go to chatgpt.com or claude.ai. Fan-out is captured only as it streams, so the session must be open when the prompt runs. NOT for Google AI Overview citations \u2014 use harvest_paa for those; this tool is ChatGPT and Claude only.`,
1447
1519
  inputSchema: BrowserCaptureFanoutInputSchema,
1448
1520
  outputSchema: BrowserCaptureFanoutOutputSchema,
1449
1521
  annotations: annotations("Capture AI Search Fan-Out")
@@ -4607,14 +4679,14 @@ function renderInstallTerminal(options) {
4607
4679
  colorize(ascii, "amber", color),
4608
4680
  `${colorize("MCP Scraper Agent", "cyan", color)} . v${options.version} . mcpscraper.dev`,
4609
4681
  "1/1 install surfaces ready",
4610
- colorize("Newest: saved hosted browser profiles for AI visibility. Open Google, share the watch_url, user signs in, close to save. Browser sessions are direct/no-proxy by default.", "lime", color),
4682
+ colorize("Newest: saved hosted browser profiles for AI visibility. Share the watch_url, user signs in, then verify with browser_profile_status. Browser sessions are direct/no-proxy by default.", "lime", color),
4611
4683
  "",
4612
- `${colorize("Tools", "cyan", color)} ${colorize("(43 MCP tools)", "muted", color)}`,
4684
+ `${colorize("Tools", "cyan", color)} ${colorize("(44 MCP tools)", "muted", color)}`,
4613
4685
  toolRow("search", ["harvest_paa", "search_serp", "maps_search", "maps_place_intel"], color),
4614
4686
  toolRow("extract", ["extract_url", "map_site_urls", "extract_site", "directory_workflow"], color),
4615
4687
  toolRow("build", ["rank_tracker_blueprint", "cron plan", "database prompt"], color),
4616
4688
  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),
4617
- toolRow("browser", ["browser_open", "browser_profile_onboard", "browser_close", "browser_screenshot", "browser_read", "browser_locate", "browser_replay_mark", "browser_replay_annotate"], color),
4689
+ toolRow("browser", ["browser_open", "browser_profile_onboard", "browser_profile_status", "browser_close", "browser_screenshot", "browser_read", "browser_locate", "browser_replay_mark", "browser_replay_annotate"], color),
4618
4690
  toolRow("account", ["credits_info", "reports", "MCP resources"], color),
4619
4691
  `${colorize("Workflows", "cyan", color)} ${colorize("(MCP + CLI + API)", "muted", color)}`,
4620
4692
  toolRow("route", ["workflow_list", "workflow_suggest", "workflow_run", "workflow_step", "workflow_status", "workflow_artifact_read"], color),
@@ -4624,7 +4696,7 @@ function renderInstallTerminal(options) {
4624
4696
  "Run mcp-scraper-install for this visible card. Run mcp-scraper-cli for setup utilities and subcommands.",
4625
4697
  "Run mcp-scraper-combined in a human terminal to print this card; MCP clients get the same command as a silent stdio server.",
4626
4698
  "Explicit card command: npx -y -p mcp-scraper@latest mcp-scraper-install",
4627
- "Customer auth setup: run browser_profile_onboard at https://google.com/, send the watch_url, let the user click Sign in, then browser_close to save.",
4699
+ "Customer auth setup: run browser_profile_onboard, send the watch_url, let the user sign in, then call browser_profile_status until AUTHENTICATED.",
4628
4700
  "Reconnect setup: if a saved profile shows login controls later, run browser_profile_onboard again with the same profile name.",
4629
4701
  "Start with workflow_suggest for broad jobs like market analysis, ICP research, CRO audits, brand briefs, content gaps, and AI visibility.",
4630
4702
  "For MCP clients, use mcp-scraper-combined so one install can mix SERP, Maps, browser, reports, and saved MCP resources.",
@@ -4636,8 +4708,8 @@ function renderInstallTerminal(options) {
4636
4708
  "npx -y -p mcp-scraper@latest mcp-scraper-cli doctor",
4637
4709
  "",
4638
4710
  colorize("Hosted profile setup", "amber", color),
4639
- 'In your MCP client, call browser_profile_onboard with profile="seo-example-com" and url="https://google.com/".',
4640
- "Give the returned watch_url to the user. After they sign in, call browser_close to persist the saved hosted profile.",
4711
+ 'In your MCP client, call browser_profile_onboard with email="seo@example.com" and domain="chatgpt.com".',
4712
+ "Give the returned watch_url to the user. After they sign in, call browser_profile_status, then browser_open with the returned profile.",
4641
4713
  "",
4642
4714
  colorize("Claude Code one-command setup", "amber", color),
4643
4715
  claudeCommand,