mcp-scraper 0.31.0 → 0.32.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.
- package/README.md +1 -1
- package/dist/bin/api-server.cjs +101 -38
- package/dist/bin/api-server.cjs.map +1 -1
- package/dist/bin/api-server.js +2 -2
- package/dist/bin/mcp-scraper-cli.cjs +4 -1
- package/dist/bin/mcp-scraper-cli.cjs.map +1 -1
- package/dist/bin/mcp-scraper-cli.js +3 -3
- package/dist/bin/mcp-scraper-install.cjs +1 -1
- package/dist/bin/mcp-scraper-install.cjs.map +1 -1
- package/dist/bin/mcp-scraper-install.js +1 -1
- package/dist/bin/mcp-stdio-server.cjs +9 -6
- package/dist/bin/mcp-stdio-server.cjs.map +1 -1
- package/dist/bin/mcp-stdio-server.js +3 -3
- package/dist/bin/paa-harvest.cjs +26 -4
- package/dist/bin/paa-harvest.cjs.map +1 -1
- package/dist/bin/paa-harvest.js +2 -2
- package/dist/{chunk-ZOXL3VWO.js → chunk-2FY4VBAY.js} +8 -8
- package/dist/chunk-2FY4VBAY.js.map +1 -0
- package/dist/{chunk-KAMKTSJQ.js → chunk-55M5CE5L.js} +2 -2
- package/dist/{chunk-ZQSHKWV4.js → chunk-PTHY7NYD.js} +4 -1
- package/dist/chunk-PTHY7NYD.js.map +1 -0
- package/dist/{chunk-YH5DRFWQ.js → chunk-RDCCU7CQ.js} +25 -6
- package/dist/chunk-RDCCU7CQ.js.map +1 -0
- package/dist/chunk-VJBS6RPB.js +7 -0
- package/dist/chunk-VJBS6RPB.js.map +1 -0
- package/dist/index.cjs +26 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +2 -2
- package/dist/{server-DS3ZSNNO.js → server-GXTYKIAX.js} +77 -35
- package/dist/{server-DS3ZSNNO.js.map → server-GXTYKIAX.js.map} +1 -1
- package/dist/{worker-RYP5EOV5.js → worker-7DJYUACV.js} +3 -3
- package/docs/mcp-tool-manifest.generated.json +7 -7
- package/package.json +1 -1
- package/dist/chunk-W3GYPHFL.js +0 -7
- package/dist/chunk-W3GYPHFL.js.map +0 -1
- package/dist/chunk-YH5DRFWQ.js.map +0 -1
- package/dist/chunk-ZOXL3VWO.js.map +0 -1
- package/dist/chunk-ZQSHKWV4.js.map +0 -1
- /package/dist/{chunk-KAMKTSJQ.js.map → chunk-55M5CE5L.js.map} +0 -0
- /package/dist/{worker-RYP5EOV5.js.map → worker-7DJYUACV.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.
|
|
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.1`, SHA-256 `a8b3ff927f58382f5e550cbe079a4276e448c6750858ec9712f2f945cd79ffa3`). 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
|
|
package/dist/bin/api-server.cjs
CHANGED
|
@@ -13834,6 +13834,15 @@ function positiveIntFromEnv(name, fallback) {
|
|
|
13834
13834
|
function proxyIdSuffix(proxyId) {
|
|
13835
13835
|
return proxyId ? proxyId.slice(-6) : null;
|
|
13836
13836
|
}
|
|
13837
|
+
function serpArrivalUrl(googleUrl) {
|
|
13838
|
+
const base = process.env.SERP_REDIRECT_BASE?.trim().replace(/\/+$/, "");
|
|
13839
|
+
if (!base) return googleUrl;
|
|
13840
|
+
return `${base}/g/${Buffer.from(googleUrl, "utf8").toString("base64url")}`;
|
|
13841
|
+
}
|
|
13842
|
+
function isUsCountry(country) {
|
|
13843
|
+
if (!country) return false;
|
|
13844
|
+
return /united states|u\.?s\.?a?\.?|^us$/i.test(country.trim());
|
|
13845
|
+
}
|
|
13837
13846
|
function errorText(err) {
|
|
13838
13847
|
return err instanceof Error ? err.message : String(err);
|
|
13839
13848
|
}
|
|
@@ -13988,7 +13997,7 @@ var init_BrowserDriver = __esm({
|
|
|
13988
13997
|
this.kernelProxyType = config.kernelProxyResolution?.proxyType ?? null;
|
|
13989
13998
|
let defaultProxyDisabled = null;
|
|
13990
13999
|
let defaultProxyDisableError = null;
|
|
13991
|
-
if (!config.kernelProxyId) {
|
|
14000
|
+
if (!config.kernelProxyId && !config.keepDefaultProxy) {
|
|
13992
14001
|
try {
|
|
13993
14002
|
await withTimeout2(
|
|
13994
14003
|
this.kernelClient.browsers.update(this.kernelSessionId, { disable_default_proxy: true }),
|
|
@@ -14038,9 +14047,15 @@ var init_BrowserDriver = __esm({
|
|
|
14038
14047
|
await this.installEsbuildHelperShims(this.context);
|
|
14039
14048
|
this.page = await this.context.newPage();
|
|
14040
14049
|
await this.page.setViewportSize(config.viewport);
|
|
14041
|
-
if (this.debugEnabled) {
|
|
14050
|
+
if (this.debugEnabled || config.requireUsEgress) {
|
|
14042
14051
|
this.debugSnapshot.networkLocation = await this.captureBrowserNetworkLocation();
|
|
14043
14052
|
}
|
|
14053
|
+
if (config.requireUsEgress) {
|
|
14054
|
+
const country = this.debugSnapshot.networkLocation?.country ?? null;
|
|
14055
|
+
if (!isUsCountry(country)) {
|
|
14056
|
+
throw new CaptchaError(`Non-US egress (${country ?? "unknown"}) \u2014 retrying with a fresh session`);
|
|
14057
|
+
}
|
|
14058
|
+
}
|
|
14044
14059
|
return;
|
|
14045
14060
|
}
|
|
14046
14061
|
const launchOpts = {
|
|
@@ -14180,6 +14195,7 @@ var init_BrowserDriver = __esm({
|
|
|
14180
14195
|
if (options?.num) params.set("num", String(options.num));
|
|
14181
14196
|
if (uule) params.set("uule", uule);
|
|
14182
14197
|
const url = "https://www.google.com/search?" + params.toString();
|
|
14198
|
+
const navUrl = serpArrivalUrl(url);
|
|
14183
14199
|
const navDebug = options?.debug ? {
|
|
14184
14200
|
requestedUrl: url,
|
|
14185
14201
|
finalUrl: null,
|
|
@@ -14192,7 +14208,7 @@ var init_BrowserDriver = __esm({
|
|
|
14192
14208
|
} : null;
|
|
14193
14209
|
if (navDebug) this.debugSnapshot.serpNavigation = navDebug;
|
|
14194
14210
|
try {
|
|
14195
|
-
await this.page.goto(
|
|
14211
|
+
await this.page.goto(navUrl, { waitUntil: "domcontentloaded", timeout: 45e3 });
|
|
14196
14212
|
} catch (err) {
|
|
14197
14213
|
await this.updateSerpNavigationDebug(navDebug, url, { hasPaa: null, captchaDetected: null });
|
|
14198
14214
|
const diag = await this.captureDiagnostics(url);
|
|
@@ -17339,6 +17355,9 @@ var init_schemas3 = __esm({
|
|
|
17339
17355
|
device: import_zod17.z.enum(["desktop", "mobile"]).default("desktop"),
|
|
17340
17356
|
proxyMode: import_zod17.z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE),
|
|
17341
17357
|
proxyZip: import_zod17.z.string().regex(/^\d{5}$/).optional(),
|
|
17358
|
+
keepDefaultProxy: import_zod17.z.boolean().optional(),
|
|
17359
|
+
requireUsEgress: import_zod17.z.boolean().optional(),
|
|
17360
|
+
maxAttempts: import_zod17.z.number().int().min(1).max(12).optional(),
|
|
17342
17361
|
debug: import_zod17.z.boolean().default(false),
|
|
17343
17362
|
depth: import_zod17.z.number().int().min(1).max(30).default(3),
|
|
17344
17363
|
maxQuestions: import_zod17.z.number().int().min(1).max(1e3).default(100),
|
|
@@ -19235,6 +19254,12 @@ function buildGoogleLocalResultsUrl(input) {
|
|
|
19235
19254
|
if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
|
|
19236
19255
|
return `https://www.google.com/search?${params.toString()}`;
|
|
19237
19256
|
}
|
|
19257
|
+
function buildGoogleOrganicSearchUrl(input) {
|
|
19258
|
+
const query = [input.query, input.location].filter(Boolean).join(" ");
|
|
19259
|
+
const params = new URLSearchParams({ q: query, gl: input.gl, hl: input.hl, pws: "0" });
|
|
19260
|
+
if (input.location) params.set("uule", encodeUule(normalizeLocation(input.location)));
|
|
19261
|
+
return `https://www.google.com/search?${params.toString()}`;
|
|
19262
|
+
}
|
|
19238
19263
|
var LOCAL_RESULTS_PAGE_LIMIT, LOCAL_RESULTS_WAIT_MS, MapsSearchExtractor;
|
|
19239
19264
|
var init_MapsSearchExtractor = __esm({
|
|
19240
19265
|
"src/extractor/MapsSearchExtractor.ts"() {
|
|
@@ -19251,13 +19276,14 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19251
19276
|
async extract(options) {
|
|
19252
19277
|
const startMs = Date.now();
|
|
19253
19278
|
const searchQuery = [options.query, options.location].filter(Boolean).join(" ");
|
|
19254
|
-
const searchUrl =
|
|
19279
|
+
const searchUrl = buildGoogleOrganicSearchUrl(options);
|
|
19255
19280
|
const config = {
|
|
19256
19281
|
headless: options.headless,
|
|
19257
19282
|
kernelApiKey: options.kernelApiKey,
|
|
19258
19283
|
kernelProxyId: options.kernelProxyId,
|
|
19259
19284
|
kernelProxyResolution: options.kernelProxyResolution,
|
|
19260
19285
|
proxyMode: options.proxyMode,
|
|
19286
|
+
keepDefaultProxy: options.proxyMode !== "location" && options.proxyMode !== "configured" && !options.kernelProxyId,
|
|
19261
19287
|
viewport: { width: 1280, height: 900 },
|
|
19262
19288
|
locale: `${options.hl}-${options.gl.toUpperCase()}`,
|
|
19263
19289
|
debug: options.debug
|
|
@@ -19268,6 +19294,10 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19268
19294
|
await page.goto(searchUrl, { waitUntil: "domcontentloaded", timeout: 6e4 });
|
|
19269
19295
|
await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
|
|
19270
19296
|
if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
|
|
19297
|
+
const reachedFinder = await this.clickIntoLocalFinder(page);
|
|
19298
|
+
if (!reachedFinder) throw new ExtractionError('Google "More businesses" control was not found on the organic results page');
|
|
19299
|
+
await page.waitForTimeout(LOCAL_RESULTS_WAIT_MS);
|
|
19300
|
+
if (await this.detectBlock(page)) throw new CaptchaError(RECAPTCHA_INSTRUCTIONS);
|
|
19271
19301
|
const results = await this.collectResults(page, options);
|
|
19272
19302
|
return {
|
|
19273
19303
|
query: options.query,
|
|
@@ -19284,6 +19314,17 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19284
19314
|
await this.driver.close();
|
|
19285
19315
|
}
|
|
19286
19316
|
}
|
|
19317
|
+
async clickIntoLocalFinder(page) {
|
|
19318
|
+
const control = page.getByRole("link", { name: /more (businesses|places|results)/i }).or(page.getByRole("button", { name: /more (businesses|places|results)/i })).first();
|
|
19319
|
+
const visible = await control.isVisible({ timeout: 1e4 }).catch(() => false);
|
|
19320
|
+
if (!visible) return false;
|
|
19321
|
+
await control.click({ timeout: 1e4 }).catch(() => {
|
|
19322
|
+
});
|
|
19323
|
+
await page.waitForTimeout(5e3);
|
|
19324
|
+
return page.evaluate(
|
|
19325
|
+
() => /[?&]udm=1/.test(location.href) || document.querySelectorAll('a[href*="/maps/place/"]').length > 0
|
|
19326
|
+
);
|
|
19327
|
+
}
|
|
19287
19328
|
async detectBlock(page) {
|
|
19288
19329
|
return page.evaluate(() => {
|
|
19289
19330
|
const text2 = document.body.innerText.slice(0, 2e3);
|
|
@@ -19337,29 +19378,38 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19337
19378
|
};
|
|
19338
19379
|
const phonePattern = /(?:\+?1[\s.-]?)?\(?\d{3}\)?[\s.-]\d{3}[\s.-]\d{4}/;
|
|
19339
19380
|
const addressPattern = /\b[A-Z]{2}\s+\d{5}(?:-\d{4})?\b|\b(?:St|Street|Ave|Avenue|Rd|Road|Blvd|Boulevard|Dr|Drive|Ln|Lane|Way|Pkwy|Parkway)\b/i;
|
|
19340
|
-
const
|
|
19341
|
-
const
|
|
19342
|
-
return Boolean(
|
|
19381
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]')).filter((heading) => {
|
|
19382
|
+
const text2 = normalize4(heading.textContent);
|
|
19383
|
+
return Boolean(text2) && !/^(?:businesses|places|sponsored|people also ask|discussions and forums|more businesses|more places|custom date range|choose what you)/i.test(text2 ?? "");
|
|
19343
19384
|
});
|
|
19344
19385
|
const seen = /* @__PURE__ */ new Set();
|
|
19345
19386
|
const out = [];
|
|
19346
|
-
|
|
19347
|
-
|
|
19387
|
+
let cardIndex = -1;
|
|
19388
|
+
for (const heading of headings) {
|
|
19389
|
+
let card = heading;
|
|
19390
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
19391
|
+
const parent = card.parentElement;
|
|
19392
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
19393
|
+
card = parent;
|
|
19394
|
+
}
|
|
19395
|
+
if (card.closest('[role="dialog"], dialog')) continue;
|
|
19396
|
+
const name = normalize4(heading.textContent);
|
|
19348
19397
|
if (!name) continue;
|
|
19349
|
-
const
|
|
19350
|
-
|
|
19398
|
+
const lines = (card.innerText ?? "").split("\n").map((line) => normalize4(line)).filter((line) => Boolean(line));
|
|
19399
|
+
if (/^sponsored$/i.test(lines[0] ?? "")) continue;
|
|
19400
|
+
const ratingLine = lines.find((line) => /\d(?:\.\d)?\s*\(/.test(line)) ?? "";
|
|
19401
|
+
const rating = ratingLine.match(/(\d(?:\.\d)?)\s*\(/)?.[1] ?? null;
|
|
19402
|
+
const reviewCount = ratingLine.match(/\((\d[\d,]*)\)/)?.[1]?.replace(/,/g, "") ?? null;
|
|
19403
|
+
const category = normalize4(ratingLine.split("\xB7").slice(1).join("\xB7"));
|
|
19404
|
+
const phone = lines.map((line) => line.match(phonePattern)?.[0]).find((value) => Boolean(value)) ?? null;
|
|
19405
|
+
const hoursStatus = normalize4((lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? "").split("\xB7")[0] ?? "");
|
|
19406
|
+
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
19407
|
+
const websiteUrl = Array.from(card.querySelectorAll("a[href]")).map((anchor) => anchor.href).find((href) => /^https?:/i.test(href) && !/google\.|gstatic|googleusercontent/.test(href)) ?? null;
|
|
19408
|
+
if (!rating && !(phone && websiteUrl)) continue;
|
|
19409
|
+
const key = `${name.toLowerCase()}|${lines.join(" ").toLowerCase()}`;
|
|
19351
19410
|
if (seen.has(key)) continue;
|
|
19352
19411
|
seen.add(key);
|
|
19353
|
-
|
|
19354
|
-
const aria = normalize4(card.getAttribute("aria-label"));
|
|
19355
|
-
const rating = (aria ?? text2).match(/(?:rated\s+)?(\d(?:\.\d)?)\s*(?:out of 5)?/i)?.[1] ?? null;
|
|
19356
|
-
const reviewCount = (aria ?? text2).match(/(?:\(|·\s*)([\d,]+)\s+(?:user\s+)?reviews?\b/i)?.[1]?.replace(/,/g, "") ?? null;
|
|
19357
|
-
const phone = lines.find((line) => phonePattern.test(line)) ?? null;
|
|
19358
|
-
const address = lines.find((line) => addressPattern.test(line)) ?? null;
|
|
19359
|
-
const hoursStatus = lines.find((line) => /\b(?:open|closed|opens|closes)\b/i.test(line)) ?? null;
|
|
19360
|
-
const category = lines.find(
|
|
19361
|
-
(line) => line !== name && line !== phone && line !== address && line !== hoursStatus && !/^(?:rated|\d[\d.,]*\s*(?:out of 5|reviews?)?)\b/i.test(line) && !/sponsored|website|directions|call|save|share|more/i.test(line)
|
|
19362
|
-
) ?? null;
|
|
19412
|
+
cardIndex += 1;
|
|
19363
19413
|
const mapsSearchUrl = `https://www.google.com/maps/search/${encodeURIComponent([name, locationHint].filter(Boolean).join(" "))}`;
|
|
19364
19414
|
out.push({
|
|
19365
19415
|
cardIndex,
|
|
@@ -19374,7 +19424,7 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19374
19424
|
address,
|
|
19375
19425
|
phone,
|
|
19376
19426
|
hoursStatus,
|
|
19377
|
-
websiteUrl
|
|
19427
|
+
websiteUrl,
|
|
19378
19428
|
directionsUrl: `https://www.google.com/maps/dir/?api=1&destination=${encodeURIComponent([name, address].filter(Boolean).join(", "))}`,
|
|
19379
19429
|
metadata: lines.slice(0, 20)
|
|
19380
19430
|
});
|
|
@@ -19383,17 +19433,27 @@ var init_MapsSearchExtractor = __esm({
|
|
|
19383
19433
|
}, fallbackLocation);
|
|
19384
19434
|
}
|
|
19385
19435
|
async openCardAndExtractDialog(page, card, includeServices) {
|
|
19436
|
+
if (!includeServices) return null;
|
|
19386
19437
|
const clicked = await page.evaluate((input) => {
|
|
19387
19438
|
const normalize4 = (value) => (value ?? "").replace(/\s+/g, " ").trim().toLowerCase();
|
|
19388
|
-
const
|
|
19389
|
-
|
|
19390
|
-
|
|
19391
|
-
|
|
19392
|
-
|
|
19393
|
-
|
|
19394
|
-
|
|
19395
|
-
|
|
19396
|
-
|
|
19439
|
+
const headings = Array.from(document.querySelectorAll('div[role="heading"]'));
|
|
19440
|
+
for (const heading of headings) {
|
|
19441
|
+
let target = heading;
|
|
19442
|
+
for (let hop = 0; hop < 8; hop++) {
|
|
19443
|
+
const parent = target.parentElement;
|
|
19444
|
+
if (!parent || parent.querySelectorAll('div[role="heading"]').length > 1) break;
|
|
19445
|
+
target = parent;
|
|
19446
|
+
}
|
|
19447
|
+
if (target.closest('[role="dialog"], dialog')) continue;
|
|
19448
|
+
const name = normalize4(heading.textContent);
|
|
19449
|
+
if (!name) continue;
|
|
19450
|
+
const lines = (target.innerText ?? "").split("\n").map((line) => normalize4(line)).filter(Boolean);
|
|
19451
|
+
if (`${name}|${lines.join(" ")}` !== input.cardKey) continue;
|
|
19452
|
+
target.click();
|
|
19453
|
+
return true;
|
|
19454
|
+
}
|
|
19455
|
+
return false;
|
|
19456
|
+
}, { cardKey: card.cardKey });
|
|
19397
19457
|
if (!clicked) return null;
|
|
19398
19458
|
const dialog = page.locator('dialog, [role="dialog"]').filter({ has: page.locator('h1, h2, [role="heading"]') }).last();
|
|
19399
19459
|
await dialog.waitFor({ state: "visible", timeout: 6e3 }).catch(() => {
|
|
@@ -28145,6 +28205,8 @@ var init_PAAExtractor = __esm({
|
|
|
28145
28205
|
kernelProxyId: options.kernelProxyId,
|
|
28146
28206
|
kernelProxyResolution: options.kernelProxyResolution,
|
|
28147
28207
|
proxyMode: options.proxyMode,
|
|
28208
|
+
keepDefaultProxy: options.keepDefaultProxy,
|
|
28209
|
+
requireUsEgress: options.requireUsEgress,
|
|
28148
28210
|
viewport: isMobile ? { width: 390, height: 844 } : { width: 1280, height: 800 },
|
|
28149
28211
|
locale: `${options.hl}-${options.gl.toUpperCase()}`,
|
|
28150
28212
|
userAgent: isMobile ? MOBILE_USER_AGENT2 : DESKTOP_USER_AGENT2,
|
|
@@ -28645,7 +28707,8 @@ async function harvest(rawOptions) {
|
|
|
28645
28707
|
};
|
|
28646
28708
|
const requestedDebug = typeof raw.debug === "boolean" ? raw.debug : false;
|
|
28647
28709
|
const needsLocationEvidence = proxyMode === "location" && Boolean(proxyOpts.location);
|
|
28648
|
-
const
|
|
28710
|
+
const requestedMaxAttempts = raw.maxAttempts;
|
|
28711
|
+
const maxAttempts = typeof requestedMaxAttempts === "number" && Number.isInteger(requestedMaxAttempts) && requestedMaxAttempts >= 1 ? requestedMaxAttempts : maxAttemptsForProxyMode(proxyMode) + 1;
|
|
28649
28712
|
const serializer = new OutputSerializer();
|
|
28650
28713
|
let lastError = null;
|
|
28651
28714
|
let effectiveProxyMode = proxyMode;
|
|
@@ -29723,7 +29786,7 @@ var PACKAGE_VERSION;
|
|
|
29723
29786
|
var init_version = __esm({
|
|
29724
29787
|
"src/version.ts"() {
|
|
29725
29788
|
"use strict";
|
|
29726
|
-
PACKAGE_VERSION = "0.
|
|
29789
|
+
PACKAGE_VERSION = "0.32.1";
|
|
29727
29790
|
}
|
|
29728
29791
|
});
|
|
29729
29792
|
|
|
@@ -30355,9 +30418,9 @@ var init_mcp_tool_schemas = __esm({
|
|
|
30355
30418
|
gl: import_zod35.z.string().length(2).default("us").describe("Google country code inferred from location."),
|
|
30356
30419
|
hl: import_zod35.z.string().length(2).default("en").describe("Language inferred from user request."),
|
|
30357
30420
|
maxResults: import_zod35.z.number().int().min(1).max(50).default(10).describe("Number of candidates to return. Default 10, maximum 50."),
|
|
30358
|
-
includeServices: import_zod35.z.boolean().default(false).describe("Open each returned
|
|
30359
|
-
proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Leave unset for the default
|
|
30360
|
-
proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override when proxyMode is location."),
|
|
30421
|
+
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."),
|
|
30422
|
+
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."),
|
|
30423
|
+
proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe("Optional US ZIP override, only used when proxyMode is location."),
|
|
30361
30424
|
debug: import_zod35.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics.")
|
|
30362
30425
|
};
|
|
30363
30426
|
DirectoryWorkflowInputSchema = {
|
|
@@ -30371,7 +30434,7 @@ var init_mcp_tool_schemas = __esm({
|
|
|
30371
30434
|
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)."),
|
|
30372
30435
|
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."),
|
|
30373
30436
|
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."),
|
|
30374
|
-
proxyMode: import_zod35.z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE).describe("Proxy behavior per city search. Leave unset for the
|
|
30437
|
+
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."),
|
|
30375
30438
|
proxyZip: import_zod35.z.string().regex(/^\d{5}$/).optional().describe("Optional ZIP override for proxy targeting; normally omitted."),
|
|
30376
30439
|
debug: import_zod35.z.boolean().default(false).describe("Include sanitized browser/proxy diagnostics.")
|
|
30377
30440
|
};
|
|
@@ -32191,7 +32254,7 @@ function registerPaaExtractorMcpTools(server, executor, options = {}) {
|
|
|
32191
32254
|
}, async (input) => formatMapsPlaceIntel(await executor.mapsPlaceIntel(input), input));
|
|
32192
32255
|
server.registerTool("maps_search", {
|
|
32193
32256
|
title: "Google Maps Business Search",
|
|
32194
|
-
description: "Search Google local results for multiple businesses by category, niche, or local market \u2014 leads, prospects, competitors, or beyond the 3-pack.
|
|
32257
|
+
description: "Search Google local results for multiple businesses by category, niche, or local market \u2014 leads, prospects, competitors, or beyond the 3-pack. Reaches the local-results list from the organic page and paginates it, returning up to 50 candidates (default 10) with names, place URLs, CIDs, and ratings. Leave proxyMode unset. Set includeServices to also open each business profile for its services and areas served; review cards are never collected by this tool.",
|
|
32195
32258
|
inputSchema: MapsSearchInputSchema,
|
|
32196
32259
|
outputSchema: recordOutputSchema("maps_search", MapsSearchOutputSchema),
|
|
32197
32260
|
annotations: liveWebToolAnnotations("Google Maps Business Search")
|