mcp-scraper 0.32.3 → 0.33.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/api-server.cjs +20 -19
  3. package/dist/bin/api-server.cjs.map +1 -1
  4. package/dist/bin/api-server.js +2 -2
  5. package/dist/bin/mcp-scraper-cli.cjs +5 -5
  6. package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
  7. package/dist/bin/mcp-scraper-cli.js +2 -2
  8. package/dist/bin/mcp-scraper-install.cjs +1 -1
  9. package/dist/bin/mcp-scraper-install.cjs.map +1 -1
  10. package/dist/bin/mcp-scraper-install.js +1 -1
  11. package/dist/bin/mcp-stdio-server.cjs +6 -6
  12. package/dist/bin/mcp-stdio-server.cjs.map +1 -1
  13. package/dist/bin/mcp-stdio-server.js +2 -2
  14. package/dist/bin/paa-harvest.js +1 -1
  15. package/dist/{chunk-MKZIL4EA.js → chunk-AT2PFWHW.js} +5 -5
  16. package/dist/chunk-AT2PFWHW.js.map +1 -0
  17. package/dist/{chunk-AEMABLEL.js → chunk-ERORC7AP.js} +1 -3
  18. package/dist/chunk-RHD6Z42L.js +7 -0
  19. package/dist/chunk-RHD6Z42L.js.map +1 -0
  20. package/dist/{chunk-GNRHBIYZ.js → chunk-Z3KL7WQ5.js} +7 -7
  21. package/dist/chunk-Z3KL7WQ5.js.map +1 -0
  22. package/dist/index.js +1 -1
  23. package/dist/{server-NHLEIKDZ.js → server-M5N6JVZ5.js} +15 -15
  24. package/dist/server-M5N6JVZ5.js.map +1 -0
  25. package/dist/{worker-ZZCZNY3R.js → worker-JU5FX3NE.js} +2 -2
  26. package/docs/adr/0003-waive-unrecoverable-scheduled-model-cost.md +22 -0
  27. package/docs/adr/README.md +1 -0
  28. package/docs/mcp-tool-manifest.generated.json +7 -12
  29. package/package.json +1 -1
  30. package/dist/chunk-GNRHBIYZ.js.map +0 -1
  31. package/dist/chunk-MKZIL4EA.js.map +0 -1
  32. package/dist/chunk-XF46AB5C.js +0 -7
  33. package/dist/chunk-XF46AB5C.js.map +0 -1
  34. package/dist/server-NHLEIKDZ.js.map +0 -1
  35. /package/dist/{chunk-AEMABLEL.js.map → chunk-ERORC7AP.js.map} +0 -0
  36. /package/dist/{worker-ZZCZNY3R.js.map → worker-JU5FX3NE.js.map} +0 -0
package/README.md CHANGED
@@ -88,7 +88,7 @@ Build the branded one-click bundle:
88
88
  npm run build:mcpb
89
89
  ```
90
90
 
91
- The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.32.3`, SHA-256 `1e44cc581a788e799b5e0eb7e909178714a50030d86bbdc6c2b119d84b04fb97`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
91
+ The generated bundle is written to `build/mcpb/mcp-scraper-<version>.mcpb` and copied to `public/downloads/` for the hosted download. The current public bundle is `https://mcpscraper.dev/downloads/mcp-scraper.mcpb` (`0.33.1`, SHA-256 `c9122255263b899e7ac95825d0212c54f63059be0370dabd67aea57af82f5754`). Install it by opening or dragging it into Claude Desktop. Claude displays the `MCP Scraper` install card, icon, and API-key configuration field from the bundle manifest.
92
92
 
93
93
  The MCPB install exposes every tool — web-intelligence plus all `browser_*` tools — through the one `mcp-scraper` server.
94
94
 
@@ -15945,7 +15945,7 @@ var init_server_schemas = __esm({
15945
15945
  gl: import_zod15.z.string().optional(),
15946
15946
  hl: import_zod15.z.string().optional(),
15947
15947
  device: import_zod15.z.enum(["desktop", "mobile"]).optional(),
15948
- proxyMode: import_zod15.z.enum(["location", "configured", "none"]).optional(),
15948
+ proxyMode: import_zod15.z.enum(["configured", "none"]).optional(),
15949
15949
  proxyZip: import_zod15.z.string().regex(/^\d{5}$/).optional(),
15950
15950
  debug: import_zod15.z.boolean().optional(),
15951
15951
  serpOnly: import_zod15.z.boolean().optional(),
@@ -19253,13 +19253,11 @@ var init_video_routes = __esm({
19253
19253
  function buildGoogleLocalResultsUrl(input) {
19254
19254
  const query = [input.query, input.location].filter(Boolean).join(" ");
19255
19255
  const params = new URLSearchParams({ q: query, udm: "1", gl: input.gl, hl: input.hl, pws: "0" });
19256
- if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
19257
19256
  return `https://www.google.com/search?${params.toString()}`;
19258
19257
  }
19259
19258
  function buildGoogleOrganicSearchUrl(input) {
19260
19259
  const query = [input.query, input.location].filter(Boolean).join(" ");
19261
19260
  const params = new URLSearchParams({ q: query, gl: input.gl, hl: input.hl, pws: "0" });
19262
- if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
19263
19261
  return `https://www.google.com/search?${params.toString()}`;
19264
19262
  }
19265
19263
  function mapsIdentifiersFromUrl(url) {
@@ -19284,7 +19282,6 @@ var init_MapsSearchExtractor = __esm({
19284
19282
  "use strict";
19285
19283
  init_errors();
19286
19284
  init_BrowserDriver();
19287
- init_uule();
19288
19285
  LOCAL_RESULTS_PAGE_LIMIT = 8;
19289
19286
  LOCAL_RESULTS_WAIT_MS = 1e3;
19290
19287
  MAPS_REDIRECT_BASE = "https://serp-redirector.vercel.app";
@@ -20092,7 +20089,9 @@ var init_MapsExtractor = __esm({
20092
20089
 
20093
20090
  // src/maps-search-rotation.ts
20094
20091
  function mapsSearchMaxAttemptsForProxyMode(proxyMode) {
20095
- return proxyMode === "location" ? MAPS_SEARCH_LOCATION_PROXY_MAX_ATTEMPTS : MAPS_SEARCH_MAX_ATTEMPTS;
20092
+ if (proxyMode === "location") return MAPS_SEARCH_LOCATION_PROXY_MAX_ATTEMPTS;
20093
+ if (proxyMode === "none") return MAPS_SEARCH_NONE_MAX_ATTEMPTS;
20094
+ return MAPS_SEARCH_MAX_ATTEMPTS;
20096
20095
  }
20097
20096
  function mapsSearchErrorMessage(err) {
20098
20097
  return sanitizeVendorName(err instanceof Error ? err.message : String(err));
@@ -20163,6 +20162,7 @@ async function cleanupDisposableProxy(kernelApiKey, proxyId, eventName) {
20163
20162
  }
20164
20163
  }
20165
20164
  async function runMapsSearchWithRotation(options) {
20165
+ if (options.proxyMode === "location") options = { ...options, proxyMode: "none" };
20166
20166
  const attempts = [];
20167
20167
  const maxAttempts = mapsSearchMaxAttemptsForProxyMode(options.proxyMode) + 1;
20168
20168
  const started = Date.now();
@@ -20191,8 +20191,8 @@ async function runMapsSearchWithRotation(options) {
20191
20191
  proxyZip,
20192
20192
  kernelProxyId: options.proxyMode === "none" ? void 0 : resolution2.kernelProxyId,
20193
20193
  kernelProxyResolution: resolution2.resolution,
20194
- serpRedirect: options.proxyMode === "none" && attemptIndex >= 1 && attemptIndex < maxAttempts - 1,
20195
- forceDirectEgress: options.proxyMode === "none" && attemptIndex >= 1
20194
+ serpRedirect: options.proxyMode === "none" && attemptIndex >= 2 && attemptIndex < 6,
20195
+ forceDirectEgress: options.proxyMode === "none" && attemptIndex >= 4
20196
20196
  };
20197
20197
  const isHeadfulEscalation = attemptIndex === maxAttempts - 1;
20198
20198
  const baseCtx = currentCostContext();
@@ -20267,7 +20267,7 @@ async function runMapsSearchWithRotation(options) {
20267
20267
  true
20268
20268
  );
20269
20269
  }
20270
- var MAPS_SEARCH_MAX_ATTEMPTS, MAPS_SEARCH_LOCATION_PROXY_MAX_ATTEMPTS, MapsSearchRotationError;
20270
+ var MAPS_SEARCH_MAX_ATTEMPTS, MAPS_SEARCH_NONE_MAX_ATTEMPTS, MAPS_SEARCH_LOCATION_PROXY_MAX_ATTEMPTS, MapsSearchRotationError;
20271
20271
  var init_maps_search_rotation = __esm({
20272
20272
  "src/maps-search-rotation.ts"() {
20273
20273
  "use strict";
@@ -20277,6 +20277,7 @@ var init_maps_search_rotation = __esm({
20277
20277
  init_kernel_proxy_resolver();
20278
20278
  init_cost_context();
20279
20279
  MAPS_SEARCH_MAX_ATTEMPTS = 3;
20280
+ MAPS_SEARCH_NONE_MAX_ATTEMPTS = 7;
20280
20281
  MAPS_SEARCH_LOCATION_PROXY_MAX_ATTEMPTS = 5;
20281
20282
  MapsSearchRotationError = class extends Error {
20282
20283
  constructor(message, attempts, retryable, errorCode = "maps_search_failed") {
@@ -24138,7 +24139,7 @@ var init_directory_workflow = __esm({
24138
24139
  saveCsv: import_zod26.z.boolean().default(true),
24139
24140
  gl: import_zod26.z.string().length(2).default("us"),
24140
24141
  hl: import_zod26.z.string().length(2).default("en"),
24141
- proxyMode: import_zod26.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
24142
+ proxyMode: import_zod26.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
24142
24143
  proxyZip: import_zod26.z.string().regex(/^\d{5}$/).optional(),
24143
24144
  debug: import_zod26.z.boolean().default(false),
24144
24145
  headless: import_zod26.z.boolean().default(true),
@@ -24794,7 +24795,7 @@ var init_directory = __esm({
24794
24795
  maxCities: import_zod28.z.number().int().min(1).max(100).default(25),
24795
24796
  maxResultsPerCity: import_zod28.z.number().int().min(1).max(50).default(20),
24796
24797
  concurrency: import_zod28.z.number().int().min(1).max(5).default(5),
24797
- proxyMode: import_zod28.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
24798
+ proxyMode: import_zod28.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
24798
24799
  saveCsv: import_zod28.z.boolean().default(true)
24799
24800
  });
24800
24801
  DIRECTORY_CSV_HEADERS = [
@@ -24949,7 +24950,7 @@ var init_get_leads = __esm({
24949
24950
  enrichWebsites: import_zod29.z.boolean().default(true).describe("Visit each business website (home + contact pages) to harvest email and social links. Uses the proxy/browser-backed extractor so blocked sites still resolve."),
24950
24951
  hydrateReviewCounts: import_zod29.z.boolean().default(true).describe("Deep-dive each profile to confirm the review count and booking URL that the Maps search list omits."),
24951
24952
  concurrency: import_zod29.z.number().int().min(1).max(4).default(3).describe("How many businesses to enrich in parallel. Keep low to respect per-account concurrency limits."),
24952
- proxyMode: import_zod29.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy targeting for the Maps search. location targets the market; none is for local debugging.")
24953
+ proxyMode: import_zod29.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy behavior for the Maps search. Leave unset for clean egress; country/region localization comes from gl/hl plus the city or region in the query.")
24953
24954
  });
24954
24955
  LEADS_CSV_HEADERS = [
24955
24956
  "position",
@@ -25168,7 +25169,7 @@ var init_local_competitive_audit = __esm({
25168
25169
  hydrateTop: import_zod30.z.number().int().min(0).max(10).default(5),
25169
25170
  maxReviews: import_zod30.z.number().int().min(0).max(500).default(50),
25170
25171
  concurrency: import_zod30.z.number().int().min(1).max(5).default(5),
25171
- proxyMode: import_zod30.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
25172
+ proxyMode: import_zod30.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
25172
25173
  returnPartial: import_zod30.z.boolean().default(true)
25173
25174
  });
25174
25175
  localCompetitiveAuditWorkflowDefinition = {
@@ -25621,7 +25622,7 @@ var init_comparison_briefs = __esm({
25621
25622
  init_directory();
25622
25623
  init_seo_workflow_utils();
25623
25624
  init_schemas3();
25624
- ProxyModeSchema = import_zod31.z.enum(["location", "configured", "none"]);
25625
+ ProxyModeSchema = import_zod31.z.enum(["configured", "none"]);
25625
25626
  MapComparisonInputSchema = import_zod31.z.object({
25626
25627
  query: import_zod31.z.string().min(1),
25627
25628
  location: import_zod31.z.string().optional(),
@@ -29814,7 +29815,7 @@ var PACKAGE_VERSION;
29814
29815
  var init_version = __esm({
29815
29816
  "src/version.ts"() {
29816
29817
  "use strict";
29817
- PACKAGE_VERSION = "0.32.3";
29818
+ PACKAGE_VERSION = "0.33.1";
29818
29819
  }
29819
29820
  });
29820
29821
 
@@ -30278,7 +30279,7 @@ var init_mcp_tool_schemas = __esm({
30278
30279
  gl: import_zod35.z.string().length(2).default("us").describe("Google country code inferred from location or user language."),
30279
30280
  hl: import_zod35.z.string().default("en").describe("Google interface/content language inferred from the user request."),
30280
30281
  device: import_zod35.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use mobile only for mobile rankings."),
30281
- proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress). Do NOT set "location" just because a city was named \u2014 that comes from city-in-query wording. "location" forces residential geo-IP for rank-tracking fidelity, is frequently CAPTCHA-blocked, and accepts failures.'),
30282
+ proxyMode: import_zod35.z.enum(["configured", "none"]).default(DEFAULT_PROXY_MODE).describe("Leave unset for clean egress (the default). Country/region localization comes from gl/hl plus the city or region in the query \u2014 not from a proxy."),
30282
30283
  proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location".'),
30283
30284
  debug: import_zod35.z.boolean().default(false).describe("Include sanitized diagnostics for debugging localization, CAPTCHA, or proxy behavior.")
30284
30285
  };
@@ -30447,7 +30448,7 @@ var init_mcp_tool_schemas = __esm({
30447
30448
  hl: import_zod35.z.string().length(2).default("en").describe("Language inferred from user request."),
30448
30449
  maxResults: import_zod35.z.number().int().min(1).max(50).default(10).describe("Number of candidates to return. Default 10, maximum 50."),
30449
30450
  includeServices: import_zod35.z.boolean().default(false).describe("Open each returned business profile to include its configured services and areas served when available. Adds a page visit per business; does not collect review cards."),
30450
- proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Leave unset for the default route (stealth browser on the managed ISP proxy, retried on a fresh session when Google blocks). Localization comes from the city in the query plus gl/hl. location forces an explicit residential proxy \u2014 not recommended for Google."),
30451
+ proxyMode: import_zod35.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Leave unset for the default route (stealth browser on the managed ISP proxy, retried on a fresh session when Google blocks). Country/region localization comes from the city or region in the query plus gl/hl \u2014 not from a proxy."),
30451
30452
  proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override, only used when proxyMode is location."),
30452
30453
  debug: import_zod35.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics.")
30453
30454
  };
@@ -30462,7 +30463,7 @@ var init_mcp_tool_schemas = __esm({
30462
30463
  includeZipGroups: import_zod35.z.boolean().default(true).describe("Attach ZIP groups from a configured US ZIPS CSV when available (MCP_SCRAPER_USZIPS_CSV_PATH or usZipsCsvPath)."),
30463
30464
  usZipsCsvPath: import_zod35.z.string().optional().describe("Local/test-only path to a US ZIPS CSV (state_abbr, zipcode, county, city columns). Deployed APIs should use MCP_SCRAPER_USZIPS_CSV_PATH instead. For ZIP enrichment, set MCP_SCRAPER_USZIPS_CSV_PATH on the server, or pass this in local/test mode."),
30464
30465
  saveCsv: import_zod35.z.boolean().default(true).describe("Save a directory-ready CSV of results to the MCP Scraper output directory and return its path."),
30465
- proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy behavior per city search. Leave unset for the default route (stealth browser on the managed ISP proxy, retried fresh on a Google block). location forces an explicit residential proxy \u2014 not recommended for Google."),
30466
+ proxyMode: import_zod35.z.enum(["configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy behavior per city search. Leave unset for the default route (stealth browser on the managed ISP proxy, retried fresh on a Google block). Country/region localization comes from the city or region in the query plus gl/hl \u2014 not from a proxy."),
30466
30467
  proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe("Optional ZIP override for proxy targeting; normally omitted."),
30467
30468
  debug: import_zod35.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics.")
30468
30469
  };
@@ -31302,7 +31303,7 @@ var init_mcp_tool_schemas = __esm({
31302
31303
  gl: import_zod35.z.string().length(2).default("us").describe("Google country code inferred from location or user language."),
31303
31304
  hl: import_zod35.z.string().default("en").describe("Google interface/content language inferred from user request."),
31304
31305
  device: import_zod35.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use mobile only for mobile rankings."),
31305
- proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress). Do NOT set "location" just because a city was named \u2014 that comes from city-in-query wording. "location" forces residential geo-IP for rank-tracking fidelity, is frequently CAPTCHA-blocked, and accepts failures.'),
31306
+ proxyMode: import_zod35.z.enum(["configured", "none"]).default(DEFAULT_PROXY_MODE).describe("Leave unset for clean egress (the default). Country/region localization comes from gl/hl plus the city or region in the query \u2014 not from a proxy."),
31306
31307
  proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location".'),
31307
31308
  debug: import_zod35.z.boolean().default(false).describe("Include sanitized diagnostics for debugging localization, CAPTCHA, or proxy behavior."),
31308
31309
  pages: import_zod35.z.number().int().min(1).max(2).default(1).describe("Number of result pages to fetch (1\u20132).")
@@ -31313,7 +31314,7 @@ var init_mcp_tool_schemas = __esm({
31313
31314
  gl: import_zod35.z.string().length(2).default("us").describe("Google country code inferred from the requested market."),
31314
31315
  hl: import_zod35.z.string().default("en").describe("Google interface/content language inferred from the user request."),
31315
31316
  device: import_zod35.z.enum(["desktop", "mobile"]).default("desktop").describe("SERP device context. Use mobile only for mobile rankings/evidence."),
31316
- proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE).describe('Leave unset (clean egress). Do NOT set "location" just because a city was named \u2014 that comes from city-in-query wording. "location" forces residential geo-IP, is frequently CAPTCHA-blocked, and accepts failures.'),
31317
+ proxyMode: import_zod35.z.enum(["configured", "none"]).default(DEFAULT_PROXY_MODE).describe("Leave unset for clean egress (the default). Country/region localization comes from gl/hl plus the city or region in the query \u2014 not from a proxy."),
31317
31318
  proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe('US ZIP for residential geo-IP targeting. Only meaningful with proxyMode "location".'),
31318
31319
  pages: import_zod35.z.number().int().min(1).max(2).default(1).describe("Google result pages to capture. Use 2 only for deeper ranking evidence."),
31319
31320
  debug: import_zod35.z.boolean().default(false).describe("Include sanitized browser/proxy/location diagnostics."),