@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 +16 -4
- package/dist/index.esm.js +16 -6
- package/dist/src/run-tool/run-tool.handler.d.ts +2 -0
- package/package.json +3 -3
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
|
|
31
|
-
|
|
32
|
-
|
|
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,
|
|
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
|
|
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:
|
|
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.
|
|
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.
|
|
28
|
-
"@opencraw/cli": "^0.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"
|