@fouradata/mcp 0.2.11

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.
@@ -0,0 +1,374 @@
1
+ import { request } from "undici";
2
+ import { z } from "zod";
3
+ import { getApiKey } from "../auth.js";
4
+ import { assertPublicTarget, SsrfBlockedError } from "../safe-target.js";
5
+ import { storePayload, THRESHOLD_BYTES } from "../resources.js";
6
+ function extractContentTypeFromHeaderInfo(headers) {
7
+ if (!Array.isArray(headers))
8
+ return null;
9
+ for (const h of headers) {
10
+ if (h && typeof h === "object") {
11
+ const entries = Object.entries(h);
12
+ for (const [k, v] of entries) {
13
+ if (k.toLowerCase() === "content-type") {
14
+ const value = Array.isArray(v) ? v[0] : v;
15
+ if (typeof value === "string")
16
+ return value.split(";")[0]?.trim() ?? null;
17
+ }
18
+ }
19
+ }
20
+ }
21
+ return null;
22
+ }
23
+ // Derive a stable error code from upstream HTTP status + envelope.
24
+ // LLM agents read `code` for retry / classify logic without parsing prose.
25
+ function deriveCode(status, envelope) {
26
+ if (status === 400)
27
+ return "bad_request";
28
+ if (status === 401)
29
+ return "auth_failed";
30
+ if (status === 403)
31
+ return "forbidden";
32
+ if (status === 404)
33
+ return "not_found";
34
+ if (status === 429)
35
+ return "rate_limited";
36
+ if (status === 503) {
37
+ if (envelope.current)
38
+ return "at_capacity";
39
+ const err = typeof envelope.error === "string" ? envelope.error : "";
40
+ if (err.toLowerCase().includes("disabled"))
41
+ return "service_disabled";
42
+ return "service_unavailable";
43
+ }
44
+ if (status >= 500)
45
+ return "upstream_error";
46
+ if (status >= 400)
47
+ return "upstream_client_error";
48
+ // 2xx-with-error-body (Bug 8): curl failures and validate-fail bubble up
49
+ // as HTTP 200 + {error, status: <curl status>, ...}. Caller flags this
50
+ // as an error before reaching us.
51
+ return "upstream_unknown";
52
+ }
53
+ const SINGLE_API_URL = (process.env.FOURA_API_BASE ?? "https://api.foura.ai/api") + "/single/";
54
+ const SingleValidateSchema = z
55
+ .object({
56
+ status: z
57
+ .object({
58
+ accept: z.array(z.number().int()).optional().describe("HTTP status codes to treat as success"),
59
+ fail: z.array(z.number().int()).optional().describe("HTTP status codes to treat as failure"),
60
+ })
61
+ .optional(),
62
+ headers: z
63
+ .object({
64
+ accept: z
65
+ .record(z.string(), z.string())
66
+ .optional()
67
+ .describe("Map of header-name-substring → header-value-substring (both case-insensitive). Response PASSES if AT LEAST ONE entry matches (header name contains the key AND value contains the value). Checked across all redirect hops. Empty / omitted = no header requirement."),
68
+ fail: z
69
+ .record(z.string(), z.string())
70
+ .optional()
71
+ .describe("Map of header-name-substring → header-value-substring (both case-insensitive). Response is treated as FAILURE if ANY entry matches a response header. Use to reject challenge / block headers, e.g. {\"x-blocked\": \"bot\", \"server\": \"cloudflare\"}."),
72
+ })
73
+ .optional(),
74
+ data: z
75
+ .object({
76
+ accept: z.array(z.string()).optional().describe("Substrings the response body must contain"),
77
+ fail: z.array(z.string()).optional().describe("Substrings the response body must NOT contain"),
78
+ })
79
+ .optional(),
80
+ })
81
+ .optional();
82
+ // HeaderInfo[] — one entry per response in the redirect chain. `result` holds
83
+ // the HTTP status line; all other keys are response header name → value pairs.
84
+ // Multi-value headers (Set-Cookie, Link, WWW-Authenticate, etc.) come as
85
+ // `string | string[]` from node-libcurl HeaderInfo — Bug 1 fix.
86
+ const HeaderInfoSchema = z
87
+ .object({
88
+ result: z
89
+ .object({
90
+ version: z.string().optional(),
91
+ code: z.number().int().optional(),
92
+ reason: z.string().optional(),
93
+ })
94
+ .optional(),
95
+ })
96
+ .catchall(z.union([z.string(), z.array(z.string())]));
97
+ const singleOutputShape = {
98
+ // Success path — matches dwstack DwResponse (packages/types/src/single.ts:47-57)
99
+ status: z.number().int().optional().describe("HTTP status code from the target. `0` indicates the request failed before any HTTP response (DNS failure, connection refused, timeout) — check the `error` field for the underlying reason."),
100
+ // `Buffer | HeaderInfo[]` — Buffer when raw mode is requested upstream
101
+ // (we don't expose that mode but accept it permissively). Array entries
102
+ // hold the libcurl HeaderInfo shape with multi-value header support.
103
+ headers: z
104
+ .union([z.array(HeaderInfoSchema), z.string(), z.record(z.string(), z.unknown())])
105
+ .optional()
106
+ .describe("Response headers per redirect hop, as an array of objects. Each entry has `result.{version, code, reason}` plus arbitrary header-name keys whose values are strings (or arrays of strings for multi-value headers like Set-Cookie / Link). Last array entry is the final response."),
107
+ data: z
108
+ .unknown()
109
+ .optional()
110
+ .describe("Decoded response body. String by default; object when tryJsonData=true and the body parsed as JSON; serialized Buffer JSON shape (`{type:\"Buffer\", data:[byte, ...]}`, bytes 0-255) when returnBuffer=true — reconstruct with `Buffer.from(data.data)` in Node, `new Uint8Array(data.data)` elsewhere. Omitted when offloaded."),
111
+ // total_time can be string | number | null per dwstack types/src/single.ts:52 — Bug 6 fix.
112
+ total_time: z
113
+ .union([z.number(), z.string(), z.null()])
114
+ .optional()
115
+ .describe("Wall-clock request duration in seconds. Number when present; string in some variants; null when the request never started."),
116
+ // Offload path — MCP layer adds these when body >= 50KB AND offload_large=true
117
+ offloaded_resource_uri: z.string().optional().describe("foura-mcp://payload/<uuid>"),
118
+ size_bytes: z.number().int().optional().describe("Total offloaded body size in bytes"),
119
+ // Error path — common envelope across all FourA services (see foura.ai/docs/api/errors)
120
+ error: z.string().optional().describe("Human-readable error message"),
121
+ service: z.enum(["single", "proxy", "browser", "api"]).optional(),
122
+ retryAfter: z.number().optional().describe("Seconds to wait before retrying (429/503)"),
123
+ current: z
124
+ .object({ concurrency: z.number().optional(), rpm: z.number().optional() })
125
+ .optional()
126
+ .describe("Caller's current usage at error time"),
127
+ limits: z
128
+ .object({ maxConcurrency: z.number().optional(), maxRpm: z.number().optional() })
129
+ .optional()
130
+ .describe("Per-service limits at error time"),
131
+ code: z.string().optional().describe("Stable error code for retry classification. One of: ssrf_blocked, upstream_non_json, output_validation_failed, bad_request (400), auth_failed (401), forbidden (403), not_found (404), rate_limited (429), at_capacity (503), service_disabled (503), service_unavailable (503), upstream_error (>=500), upstream_client_error (other 4xx), upstream_unknown (defensive)."),
132
+ };
133
+ const singleInputShape = {
134
+ // method is z.string() in upstream (packages/types/src/single.ts:29) — Bug 9.
135
+ // We don't restrict to a closed enum; libcurl accepts arbitrary verbs
136
+ // (PROPFIND, MKCOL, REPORT, etc.) used by WebDAV / OData / GraphQL clients.
137
+ method: z
138
+ .string()
139
+ .min(1)
140
+ .describe("HTTP method (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS, or any WebDAV verb like PROPFIND/MKCOL)"),
141
+ url: z.string().url().describe("Target URL. Public hosts only — private/reserved ranges (RFC 1918 10/8, 172.16/12, 192.168/16, loopback 127/8, link-local, IPv6 ULA fc00::/7, IPv6 loopback ::1, plus *.local mDNS) are refused with code `ssrf_blocked`. Example: https://example.com/page or https://api.example.com/v1/users. Use {ts} anywhere in the URL to insert current Unix timestamp for cache-bust."),
142
+ headers: z
143
+ .array(z.tuple([z.string(), z.string()]))
144
+ .optional()
145
+ .describe("Custom HTTP headers as [name, value] tuples. Example: [[\"Accept\", \"application/json\"], [\"Referer\", \"https://google.com/\"]]"),
146
+ unblocker: z
147
+ .boolean()
148
+ .optional()
149
+ .describe("Inject realistic browser headers (User-Agent, Sec-Ch-Ua, Accept-Encoding, …) and make the request look like it's coming from a real browser at the wire level. Default false — set true for any target with anti-bot or WAF (Cloudflare, Akamai, PerimeterX, Datadome). Cheap to leave on for production scrapes."),
150
+ data: z
151
+ .union([z.string(), z.record(z.string(), z.unknown())])
152
+ .optional()
153
+ .describe("Request body. Strings sent as-is; objects auto-serialized to JSON. Example: {\"query\": \"hello\"} for POST APIs."),
154
+ proxy: z
155
+ .string()
156
+ .optional()
157
+ .describe("Optional proxy. Two forms: (1) URL `http://host:port` or `socks5://host:port`; " +
158
+ "(2) base36 ID from foura_proxy (e.g. `4DZ3VE`) — same exit IP. For rotation, use foura_proxy."),
159
+ // Note: `proxyId` (number) is intentionally NOT exposed. The backend zod
160
+ // schema declares it, but no code path reads it — gateway only resolves
161
+ // base36 IDs from the `proxy` string field, and libcurl never reads
162
+ // request.proxyId. Exposing the dead field would silently no-op.
163
+ timeout_ms: z.number().int().min(0).max(120_000).optional().describe("Overall request timeout in ms (max 120000, default 15000)"),
164
+ connect_timeout_ms: z.number().int().min(0).max(120_000).optional(),
165
+ accept_timeout_ms: z.number().int().min(0).max(120_000).optional(),
166
+ server_response_timeout_ms: z.number().int().min(0).max(120_000).optional(),
167
+ dns_cache_timeout_sec: z.number().int().min(0).max(240).optional(),
168
+ followRedirects: z
169
+ .number()
170
+ .int()
171
+ .min(0)
172
+ .max(20)
173
+ .optional()
174
+ .describe("Max number of redirects to follow (0-20). Omit to disable redirect following."),
175
+ tryJsonData: z.boolean().optional().describe("If true, attempt JSON.parse on the response body. On success, `data` is the parsed value (typically object or array). On parse failure, `data` silently stays as the original string — no error, no warning. Set false (or omit) when you need to detect parse failures explicitly."),
176
+ returnBuffer: z.boolean().optional().describe("Return raw bytes as a serialized Buffer JSON shape (`{type:\"Buffer\", data:[byte, ...]}`, bytes 0-255) instead of decoded string. Use for binary responses (images, protobuf). Reconstruct: `Buffer.from(data.data)` in Node, `new Uint8Array(data.data)` elsewhere."),
177
+ validate: SingleValidateSchema,
178
+ // Bug 3 fix — opt-in offload. Default false → response inline regardless
179
+ // of size so Claude Desktop (which can't read resource_link content blocks)
180
+ // gets usable output on real product pages.
181
+ offload_large: z
182
+ .boolean()
183
+ .optional()
184
+ .describe("If true, response bodies >= 50KB are written to disk and returned as a resource_link instead of inlined. Saves token context but requires a client that supports `resources/read`. Default false."),
185
+ };
186
+ // Bug 2 fix — convert any handler-level crash OR output-validation failure
187
+ // into the documented {service, code, error} envelope. Two guards:
188
+ // 1. Outer try/catch around handler — catches throws (network, JSON, etc).
189
+ // 2. Output validation against outputSchema BEFORE returning — catches
190
+ // shape mismatches that would otherwise bubble up as MCP -32602 errors
191
+ // without a structuredContent envelope.
192
+ // Return type is `any` so the strict CallToolResult union from the SDK
193
+ // doesn't trip on our heterogeneous content arrays.
194
+ async function guardHandler(service,
195
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
196
+ outputSchema,
197
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
198
+ fn) {
199
+ try {
200
+ const result = await fn();
201
+ if (result?.structuredContent) {
202
+ const parsed = outputSchema.safeParse(result.structuredContent);
203
+ if (!parsed.success) {
204
+ const issues = parsed.error.issues.slice(0, 5).map((i) => `${i.path.join(".") || "(root)"}: ${i.message}`).join("; ");
205
+ return {
206
+ isError: true,
207
+ content: [{ type: "text", text: `FourA ${service} — upstream response failed schema: ${issues}` }],
208
+ structuredContent: {
209
+ service,
210
+ code: "output_validation_failed",
211
+ error: `Upstream response did not match the expected schema: ${issues}`,
212
+ },
213
+ };
214
+ }
215
+ }
216
+ return result;
217
+ }
218
+ catch (e) {
219
+ const msg = e instanceof Error ? e.message : String(e);
220
+ return {
221
+ isError: true,
222
+ content: [{ type: "text", text: `FourA ${service} — internal error: ${msg}` }],
223
+ structuredContent: {
224
+ service,
225
+ code: "output_validation_failed",
226
+ error: `Tool handler crashed before producing a response: ${msg}`,
227
+ },
228
+ };
229
+ }
230
+ }
231
+ export function registerSingleTool(server) {
232
+ server.registerTool("foura_single", {
233
+ title: "FourA — single HTTP request",
234
+ description: "Send one HTTP request and return the response. Fastest of the three tools (typically 200ms–2s). " +
235
+ "Use for static pages, JSON APIs, server-rendered HTML. Set unblocker:true if the target has " +
236
+ "wire-level anti-bot protection. Switch to foura_proxy if you get blocked — status 403, status 429, " +
237
+ "captcha page, OR response carries `x-vercel-mitigated: challenge` / `cf-mitigated: challenge` " +
238
+ "headers, OR body title matches `Vercel Security Checkpoint` / `Just a moment` / `Attention Required` / " +
239
+ "`We're verifying your browser`. For these tier-1 WAF challenges call foura_proxy with maxTries:25-30 " +
240
+ "(the default 5 is sized for lightly-blocked sites). On success, chain the returned proxy ID into " +
241
+ "foura_browser.proxy if the page also needs JavaScript to render.",
242
+ inputSchema: singleInputShape,
243
+ outputSchema: singleOutputShape,
244
+ annotations: {
245
+ readOnlyHint: true,
246
+ destructiveHint: false,
247
+ openWorldHint: true,
248
+ },
249
+ }, async (input) => guardHandler("single", z.object(singleOutputShape), async () => {
250
+ try {
251
+ await assertPublicTarget(input.url);
252
+ }
253
+ catch (e) {
254
+ if (e instanceof SsrfBlockedError) {
255
+ return {
256
+ isError: true,
257
+ content: [{ type: "text", text: e.message }],
258
+ structuredContent: { service: "single", code: "ssrf_blocked", error: e.message },
259
+ };
260
+ }
261
+ throw e;
262
+ }
263
+ // Strip MCP-layer-only fields before forwarding upstream.
264
+ const { offload_large, ...upstreamBody } = input;
265
+ const res = await request(SINGLE_API_URL, {
266
+ method: "POST",
267
+ headers: {
268
+ "X-API-Key": getApiKey(),
269
+ "Content-Type": "application/json",
270
+ "User-Agent": "foura-mcp/0.2.11 (single)",
271
+ },
272
+ body: JSON.stringify(upstreamBody),
273
+ });
274
+ const text = await res.body.text();
275
+ let parsed;
276
+ try {
277
+ parsed = JSON.parse(text);
278
+ }
279
+ catch {
280
+ return {
281
+ isError: true,
282
+ content: [
283
+ {
284
+ type: "text",
285
+ text: `FourA single — non-JSON response (${res.statusCode}): ${text.slice(0, 200)}`,
286
+ },
287
+ ],
288
+ structuredContent: {
289
+ service: "single",
290
+ code: "upstream_non_json",
291
+ status: res.statusCode,
292
+ error: `Upstream returned non-JSON (${res.statusCode}): ${text.slice(0, 200)}`,
293
+ },
294
+ };
295
+ }
296
+ if (res.statusCode < 200 || res.statusCode >= 300) {
297
+ const e = parsed;
298
+ const errMsg = typeof e.error === "string" ? e.error : "Unknown";
299
+ const retryStr = typeof e.retryAfter === "number" ? ` · retry ${e.retryAfter}s` : "";
300
+ return {
301
+ isError: true,
302
+ content: [{ type: "text", text: `FourA single error ${res.statusCode}: ${errMsg}${retryStr}` }],
303
+ structuredContent: {
304
+ ...e,
305
+ service: "single",
306
+ code: deriveCode(res.statusCode, e),
307
+ status: typeof e.status === "number" ? e.status : res.statusCode,
308
+ },
309
+ };
310
+ }
311
+ const parsedObj = parsed;
312
+ // Bug 8 fix — dwstack returns HTTP 200 + {error, status, headers, data}
313
+ // when libcurl itself failed (DNS, refused, timeout) or when validate.*
314
+ // rejected the response. The api gateway forwards the inner status
315
+ // verbatim. Surface this as a structured error instead of a fake success.
316
+ if (typeof parsedObj.error === "string" && parsedObj.error.length > 0) {
317
+ const innerStatus = typeof parsedObj.status === "number" ? parsedObj.status : 0;
318
+ return {
319
+ isError: true,
320
+ content: [
321
+ {
322
+ type: "text",
323
+ text: `FourA single — upstream failure (status ${innerStatus}): ${parsedObj.error}`,
324
+ },
325
+ ],
326
+ structuredContent: {
327
+ ...parsedObj,
328
+ service: "single",
329
+ code: deriveCode(innerStatus, parsedObj),
330
+ status: innerStatus,
331
+ },
332
+ };
333
+ }
334
+ const data = parsedObj.data;
335
+ let bodyStr = null;
336
+ if (typeof data === "string")
337
+ bodyStr = data;
338
+ else if (data && typeof data === "object")
339
+ bodyStr = JSON.stringify(data);
340
+ const statusLabel = parsedObj.status ?? "?";
341
+ const timeLabel = parsedObj.total_time !== undefined && parsedObj.total_time !== null
342
+ ? `${parsedObj.total_time}s`
343
+ : "—";
344
+ const shouldOffload = offload_large === true
345
+ && bodyStr
346
+ && Buffer.byteLength(bodyStr, "utf8") >= THRESHOLD_BYTES;
347
+ if (shouldOffload && bodyStr) {
348
+ const ct = extractContentTypeFromHeaderInfo(parsedObj.headers) ?? "text/plain";
349
+ const stored = await storePayload(bodyStr, ct, "response-body");
350
+ const sizeKb = (stored.size / 1024).toFixed(1);
351
+ return {
352
+ content: [
353
+ { type: "text", text: `${statusLabel} · offloaded ${sizeKb} KB · ${timeLabel}` },
354
+ { type: "resource_link", uri: stored.uri, name: stored.name, mimeType: stored.mimeType },
355
+ ],
356
+ structuredContent: {
357
+ status: parsedObj.status,
358
+ headers: parsedObj.headers,
359
+ total_time: parsedObj.total_time,
360
+ offloaded_resource_uri: stored.uri,
361
+ size_bytes: stored.size,
362
+ },
363
+ };
364
+ }
365
+ const sizeKb = bodyStr ? (Buffer.byteLength(bodyStr, "utf8") / 1024).toFixed(1) : "0";
366
+ return {
367
+ content: [{ type: "text", text: `${statusLabel} OK · ${sizeKb} KB · ${timeLabel}` }],
368
+ structuredContent: parsedObj,
369
+ };
370
+ }));
371
+ }
372
+ // Export internals for unit tests + schema-parity checks.
373
+ export const __test = { deriveCode, HeaderInfoSchema, singleInputShape, singleOutputShape, guardHandler };
374
+ //# sourceMappingURL=single.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"single.js","sourceRoot":"","sources":["../../src/tools/single.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@fouradata/mcp",
3
+ "version": "0.2.11",
4
+ "description": "MCP server for the FourA web scraping API — three tools for HTTP requests, rotating proxies, and full browser sessions, usable from any MCP client.",
5
+ "type": "module",
6
+ "main": "dist/server.js",
7
+ "bin": {
8
+ "mcp": "bin/foura-mcp.js",
9
+ "foura-mcp": "bin/foura-mcp.js"
10
+ },
11
+ "files": [
12
+ "bin",
13
+ "dist",
14
+ "README.md"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "dev": "tsx src/stdio.ts",
19
+ "dev:http": "tsx src/http.ts",
20
+ "start:http": "node dist/http.js",
21
+ "test": "npm run build && npm run test:unit && npm run test:integration:stdio && npm run test:docs && npm run test:schema-parity",
22
+ "test:unit": "node --test --test-reporter=spec 'tests/unit/**/*.test.mjs'",
23
+ "test:integration:stdio": "node --test --test-concurrency=1 --test-reporter=spec 'tests/integration-stdio/**/*.test.mjs'",
24
+ "test:integration:http": "node --test --test-reporter=spec 'tests/integration-http/**/*.test.mjs'",
25
+ "test:docs": "node --test --test-reporter=spec 'tests/docs-compliance/**/*.test.mjs'",
26
+ "test:schema-parity": "node --test --test-reporter=spec 'tests/schema-parity/**/*.test.mjs'",
27
+ "test:ai": "node --test --test-reporter=spec 'tests/ai-compliance/**/*.test.mjs'",
28
+ "test:all": "npm run test && npm run test:integration:http && npm run test:ai",
29
+ "smoke": "node tests/smoke.mjs",
30
+ "inspector": "npx -y @modelcontextprotocol/inspector tsx src/stdio.ts",
31
+ "lint": "tsc --noEmit",
32
+ "audit:tokens": "node scripts/audit-tokens.mjs",
33
+ "bump": "node scripts/bump.mjs",
34
+ "prepublishOnly": "npm run lint && npm run build"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.29.0",
38
+ "express": "^5.2.1",
39
+ "undici": "^8.2.0",
40
+ "zod": "^4.4.3"
41
+ },
42
+ "devDependencies": {
43
+ "@anthropic-ai/sdk": "^0.96.0",
44
+ "@types/express": "^5.0.6",
45
+ "@types/node": "^25.7.0",
46
+ "tsx": "^4.21.0",
47
+ "typescript": "^6.0.3"
48
+ },
49
+ "engines": {
50
+ "node": ">=20.0.0"
51
+ },
52
+ "keywords": [
53
+ "mcp",
54
+ "model-context-protocol",
55
+ "foura",
56
+ "web-scraping",
57
+ "scraping-api",
58
+ "rotating-proxies",
59
+ "anti-bot",
60
+ "browser-automation"
61
+ ],
62
+ "license": "MIT"
63
+ }