mcpscraper-sdk 0.34.0 → 0.35.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 CHANGED
@@ -45,7 +45,7 @@ Current Google search pricing is 60 Credits per SERP search and 400 Credits plus
45
45
 
46
46
  ## API surface
47
47
 
48
- `client.tools` is the generated, typed 339-tool MCP surface. It includes 238 MCP Scraper tools and all 101 mirrored Memory tools from `contracts/mcp.tools.json`. Those output types come from the versioned complete server build manifest; the compact live MCP `tools/list` response intentionally omits output schemas and is not a code-generation source.
48
+ `client.tools` is the generated, typed 346-tool MCP surface from `contracts/mcp.tools.json`, including the governed personal-assistant namespace.
49
49
 
50
50
  For multimodal results such as `meta_ad_creative_media`, call `client.tools.callToolResult(...)` to preserve native MCP image/audio/resource blocks. `callTool(...)` remains backward-compatible and returns the parsed structured or text value.
51
51
 
@@ -87,7 +87,52 @@ Search Console also provides six API-only batches through those connection bridg
87
87
 
88
88
  Integrations are included with an active Starter plan or higher: OAuth connect/reconnect and direct connected-service reads, approved actions, exports, and snapshots do not currently have an extra connection-operation debit. Scheduled Actions use the shared Credit balance at 75 Credits per started occurrence; agent-mode runs also add 1.5 times OpenRouter's actual reported model cost. Inspect the live policy with `await client.tools.schedule.getScheduleStatus()`.
89
89
 
90
- Core operations are flat on the client: `searchSerp`, `harvestPaa`, `extractUrl`, `mapSiteUrls`, `extractSite`, `auditSite`, `getExtractSiteStatus`, `readExtractSiteExport`, `readExtractSiteImage`, `listJobs`, `getJob`, `getHistory`, `getLedger`.
90
+ Core operations are flat on the client: `startHarvest`, `searchSerp`, `harvestPaa`, `extractUrl`, `mapSiteUrls`, `extractSite`, `auditSite`, `getExtractSiteStatus`, `archiveRead`, `listJobs`, `getJob`, `getHistory`, `getLedger`.
91
+
92
+ ### Durable acquisition
93
+
94
+ Long-running agents can start SERP/PAA work once and poll the provider-owned job
95
+ instead of holding one synchronous request open:
96
+
97
+ ```ts
98
+ const started = await client.startHarvest({
99
+ query: 'roofers dallas',
100
+ location: 'Dallas, TX',
101
+ serpOnly: true,
102
+ })
103
+
104
+ let job
105
+ do {
106
+ await new Promise(resolve => setTimeout(resolve, 2_000))
107
+ job = await client.getJob(started.job_id, { timeoutMs: 30_000 })
108
+ } while (job.status === 'pending' || job.status === 'running')
109
+
110
+ if (job.status !== 'done') throw new Error(job.error ?? `Harvest ${job.status}`)
111
+ console.log(job.result)
112
+ ```
113
+
114
+ Background site extraction accepts a caller-owned idempotency key, and the
115
+ archive reader exposes the resulting ZIP without switching to the MCP surface:
116
+
117
+ ```ts
118
+ const crawl = await client.extractSite(
119
+ { url: 'https://example.com', background: true, formats: ['markdown', 'links', 'json'] },
120
+ { idempotencyKey: 'foundation-run-123:crawl', timeoutMs: 30_000 },
121
+ )
122
+
123
+ const status = await client.getExtractSiteStatus(crawl.jobId)
124
+ const bundle = status.artifacts?.find(artifact => artifact.contentType === 'application/zip')
125
+ if (bundle?.downloadUrl) {
126
+ const pages = await client.archiveRead({ url: bundle.downloadUrl, path: 'pages.jsonl' })
127
+ const pageCorpus = await client.archiveRead({
128
+ url: bundle.downloadUrl,
129
+ pathPrefix: 'pages/',
130
+ maxEntries: 1000,
131
+ maxTotalBytes: 20_000_000,
132
+ })
133
+ console.log(pages.content)
134
+ }
135
+ ```
91
136
 
92
137
  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`, `client.gmail`. The REST Gmail namespace preserves opaque path handles and requires explicit idempotency keys for mutations; the generated `client.tools.connections.gmail*` methods expose the exact MCP input/output contracts.
93
138
 
@@ -137,4 +182,4 @@ npm run generate
137
182
 
138
183
  ## See also
139
184
 
140
- [Repo README](../../README.md) (including complete Gmail and reversible bulk examples) · [`mcpscraper-memory-sdk`](../memory) (Node, full 116-tool direct-memory surface) · [`mcpscraper-sdk` on PyPI](https://pypi.org/project/mcpscraper-sdk/) · [`mcpscraper-cli`](../cli)
185
+ [Repo README](../../README.md) (multi-language examples with real sample output) · [`mcpscraper-memory-sdk`](../memory) (Node, full 121-tool direct-memory surface) · [`mcpscraper-sdk` on PyPI](https://pypi.org/project/mcpscraper-sdk/) · [`mcpscraper-cli`](../cli)
package/dist/index.cjs CHANGED
@@ -196,19 +196,38 @@ var Requester = class {
196
196
  throw error;
197
197
  }
198
198
  }
199
- async call(method, path, body, extraHeaders = {}) {
200
- return (await this.callWithReceipt(method, path, body, extraHeaders)).data;
201
- }
202
- async callWithReceipt(method, path, body, extraHeaders = {}) {
203
- const res = await this.request(`${this.baseUrl}${path}`, {
204
- method,
205
- headers: {
206
- "x-api-key": this.apiKey,
207
- ...body !== void 0 ? { "content-type": "application/json" } : {},
208
- ...extraHeaders
209
- },
210
- body: body !== void 0 ? JSON.stringify(body) : void 0
211
- });
199
+ async call(method, path, body, extraHeaders = {}, options = {}) {
200
+ return (await this.callWithReceipt(method, path, body, extraHeaders, options)).data;
201
+ }
202
+ async callWithReceipt(method, path, body, extraHeaders = {}, options = {}) {
203
+ const requestTimeoutMs = options.timeoutMs ?? this.timeoutMs;
204
+ const timeoutSignal = AbortSignal.timeout(requestTimeoutMs);
205
+ const signal = options.signal ? AbortSignal.any([options.signal, timeoutSignal]) : timeoutSignal;
206
+ let res;
207
+ try {
208
+ res = await this.fetchImpl(`${this.baseUrl}${path}`, {
209
+ method,
210
+ headers: {
211
+ "x-api-key": this.apiKey,
212
+ ...body !== void 0 ? { "content-type": "application/json" } : {},
213
+ ...extraHeaders
214
+ },
215
+ body: body !== void 0 ? JSON.stringify(body) : void 0,
216
+ signal
217
+ });
218
+ } catch (error) {
219
+ if (error instanceof DOMException && (error.name === "TimeoutError" || error.name === "AbortError")) {
220
+ if (options.signal?.aborted && !timeoutSignal.aborted) throw error;
221
+ throw new ScraperApiError(408, {
222
+ error: "mcp_request_timeout",
223
+ error_code: "mcp_request_timeout",
224
+ error_type: "timeout",
225
+ message: `The client stopped waiting after ${Math.round(requestTimeoutMs / 1e3)}s. This does not prove server-side work stopped; use the same Idempotency-Key or poll a returned job before starting a new paid run.`,
226
+ retryable: true
227
+ });
228
+ }
229
+ throw error;
230
+ }
212
231
  const data = await res.json().catch(() => void 0);
213
232
  if (!res.ok) throw new ScraperApiError(res.status, data);
214
233
  return { data, headers: res.headers };
@@ -320,8 +339,8 @@ var MapsNamespace = class {
320
339
  this.r = r;
321
340
  }
322
341
  r;
323
- search(params) {
324
- return this.r.call("POST", "/maps/search", params);
342
+ search(params, options = {}) {
343
+ return this.r.call("POST", "/maps/search", params, {}, options);
325
344
  }
326
345
  place(params) {
327
346
  return this.r.call("POST", "/maps/place", params);
@@ -530,26 +549,45 @@ var ScraperClient = class {
530
549
  }
531
550
  return result;
532
551
  }
533
- searchSerp(params) {
534
- return this.r.call("POST", "/harvest/sync", { ...params, serpOnly: true });
552
+ startHarvest(params, options = {}) {
553
+ return this.r.call(
554
+ "POST",
555
+ "/harvest",
556
+ params,
557
+ {},
558
+ options
559
+ );
560
+ }
561
+ searchSerp(params, options = {}) {
562
+ return this.r.call("POST", "/harvest/sync", { ...params, serpOnly: true }, {}, options);
535
563
  }
536
- harvestPaa(params) {
537
- return this.r.call("POST", "/harvest/sync", params);
564
+ harvestPaa(params, options = {}) {
565
+ return this.r.call("POST", "/harvest/sync", params, {}, options);
538
566
  }
539
567
  extractUrl(params, options = {}) {
540
- return this.r.call("POST", "/extract-url", params, options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : {});
568
+ return this.r.call("POST", "/extract-url", params, {}, options);
541
569
  }
542
- mapSiteUrls(params) {
543
- return this.r.call("POST", "/map-urls", params);
570
+ mapSiteUrls(params, options = {}) {
571
+ return this.r.call("POST", "/map-urls", params, {}, options);
544
572
  }
545
573
  extractSite(params, options = {}) {
546
- return this.r.call("POST", "/extract-site", params, options.idempotencyKey ? { "Idempotency-Key": options.idempotencyKey } : {});
574
+ const headers = options.idempotencyKey === void 0 ? {} : { "Idempotency-Key": options.idempotencyKey };
575
+ return this.r.call("POST", "/extract-site", params, headers, options);
547
576
  }
548
577
  auditSite(params, options = {}) {
549
578
  return this.extractSite(params, options);
550
579
  }
551
- getExtractSiteStatus(id) {
552
- return this.r.call("GET", `/extract-site/status/${encodeURIComponent(id)}`);
580
+ getExtractSiteStatus(id, options = {}) {
581
+ return this.r.call("GET", `/extract-site/status/${encodeURIComponent(id)}`, void 0, {}, options);
582
+ }
583
+ archiveRead(params, options = {}) {
584
+ return this.r.call(
585
+ "POST",
586
+ "/archive/read",
587
+ params,
588
+ {},
589
+ options
590
+ );
553
591
  }
554
592
  readExtractSiteExport(params) {
555
593
  return this.r.call("POST", "/extract-site/read", params);
@@ -560,8 +598,8 @@ var ScraperClient = class {
560
598
  listJobs() {
561
599
  return this.r.call("GET", "/jobs");
562
600
  }
563
- getJob(id) {
564
- return this.r.call("GET", `/jobs/${encodeURIComponent(id)}`);
601
+ getJob(id, options = {}) {
602
+ return this.r.call("GET", `/jobs/${encodeURIComponent(id)}`, void 0, {}, options);
565
603
  }
566
604
  getHistory() {
567
605
  return this.r.call("GET", "/history");