scrapeunblocker-mcp 0.2.0 → 0.2.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 (2) hide show
  1. package/dist/index.js +45 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@
4
4
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
5
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
6
  import { z } from "zod";
7
- import { ScrapeUnblockerClient } from "scrapeunblocker";
8
- var VERSION = "0.2.0";
7
+ import { APIError, ScrapeUnblockerClient } from "scrapeunblocker";
8
+ var VERSION = "0.2.1";
9
9
  var DEFAULT_BASE_URL = "https://api.scrapeunblocker.com";
10
10
  var API_KEY_HEADER = "x-scrapeunblocker-key";
11
11
  function resolveApiKey() {
@@ -28,6 +28,31 @@ function errorText(err) {
28
28
  if (err instanceof Error) return err.message;
29
29
  return String(err);
30
30
  }
31
+ var TARGET_GONE = /* @__PURE__ */ new Set([404, 410]);
32
+ function targetGoneStatus(status, originStatus) {
33
+ const origin = Number(originStatus);
34
+ if (TARGET_GONE.has(origin)) return origin;
35
+ return TARGET_GONE.has(status) ? status : null;
36
+ }
37
+ function targetGoneText(url, code, page) {
38
+ const reason = code === 410 ? "Gone" : "Not Found";
39
+ const head = `The target page does not exist: ${url} answered HTTP ${code} (${reason}). This is the website's own answer, not a block or an API failure. The call was billed, and retrying returns the same result - check the URL instead.`;
40
+ return page.trim() ? `${head}
41
+
42
+ The target's own ${code} page follows:
43
+
44
+ ${page}` : `${head}
45
+
46
+ The target sent no page body.`;
47
+ }
48
+ function errorResult(url, err) {
49
+ const gone = err instanceof APIError ? targetGoneStatus(err.statusCode) : null;
50
+ if (gone !== null) {
51
+ const body = err instanceof APIError ? err.body ?? "" : "";
52
+ return { content: [{ type: "text", text: targetGoneText(url, gone, body) }] };
53
+ }
54
+ return { content: [{ type: "text", text: errorText(err) }], isError: true };
55
+ }
31
56
  async function getPageSourceRaw(params) {
32
57
  const apiKey = resolveApiKey();
33
58
  if (!apiKey) throw new Error(MISSING_KEY_MESSAGE);
@@ -46,7 +71,12 @@ async function getPageSourceRaw(params) {
46
71
  }
47
72
  });
48
73
  const text = await response.text();
49
- return { status: response.status, ok: response.ok, text };
74
+ return {
75
+ status: response.status,
76
+ ok: response.ok,
77
+ text,
78
+ originStatus: response.headers.get("x-origin-status")
79
+ };
50
80
  }
51
81
  var server = new McpServer({
52
82
  name: "scrapeunblocker",
@@ -159,6 +189,10 @@ server.registerTool(
159
189
  time_sleep: args.sleep_seconds,
160
190
  steps: JSON.stringify(args.steps)
161
191
  });
192
+ const gone = targetGoneStatus(res.status, res.originStatus);
193
+ if (gone !== null) {
194
+ return { content: [{ type: "text", text: targetGoneText(args.url, gone, res.text) }] };
195
+ }
162
196
  if (res.ok) {
163
197
  return { content: [{ type: "text", text: res.text }] };
164
198
  }
@@ -192,7 +226,7 @@ Fix the selector or step (use list_elements to inspect the page) and retry. The
192
226
  isError: true
193
227
  };
194
228
  } catch (err) {
195
- return { content: [{ type: "text", text: errorText(err) }], isError: true };
229
+ return errorResult(args.url, err);
196
230
  }
197
231
  }
198
232
  );
@@ -213,7 +247,8 @@ server.registerTool(
213
247
  list_elements: true,
214
248
  proxy_country: args.proxy_country
215
249
  });
216
- if (!res.ok) {
250
+ const gone = targetGoneStatus(res.status, res.originStatus);
251
+ if (!res.ok && gone === null) {
217
252
  return {
218
253
  content: [
219
254
  {
@@ -229,9 +264,12 @@ server.registerTool(
229
264
  out = JSON.stringify(JSON.parse(res.text), null, 2);
230
265
  } catch {
231
266
  }
267
+ if (gone !== null) {
268
+ return { content: [{ type: "text", text: targetGoneText(args.url, gone, out) }] };
269
+ }
232
270
  return { content: [{ type: "text", text: out }] };
233
271
  } catch (err) {
234
- return { content: [{ type: "text", text: errorText(err) }], isError: true };
272
+ return errorResult(args.url, err);
235
273
  }
236
274
  }
237
275
  );
@@ -258,7 +296,7 @@ server.registerTool(
258
296
  content: [{ type: "text", text: JSON.stringify(parsed, null, 2) }]
259
297
  };
260
298
  } catch (err) {
261
- return { content: [{ type: "text", text: errorText(err) }], isError: true };
299
+ return errorResult(args.url, err);
262
300
  }
263
301
  }
264
302
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scrapeunblocker-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "mcpName": "com.scrapeunblocker/scrapeunblocker-mcp",
5
5
  "description": "Model Context Protocol (MCP) server for ScrapeUnblocker - lets Claude fetch any web page's HTML (or AI-parsed JSON) through the ScrapeUnblocker anti-bot API, using your own API key.",
6
6
  "keywords": [