@opencraw/mcp 0.1.3 → 0.1.4
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
|
@@ -109,6 +109,21 @@ call, for checking what already exists before writing a new recipe.
|
|
|
109
109
|
|
|
110
110
|
Returns `{ outputs: [{ path, id }], inputs: [{ path, id, output, mode }], others: string[] }`.
|
|
111
111
|
|
|
112
|
+
### `diff`
|
|
113
|
+
|
|
114
|
+
Compares two runs' JSON Lines files by record key: what was added, what was removed, and which fields changed,
|
|
115
|
+
before and after. For "what changed in this price list since last week" without re-reading it all.
|
|
116
|
+
|
|
117
|
+
| Input | Meaning |
|
|
118
|
+
|---|---|
|
|
119
|
+
| `previous`, `current` | The two runs' files (a `run`'s `out`). |
|
|
120
|
+
| `key?` | The fields that identify a record (the output recipe's key fields). Default: each line's `_key`, which a run with `append` writes. |
|
|
121
|
+
| `ignore?` | Fields not compared, such as a `scrapedAt` the crawl stamps. |
|
|
122
|
+
|
|
123
|
+
Returns `{ added, removed, changed, unchanged, shrunk?, summary, changes }`: `summary` is the report a person
|
|
124
|
+
reads, `changes` the first 200 changes (`removed`, `changed` with `fields: [{ field, before, after }]`, `added`),
|
|
125
|
+
and `shrunk` is set when the current run holds under half the records the previous one did.
|
|
126
|
+
|
|
112
127
|
## Building
|
|
113
128
|
|
|
114
129
|
`nx build @opencraw/mcp`, `nx test @opencraw/mcp` (unit tests per tool), `nx run @opencraw/mcp:e2e`
|
package/dist/index.esm.js
CHANGED
|
@@ -1,8 +1,60 @@
|
|
|
1
1
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
-
import {
|
|
3
|
+
import { readRecordsFile, diffRecords, memorySink, jsonLinesSink, createCrawler, RecipeSet, RecipeValidationError, RecipeBindingError, parseOutputRecipe, parseInputRecipe, bindRecipeSet } from '@opencraw/core';
|
|
4
|
+
import { diffReport, readRecipeFiles, probeUrl, loadForRun, loadPlugins, resolveAccess } from '@opencraw/cli';
|
|
4
5
|
import { z } from 'zod';
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
/** Changes returned at most; the counts cover all of them. */
|
|
8
|
+
const CHANGE_LIMIT = 200;
|
|
9
|
+
/** Input schema for the `diff` tool. */
|
|
10
|
+
const diffInputShape = {
|
|
11
|
+
previous: z.string().describe('The earlier run\'s JSON Lines file (a run\'s "out").'),
|
|
12
|
+
current: z.string().describe('The later run\'s JSON Lines file.'),
|
|
13
|
+
key: z.array(z.string()).optional().describe('The fields that identify a record (the output recipe\'s key fields). Default: each line\'s _key, which an appending run writes.'),
|
|
14
|
+
ignore: z.array(z.string()).optional().describe('Fields left out of the comparison, such as a scrapedAt the crawl stamps.')
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* The `diff` tool: compares two runs' records by key, so an agent watching a
|
|
18
|
+
* source can say what changed since last time instead of re-reading it all.
|
|
19
|
+
*
|
|
20
|
+
* @param args - The tool's parsed input.
|
|
21
|
+
* @returns The MCP tool result.
|
|
22
|
+
*/
|
|
23
|
+
async function diffTool(args) {
|
|
24
|
+
try {
|
|
25
|
+
const [previous, current] = await Promise.all([readRecordsFile(args.previous), readRecordsFile(args.current)]);
|
|
26
|
+
const diff = diffRecords(previous, current, {
|
|
27
|
+
key: args.key,
|
|
28
|
+
ignore: args.ignore
|
|
29
|
+
});
|
|
30
|
+
const result = {
|
|
31
|
+
added: diff.added,
|
|
32
|
+
removed: diff.removed,
|
|
33
|
+
changed: diff.changed,
|
|
34
|
+
unchanged: diff.unchanged,
|
|
35
|
+
...(diff.shrunk !== undefined && {
|
|
36
|
+
shrunk: diff.shrunk
|
|
37
|
+
}),
|
|
38
|
+
summary: diffReport(diff),
|
|
39
|
+
changes: diff.changes.slice(0, CHANGE_LIMIT)
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
content: [{
|
|
43
|
+
type: 'text',
|
|
44
|
+
text: JSON.stringify(result)
|
|
45
|
+
}],
|
|
46
|
+
structuredContent: result
|
|
47
|
+
};
|
|
48
|
+
} catch (error) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{
|
|
51
|
+
type: 'text',
|
|
52
|
+
text: error instanceof Error ? error.message : String(error)
|
|
53
|
+
}],
|
|
54
|
+
isError: true
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
6
58
|
|
|
7
59
|
/** Input schema for the `list_recipes` tool. */
|
|
8
60
|
const listRecipesInputShape = {
|
|
@@ -342,7 +394,7 @@ const SERVER_INFO = {
|
|
|
342
394
|
};
|
|
343
395
|
/**
|
|
344
396
|
* Builds the MCP server: one tool per crawl primitive (`probe`, `validate`,
|
|
345
|
-
* `run`, `list_recipes`), each a thin wrapper over `@opencraw/core` and
|
|
397
|
+
* `run`, `list_recipes`, `diff`), each a thin wrapper over `@opencraw/core` and
|
|
346
398
|
* `@opencraw/cli`'s structured helpers. No transport is attached; `main`
|
|
347
399
|
* connects it over stdio.
|
|
348
400
|
*
|
|
@@ -366,6 +418,10 @@ function createServer() {
|
|
|
366
418
|
description: 'List the recipe files in a directory, split by kind, with their ids. Check before writing a new recipe, or to see what an existing output recipe covers.',
|
|
367
419
|
inputSchema: listRecipesInputShape
|
|
368
420
|
}, args => listRecipesTool(args));
|
|
421
|
+
server.registerTool('diff', {
|
|
422
|
+
description: 'Compare two runs\' JSON Lines files by record key: what was added, removed, and changed (each field before and after). Use to report what changed in a source since the last crawl.',
|
|
423
|
+
inputSchema: diffInputShape
|
|
424
|
+
}, args => diffTool(args));
|
|
369
425
|
return server;
|
|
370
426
|
}
|
|
371
427
|
|
|
@@ -379,5 +435,5 @@ async function main() {
|
|
|
379
435
|
await server.connect(new StdioServerTransport());
|
|
380
436
|
}
|
|
381
437
|
|
|
382
|
-
export { createServer, listRecipesInputShape, listRecipesTool, main, probeInputShape, probeTool, runInputShape, runTool, validateInputShape, validateTool };
|
|
438
|
+
export { createServer, diffInputShape, diffTool, listRecipesInputShape, listRecipesTool, main, probeInputShape, probeTool, runInputShape, runTool, validateInputShape, validateTool };
|
|
383
439
|
//# sourceMappingURL=index.esm.js.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import type { RecordChange } from '@opencraw/core';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
/** Input schema for the `diff` tool. */
|
|
5
|
+
export declare const diffInputShape: {
|
|
6
|
+
previous: z.ZodString;
|
|
7
|
+
current: z.ZodString;
|
|
8
|
+
key: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
9
|
+
ignore: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
10
|
+
};
|
|
11
|
+
interface DiffArgs {
|
|
12
|
+
previous: string;
|
|
13
|
+
current: string;
|
|
14
|
+
key?: string[];
|
|
15
|
+
ignore?: string[];
|
|
16
|
+
}
|
|
17
|
+
/** What the `diff` tool returns. */
|
|
18
|
+
export interface DiffResult {
|
|
19
|
+
added: number;
|
|
20
|
+
removed: number;
|
|
21
|
+
changed: number;
|
|
22
|
+
unchanged: number;
|
|
23
|
+
/** Set when the current run lost most of the previous run's records. */
|
|
24
|
+
shrunk?: {
|
|
25
|
+
previous: number;
|
|
26
|
+
current: number;
|
|
27
|
+
};
|
|
28
|
+
/** The report a person reads, one line per change. */
|
|
29
|
+
summary: string[];
|
|
30
|
+
/** The changes, up to 200: removed, changed (with each field's before and after), added. */
|
|
31
|
+
changes: RecordChange[];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The `diff` tool: compares two runs' records by key, so an agent watching a
|
|
35
|
+
* source can say what changed since last time instead of re-reading it all.
|
|
36
|
+
*
|
|
37
|
+
* @param args - The tool's parsed input.
|
|
38
|
+
* @returns The MCP tool result.
|
|
39
|
+
*/
|
|
40
|
+
export declare function diffTool(args: DiffArgs): Promise<CallToolResult>;
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=diff-tool.handler.d.ts.map
|
package/dist/src/index.d.ts
CHANGED
|
@@ -2,6 +2,8 @@ export { main } from './main.js';
|
|
|
2
2
|
export { createServer } from './server/index.js';
|
|
3
3
|
export { probeTool, probeInputShape } from './probe-tool/index.js';
|
|
4
4
|
export { validateTool, validateInputShape } from './validate-tool/index.js';
|
|
5
|
+
export { diffTool, diffInputShape } from './diff-tool/index.js';
|
|
6
|
+
export type { DiffResult } from './diff-tool/index.js';
|
|
5
7
|
export type { ValidateResult } from './validate-tool/index.js';
|
|
6
8
|
export { runTool, runInputShape } from './run-tool/index.js';
|
|
7
9
|
export type { RunResult } from './run-tool/index.js';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
/**
|
|
3
3
|
* Builds the MCP server: one tool per crawl primitive (`probe`, `validate`,
|
|
4
|
-
* `run`, `list_recipes`), each a thin wrapper over `@opencraw/core` and
|
|
4
|
+
* `run`, `list_recipes`, `diff`), each a thin wrapper over `@opencraw/core` and
|
|
5
5
|
* `@opencraw/cli`'s structured helpers. No transport is attached; `main`
|
|
6
6
|
* connects it over stdio.
|
|
7
7
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opencraw/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
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.4",
|
|
28
|
+
"@opencraw/cli": "^0.1.4",
|
|
29
29
|
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
30
30
|
"playwright": "^1.63.0",
|
|
31
31
|
"zod": "^4.6.5"
|