mcp-scraper 0.88.2 → 0.89.0

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 (87) hide show
  1. package/CHANGELOG.md +36 -15
  2. package/README.md +6 -5
  3. package/THIRD_PARTY_NOTICES.html +203 -0
  4. package/dist/analytics-repository-2BMT5JNE.js +1 -0
  5. package/dist/bin/api-server.js +2 -41
  6. package/dist/bin/mcp-scraper-cli.js +39 -756
  7. package/dist/bin/mcp-scraper-core.js +1 -60
  8. package/dist/bin/mcp-scraper-install.js +2 -25
  9. package/dist/bin/mcp-stdio-server.js +1 -19
  10. package/dist/bin/paa-harvest.js +1 -41
  11. package/dist/chunk-3GP5CYZX.js +1 -0
  12. package/dist/chunk-4AI7DOS7.js +59 -0
  13. package/dist/chunk-4FROKQJN.js +1 -0
  14. package/dist/chunk-7YGVI5J4.js +21710 -0
  15. package/dist/chunk-CCYWSJNG.js +16 -0
  16. package/dist/chunk-CFI6CXIV.js +182 -0
  17. package/dist/chunk-E2WRWV3A.js +1 -0
  18. package/dist/chunk-GMWKPIYX.js +1172 -0
  19. package/dist/chunk-HDPYG3XV.js +102 -0
  20. package/dist/chunk-HE45FFBU.js +1 -0
  21. package/dist/chunk-HUV2WTRW.js +1 -0
  22. package/dist/chunk-KJQXUZ4Y.js +4 -0
  23. package/dist/chunk-L4CGLFPU.js +4 -0
  24. package/dist/chunk-M22MM4N4.js +84 -0
  25. package/dist/chunk-MASR22K4.js +73 -0
  26. package/dist/chunk-MZN4U5BL.js +1 -0
  27. package/dist/chunk-PUHFVA7P.js +1280 -0
  28. package/dist/chunk-QPWPR5XG.js +10 -0
  29. package/dist/chunk-TMB56NCA.js +1 -0
  30. package/dist/chunk-TXENITMS.js +20 -0
  31. package/dist/chunk-W2BVJ7S2.js +13 -0
  32. package/dist/chunk-WO3N5FH2.js +5 -0
  33. package/dist/chunk-WSCGYRWA.js +2595 -0
  34. package/dist/chunk-X54CQLK2.js +1 -0
  35. package/dist/chunk-XLWNEVUZ.js +27 -0
  36. package/dist/chunk-XPZVJIZ2.js +100 -0
  37. package/dist/chunk-YQZGZBB4.js +1 -0
  38. package/dist/chunk-Z2QGQJS2.js +1 -0
  39. package/dist/db-F2MX63GI.js +1 -0
  40. package/dist/extract-bundle-SNUIHM3J.js +26 -0
  41. package/dist/gmail-service-BZ3H75XC.js +1 -0
  42. package/dist/index.cjs +21750 -6045
  43. package/dist/index.d.cts +14 -14
  44. package/dist/index.d.ts +14 -14
  45. package/dist/index.js +18 -315
  46. package/dist/lead-list-enrichment-repository-S2H3U7T7.js +1 -0
  47. package/dist/location-data-repository-OTWHWMV6.js +1 -0
  48. package/dist/server-RFR2A5UJ.js +7303 -0
  49. package/dist/site-extract-repository-SE776XDC.js +1 -0
  50. package/dist/worker-XUDSM3AL.js +1 -0
  51. package/package.json +17 -124
  52. package/dist/analytics-repository-GGJJCVVP.js +0 -194
  53. package/dist/chunk-4QMUF6XM.js +0 -1013
  54. package/dist/chunk-6HAV7LCE.js +0 -265
  55. package/dist/chunk-ABF2CGOZ.js +0 -113
  56. package/dist/chunk-C5Z4OFKW.js +0 -404
  57. package/dist/chunk-DNM65UCK.js +0 -299
  58. package/dist/chunk-EQGTEHLZ.js +0 -592
  59. package/dist/chunk-F5GQJWZU.js +0 -732
  60. package/dist/chunk-GGZEC22A.js +0 -215
  61. package/dist/chunk-GXBZXWXB.js +0 -184
  62. package/dist/chunk-IHXAXYIS.js +0 -843
  63. package/dist/chunk-K3Z5AQYE.js +0 -683
  64. package/dist/chunk-K45K75OF.js +0 -6
  65. package/dist/chunk-LFW2FRPJ.js +0 -224
  66. package/dist/chunk-MZDNZQWT.js +0 -2078
  67. package/dist/chunk-NVUKO5NN.js +0 -256
  68. package/dist/chunk-OM7HVEJ3.js +0 -26
  69. package/dist/chunk-OPQIGAFB.js +0 -286
  70. package/dist/chunk-OZJMVCDK.js +0 -16
  71. package/dist/chunk-P7FWOMU7.js +0 -505
  72. package/dist/chunk-PGJQDMC2.js +0 -383
  73. package/dist/chunk-PKZS6SHW.js +0 -33139
  74. package/dist/chunk-RJ7JVYKU.js +0 -68
  75. package/dist/chunk-S24LFPL7.js +0 -5262
  76. package/dist/chunk-T3MZISOF.js +0 -240
  77. package/dist/chunk-UZPTGUDV.js +0 -1915
  78. package/dist/chunk-X623GTBV.js +0 -8290
  79. package/dist/chunk-YXNDOQXN.js +0 -4018
  80. package/dist/db-Z34LPZNR.js +0 -284
  81. package/dist/extract-bundle-565SBZCR.js +0 -1003
  82. package/dist/gmail-service-E6ALS7JG.js +0 -25
  83. package/dist/lead-list-enrichment-repository-36RPVV6N.js +0 -67
  84. package/dist/location-data-repository-WPRG62GE.js +0 -34
  85. package/dist/server-SQZ3A7SY.js +0 -86606
  86. package/dist/site-extract-repository-VYFZASPU.js +0 -69
  87. package/dist/worker-LDCAULWL.js +0 -146
@@ -1,215 +0,0 @@
1
- // src/api/url-utils.ts
2
- import { isIP } from "net";
3
- import { lookup } from "dns/promises";
4
- import ipaddr from "ipaddr.js";
5
- function unbracketIpLiteral(value) {
6
- return value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
7
- }
8
- function isPrivateIpAddress(address) {
9
- const normalized = unbracketIpLiteral(address);
10
- if (!isIP(normalized)) return false;
11
- try {
12
- const parsed = ipaddr.parse(normalized);
13
- const isExtraNonGlobalIpv4 = (ipv4) => {
14
- const extraNonGlobal = [
15
- ["192.0.0.0", 24],
16
- ["192.0.2.0", 24],
17
- ["198.18.0.0", 15],
18
- ["198.51.100.0", 24],
19
- ["203.0.113.0", 24]
20
- ];
21
- return extraNonGlobal.some(([network, bits]) => ipv4.match(ipaddr.parse(network), bits));
22
- };
23
- if (parsed instanceof ipaddr.IPv6 && parsed.isIPv4MappedAddress()) {
24
- const mapped = parsed.toIPv4Address();
25
- return mapped.range() !== "unicast" || isExtraNonGlobalIpv4(mapped);
26
- }
27
- if (parsed instanceof ipaddr.IPv4) {
28
- if (isExtraNonGlobalIpv4(parsed)) return true;
29
- }
30
- return parsed.range() !== "unicast";
31
- } catch {
32
- return true;
33
- }
34
- }
35
- async function resolvesToPrivateAddress(hostname) {
36
- const host = unbracketIpLiteral(hostname.toLowerCase());
37
- if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".local")) return true;
38
- if (isPrivateIpAddress(host)) return true;
39
- try {
40
- const addresses = await lookup(host, { all: true, verbatim: true });
41
- return addresses.length === 0 || addresses.some((entry) => isPrivateIpAddress(entry.address));
42
- } catch {
43
- return true;
44
- }
45
- }
46
- async function validatePublicHttpUrl(raw, opts) {
47
- let parsed;
48
- try {
49
- parsed = new URL(raw.trim());
50
- } catch {
51
- return { error: `Invalid ${opts.field}` };
52
- }
53
- const allowedProtocols = opts.requireHttps ? ["https:"] : ["http:", "https:"];
54
- if (!allowedProtocols.includes(parsed.protocol)) {
55
- return { error: opts.requireHttps ? `${opts.field} must use https` : `${opts.field} must use http or https` };
56
- }
57
- if (await resolvesToPrivateAddress(parsed.hostname)) {
58
- return { error: `${opts.field} must resolve to a public internet host` };
59
- }
60
- return { parsed };
61
- }
62
-
63
- // src/lib/html-document.ts
64
- import { load } from "cheerio";
65
- var REMOVED_CONTENT = "script,style,noscript,svg,iframe,canvas,nav,header,footer,aside";
66
- var MAX_CONTENT_URL_ATTRIBUTE_CHARS = 4096;
67
- function normalizedText(value) {
68
- return (value ?? "").replace(/\s+/g, " ").trim();
69
- }
70
- function parseJsonLd(raw) {
71
- const clean = raw.replace(/[\x00-\x09\x0b\x0c\x0e-\x1f]/g, " ").trim();
72
- if (!clean) return null;
73
- try {
74
- return JSON.parse(clean);
75
- } catch (error) {
76
- const position = /at position (\d+)/.exec(error instanceof Error ? error.message : "")?.[1];
77
- if (!position) return null;
78
- try {
79
- return JSON.parse(clean.slice(0, Number(position)));
80
- } catch {
81
- return null;
82
- }
83
- }
84
- }
85
- function collectSchemaTypes(value, output, remaining = { value: 2e3 }) {
86
- if (remaining.value-- <= 0 || value == null) return;
87
- if (Array.isArray(value)) {
88
- for (const item of value) collectSchemaTypes(item, output, remaining);
89
- return;
90
- }
91
- if (typeof value !== "object") return;
92
- const record = value;
93
- const type = record["@type"];
94
- if (typeof type === "string" && type) output.add(type);
95
- if (Array.isArray(type)) {
96
- for (const item of type) if (typeof item === "string" && item) output.add(item);
97
- }
98
- if (Array.isArray(record["@graph"])) collectSchemaTypes(record["@graph"], output, remaining);
99
- }
100
- function contentRoot($) {
101
- const main = $("main").first();
102
- if (main.length) return main;
103
- const article = $("article").first();
104
- if (article.length) return article;
105
- const body = $("body").first();
106
- return body.length ? body : $.root();
107
- }
108
- function numericAttribute(element, name) {
109
- const value = Number(element.attr(name) ?? 0);
110
- return Number.isFinite(value) && value > 0 ? value : null;
111
- }
112
- function loadHtmlDocument(sourceHtml) {
113
- const $ = load(sourceHtml);
114
- const meta = {};
115
- $("meta").each((_index, element) => {
116
- const node = $(element);
117
- const key = normalizedText(node.attr("name") ?? node.attr("property")).toLowerCase();
118
- const content = normalizedText(node.attr("content"));
119
- if (key && content) meta[key] = content;
120
- });
121
- const headings = [];
122
- $("h1,h2,h3,h4,h5,h6").each((_index, element) => {
123
- const node = $(element);
124
- const text = normalizedText(node.text());
125
- if (text) headings.push({ level: Number(element.tagName.slice(1)), text });
126
- });
127
- const schema = [];
128
- const schemaTypeSet = /* @__PURE__ */ new Set();
129
- $('script[type="application/ld+json"]').each((_index, element) => {
130
- const parsed = parseJsonLd($(element).text());
131
- if (parsed == null) return;
132
- if (Array.isArray(parsed)) schema.push(...parsed);
133
- else schema.push(parsed);
134
- collectSchemaTypes(parsed, schemaTypeSet);
135
- });
136
- const microdataTypes = /* @__PURE__ */ new Set();
137
- $("[itemtype]").each((_index, element) => {
138
- const itemtype = $(element).attr("itemtype") ?? "";
139
- for (const value of itemtype.split(/\s+/)) {
140
- try {
141
- const url = new URL(value);
142
- if (url.hostname === "schema.org" || url.hostname === "www.schema.org") {
143
- const type = url.pathname.replace(/^\/+/, "");
144
- if (type) microdataTypes.add(type);
145
- }
146
- } catch {
147
- }
148
- }
149
- });
150
- const root = contentRoot($).clone();
151
- root.find(REMOVED_CONTENT).remove();
152
- root.find("[href],[src],[srcset],[data-src],[data-srcset]").each((_index, element) => {
153
- const node = $(element);
154
- for (const attribute of ["href", "src", "srcset", "data-src", "data-srcset"]) {
155
- const value = node.attr(attribute);
156
- if (value && value.length > MAX_CONTENT_URL_ATTRIBUTE_CHARS) node.removeAttr(attribute);
157
- }
158
- });
159
- root.find("img").each((_index, element) => {
160
- const image = $(element);
161
- const src = image.attr("src");
162
- if (!src || src.startsWith("data:")) {
163
- const lazy = image.attr("data-src") ?? image.attr("data-lazy-src") ?? image.attr("data-original");
164
- if (lazy) image.attr("src", lazy);
165
- }
166
- });
167
- const mainHtml = root.html() ?? "";
168
- const mainText = normalizedText(root.text());
169
- const links = [];
170
- $("a[href]").each((_index, element) => {
171
- const node = $(element);
172
- const href = normalizedText(node.attr("href"));
173
- if (!href) return;
174
- links.push({
175
- href,
176
- text: normalizedText(node.text()),
177
- rel: normalizedText(node.attr("rel")).toLowerCase() || null
178
- });
179
- });
180
- const images = [];
181
- $("img").each((_index, element) => {
182
- const node = $(element);
183
- const attributes = Object.fromEntries(Object.entries(element.attribs ?? {}).map(([key, value]) => [key.toLowerCase(), value]));
184
- images.push({
185
- src: node.attr("src") ?? node.attr("data-src") ?? node.attr("data-lazy-src") ?? node.attr("data-original") ?? null,
186
- srcset: node.attr("srcset") ?? node.attr("data-srcset") ?? null,
187
- alt: node.attr("alt") ?? null,
188
- width: numericAttribute(node, "width"),
189
- height: numericAttribute(node, "height"),
190
- attributes
191
- });
192
- });
193
- return {
194
- $,
195
- sourceHtml,
196
- title: normalizedText($("title").first().text()) || null,
197
- meta,
198
- headings,
199
- schema,
200
- schemaTypes: [...schemaTypeSet],
201
- microdataTypes: [...microdataTypes],
202
- canonicalUrl: normalizedText($('link[rel~="canonical"]').first().attr("href")) || null,
203
- mainHtml,
204
- mainText,
205
- bodyClass: $("body").first().attr("class") ?? "",
206
- links,
207
- images
208
- };
209
- }
210
-
211
- export {
212
- isPrivateIpAddress,
213
- validatePublicHttpUrl,
214
- loadHtmlDocument
215
- };
@@ -1,184 +0,0 @@
1
- // src/schemas.ts
2
- import { z } from "zod";
3
- var DEFAULT_PROXY_MODE = "none";
4
- var DEFAULT_MAPS_PROXY_MODE = "none";
5
- var HarvestOptionsSchema = z.object({
6
- query: z.string().min(1),
7
- location: z.string().optional(),
8
- gl: z.string().length(2).default("us"),
9
- hl: z.string().length(2).default("en"),
10
- device: z.enum(["desktop", "mobile"]).default("desktop"),
11
- proxyMode: z.enum(["location", "configured", "none"]).default(DEFAULT_PROXY_MODE),
12
- proxyZip: z.string().regex(/^\d{5}$/).optional(),
13
- keepDefaultProxy: z.boolean().optional(),
14
- requireUsEgress: z.boolean().optional(),
15
- maxAttempts: z.number().int().min(1).max(12).optional(),
16
- debug: z.boolean().default(false),
17
- depth: z.number().int().min(1).max(30).default(3),
18
- maxQuestions: z.number().int().min(1).max(1e3).default(100),
19
- headless: z.boolean().default(false),
20
- profileDir: z.string().optional(),
21
- proxy: z.string().url().optional(),
22
- kernelApiKey: z.string().optional(),
23
- kernelProxyId: z.string().optional(),
24
- kernelProfileName: z.string().optional(),
25
- kernelProfileSaveChanges: z.boolean().optional(),
26
- kernelStealth: z.boolean().optional(),
27
- serpIdentity: z.string().regex(/^[a-z0-9][a-z0-9_-]{0,63}$/).optional(),
28
- kernelProxyResolution: z.unknown().optional(),
29
- outputDir: z.string().default("./paa-output"),
30
- format: z.enum(["json", "csv", "both"]).default("both"),
31
- serpOnly: z.boolean().default(false),
32
- questionsOnly: z.boolean().default(false),
33
- questionGrowthRecoveryRounds: z.number().int().min(0).max(4).default(2),
34
- pages: z.number().int().min(1).max(2).default(1),
35
- includeAllSerpFeatures: z.boolean().default(false),
36
- includeLocalPack: z.boolean().default(false),
37
- includeForums: z.boolean().default(false),
38
- includeVideos: z.boolean().default(false),
39
- includeAiOverview: z.boolean().default(false),
40
- includeWhatPeopleSaying: z.boolean().default(false),
41
- includeShortVideos: z.boolean().default(false),
42
- recency: z.enum(["day", "week", "month", "year"]).optional(),
43
- softDeadlineMs: z.number().optional()
44
- });
45
- function recencyToTbs(recency) {
46
- switch (recency) {
47
- case "day":
48
- return "qdr:d";
49
- case "week":
50
- return "qdr:w";
51
- case "month":
52
- return "qdr:m";
53
- case "year":
54
- return "qdr:y";
55
- default:
56
- return void 0;
57
- }
58
- }
59
- var MapsPlaceOptionsSchema = z.object({
60
- businessName: z.string().min(1),
61
- location: z.string().min(1),
62
- gl: z.string().length(2).default("us"),
63
- hl: z.string().length(2).default("en"),
64
- includeReviews: z.boolean().default(false),
65
- maxReviews: z.number().int().min(1).max(500).default(50),
66
- includeServices: z.boolean().default(false),
67
- includeImages: z.boolean().default(false),
68
- imageScope: z.enum(["owner", "all"]).default("all"),
69
- maxImages: z.number().int().min(1).max(250).default(100),
70
- maxInlineImages: z.number().int().min(0).max(5).default(3),
71
- kernelApiKey: z.string().optional(),
72
- kernelProxyId: z.string().optional(),
73
- headless: z.boolean().default(true)
74
- });
75
- var MapsSearchOptionsSchema = z.object({
76
- query: z.string().min(1),
77
- location: z.string().optional(),
78
- gl: z.string().length(2).default("us"),
79
- hl: z.string().length(2).default("en"),
80
- maxResults: z.number().int().min(1).max(50).default(10),
81
- includeServices: z.boolean().default(false),
82
- proxyMode: z.enum(["location", "configured", "none"]).default(DEFAULT_MAPS_PROXY_MODE),
83
- proxyZip: z.string().regex(/^\d{5}$/).optional(),
84
- serpRedirect: z.boolean().optional(),
85
- forceDirectEgress: z.boolean().optional(),
86
- debug: z.boolean().default(false),
87
- kernelApiKey: z.string().optional(),
88
- kernelProxyId: z.string().optional(),
89
- kernelProxyResolution: z.unknown().optional(),
90
- headless: z.boolean().default(true)
91
- });
92
- var RawPAAItemSchema = z.object({
93
- questionId: z.string().min(1),
94
- googleLinkId: z.string().nullable(),
95
- googleEvidenceId: z.string().nullable(),
96
- question: z.string().min(1),
97
- answer: z.string().optional(),
98
- sourceTitle: z.string().optional(),
99
- sourceSite: z.string().optional(),
100
- sourceCite: z.string().optional(),
101
- sources: z.array(z.object({
102
- title: z.string().nullable(),
103
- site: z.string().nullable(),
104
- url: z.string().min(1),
105
- rawUrl: z.string().min(1),
106
- resolvedUrl: z.string().nullable(),
107
- linkType: z.enum(["plain", "google_url_redirect", "google_goto_redirect"]),
108
- resolutionStatus: z.enum(["not_needed", "resolved", "unresolved", "rejected"])
109
- })).default([])
110
- });
111
- var RawMapsOverviewSchema = z.object({
112
- name: z.string().nullable(),
113
- rating: z.string().nullable(),
114
- reviewCount: z.string().nullable(),
115
- category: z.string().nullable(),
116
- address: z.string().nullable(),
117
- hoursSummary: z.string().nullable(),
118
- phone: z.string().nullable(),
119
- phoneDisplay: z.string().nullable(),
120
- website: z.string().nullable(),
121
- plusCode: z.string().nullable(),
122
- bookingUrl: z.string().nullable()
123
- });
124
- var RawMapsHoursRowSchema = z.object({
125
- day: z.string(),
126
- hours: z.string()
127
- });
128
- var RawMapsReviewStatsSchema = z.object({
129
- reviewHistogram: z.array(z.object({
130
- stars: z.number(),
131
- count: z.string()
132
- })),
133
- reviewTopics: z.array(z.object({
134
- label: z.string(),
135
- count: z.string()
136
- }))
137
- });
138
- var RawMapsReviewCardSchema = z.object({
139
- reviewId: z.string(),
140
- author: z.string().nullable(),
141
- stars: z.string().nullable(),
142
- date: z.string().nullable(),
143
- text: z.string().nullable(),
144
- ownerResponse: z.string().nullable()
145
- });
146
- var RawMapsAboutAttributeSchema = z.object({
147
- section: z.string(),
148
- attribute: z.string()
149
- });
150
-
151
- // src/output/memory-library-sink.ts
152
- async function postToMemoryLibrary(args) {
153
- const key = process.env.MCP_SCRAPER_API_KEY?.trim();
154
- const baseUrl = (process.env.MCP_SCRAPER_BASE_URL ?? "https://mcpscraper.dev").replace(/\/$/, "");
155
- if (!key) return;
156
- try {
157
- const res = await fetch(`${baseUrl}/memory/mcp-call`, {
158
- method: "POST",
159
- headers: { "content-type": "application/json", "x-api-key": key },
160
- body: JSON.stringify({ toolName: "libraryIngestTool", args })
161
- });
162
- const body = await res.json().catch(() => null);
163
- if (!res.ok || body?.ok === false) {
164
- console.warn("[memory-library-sink] ingest not accepted:", res.status, body?.error ?? "");
165
- }
166
- } catch (err) {
167
- console.warn("[memory-library-sink] ingest failed:", err?.message);
168
- }
169
- }
170
-
171
- export {
172
- DEFAULT_PROXY_MODE,
173
- DEFAULT_MAPS_PROXY_MODE,
174
- HarvestOptionsSchema,
175
- recencyToTbs,
176
- MapsPlaceOptionsSchema,
177
- MapsSearchOptionsSchema,
178
- RawPAAItemSchema,
179
- RawMapsOverviewSchema,
180
- RawMapsHoursRowSchema,
181
- RawMapsReviewStatsSchema,
182
- RawMapsAboutAttributeSchema,
183
- postToMemoryLibrary
184
- };