@opencraw/mcp 0.1.1 → 0.1.3

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
@@ -27,14 +27,19 @@ can write files passes their `paths`; one that can't (a chat-only host) passes t
27
27
  `probe`/`run` call's `browserPath`/`insecureTls`, so a sandbox without Playwright's own bundled browser
28
28
  does not need every tool call to repeat them.
29
29
 
30
- `OPENCRAW_HOOKS` points at a JavaScript module whose default export is `{ name: function }`: the hooks the
31
- recipes call (`hook` steps and transforms). Only the server's environment names it, never a tool call, so an
32
- agent can run recipes that use your hooks but can't make the server load a module of its choosing.
30
+ `OPENCRAW_PLUGINS` (or `OPENCRAW_HOOKS`) points at a plugins module: named exports `hooks` (the recipes'
31
+ `hook` steps and transforms), `accessPlugins` (for `{ kind: "plugin" }` access profiles) and `captchaSolvers`;
32
+ a module whose default export is `{ name: function }` is read as hooks alone. Only the server's environment
33
+ names it, never a tool call, so an agent can run recipes that use your plugins but can't make the server load
34
+ a module of its choosing.
33
35
 
34
36
  `OPENCRAW_ACCESS` points at an access config ([access.md](../../docs/recipes/access.md)): proxy profiles, with
35
37
  credentials as `{{env.NAME}}` read from the server's environment. The `probe` and `run` tools then take an
36
38
  `access` argument naming a profile. The file and the credentials never pass through a tool call.
37
39
 
40
+ `OPENCRAW_PROFILES` is the directory of the persistent browser profiles recipes name in
41
+ `session.browserProfile` (default `.opencraw/profiles` in the server's working directory).
42
+
38
43
  ## Tools
39
44
 
40
45
  ### `probe`
@@ -53,7 +58,13 @@ endpoints only a script fetches after load.
53
58
 
54
59
  Returns `{ url, status, findings: { jsonLd, inlineJson, jsonUrls, scriptHosts, apiLinks }, observed }`. For a
55
60
  PDF (served as `application/pdf`, or a local path) it adds `pdf: { pages, rows, headers }`: the first rows and
56
- every likely table header with the `selector` a `table` extract needs.
61
+ every likely table header with the `selector` a `table` extract needs. For a spreadsheet or a CSV (served as a
62
+ spreadsheet type or `text/csv`, or a local `.xlsx`, `.csv` or `.tsv` path) it adds
63
+ `workbook: { csv?: { encoding, delimiter }, sheets, rows, headers }`. For a presentation it adds
64
+ `deck: { width, height, slides, headers, charts, grids }`, and for JSON, JSON Lines or YAML
65
+ `json: { format, type, tree, lists }`: the structure, and every list of records with its path. An HTML page
66
+ adds `html: { tables, outline?, frontMatter? }`: its tables' header rows, and for Markdown its sections and
67
+ front matter keys.
57
68
 
58
69
  ### `validate`
59
70
 
@@ -82,6 +93,7 @@ Crawls the recipes at the given paths, or passed inline.
82
93
  | `dryRun?` | One record per input recipe instead of a full crawl — for checking a recipe under construction. |
83
94
  | `headed?`, `browserPath?`, `insecureTls?`, `userAgent?` | As in the cli. |
84
95
  | `access?` | The access profile for recipes that name none, from the server's `OPENCRAW_ACCESS` config. |
96
+ | `parallel?` | How many input recipes run at once (1 to 16, default 1). |
85
97
 
86
98
  Returns `{ report: CrawlReport, records?, truncated? }`. `records`/`truncated` are present only when `out`
87
99
  was not given, and `records` is capped at 50 even then.
package/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
2
2
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
- import { readRecipeFiles, probeUrl, loadForRun, resolveAccess, loadHooks } from '@opencraw/cli';
3
+ import { readRecipeFiles, probeUrl, loadForRun, loadPlugins, resolveAccess } from '@opencraw/cli';
4
4
  import { z } from 'zod';
5
5
  import { memorySink, jsonLinesSink, createCrawler, RecipeSet, RecipeValidationError, RecipeBindingError, parseOutputRecipe, parseInputRecipe, bindRecipeSet } from '@opencraw/core';
6
6
 
@@ -72,7 +72,8 @@ async function probeTool(args) {
72
72
  insecureTls: args.insecureTls === true || process.env.OPENCRAW_INSECURE_TLS === '1',
73
73
  userAgent: args.userAgent,
74
74
  access: process.env.OPENCRAW_ACCESS === '' ? undefined : process.env.OPENCRAW_ACCESS,
75
- accessProfile: args.access
75
+ accessProfile: args.access,
76
+ plugins: nonEmpty(process.env.OPENCRAW_PLUGINS) ?? nonEmpty(process.env.OPENCRAW_HOOKS)
76
77
  });
77
78
  return {
78
79
  content: [{
@@ -91,6 +92,9 @@ async function probeTool(args) {
91
92
  };
92
93
  }
93
94
  }
95
+ function nonEmpty(value) {
96
+ return value === '' ? undefined : value;
97
+ }
94
98
 
95
99
  const recipeObject = z.record(z.string(), z.unknown());
96
100
  const recipeObjects = z.array(recipeObject).min(1);
@@ -126,7 +130,8 @@ const runInputShape = {
126
130
  browserPath: z.string().optional().describe('A browser binary other than the one Playwright installed. Defaults to OPENCRAW_CHROMIUM in the server\'s environment.'),
127
131
  insecureTls: z.boolean().optional().describe("Accept an intercepting proxy's certificate. Defaults to OPENCRAW_INSECURE_TLS=1 in the server's environment."),
128
132
  userAgent: z.string().optional().describe('The user agent to send.'),
129
- access: z.string().optional().describe('An access profile (a proxy) from the server\'s access config file, OPENCRAW_ACCESS, used by every recipe that names none. The error for an unknown name lists the profiles.')
133
+ access: z.string().optional().describe('An access profile (a proxy) from the server\'s access config file, OPENCRAW_ACCESS, used by every recipe that names none. The error for an unknown name lists the profiles.'),
134
+ parallel: z.int().min(1).max(16).optional().describe('How many input recipes run at once. Default 1. Iterations inside a recipe follow its limits.concurrency.')
130
135
  };
131
136
  /**
132
137
  * The `run` tool: crawls the recipes in `paths` or `recipes` (exactly one
@@ -163,15 +168,20 @@ async function runTool(args) {
163
168
  append: args.append
164
169
  });
165
170
  try {
166
- const hooksFile = serverFile('OPENCRAW_HOOKS');
171
+ const pluginsFile = serverFile('OPENCRAW_PLUGINS') ?? serverFile('OPENCRAW_HOOKS');
172
+ const plugins = pluginsFile === undefined ? undefined : await loadPlugins(pluginsFile);
167
173
  crawler = createCrawler({
168
174
  sink,
169
- hooks: hooksFile === undefined ? undefined : await loadHooks(hooksFile),
175
+ hooks: plugins?.hooks,
176
+ accessPlugins: plugins?.accessPlugins,
177
+ captchaSolvers: plugins?.captchaSolvers,
170
178
  access: await resolveAccess({
171
179
  insecureTls: false,
172
180
  access: serverFile('OPENCRAW_ACCESS'),
173
181
  accessProfile: args.access
174
182
  }),
183
+ profilesDir: serverFile('OPENCRAW_PROFILES'),
184
+ parallel: args.parallel,
175
185
  resume: args.resume,
176
186
  browser: {
177
187
  headless: args.headed !== true,
@@ -218,7 +228,7 @@ async function runTool(args) {
218
228
  }
219
229
  }
220
230
  /**
221
- * A file the server was started with (`OPENCRAW_ACCESS`, `OPENCRAW_HOOKS`).
231
+ * A file the server was started with (`OPENCRAW_ACCESS`, `OPENCRAW_PLUGINS` or `OPENCRAW_HOOKS`).
222
232
  * Never a tool argument: a caller picks a profile, never a file, and never
223
233
  * names a module for the server to run.
224
234
  */
@@ -14,6 +14,7 @@ export declare const runInputShape: {
14
14
  insecureTls: z.ZodOptional<z.ZodBoolean>;
15
15
  userAgent: z.ZodOptional<z.ZodString>;
16
16
  access: z.ZodOptional<z.ZodString>;
17
+ parallel: z.ZodOptional<z.ZodInt>;
17
18
  paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
18
19
  recipes: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodRecord<z.ZodString, z.ZodUnknown>>]>>;
19
20
  };
@@ -28,6 +29,7 @@ interface RunArgs extends RecipeSourceArgs {
28
29
  insecureTls?: boolean;
29
30
  userAgent?: string;
30
31
  access?: string;
32
+ parallel?: number;
31
33
  }
32
34
  /** What the `run` tool returns. */
33
35
  export interface RunResult {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opencraw/mcp",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "main": "./dist/index.esm.js",
6
6
  "module": "./dist/index.esm.js",
@@ -24,8 +24,8 @@
24
24
  "!**/*.js.map"
25
25
  ],
26
26
  "dependencies": {
27
- "@opencraw/core": "^0.1.1",
28
- "@opencraw/cli": "^0.1.1",
27
+ "@opencraw/core": "^0.1.3",
28
+ "@opencraw/cli": "^0.1.3",
29
29
  "@modelcontextprotocol/sdk": "^1.30.1",
30
30
  "playwright": "^1.63.0",
31
31
  "zod": "^4.6.5"