@spicrawl/mcp 0.0.0-stage → 0.1.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 (49) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +61 -0
  3. package/README.md +411 -2
  4. package/dist/client.d.ts +89 -0
  5. package/dist/client.js +187 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/http.d.ts +27 -0
  8. package/dist/http.js +220 -0
  9. package/dist/http.js.map +1 -0
  10. package/dist/index.d.ts +30 -0
  11. package/dist/index.js +79 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/server.d.ts +16 -0
  14. package/dist/server.js +141 -0
  15. package/dist/server.js.map +1 -0
  16. package/dist/tools/actions.d.ts +534 -0
  17. package/dist/tools/actions.js +103 -0
  18. package/dist/tools/actions.js.map +1 -0
  19. package/dist/tools/batch.d.ts +2 -0
  20. package/dist/tools/batch.js +307 -0
  21. package/dist/tools/batch.js.map +1 -0
  22. package/dist/tools/browser.d.ts +2 -0
  23. package/dist/tools/browser.js +101 -0
  24. package/dist/tools/browser.js.map +1 -0
  25. package/dist/tools/common.d.ts +64 -0
  26. package/dist/tools/common.js +64 -0
  27. package/dist/tools/common.js.map +1 -0
  28. package/dist/tools/docs.d.ts +12 -0
  29. package/dist/tools/docs.js +277 -0
  30. package/dist/tools/docs.js.map +1 -0
  31. package/dist/tools/pdf.d.ts +11 -0
  32. package/dist/tools/pdf.js +36 -0
  33. package/dist/tools/pdf.js.map +1 -0
  34. package/dist/tools/requests.d.ts +2 -0
  35. package/dist/tools/requests.js +71 -0
  36. package/dist/tools/requests.js.map +1 -0
  37. package/dist/tools/scrape.d.ts +2 -0
  38. package/dist/tools/scrape.js +213 -0
  39. package/dist/tools/scrape.js.map +1 -0
  40. package/dist/tools/screenshots.d.ts +15 -0
  41. package/dist/tools/screenshots.js +69 -0
  42. package/dist/tools/screenshots.js.map +1 -0
  43. package/dist/tools/sessions.d.ts +2 -0
  44. package/dist/tools/sessions.js +145 -0
  45. package/dist/tools/sessions.js.map +1 -0
  46. package/dist/tools/usage.d.ts +2 -0
  47. package/dist/tools/usage.js +93 -0
  48. package/dist/tools/usage.js.map +1 -0
  49. package/package.json +75 -4
@@ -0,0 +1,103 @@
1
+ import { z } from "zod";
2
+ // ---------------------------------------------------------------------------
3
+ // Browser actions for spicrawl_scrape, as an explicit discriminated union.
4
+ //
5
+ // The API's step shape is an object keyed by its kind — {"click": {...}} — which
6
+ // a JSON schema can only describe as "any object". Agents given that schema
7
+ // guessed field names (`scroll.pixels`, `evaluate.script`) and got 400s. Here
8
+ // each step is `{type, ...fields}` with its fields spelt exactly as the Go
9
+ // router (api/internal/router/actions.go) reads them; toApiActions maps it back
10
+ // onto the keyed shape. Only kinds the API supports are offered: there is no
11
+ // hover or press step to map to.
12
+ // ---------------------------------------------------------------------------
13
+ const until = z
14
+ .enum(["load", "domcontentloaded", "networkidle"])
15
+ .describe("Load state the new document must reach. Default load.");
16
+ /** Keys every step accepts; they sit beside the kind key in the API shape. */
17
+ const meta = {
18
+ timeout_ms: z.number().int().min(1).optional().describe("Budget for this step in ms. The step fails (or is skipped) when it runs out."),
19
+ on_error: z.enum(["fail", "skip"]).optional().describe("fail (default) aborts the workflow; skip records the failure and continues."),
20
+ label: z.string().optional().describe("Name echoed in the response's `actions` and `screenshots`."),
21
+ };
22
+ const META_KEYS = Object.keys(meta);
23
+ const step = (type, fields, description) => z.object({ type: z.literal(type), ...fields, ...meta }).strict().describe(description);
24
+ export const ActionSchema = z.discriminatedUnion("type", [
25
+ step("click", {
26
+ selector: z.string().min(1).describe("CSS selector of the element to click."),
27
+ wait_for_navigation: z.boolean().optional().describe("The click navigates: finish the step only once the new page has loaded."),
28
+ until: until.optional(),
29
+ }, "Click an element. On a checkbox or radio this toggles it (there is no 'set checked'); read its state with evaluate if it matters."),
30
+ step("fill", {
31
+ selector: z.string().min(1),
32
+ value: z.string(),
33
+ secret: z.boolean().optional().describe("A credential: redacted from logs and the request log."),
34
+ }, "Type a value into an input."),
35
+ step("wait_for", {
36
+ selector: z.string().min(1).optional().describe("CSS selector to wait for."),
37
+ ms: z.number().int().min(1).optional().describe("Or: sleep this many ms."),
38
+ }, "Wait for a selector to appear, or sleep `ms`."),
39
+ step("wait_for_navigation", { until: until.optional() }, "Wait for a navigation started by the previous step (a click, a form submit, a redirect) to load."),
40
+ step("scroll", {
41
+ y: z.number().int().optional().describe("Pixels to scroll down (negative scrolls up)."),
42
+ to_bottom: z.boolean().optional().describe("Scroll to the bottom repeatedly until the page stops growing (infinite scroll)."),
43
+ selector: z.string().min(1).optional().describe("Scroll this element into view."),
44
+ }, "Scroll the page: give exactly one of y, to_bottom or selector."),
45
+ step("select", {
46
+ selector: z.string().min(1).describe("CSS selector of the <select>."),
47
+ value: z.string().optional(),
48
+ values: z.array(z.string()).optional().describe("Several options, for a multi-select."),
49
+ }, "Choose option(s) in a <select> by value."),
50
+ step("evaluate", {
51
+ expression: z.string().min(1).describe("JavaScript expression evaluated in the page."),
52
+ return_value: z.boolean().optional().describe("Return the value under `actions` in the response (forces format json)."),
53
+ await_promise: z.boolean().optional(),
54
+ }, "Run JavaScript in the page."),
55
+ step("screenshot", {
56
+ full_page: z.boolean().optional(),
57
+ selector: z.string().min(1).optional().describe("Capture only this element."),
58
+ format: z.enum(["png", "jpeg", "webp"]).optional(),
59
+ quality: z.number().int().min(1).max(100).optional(),
60
+ }, "Capture the page at this point. The image is returned as an image block; the response becomes the JSON envelope whatever `format` says."),
61
+ ]);
62
+ export const ActionsSchema = z
63
+ .array(ActionSchema)
64
+ .superRefine((steps, ctx) => {
65
+ steps.forEach((s, i) => {
66
+ if (s.type === "scroll" && [s.y !== undefined, s.to_bottom === true, s.selector !== undefined].filter(Boolean).length !== 1) {
67
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: [i], message: "scroll needs exactly one of y, to_bottom or selector" });
68
+ }
69
+ if (s.type === "wait_for" && s.selector === undefined && s.ms === undefined) {
70
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: [i], message: "wait_for needs selector or ms" });
71
+ }
72
+ if (s.type === "select" && s.value === undefined && !s.values?.length) {
73
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: [i], message: "select needs value or values" });
74
+ }
75
+ if (s.type === "click" && s.until !== undefined && s.wait_for_navigation !== true) {
76
+ ctx.addIssue({ code: z.ZodIssueCode.custom, path: [i], message: "click.until only applies with wait_for_navigation: true" });
77
+ }
78
+ });
79
+ })
80
+ .describe("Browser steps run in order before capture (render only). Each step is {type, ...fields}. Examples: " +
81
+ '[{"type":"click","selector":"#load-more"},{"type":"wait_for","selector":".item:nth-child(20)","timeout_ms":5000}] · ' +
82
+ 'infinite scroll: [{"type":"scroll","to_bottom":true},{"type":"wait_for","ms":1000}] · ' +
83
+ 'login: [{"type":"fill","selector":"#user","value":"me"},{"type":"fill","selector":"#pass","value":"…","secret":true},' +
84
+ '{"type":"click","selector":"button[type=submit]","wait_for_navigation":true}]. ' +
85
+ "A screenshot step switches the response to the JSON envelope (a FORMAT_COERCED warning says so).");
86
+ /** Map typed steps onto the API's keyed shape: {kind: {fields}, timeout_ms?, on_error?, label?}. */
87
+ export function toApiActions(steps) {
88
+ return steps.map((s) => {
89
+ const { type, ...rest } = s;
90
+ const body = {};
91
+ const out = {};
92
+ for (const [k, v] of Object.entries(rest)) {
93
+ if (v === undefined)
94
+ continue;
95
+ if (META_KEYS.includes(k))
96
+ out[k] = v;
97
+ else
98
+ body[k] = v;
99
+ }
100
+ return { [type]: body, ...out };
101
+ });
102
+ }
103
+ //# sourceMappingURL=actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actions.js","sourceRoot":"","sources":["../../src/tools/actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type RegisterTools } from "./common.js";
2
+ export declare const registerBatchTools: RegisterTools;
@@ -0,0 +1,307 @@
1
+ import { z } from "zod";
2
+ import { COMING_SOON, run } from "./common.js";
3
+ const jobPath = (id) => `/v1/batch/${encodeURIComponent(id)}`;
4
+ /** Appends a query string built from the defined entries of `q`. */
5
+ function withQuery(path, q) {
6
+ const params = new URLSearchParams();
7
+ for (const [k, v] of Object.entries(q))
8
+ if (v !== undefined)
9
+ params.set(k, String(v));
10
+ const s = params.toString();
11
+ return s ? `${path}?${s}` : path;
12
+ }
13
+ const jobId = z.string().min(1).describe("The batch job id returned by spicrawl_batch_submit or spicrawl_batch_list.");
14
+ // Shared scrape settings: a subset of the /v1/scrape request object, applied to
15
+ // every item of the job (an item in `items` may override any of them).
16
+ const sharedParams = {
17
+ render: z.boolean().optional().describe("Render every URL with a browser (`js_render`)."),
18
+ // Batch can pin only these three: its worker picks the render engine from
19
+ // capability flags and has no way to name chromium, so the API refuses a
20
+ // chromium pin (use `render: true`, or spicrawl_scrape to pin chromium).
21
+ engine: z
22
+ .enum(["fetch", "obscura", "camoufox"])
23
+ .optional()
24
+ .describe("Pin the scrape engine for every item: `fetch` or `obscura` (must be allowed by the plan and served by the deployment); `camoufox` is coming soon, do not pin it yet. `chromium` cannot be pinned in a batch — use `render: true`, or spicrawl_scrape."),
25
+ format: z
26
+ .enum(["markdown", "text", "html", "json"])
27
+ .optional()
28
+ .describe("Output format for every item (`response_format`). spicrawl_batch_submit defaults to 'markdown', the same as spicrawl_scrape; an item's own `response_format` overrides it."),
29
+ main_content_only: z.boolean().optional().describe("Strip each page to its main article."),
30
+ premium_proxy: z.boolean().optional().describe(COMING_SOON + "Use residential managed-pool exits for every URL."),
31
+ proxy_country: z
32
+ .string()
33
+ .length(2)
34
+ .optional()
35
+ .describe(COMING_SOON + "ISO-3166 alpha-2 exit country; requires premium_proxy."),
36
+ wait: z.number().int().min(0).optional().describe("Milliseconds to wait after load (rendered scrapes)."),
37
+ wait_for: z.string().optional().describe("CSS selector to wait for before capturing (rendered scrapes)."),
38
+ block_resources: z
39
+ .array(z.string())
40
+ .optional()
41
+ .describe("Resource types to block while rendering, e.g. [\"image\",\"font\",\"media\"]."),
42
+ custom_headers: z.record(z.string()).optional().describe("Extra request headers sent with every URL."),
43
+ max_cost: z
44
+ .number()
45
+ .int()
46
+ .min(1)
47
+ .optional()
48
+ .describe("Ceiling in credits for ONE item (not the whole job — see credit_budget)."),
49
+ };
50
+ function sharedBody(input) {
51
+ const b = {};
52
+ if (input.render !== undefined)
53
+ b.js_render = input.render;
54
+ if (input.engine !== undefined)
55
+ b.engine = input.engine;
56
+ if (input.format !== undefined)
57
+ b.response_format = input.format;
58
+ if (input.main_content_only !== undefined)
59
+ b.main_content_only = input.main_content_only;
60
+ if (input.premium_proxy !== undefined)
61
+ b.premium_proxy = input.premium_proxy;
62
+ if (input.proxy_country !== undefined)
63
+ b.proxy_country = input.proxy_country;
64
+ if (input.wait !== undefined)
65
+ b.wait = input.wait;
66
+ if (input.wait_for !== undefined)
67
+ b.wait_for = input.wait_for;
68
+ if (input.block_resources !== undefined)
69
+ b.block_resources = input.block_resources;
70
+ if (input.custom_headers !== undefined)
71
+ b.custom_headers = input.custom_headers;
72
+ if (input.max_cost !== undefined)
73
+ b.max_cost = input.max_cost;
74
+ return b;
75
+ }
76
+ const itemsInput = {
77
+ urls: z
78
+ .array(z.string().url())
79
+ .optional()
80
+ .describe("Shorthand: URLs scraped with the shared settings and no per-item overrides. Mutually exclusive with `items`."),
81
+ items: z
82
+ .array(z
83
+ .object({
84
+ url: z.string().url().describe("The URL of this item."),
85
+ external_id: z
86
+ .string()
87
+ .optional()
88
+ .describe("Your own correlation id, echoed back on this item's result record."),
89
+ })
90
+ .passthrough())
91
+ .optional()
92
+ .describe("Long form: one /v1/scrape request object per item. Besides `url` and `external_id`, any /v1/scrape " +
93
+ "field (e.g. `js_render`, `wait_for`, `response_format`) overrides the shared setting for that item only. Mutually exclusive with `urls`."),
94
+ };
95
+ export const registerBatchTools = (server, client) => {
96
+ // -------------------------------------------------------------------------
97
+ // spicrawl_batch_submit — POST /v1/batch
98
+ // -------------------------------------------------------------------------
99
+ server.registerTool("spicrawl_batch_submit", {
100
+ title: "Submit a batch scrape job",
101
+ description: "Submit many URLs to be scraped as one asynchronous job, with shared settings applied to every URL. " +
102
+ "Give EITHER `urls` or `items`, not both (at least one URL, unless `open` is true). Returns the job object " +
103
+ "(id, status, estimated_credits, progress). Poll with `spicrawl_batch_status`, read with `spicrawl_batch_results` " +
104
+ "or `spicrawl_batch_task_content`. Use this instead of many `spicrawl_scrape` calls when you have tens or thousands " +
105
+ "of URLs. Set `open: true` to keep the job accepting more URLs via `spicrawl_batch_add_items`; an open job never " +
106
+ "finishes until you call `spicrawl_batch_close`.",
107
+ inputSchema: {
108
+ ...itemsInput,
109
+ ...sharedParams,
110
+ name: z.string().optional().describe("A human label for the job."),
111
+ open: z
112
+ .boolean()
113
+ .optional()
114
+ .describe("Keep the job accepting items after submission (append with spicrawl_batch_add_items, finish with spicrawl_batch_close)."),
115
+ concurrency: z.number().int().min(1).optional().describe("Max items in flight at once for this job (may be capped by the server; see warnings)."),
116
+ priority: z.number().int().optional().describe("Scheduling priority of the job relative to your other jobs."),
117
+ max_attempts: z.number().int().min(1).max(10).optional().describe("Per-item retry attempts on failure."),
118
+ failure_threshold: z
119
+ .number()
120
+ .int()
121
+ .min(1)
122
+ .optional()
123
+ .describe("Abort the job once this many items have failed."),
124
+ credit_budget: z
125
+ .number()
126
+ .int()
127
+ .min(1)
128
+ .optional()
129
+ .describe("Ceiling on the WHOLE job, in credits; the run aborts when it would exceed this."),
130
+ webhook_endpoint_id: z
131
+ .string()
132
+ .optional()
133
+ .describe("Id of a registered webhook endpoint notified (with the job object) when the job completes."),
134
+ },
135
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
136
+ }, async (input) => {
137
+ const body = sharedBody(input);
138
+ // Same default as spicrawl_scrape. Set here, not in sharedBody, so an
139
+ // append (spicrawl_batch_add_items) inherits the job's format instead.
140
+ if (body.response_format === undefined)
141
+ body.response_format = "markdown";
142
+ if (input.urls)
143
+ body.urls = input.urls;
144
+ if (input.items)
145
+ body.items = input.items;
146
+ if (input.name !== undefined)
147
+ body.name = input.name;
148
+ if (input.open)
149
+ body.open = true;
150
+ if (input.concurrency !== undefined)
151
+ body.concurrency = input.concurrency;
152
+ if (input.priority !== undefined)
153
+ body.priority = input.priority;
154
+ if (input.max_attempts !== undefined)
155
+ body.max_attempts = input.max_attempts;
156
+ if (input.failure_threshold !== undefined)
157
+ body.failure_threshold = input.failure_threshold;
158
+ if (input.credit_budget !== undefined)
159
+ body.credit_budget = input.credit_budget;
160
+ if (input.webhook_endpoint_id !== undefined)
161
+ body.webhook_endpoint_id = input.webhook_endpoint_id;
162
+ return run(() => client.request("POST", "/v1/batch", body));
163
+ });
164
+ // -------------------------------------------------------------------------
165
+ // spicrawl_batch_list — GET /v1/batch
166
+ // -------------------------------------------------------------------------
167
+ server.registerTool("spicrawl_batch_list", {
168
+ title: "List batch jobs",
169
+ description: "List this API key's project's batch jobs, newest first, with status and progress. " +
170
+ "Returns `{ batches: [...], next_cursor? }`; pass `next_cursor` back as `cursor` for the next page.",
171
+ inputSchema: {
172
+ status: z
173
+ .enum(["queued", "running", "paused", "cancelling", "completed", "failed", "cancelled"])
174
+ .optional()
175
+ .describe("Only jobs in this status."),
176
+ limit: z.number().int().min(1).max(200).optional().describe("Page size (default 50, max 200)."),
177
+ cursor: z.string().optional().describe("`next_cursor` from a previous page, verbatim."),
178
+ },
179
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
180
+ }, async ({ status, limit, cursor }) => run(() => client.request("GET", withQuery("/v1/batch", { status, limit, cursor }))));
181
+ // -------------------------------------------------------------------------
182
+ // spicrawl_batch_status — GET /v1/batch/{id}
183
+ // -------------------------------------------------------------------------
184
+ server.registerTool("spicrawl_batch_status", {
185
+ title: "Check a batch job's status",
186
+ description: "Return one batch job with its status and progress (total/completed/succeeded/failed/remaining, credits charged). " +
187
+ "Poll this after `spicrawl_batch_submit`; once status is `completed`, `failed` or `cancelled`, read `spicrawl_batch_results`.",
188
+ inputSchema: { job_id: jobId },
189
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
190
+ }, async ({ job_id }) => run(() => client.request("GET", jobPath(job_id))));
191
+ // -------------------------------------------------------------------------
192
+ // spicrawl_batch_results — GET /v1/batch/{id}/results (JSON Lines)
193
+ // -------------------------------------------------------------------------
194
+ server.registerTool("spicrawl_batch_results", {
195
+ title: "Read a batch job's results",
196
+ description: "Return a page of FINISHED items of a batch job (one record per item: seq, url, external_id, status, error, " +
197
+ "and content, or a `result_url` API path (GET /v1/batch/{id}/tasks/{seq}/content, same key) for large bodies). Unfinished items are not listed yet. Returns " +
198
+ "`{ results: [...], next_cursor? }`; pass `next_cursor` back as `cursor` for the next page. " +
199
+ "Results expire after the job's retention window (410 Gone).",
200
+ inputSchema: {
201
+ job_id: jobId,
202
+ status: z
203
+ .enum(["succeeded", "failed", "cancelled", "skipped"])
204
+ .optional()
205
+ .describe("Only items that finished with this status."),
206
+ limit: z.number().int().min(1).max(5000).optional().describe("Page size (default 500, max 5000)."),
207
+ cursor: z.string().optional().describe("`next_cursor` from a previous page, verbatim."),
208
+ },
209
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
210
+ }, async ({ job_id, status, limit, cursor }) => run(async () => {
211
+ const raw = await client.request("GET", withQuery(`${jobPath(job_id)}/results`, { status, limit, cursor }));
212
+ // The endpoint streams JSON Lines; the client hands non-JSON bodies back as `{content}`.
213
+ // A single-line page parses as a plain object instead.
214
+ let results;
215
+ if (raw && typeof raw === "object" && typeof raw.content === "string") {
216
+ results = raw.content
217
+ .split("\n")
218
+ .filter((l) => l.trim() !== "")
219
+ .map((l) => JSON.parse(l));
220
+ }
221
+ else if (raw && typeof raw === "object" && Object.keys(raw).length > 0) {
222
+ results = [raw];
223
+ }
224
+ else {
225
+ results = [];
226
+ }
227
+ const out = { results };
228
+ // The cursor travels in the X-Next-Cursor header, which the client does not expose.
229
+ // It is the hex of the last seq, so it is recomputed here when the page was full.
230
+ const pageSize = limit ?? 500;
231
+ const last = results[results.length - 1];
232
+ if (results.length === pageSize && last && typeof last.seq === "number") {
233
+ out.next_cursor = Buffer.from(String(last.seq)).toString("hex");
234
+ }
235
+ return out;
236
+ }));
237
+ // -------------------------------------------------------------------------
238
+ // spicrawl_batch_task_content — GET /v1/batch/{id}/tasks/{seq}/content
239
+ // -------------------------------------------------------------------------
240
+ server.registerTool("spicrawl_batch_task_content", {
241
+ title: "Read one batch item's content",
242
+ description: "Return the full payload one item of a batch job produced, by its `seq` (items are numbered from 0 in " +
243
+ "submission order). Cheaper than paging results when you need one URL's output. A CONFLICT error means " +
244
+ "either the item has not finished yet (poll `spicrawl_batch_status` and ask again) or it finished as failed " +
245
+ "(it will never produce content; the message says which). NOT_FOUND means no such seq.",
246
+ inputSchema: {
247
+ job_id: jobId,
248
+ seq: z.number().int().min(0).describe("The item's sequence number (0-based, submission order)."),
249
+ },
250
+ annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
251
+ }, async ({ job_id, seq }) => run(() => client.request("GET", `${jobPath(job_id)}/tasks/${encodeURIComponent(String(seq))}/content`)));
252
+ // -------------------------------------------------------------------------
253
+ // spicrawl_batch_cancel — POST /v1/batch/{id}/cancel
254
+ // -------------------------------------------------------------------------
255
+ server.registerTool("spicrawl_batch_cancel", {
256
+ title: "Cancel a batch job",
257
+ description: "Cancel a batch job: items not yet started are cancelled and will never run; items already finished keep " +
258
+ "their results; items already running finish first, so the job comes back `cancelling` and moves to " +
259
+ "`cancelled` when they drain. Cannot be undone — resubmit to run the URLs again. Returns the job object.",
260
+ inputSchema: { job_id: jobId },
261
+ annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: true, openWorldHint: true },
262
+ }, async ({ job_id }) => run(() => client.request("POST", `${jobPath(job_id)}/cancel`)));
263
+ // -------------------------------------------------------------------------
264
+ // spicrawl_batch_retry — POST /v1/batch/{id}/retry
265
+ // -------------------------------------------------------------------------
266
+ server.registerTool("spicrawl_batch_retry", {
267
+ title: "Retry a batch job's failed items",
268
+ description: "Re-queue every FAILED item of a batch job so it runs again (succeeded items are untouched; a job with no " +
269
+ "failures is returned unchanged). Returns `{ job, items_reset, items_dispatched }`.",
270
+ inputSchema: { job_id: jobId },
271
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
272
+ }, async ({ job_id }) => run(() => client.request("POST", `${jobPath(job_id)}/retry`)));
273
+ // -------------------------------------------------------------------------
274
+ // spicrawl_batch_add_items — POST /v1/batch/{id}/items
275
+ // -------------------------------------------------------------------------
276
+ server.registerTool("spicrawl_batch_add_items", {
277
+ title: "Add URLs to an open batch job",
278
+ description: "Append URLs to a batch job that was submitted with `open: true`. Same item vocabulary as " +
279
+ "`spicrawl_batch_submit` (EITHER `urls` or `items`, not both, plus shared settings for these new items). Fails with CONFLICT " +
280
+ "if the job is closed or finished. Not idempotent: calling twice adds the URLs twice. " +
281
+ "Returns `{ job, items_added, items_dispatched }`.",
282
+ inputSchema: { job_id: jobId, ...itemsInput, ...sharedParams },
283
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
284
+ }, async (input) => {
285
+ const body = sharedBody(input);
286
+ // Same default as spicrawl_scrape. Set here, not in sharedBody, so an
287
+ // append (spicrawl_batch_add_items) inherits the job's format instead.
288
+ if (body.response_format === undefined)
289
+ body.response_format = "markdown";
290
+ if (input.urls)
291
+ body.urls = input.urls;
292
+ if (input.items)
293
+ body.items = input.items;
294
+ return run(() => client.request("POST", `${jobPath(input.job_id)}/items`, body));
295
+ });
296
+ // -------------------------------------------------------------------------
297
+ // spicrawl_batch_close — POST /v1/batch/{id}/close
298
+ // -------------------------------------------------------------------------
299
+ server.registerTool("spicrawl_batch_close", {
300
+ title: "Close an open batch job",
301
+ description: "Stop an open batch job accepting items, so it completes once its queued work drains. " +
302
+ "Idempotent (closing a closed job succeeds). Returns the job object.",
303
+ inputSchema: { job_id: jobId },
304
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
305
+ }, async ({ job_id }) => run(() => client.request("POST", `${jobPath(job_id)}/close`)));
306
+ };
307
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","sourceRoot":"","sources":["../../src/tools/batch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type RegisterTools } from "./common.js";
2
+ export declare const registerBrowserTools: RegisterTools;
@@ -0,0 +1,101 @@
1
+ import { z } from "zod";
2
+ import { run } from "./common.js";
3
+ // Browser (CDP): GET /v1/browser is a WebSocket; MCP cannot carry it, so this
4
+ // module mints a single-use token URL for the caller's own Puppeteer/Playwright.
5
+ export const registerBrowserTools = (server, client) => {
6
+ server.registerTool("spicrawl_browser_connect_url", {
7
+ title: "Browser (CDP) connect URL",
8
+ description: "Coming soon: remote browsers are not available yet, so minting fails; do not rely on this tool. For scripted page " +
9
+ "interaction today use `actions` on spicrawl_scrape. " +
10
+ "Mints a single-use connect URL for Spicrawl's remote browser (GET /v1/browser, Chrome DevTools Protocol) so YOUR code can drive it with " +
11
+ "puppeteer.connect({ browserWSEndpoint }) or playwright.chromium.connectOverCDP(url). It calls POST /v1/browser/token and returns a " +
12
+ "ws:// or wss:// URL carrying a short-lived token, never the API key: the URL works ONCE, within 60 seconds, and only with the options " +
13
+ "given here (editing them in the URL is refused), so call this right before connecting and again for every new session. " +
14
+ "Prefer sending the key as an Authorization header when the client supports headers on the upgrade " +
15
+ "(playwright connectOverCDP(url, { headers }), puppeteer.connect({ browserWSEndpoint, headers })): then connect to the plain /v1/browser URL " +
16
+ "with 'Authorization: Bearer <key>' and no token is needed. The endpoint exists only when the deployment was installed with --with-cdp, " +
17
+ "and the key must carry the `browser` scope; otherwise minting fails (404 or 403). Parameter errors are reported when minting.",
18
+ inputSchema: {
19
+ engine: z
20
+ .enum(["chromium", "obscura"])
21
+ .optional()
22
+ .describe("Browser engine. Default: the deployment's default (chromium). 'obscura' cannot run headful."),
23
+ proxy_country: z
24
+ .string()
25
+ .regex(/^[a-z]{2}$/)
26
+ .optional()
27
+ .describe("Exit country, ISO-3166 alpha-2 lowercase (e.g. 'de'). Mutually exclusive with proxy_region."),
28
+ proxy_region: z
29
+ .string()
30
+ .optional()
31
+ .describe("Broader exit region/pool name; 'global' means no constraint. Mutually exclusive with proxy_country."),
32
+ sticky_key: z
33
+ .string()
34
+ .regex(/^[A-Za-z0-9-]{2,64}$/)
35
+ .optional()
36
+ .describe("Keep one exit IP for the session under this key (2-64 letters, digits, hyphens). Omit to rotate (the default)."),
37
+ session_ttl: z
38
+ .number()
39
+ .int()
40
+ .min(60)
41
+ .max(900)
42
+ .optional()
43
+ .describe("Session lifetime in seconds, 60-900. Default 180."),
44
+ headless: z
45
+ .boolean()
46
+ .optional()
47
+ .describe("false = headful browser with a display (desktop-sized screen). Omit for the deployment default."),
48
+ proxy: z
49
+ .string()
50
+ .optional()
51
+ .describe("Your own proxy, as http://user:pass@host:port. Replaces our pool, so proxy_country, proxy_region and sticky_key cannot be combined with it. Kept out of the returned URL."),
52
+ },
53
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false },
54
+ }, async (args) => run(async () => {
55
+ if (args.proxy_country && args.proxy_region && args.proxy_region.toLowerCase() !== "global") {
56
+ throw new Error("Send either proxy_country or proxy_region, not both: they choose the same thing.");
57
+ }
58
+ if (args.engine === "obscura" && args.headless === false) {
59
+ throw new Error("engine=obscura cannot run headful (headless=false). Use engine=chromium or drop headless.");
60
+ }
61
+ const body = {};
62
+ if (args.engine)
63
+ body.engine = args.engine;
64
+ if (args.proxy_country)
65
+ body.proxy_country = args.proxy_country;
66
+ if (args.proxy_region)
67
+ body.proxy_region = args.proxy_region;
68
+ if (args.sticky_key)
69
+ body.sticky_key = args.sticky_key;
70
+ if (args.session_ttl !== undefined)
71
+ body.session_ttl = args.session_ttl;
72
+ if (args.headless !== undefined)
73
+ body.headless = args.headless;
74
+ if (args.proxy)
75
+ body.proxy = args.proxy;
76
+ const minted = (await client.request("POST", "/v1/browser/token", body));
77
+ if (!minted?.path || !minted.path.startsWith("/v1/browser?")) {
78
+ throw new Error("The API did not return a browser token path.");
79
+ }
80
+ // The public base, not the upstream one: a hosted MCP reaches the API
81
+ // over loopback, and a ws://127.0.0.1 URL is useless to a remote caller.
82
+ // Concatenated, not resolved: an absolute path would drop a prefix in the base.
83
+ const url = new URL(client.publicBaseURL.replace(/\/+$/, "") + minted.path);
84
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
85
+ const ws = url.toString();
86
+ return {
87
+ url: ws,
88
+ puppeteer: `const browser = await puppeteer.connect({ browserWSEndpoint: ${JSON.stringify(ws)} });`,
89
+ playwright: `const browser = await chromium.connectOverCDP(${JSON.stringify(ws)});`,
90
+ expires_at: minted.expires_at,
91
+ single_use: true,
92
+ notes: [
93
+ "The URL carries a single-use token, not your API key. It expires 60 s after minting and works for one connection; mint a new one per session.",
94
+ "If your client can set headers on the WebSocket upgrade, you can instead connect to /v1/browser with 'Authorization: Bearer <key>'.",
95
+ "Requires a deployment installed with --with-cdp and a key with the `browser` scope.",
96
+ "The session ends after session_ttl seconds (default 180) or when you disconnect.",
97
+ ],
98
+ };
99
+ }));
100
+ };
101
+ //# sourceMappingURL=browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.js","sourceRoot":"","sources":["../../src/tools/browser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { ILayerClient } from "../client.js";
3
+ /** Every tools module exports one of these; server.ts calls them all. */
4
+ export type RegisterTools = (server: McpServer, client: ILayerClient) => void;
5
+ /**
6
+ * Leads the description of an argument for a feature that is not available yet (the
7
+ * docs' "Coming soon" badge). The schema still accepts it, so nothing breaks the day it
8
+ * ships; the words tell an agent not to send it now.
9
+ */
10
+ export declare const COMING_SOON = "Coming soon: not available yet, do not send. ";
11
+ export type ImageBlock = {
12
+ type: "image";
13
+ data: string;
14
+ mimeType: string;
15
+ };
16
+ /** A file handed to the model host whole, such as a printed PDF (an MCP embedded resource). */
17
+ export type ResourceBlock = {
18
+ type: "resource";
19
+ resource: {
20
+ uri: string;
21
+ mimeType: string;
22
+ blob: string;
23
+ };
24
+ };
25
+ /** A payload with some of its parts lifted out into image or resource blocks. */
26
+ export type Attached = {
27
+ data: unknown;
28
+ blocks: (ImageBlock | ResourceBlock)[];
29
+ };
30
+ /**
31
+ * Wraps a tool body so any ILayerError becomes an actionable MCP error result.
32
+ *
33
+ * `attach` lets a tool lift binary parts (screenshots, a PDF) out of the payload
34
+ * into image or resource blocks placed after the text; the shaping below then
35
+ * applies to what is left, so a tool that passes none behaves exactly as before.
36
+ */
37
+ export declare function run(fn: () => Promise<unknown>, attach?: (data: unknown) => Attached, argNames?: Record<string, string>): Promise<{
38
+ content: (ImageBlock | ResourceBlock | {
39
+ type: "text";
40
+ text: string;
41
+ })[];
42
+ structuredContent: Record<string, unknown>;
43
+ isError?: undefined;
44
+ } | {
45
+ content: (ImageBlock | ResourceBlock | {
46
+ type: "text";
47
+ text: string;
48
+ })[];
49
+ structuredContent?: undefined;
50
+ isError?: undefined;
51
+ } | {
52
+ isError: boolean;
53
+ content: {
54
+ type: "text";
55
+ text: string;
56
+ }[];
57
+ structuredContent?: undefined;
58
+ }>;
59
+ /**
60
+ * Rewrite API parameter names to the tool's argument names, as whole
61
+ * identifiers only: `js_render` becomes `render`, but `js_render_budget` or a
62
+ * URL containing the word is left alone.
63
+ */
64
+ export declare function renameArgs(text: string, names: Record<string, string>): string;