mcpscraper-sdk 0.3.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.
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # mcpscraper-sdk
2
+
3
+ Official TypeScript/JavaScript client for the [mcpscraper.dev](https://mcpscraper.dev) REST API — SERP search, People-Also-Ask harvesting, single-page and whole-site extraction, YouTube, Facebook/Google Ads Transparency, Instagram, Reddit, video breakdown, Google Maps, and directory/rank-tracking workflows.
4
+
5
+ This is a thin HTTP client generated against [`../../contracts/scraper.openapi.yaml`](../../contracts/scraper.openapi.yaml), the public contract for the hosted API. It contains no scraping, proxy, or billing logic — only typed request/response plumbing.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install mcpscraper-sdk
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```ts
16
+ import { ScraperClient, ScraperApiError } from 'mcpscraper-sdk'
17
+
18
+ const client = new ScraperClient({ apiKey: process.env.MCPSCRAPER_API_KEY! })
19
+
20
+ const serp = await client.searchSerp({ query: 'roof repair Denver' })
21
+
22
+ try {
23
+ const places = await client.maps.search({ query: 'roofers', location: 'Denver, CO' })
24
+ console.log(places)
25
+ } catch (err) {
26
+ if (err instanceof ScraperApiError && err.isInsufficientBalance()) {
27
+ console.error(`Need ${err.body.required_credits} credits, have ${err.body.balance_credits}. Top up: ${err.body.topup_url}`)
28
+ } else {
29
+ throw err
30
+ }
31
+ }
32
+ ```
33
+
34
+ ## Errors
35
+
36
+ Every non-2xx response throws a `ScraperApiError` with `status`, `code`, and the raw response `body`. Two cases have typed narrowing helpers:
37
+
38
+ - `err.isInsufficientBalance()` — narrows `err.body` to `{ balance_credits, required_credits, topup_url, ... }`.
39
+ - `err.isConcurrencyLimitExceeded()` — narrows `err.body` to `{ active, limit, retryable, ... }`.
40
+
41
+ ## API surface
42
+
43
+ Core operations are flat on the client: `searchSerp`, `harvestPaa`, `extractUrl`, `mapSiteUrls`, `extractSite`, `auditSite`, `getExtractSiteStatus`, `listJobs`, `getJob`, `getHistory`, `getLedger`.
44
+
45
+ Everything else is namespaced by product area, matching the OpenAPI spec's tags: `client.youtube`, `client.screenshot`, `client.facebook`, `client.googleAds`, `client.instagram`, `client.reddit`, `client.video`, `client.maps`, `client.directory`, `client.serpIntelligence`, `client.workflows`.
46
+
47
+ ## Scrape → memory vault
48
+
49
+ `extractUrl` accepts `depositToVault: true` (optionally with `vaultName`) to embed the full scraped body server-side into your mcp-memory vault instead of returning it inline — the response's `memory` field reports `{ deposited, vault, noteId, path, chunks }` (or falls back to a temporary `fileUrl` download if the vault deposit itself fails):
50
+
51
+ ```ts
52
+ const page = await client.extractUrl({ url: 'https://example.com/pricing', depositToVault: true, vaultName: 'competitors' })
53
+ console.log(page.memory) // { deposited: true, vault: 'competitors', noteId: '...', path: '...', chunks: 4 }
54
+ ```
55
+
56
+ ## Memory tools, using only this API key
57
+
58
+ `client.memoryTools` exposes every tool from [`mcpscraper-memory-sdk`](../memory) — access/keys, channels, memory search/CRUD, tables, vaults, facts, schedule, webhooks, video — dispatched through `POST /memory/mcp-call` with your mcpscraper.dev API key. No separate memory key needed; a memory identity is auto-provisioned for your account on first use:
59
+
60
+ ```ts
61
+ const hits = await client.memoryTools.memory.search({ query: 'competitor pricing pages' })
62
+ const vaults = await client.memoryTools.vaults.listVaults({})
63
+ ```
64
+
65
+ Use `mcpscraper-memory-sdk`'s own `MemoryClient` instead if you already have a dedicated `mk_...` memory key and want to talk to `memory.mcpscraper.dev` directly.
66
+
67
+ ## Regenerating types
68
+
69
+ `src/schema.ts` is generated from the OpenAPI spec and checked in. After editing `../../contracts/scraper.openapi.yaml`, regenerate with:
70
+
71
+ ```bash
72
+ npm run generate
73
+ ```
74
+
75
+ ## See also
76
+
77
+ [Repo README](../../README.md) (multi-language examples with real sample output) · [`mcpscraper-memory-sdk`](../memory) (Node, full 85-tool typed surface) · [`mcpscraper-sdk` on PyPI](../scraper-python) (Python) · [`mcpscraper-cli`](../cli)
package/dist/index.cjs ADDED
@@ -0,0 +1,371 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ ScraperApiError: () => ScraperApiError,
24
+ ScraperClient: () => ScraperClient
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/errors.ts
29
+ function readString(body, key) {
30
+ if (body && typeof body === "object" && key in body) {
31
+ const value = body[key];
32
+ if (typeof value === "string") return value;
33
+ }
34
+ return void 0;
35
+ }
36
+ var ScraperApiError = class extends Error {
37
+ status;
38
+ code;
39
+ body;
40
+ constructor(status, body) {
41
+ super(readString(body, "message") ?? `mcpscraper.dev API request failed with status ${status}`);
42
+ this.name = "ScraperApiError";
43
+ this.status = status;
44
+ this.code = readString(body, "error_code") ?? readString(body, "error");
45
+ this.body = body;
46
+ }
47
+ isInsufficientBalance() {
48
+ return this.code === "insufficient_balance";
49
+ }
50
+ isConcurrencyLimitExceeded() {
51
+ return this.code === "concurrency_limit_exceeded";
52
+ }
53
+ isStructuredError() {
54
+ return typeof readString(this.body, "error_type") === "string";
55
+ }
56
+ };
57
+
58
+ // src/client.ts
59
+ var import_mcpscraper_memory_sdk = require("mcpscraper-memory-sdk");
60
+ var Requester = class {
61
+ constructor(apiKey, baseUrl, fetchImpl) {
62
+ this.apiKey = apiKey;
63
+ this.baseUrl = baseUrl;
64
+ this.fetchImpl = fetchImpl;
65
+ }
66
+ apiKey;
67
+ baseUrl;
68
+ fetchImpl;
69
+ async call(method, path, body) {
70
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, {
71
+ method,
72
+ headers: {
73
+ "x-api-key": this.apiKey,
74
+ ...body !== void 0 ? { "content-type": "application/json" } : {}
75
+ },
76
+ body: body !== void 0 ? JSON.stringify(body) : void 0
77
+ });
78
+ const data = await res.json().catch(() => void 0);
79
+ if (!res.ok) throw new ScraperApiError(res.status, data);
80
+ return data;
81
+ }
82
+ async callRaw(method, path) {
83
+ const res = await this.fetchImpl(`${this.baseUrl}${path}`, { method, headers: { "x-api-key": this.apiKey } });
84
+ if (!res.ok) {
85
+ const data = await res.json().catch(() => void 0);
86
+ throw new ScraperApiError(res.status, data);
87
+ }
88
+ return res.arrayBuffer();
89
+ }
90
+ };
91
+ var YoutubeNamespace = class {
92
+ constructor(r) {
93
+ this.r = r;
94
+ }
95
+ r;
96
+ harvest(params) {
97
+ return this.r.call("POST", "/youtube/harvest", params);
98
+ }
99
+ transcribe(params) {
100
+ return this.r.call("POST", "/youtube/transcribe", params);
101
+ }
102
+ };
103
+ var ScreenshotNamespace = class {
104
+ constructor(r) {
105
+ this.r = r;
106
+ }
107
+ r;
108
+ capture(params) {
109
+ return this.r.call("POST", "/screenshot", params);
110
+ }
111
+ };
112
+ var FacebookNamespace = class {
113
+ constructor(r) {
114
+ this.r = r;
115
+ }
116
+ r;
117
+ ad(params) {
118
+ return this.r.call("POST", "/facebook/ad", params);
119
+ }
120
+ pageIntel(params) {
121
+ return this.r.call("POST", "/facebook/page-intel", params);
122
+ }
123
+ adTranscribe(params) {
124
+ return this.r.call("POST", "/facebook/transcribe", params);
125
+ }
126
+ videoTranscribe(params) {
127
+ return this.r.call("POST", "/facebook/video-transcribe", params);
128
+ }
129
+ search(params) {
130
+ return this.r.call("POST", "/facebook/search", params);
131
+ }
132
+ media(params) {
133
+ return this.r.call("POST", "/facebook/media", params);
134
+ }
135
+ };
136
+ var GoogleAdsNamespace = class {
137
+ constructor(r) {
138
+ this.r = r;
139
+ }
140
+ r;
141
+ search(params) {
142
+ return this.r.call("POST", "/google-ads/search", params);
143
+ }
144
+ pageIntel(params) {
145
+ return this.r.call("POST", "/google-ads/page-intel", params);
146
+ }
147
+ transcribe(params) {
148
+ return this.r.call("POST", "/google-ads/transcribe", params);
149
+ }
150
+ };
151
+ var InstagramNamespace = class {
152
+ constructor(r) {
153
+ this.r = r;
154
+ }
155
+ r;
156
+ profileContent(params) {
157
+ return this.r.call("POST", "/instagram/profile-content", params);
158
+ }
159
+ mediaDownload(params) {
160
+ return this.r.call("POST", "/instagram/media-download", params);
161
+ }
162
+ };
163
+ var RedditNamespace = class {
164
+ constructor(r) {
165
+ this.r = r;
166
+ }
167
+ r;
168
+ thread(params) {
169
+ return this.r.call("POST", "/reddit/thread", params);
170
+ }
171
+ };
172
+ var VideoNamespace = class {
173
+ constructor(r) {
174
+ this.r = r;
175
+ }
176
+ r;
177
+ analyze(params) {
178
+ return this.r.call("POST", "/video/analyze", params);
179
+ }
180
+ status(params) {
181
+ return this.r.call("POST", "/video/status", params);
182
+ }
183
+ };
184
+ var MapsNamespace = class {
185
+ constructor(r) {
186
+ this.r = r;
187
+ }
188
+ r;
189
+ search(params) {
190
+ return this.r.call("POST", "/maps/search", params);
191
+ }
192
+ place(params) {
193
+ return this.r.call("POST", "/maps/place", params);
194
+ }
195
+ };
196
+ var DirectoryNamespace = class {
197
+ constructor(r) {
198
+ this.r = r;
199
+ }
200
+ r;
201
+ run(params) {
202
+ return this.r.call("POST", "/directory/run", params);
203
+ }
204
+ };
205
+ var SerpIntelligenceNamespace = class {
206
+ constructor(r) {
207
+ this.r = r;
208
+ }
209
+ r;
210
+ capture(params) {
211
+ return this.r.call("POST", "/serp-intelligence/capture", params);
212
+ }
213
+ pageSnapshots(params) {
214
+ return this.r.call("POST", "/serp-intelligence/page-snapshots", params);
215
+ }
216
+ };
217
+ var WorkflowsNamespace = class {
218
+ constructor(r) {
219
+ this.r = r;
220
+ }
221
+ r;
222
+ listDefinitions() {
223
+ return this.r.call("GET", "/workflows/definitions");
224
+ }
225
+ run(params) {
226
+ return this.r.call("POST", "/workflows/run", params);
227
+ }
228
+ advanceStep(id) {
229
+ return this.r.call("POST", `/workflows/runs/${encodeURIComponent(id)}/step`);
230
+ }
231
+ listRuns() {
232
+ return this.r.call("GET", "/workflows/runs");
233
+ }
234
+ getRun(id) {
235
+ return this.r.call("GET", `/workflows/runs/${encodeURIComponent(id)}`);
236
+ }
237
+ getRunArtifact(id, artifactId) {
238
+ return this.r.callRaw(
239
+ "GET",
240
+ `/workflows/runs/${encodeURIComponent(id)}/artifacts/${encodeURIComponent(artifactId)}`
241
+ );
242
+ }
243
+ createSchedule(params) {
244
+ return this.r.call("POST", "/workflows/schedules", params);
245
+ }
246
+ listSchedules() {
247
+ return this.r.call("GET", "/workflows/schedules");
248
+ }
249
+ patchSchedule(id, params) {
250
+ return this.r.call("PATCH", `/workflows/schedules/${encodeURIComponent(id)}`, params);
251
+ }
252
+ deleteSchedule(id) {
253
+ return this.r.call("DELETE", `/workflows/schedules/${encodeURIComponent(id)}`);
254
+ }
255
+ runScheduleNow(id) {
256
+ return this.r.call("POST", `/workflows/schedules/${encodeURIComponent(id)}/run`);
257
+ }
258
+ };
259
+ var MemoryTools = class {
260
+ access;
261
+ capture;
262
+ channels;
263
+ facts;
264
+ graph;
265
+ library;
266
+ memory;
267
+ recall;
268
+ schedule;
269
+ storage;
270
+ tables;
271
+ tags;
272
+ vaults;
273
+ video;
274
+ webhooks;
275
+ constructor(callTool) {
276
+ this.access = new import_mcpscraper_memory_sdk.AccessNamespace(callTool);
277
+ this.capture = new import_mcpscraper_memory_sdk.CaptureNamespace(callTool);
278
+ this.channels = new import_mcpscraper_memory_sdk.ChannelsNamespace(callTool);
279
+ this.facts = new import_mcpscraper_memory_sdk.FactsNamespace(callTool);
280
+ this.graph = new import_mcpscraper_memory_sdk.GraphNamespace(callTool);
281
+ this.library = new import_mcpscraper_memory_sdk.LibraryNamespace(callTool);
282
+ this.memory = new import_mcpscraper_memory_sdk.MemoryNamespace(callTool);
283
+ this.recall = new import_mcpscraper_memory_sdk.RecallNamespace(callTool);
284
+ this.schedule = new import_mcpscraper_memory_sdk.ScheduleNamespace(callTool);
285
+ this.storage = new import_mcpscraper_memory_sdk.StorageNamespace(callTool);
286
+ this.tables = new import_mcpscraper_memory_sdk.TablesNamespace(callTool);
287
+ this.tags = new import_mcpscraper_memory_sdk.TagsNamespace(callTool);
288
+ this.vaults = new import_mcpscraper_memory_sdk.VaultsNamespace(callTool);
289
+ this.video = new import_mcpscraper_memory_sdk.VideoNamespace(callTool);
290
+ this.webhooks = new import_mcpscraper_memory_sdk.WebhooksNamespace(callTool);
291
+ }
292
+ };
293
+ var ScraperClient = class {
294
+ r;
295
+ youtube;
296
+ screenshot;
297
+ facebook;
298
+ googleAds;
299
+ instagram;
300
+ reddit;
301
+ video;
302
+ maps;
303
+ directory;
304
+ serpIntelligence;
305
+ workflows;
306
+ memoryTools;
307
+ constructor(options) {
308
+ this.r = new Requester(options.apiKey, options.baseUrl ?? "https://mcpscraper.dev", options.fetch ?? globalThis.fetch);
309
+ this.youtube = new YoutubeNamespace(this.r);
310
+ this.screenshot = new ScreenshotNamespace(this.r);
311
+ this.facebook = new FacebookNamespace(this.r);
312
+ this.googleAds = new GoogleAdsNamespace(this.r);
313
+ this.instagram = new InstagramNamespace(this.r);
314
+ this.reddit = new RedditNamespace(this.r);
315
+ this.video = new VideoNamespace(this.r);
316
+ this.maps = new MapsNamespace(this.r);
317
+ this.directory = new DirectoryNamespace(this.r);
318
+ this.serpIntelligence = new SerpIntelligenceNamespace(this.r);
319
+ this.workflows = new WorkflowsNamespace(this.r);
320
+ this.memoryTools = new MemoryTools(this.callMemoryTool.bind(this));
321
+ }
322
+ async callMemoryTool(toolName, args) {
323
+ const result = await this.r.call("POST", "/memory/mcp-call", {
324
+ toolName,
325
+ args: args ?? {}
326
+ });
327
+ if (result && typeof result === "object" && result.ok === false) {
328
+ const failure = result;
329
+ throw new ScraperApiError(200, { message: failure.error, ...failure });
330
+ }
331
+ return result;
332
+ }
333
+ searchSerp(params) {
334
+ return this.r.call("POST", "/harvest/sync", { ...params, serpOnly: true });
335
+ }
336
+ harvestPaa(params) {
337
+ return this.r.call("POST", "/harvest/sync", params);
338
+ }
339
+ extractUrl(params) {
340
+ return this.r.call("POST", "/extract-url", params);
341
+ }
342
+ mapSiteUrls(params) {
343
+ return this.r.call("POST", "/map-urls", params);
344
+ }
345
+ extractSite(params) {
346
+ return this.r.call("POST", "/extract-site", params);
347
+ }
348
+ auditSite(params) {
349
+ return this.extractSite(params);
350
+ }
351
+ getExtractSiteStatus(id) {
352
+ return this.r.call("GET", `/extract-site/status/${encodeURIComponent(id)}`);
353
+ }
354
+ listJobs() {
355
+ return this.r.call("GET", "/jobs");
356
+ }
357
+ getJob(id) {
358
+ return this.r.call("GET", `/jobs/${encodeURIComponent(id)}`);
359
+ }
360
+ getHistory() {
361
+ return this.r.call("GET", "/history");
362
+ }
363
+ getLedger() {
364
+ return this.r.call("GET", "/ledger");
365
+ }
366
+ };
367
+ // Annotate the CommonJS export names for ESM import in node:
368
+ 0 && (module.exports = {
369
+ ScraperApiError,
370
+ ScraperClient
371
+ });