mcp-scraper 0.88.2 → 0.89.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 (84) hide show
  1. package/CHANGELOG.md +41 -2
  2. package/README.md +6 -3
  3. package/dist/analytics-repository-J25XR5E7.js +1 -0
  4. package/dist/bin/api-server.js +2 -41
  5. package/dist/bin/mcp-scraper-cli.js +39 -756
  6. package/dist/bin/mcp-scraper-core.js +1 -60
  7. package/dist/bin/mcp-scraper-install.js +2 -25
  8. package/dist/bin/mcp-stdio-server.js +1 -19
  9. package/dist/bin/paa-harvest.js +1 -41
  10. package/dist/chunk-3GP5CYZX.js +1 -0
  11. package/dist/chunk-4FROKQJN.js +1 -0
  12. package/dist/chunk-57AHYL2O.js +20 -0
  13. package/dist/chunk-5H3MCTTP.js +1 -0
  14. package/dist/chunk-63T4W2LX.js +1271 -0
  15. package/dist/chunk-645LQBE7.js +2595 -0
  16. package/dist/chunk-6QO4F2KC.js +21710 -0
  17. package/dist/chunk-CCYWSJNG.js +16 -0
  18. package/dist/chunk-D6IQJP64.js +84 -0
  19. package/dist/chunk-DGBLGFNJ.js +182 -0
  20. package/dist/chunk-FFPD2DOF.js +59 -0
  21. package/dist/chunk-FXEWHK54.js +1 -0
  22. package/dist/chunk-HE45FFBU.js +1 -0
  23. package/dist/chunk-HUV2WTRW.js +1 -0
  24. package/dist/chunk-IJ2AO7AO.js +102 -0
  25. package/dist/chunk-KJQXUZ4Y.js +4 -0
  26. package/dist/chunk-MEM4D2QN.js +1280 -0
  27. package/dist/chunk-MZN4U5BL.js +1 -0
  28. package/dist/chunk-PRWZNHQB.js +1 -0
  29. package/dist/chunk-QPWPR5XG.js +10 -0
  30. package/dist/chunk-RYNHNEF3.js +73 -0
  31. package/dist/chunk-TMB56NCA.js +1 -0
  32. package/dist/chunk-W2BVJ7S2.js +13 -0
  33. package/dist/chunk-WO3N5FH2.js +5 -0
  34. package/dist/chunk-XLWNEVUZ.js +27 -0
  35. package/dist/chunk-YQZGZBB4.js +1 -0
  36. package/dist/chunk-YUPLOOTB.js +4 -0
  37. package/dist/chunk-ZHORX44A.js +100 -0
  38. package/dist/db-JJWJLAVQ.js +1 -0
  39. package/dist/extract-bundle-TTSEGWYF.js +26 -0
  40. package/dist/gmail-service-34PIJRLK.js +1 -0
  41. package/dist/index.cjs +21838 -6034
  42. package/dist/index.js +18 -315
  43. package/dist/lead-list-enrichment-repository-VJBBMBCG.js +1 -0
  44. package/dist/location-data-repository-W3LPT6G3.js +1 -0
  45. package/dist/server-UEY5YQL6.js +7329 -0
  46. package/dist/site-extract-repository-7W5ZUNPR.js +1 -0
  47. package/dist/worker-ZOTOKG56.js +1 -0
  48. package/package.json +11 -4
  49. package/dist/analytics-repository-GGJJCVVP.js +0 -194
  50. package/dist/chunk-4QMUF6XM.js +0 -1013
  51. package/dist/chunk-6HAV7LCE.js +0 -265
  52. package/dist/chunk-ABF2CGOZ.js +0 -113
  53. package/dist/chunk-C5Z4OFKW.js +0 -404
  54. package/dist/chunk-DNM65UCK.js +0 -299
  55. package/dist/chunk-EQGTEHLZ.js +0 -592
  56. package/dist/chunk-F5GQJWZU.js +0 -732
  57. package/dist/chunk-GGZEC22A.js +0 -215
  58. package/dist/chunk-GXBZXWXB.js +0 -184
  59. package/dist/chunk-IHXAXYIS.js +0 -843
  60. package/dist/chunk-K3Z5AQYE.js +0 -683
  61. package/dist/chunk-K45K75OF.js +0 -6
  62. package/dist/chunk-LFW2FRPJ.js +0 -224
  63. package/dist/chunk-MZDNZQWT.js +0 -2078
  64. package/dist/chunk-NVUKO5NN.js +0 -256
  65. package/dist/chunk-OM7HVEJ3.js +0 -26
  66. package/dist/chunk-OPQIGAFB.js +0 -286
  67. package/dist/chunk-OZJMVCDK.js +0 -16
  68. package/dist/chunk-P7FWOMU7.js +0 -505
  69. package/dist/chunk-PGJQDMC2.js +0 -383
  70. package/dist/chunk-PKZS6SHW.js +0 -33139
  71. package/dist/chunk-RJ7JVYKU.js +0 -68
  72. package/dist/chunk-S24LFPL7.js +0 -5262
  73. package/dist/chunk-T3MZISOF.js +0 -240
  74. package/dist/chunk-UZPTGUDV.js +0 -1915
  75. package/dist/chunk-X623GTBV.js +0 -8290
  76. package/dist/chunk-YXNDOQXN.js +0 -4018
  77. package/dist/db-Z34LPZNR.js +0 -284
  78. package/dist/extract-bundle-565SBZCR.js +0 -1003
  79. package/dist/gmail-service-E6ALS7JG.js +0 -25
  80. package/dist/lead-list-enrichment-repository-36RPVV6N.js +0 -67
  81. package/dist/location-data-repository-WPRG62GE.js +0 -34
  82. package/dist/server-SQZ3A7SY.js +0 -86606
  83. package/dist/site-extract-repository-VYFZASPU.js +0 -69
  84. 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
- };