@reclaimprotocol/agent 0.1.18 → 0.1.21
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 +6 -2
- package/lib/authoring/backend.d.ts +4 -0
- package/lib/authoring/tools.js +4 -1
- package/lib/cdp/capture.d.ts +2 -2
- package/lib/cdp/capture.js +25 -21
- package/lib/cdp/client.d.ts +39 -1
- package/lib/cdp/client.js +125 -1
- package/lib/mcp/api/operations.gen.js +33 -9
- package/lib/mcp/instructions.js +27 -3
- package/lib/mcp/remap_errors.js +2 -1
- package/lib/mcp/start.js +16 -9
- package/lib/mcp/tools/agent/attach.d.ts +18 -4
- package/lib/mcp/tools/agent/attach.js +142 -52
- package/lib/mcp/tools/agent/build.d.ts +9 -2
- package/lib/mcp/tools/agent/build.js +15 -7
- package/lib/mcp/tools/agent/capture.d.ts +1 -0
- package/lib/mcp/tools/agent/capture.js +8 -1
- package/lib/mcp/tools/agent/eval.js +2 -3
- package/lib/mcp/tools/agent/how-it-works.d.ts +1 -1
- package/lib/mcp/tools/agent/how-it-works.js +1 -1
- package/lib/mcp/tools/agent/index.d.ts +1 -1
- package/lib/mcp/tools/agent/index.js +1 -1
- package/lib/mcp/tools/agent/publish.d.ts +4 -1
- package/lib/mcp/tools/agent/publish.js +42 -3
- package/lib/mcp/tools/agent/session.d.ts +2 -2
- package/lib/mcp/tools/agent/session.js +21 -5
- package/lib/mcp/tools/agent/shared.js +4 -6
- package/lib/mcp/tools/authenticate/authenticate.d.ts +1 -1
- package/lib/mcp/tools/authenticate/authenticate.js +13 -6
- package/lib/mcp/tools/authenticate/builder-access.d.ts +8 -0
- package/lib/mcp/tools/authenticate/builder-access.js +31 -0
- package/lib/mcp/tools/authenticate/index.d.ts +1 -0
- package/lib/mcp/tools/authenticate/index.js +1 -0
- package/lib/old/login-cdp.js +11 -3
- package/lib/old/tools/build.d.ts +8 -1
- package/lib/old/tools/build.js +6 -2
- package/lib/old/tools/publish.d.ts +10 -1
- package/lib/old/tools/publish.js +49 -3
- package/lib/provider/draft.d.ts +20 -0
- package/lib/provider/draft.js +75 -51
- package/lib/provider/index.d.ts +1 -1
- package/lib/provider/index.js +1 -1
- package/lib/provider/secrets.d.ts +37 -0
- package/lib/provider/secrets.js +147 -6
- package/lib/provider/to-version.d.ts +7 -0
- package/lib/provider/to-version.js +11 -1
- package/package.json +2 -2
- package/skill/SKILL.builder.md +44 -94
- package/skill/SKILL.common.md +102 -0
- package/skill/SKILL.old.md +21 -73
- package/skill/builder-mode.md +2 -2
- package/skill/injection-api.md +95 -10
- package/skill/old-mode.md +2 -2
- package/src/authoring/backend.ts +4 -0
- package/src/authoring/tools.ts +4 -1
- package/src/cdp/capture.ts +24 -24
- package/src/cdp/client.ts +197 -2
- package/src/mcp/api/operations.gen.ts +33 -9
- package/src/mcp/instructions.ts +36 -3
- package/src/mcp/remap_errors.ts +2 -1
- package/src/mcp/start.ts +24 -9
- package/src/mcp/tools/agent/attach.ts +198 -57
- package/src/mcp/tools/agent/build.ts +20 -6
- package/src/mcp/tools/agent/capture.ts +10 -1
- package/src/mcp/tools/agent/eval.ts +2 -3
- package/src/mcp/tools/agent/how-it-works.ts +1 -1
- package/src/mcp/tools/agent/index.ts +1 -1
- package/src/mcp/tools/agent/publish.ts +46 -2
- package/src/mcp/tools/agent/session.ts +29 -8
- package/src/mcp/tools/agent/shared.ts +5 -10
- package/src/mcp/tools/authenticate/authenticate.ts +17 -9
- package/src/mcp/tools/authenticate/builder-access.ts +42 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/old/login-cdp.ts +13 -3
- package/src/old/tools/build.ts +7 -1
- package/src/old/tools/publish.ts +55 -4
- package/src/provider/draft.ts +98 -56
- package/src/provider/index.ts +9 -1
- package/src/provider/secrets.ts +171 -6
- package/src/provider/to-version.ts +12 -1
- package/lib/authoring/find.d.ts +0 -3
- package/lib/authoring/find.js +0 -54
- package/lib/authoring/propose.d.ts +0 -3
- package/lib/authoring/propose.js +0 -109
- package/lib/authoring/replay.d.ts +0 -10
- package/lib/authoring/replay.js +0 -34
- package/lib/cli/args.d.ts +0 -14
- package/lib/cli/args.js +0 -19
- package/lib/cli/commands.d.ts +0 -1
- package/lib/cli/commands.js +0 -19
- package/lib/cli.d.ts +0 -1
- package/lib/cli.js +0 -7
- package/lib/mcp/credentials/authenticate.d.ts +0 -3
- package/lib/mcp/credentials/authenticate.js +0 -108
- package/lib/mcp/credentials/build.d.ts +0 -5
- package/lib/mcp/credentials/build.js +0 -18
- package/lib/mcp/credentials/cache.d.ts +0 -70
- package/lib/mcp/credentials/cache.js +0 -131
- package/lib/mcp/credentials/env-file.d.ts +0 -25
- package/lib/mcp/credentials/env-file.js +0 -71
- package/lib/mcp/credentials/import.d.ts +0 -2
- package/lib/mcp/credentials/import.js +0 -52
- package/lib/mcp/credentials/issue.d.ts +0 -2
- package/lib/mcp/credentials/issue.js +0 -84
- package/lib/mcp/credentials/keypair.d.ts +0 -17
- package/lib/mcp/credentials/keypair.js +0 -48
- package/lib/mcp/credentials/link.d.ts +0 -3
- package/lib/mcp/credentials/link.js +0 -107
- package/lib/mcp/credentials/list-cached.d.ts +0 -2
- package/lib/mcp/credentials/list-cached.js +0 -55
- package/lib/mcp/credentials/owner-key.d.ts +0 -23
- package/lib/mcp/credentials/owner-key.js +0 -58
- package/lib/mcp/credentials/paths.d.ts +0 -12
- package/lib/mcp/credentials/paths.js +0 -35
- package/lib/mcp/credentials/poll.d.ts +0 -27
- package/lib/mcp/credentials/poll.js +0 -61
- package/lib/mcp/credentials/register.d.ts +0 -18
- package/lib/mcp/credentials/register.js +0 -30
- package/lib/mcp/credentials/resolve-owner-key.d.ts +0 -12
- package/lib/mcp/credentials/resolve-owner-key.js +0 -68
- package/lib/mcp/credentials/session-cache.d.ts +0 -14
- package/lib/mcp/credentials/session-cache.js +0 -42
- package/lib/mcp/credentials/status.d.ts +0 -3
- package/lib/mcp/credentials/status.js +0 -76
- package/lib/mcp/register.d.ts +0 -38
- package/lib/mcp/register.js +0 -80
- package/lib/mcp/tools/analyze.d.ts +0 -3
- package/lib/mcp/tools/analyze.js +0 -26
- package/lib/mcp/tools/attach.d.ts +0 -11
- package/lib/mcp/tools/attach.js +0 -72
- package/lib/mcp/tools/capture.d.ts +0 -10
- package/lib/mcp/tools/capture.js +0 -142
- package/lib/mcp/tools/eval.d.ts +0 -5
- package/lib/mcp/tools/eval.js +0 -127
- package/lib/mcp/tools/find.d.ts +0 -3
- package/lib/mcp/tools/find.js +0 -60
- package/lib/mcp/tools/owner-key.d.ts +0 -2
- package/lib/mcp/tools/owner-key.js +0 -63
- package/lib/mcp/tools/proof.d.ts +0 -3
- package/lib/mcp/tools/proof.js +0 -214
- package/lib/mcp/tools/propose.d.ts +0 -9
- package/lib/mcp/tools/propose.js +0 -75
- package/lib/mcp/tools/publish.d.ts +0 -3
- package/lib/mcp/tools/publish.js +0 -59
- package/lib/mcp/tools/replay.d.ts +0 -3
- package/lib/mcp/tools/replay.js +0 -46
- package/lib/mcp/tools/session.d.ts +0 -10
- package/lib/mcp/tools/session.js +0 -29
- package/lib/mcp/tools/verification/diagnose.d.ts +0 -11
- package/lib/mcp/tools/verification/diagnose.js +0 -132
- package/lib/mcp/verifications/build.d.ts +0 -5
- package/lib/mcp/verifications/build.js +0 -14
- package/lib/mcp/verifications/create.d.ts +0 -3
- package/lib/mcp/verifications/create.js +0 -57
- package/lib/mcp/verifications/find.d.ts +0 -3
- package/lib/mcp/verifications/find.js +0 -37
- package/lib/mcp/verifications/get.d.ts +0 -3
- package/lib/mcp/verifications/get.js +0 -26
- package/lib/mcp/verifications/update.d.ts +0 -3
- package/lib/mcp/verifications/update.js +0 -78
- package/lib/old/tools/get-version-config.d.ts +0 -17
- package/lib/old/tools/get-version-config.js +0 -47
- package/lib/routes.gen.d.ts +0 -271
- package/lib/routes.gen.js +0 -73
- package/lib/types/openapi.d.ts +0 -4
- package/lib/types/openapi.gen.d.ts +0 -3967
- package/lib/types/openapi.gen.js +0 -5
- package/lib/types/openapi.js +0 -1
package/lib/mcp/tools/capture.js
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { startCapture } from "../../cdp/capture.js";
|
|
2
|
-
import { defineTool } from "../server.js";
|
|
3
|
-
export function captureTools(attachRef, captures) {
|
|
4
|
-
const requireAttached = () => {
|
|
5
|
-
if (!attachRef.current) {
|
|
6
|
-
throw new Error('Not attached. Call attach_chrome first.');
|
|
7
|
-
}
|
|
8
|
-
return attachRef.current;
|
|
9
|
-
};
|
|
10
|
-
const startTool = defineTool({
|
|
11
|
-
name: 'start_capture',
|
|
12
|
-
description: 'Begin recording network requests on the specified tab. ' +
|
|
13
|
-
'Returns a captureId.',
|
|
14
|
-
inputSchema: {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: { tabId: { type: 'string' } },
|
|
17
|
-
required: ['tabId'],
|
|
18
|
-
},
|
|
19
|
-
}, async ({ tabId }) => {
|
|
20
|
-
const attached = requireAttached();
|
|
21
|
-
const tabClient = await attached.handles.attachToTab(tabId);
|
|
22
|
-
const session = await startCapture(tabClient);
|
|
23
|
-
captures.sessions.set(session.captureId, session);
|
|
24
|
-
captures.activeTab = tabId;
|
|
25
|
-
return { captureId: session.captureId };
|
|
26
|
-
});
|
|
27
|
-
const stopTool = defineTool({
|
|
28
|
-
name: 'stop_capture',
|
|
29
|
-
description: 'Stop recording on the given capture. ' +
|
|
30
|
-
'Captured data remains queryable until reset_session.',
|
|
31
|
-
inputSchema: {
|
|
32
|
-
type: 'object',
|
|
33
|
-
properties: { captureId: { type: 'string' } },
|
|
34
|
-
required: ['captureId'],
|
|
35
|
-
},
|
|
36
|
-
}, async ({ captureId }) => {
|
|
37
|
-
const session = captures.sessions.get(captureId);
|
|
38
|
-
if (!session) {
|
|
39
|
-
throw new Error(`no capture ${captureId}`);
|
|
40
|
-
}
|
|
41
|
-
await session.stop();
|
|
42
|
-
return { stopped: true, requestCount: session.requests.size };
|
|
43
|
-
});
|
|
44
|
-
const listTool = defineTool({
|
|
45
|
-
name: 'list_requests',
|
|
46
|
-
description: 'List metadata for captured requests. ' +
|
|
47
|
-
'Filter by method, URL glob, status, content-type, ' +
|
|
48
|
-
'or graphqlOp. Returns only metadata, never bodies — ' +
|
|
49
|
-
'use get_request for those.',
|
|
50
|
-
inputSchema: {
|
|
51
|
-
type: 'object',
|
|
52
|
-
properties: {
|
|
53
|
-
captureId: { type: 'string' },
|
|
54
|
-
filter: {
|
|
55
|
-
type: 'object',
|
|
56
|
-
properties: {
|
|
57
|
-
method: { type: 'string' },
|
|
58
|
-
urlGlob: { type: 'string' },
|
|
59
|
-
statusMin: { type: 'number' },
|
|
60
|
-
statusMax: { type: 'number' },
|
|
61
|
-
contentType: { type: 'string' },
|
|
62
|
-
graphqlOp: { type: 'string' },
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
},
|
|
66
|
-
required: ['captureId'],
|
|
67
|
-
},
|
|
68
|
-
}, async ({ captureId, filter }) => {
|
|
69
|
-
const session = captures.sessions.get(captureId);
|
|
70
|
-
if (!session) {
|
|
71
|
-
throw new Error(`no capture ${captureId}`);
|
|
72
|
-
}
|
|
73
|
-
const out = [];
|
|
74
|
-
for (const r of session.requests.values()) {
|
|
75
|
-
if (filter?.method && r.method !== filter.method.toUpperCase()) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
if (filter?.urlGlob && !globMatch(filter.urlGlob, r.url)) {
|
|
79
|
-
continue;
|
|
80
|
-
}
|
|
81
|
-
if (filter?.statusMin !== undefined && r.status < filter.statusMin) {
|
|
82
|
-
continue;
|
|
83
|
-
}
|
|
84
|
-
if (filter?.statusMax !== undefined && r.status > filter.statusMax) {
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
if (filter?.contentType &&
|
|
88
|
-
!r.contentType.includes(filter.contentType)) {
|
|
89
|
-
continue;
|
|
90
|
-
}
|
|
91
|
-
if (filter?.graphqlOp && r.graphqlOp !== filter.graphqlOp) {
|
|
92
|
-
continue;
|
|
93
|
-
}
|
|
94
|
-
const item = {
|
|
95
|
-
requestId: r.requestId,
|
|
96
|
-
method: r.method,
|
|
97
|
-
url: r.url,
|
|
98
|
-
status: r.status,
|
|
99
|
-
contentType: r.contentType,
|
|
100
|
-
size: r.size,
|
|
101
|
-
};
|
|
102
|
-
if (r.graphqlOp !== undefined) {
|
|
103
|
-
item.graphqlOp = r.graphqlOp;
|
|
104
|
-
}
|
|
105
|
-
out.push(item);
|
|
106
|
-
}
|
|
107
|
-
return { requests: out };
|
|
108
|
-
});
|
|
109
|
-
const getTool = defineTool({
|
|
110
|
-
name: 'get_request',
|
|
111
|
-
description: 'Return full headers + bodies for a specific captured request.',
|
|
112
|
-
inputSchema: {
|
|
113
|
-
type: 'object',
|
|
114
|
-
properties: {
|
|
115
|
-
captureId: { type: 'string' },
|
|
116
|
-
requestId: { type: 'string' },
|
|
117
|
-
},
|
|
118
|
-
required: ['captureId', 'requestId'],
|
|
119
|
-
},
|
|
120
|
-
}, async ({ captureId, requestId }) => {
|
|
121
|
-
const session = captures.sessions.get(captureId);
|
|
122
|
-
if (!session) {
|
|
123
|
-
throw new Error(`no capture ${captureId}`);
|
|
124
|
-
}
|
|
125
|
-
const r = session.requests.get(requestId);
|
|
126
|
-
if (!r) {
|
|
127
|
-
throw new Error(`no request ${requestId} in capture ${captureId}`);
|
|
128
|
-
}
|
|
129
|
-
const body = session.bodies.get(requestId);
|
|
130
|
-
if (!body.available) {
|
|
131
|
-
return { ...r, bodyAvailable: false, reason: body.reason };
|
|
132
|
-
}
|
|
133
|
-
return { ...r, responseBody: body.body, bodyAvailable: true };
|
|
134
|
-
});
|
|
135
|
-
return [startTool, stopTool, listTool, getTool];
|
|
136
|
-
}
|
|
137
|
-
function globMatch(pattern, str) {
|
|
138
|
-
const re = new RegExp('^' +
|
|
139
|
-
pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') +
|
|
140
|
-
'$');
|
|
141
|
-
return re.test(str);
|
|
142
|
-
}
|
package/lib/mcp/tools/eval.d.ts
DELETED
package/lib/mcp/tools/eval.js
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import { listTabs } from "../../cdp/tabs.js";
|
|
2
|
-
import { defineTool } from "../server.js";
|
|
3
|
-
export function browserTools(attachRef) {
|
|
4
|
-
const requireAttached = () => {
|
|
5
|
-
if (!attachRef.current) {
|
|
6
|
-
throw new Error('Not attached. Call attach_chrome first.');
|
|
7
|
-
}
|
|
8
|
-
return attachRef.current;
|
|
9
|
-
};
|
|
10
|
-
return [
|
|
11
|
-
defineTool({
|
|
12
|
-
name: 'list_tabs',
|
|
13
|
-
description: 'List open Chrome tabs.',
|
|
14
|
-
inputSchema: { type: 'object', properties: {} },
|
|
15
|
-
}, async () => {
|
|
16
|
-
const attached = requireAttached();
|
|
17
|
-
return { tabs: await listTabs(attached.port) };
|
|
18
|
-
}),
|
|
19
|
-
defineTool({
|
|
20
|
-
name: 'eval_in_page',
|
|
21
|
-
description: 'Run a JS expression in a tab via Runtime.evaluate ' +
|
|
22
|
-
'and return the result. ' +
|
|
23
|
-
'Useful for reading visible values from the DOM.',
|
|
24
|
-
inputSchema: {
|
|
25
|
-
type: 'object',
|
|
26
|
-
properties: {
|
|
27
|
-
tabId: { type: 'string' },
|
|
28
|
-
expression: { type: 'string' },
|
|
29
|
-
},
|
|
30
|
-
required: ['tabId', 'expression'],
|
|
31
|
-
},
|
|
32
|
-
}, async ({ tabId, expression }) => {
|
|
33
|
-
const attached = requireAttached();
|
|
34
|
-
const { Runtime } = await attached.handles.attachToTab(tabId);
|
|
35
|
-
const result = await Runtime.evaluate({
|
|
36
|
-
expression,
|
|
37
|
-
returnByValue: true,
|
|
38
|
-
});
|
|
39
|
-
if (result.exceptionDetails) {
|
|
40
|
-
return { error: result.exceptionDetails.text };
|
|
41
|
-
}
|
|
42
|
-
return { value: result.result.value };
|
|
43
|
-
}),
|
|
44
|
-
defineTool({
|
|
45
|
-
name: 'navigate',
|
|
46
|
-
description: 'Navigate a tab to a URL via Page.navigate, ' +
|
|
47
|
-
'waiting for the load event. ' +
|
|
48
|
-
'Use this to drive the browser yourself ' +
|
|
49
|
-
'instead of asking the developer to navigate. ' +
|
|
50
|
-
'Returns the final URL after navigation ' +
|
|
51
|
-
'(which may differ from the requested URL due to redirects).',
|
|
52
|
-
inputSchema: {
|
|
53
|
-
type: 'object',
|
|
54
|
-
properties: {
|
|
55
|
-
tabId: { type: 'string' },
|
|
56
|
-
url: { type: 'string' },
|
|
57
|
-
timeoutMs: { type: 'number' },
|
|
58
|
-
},
|
|
59
|
-
required: ['tabId', 'url'],
|
|
60
|
-
},
|
|
61
|
-
}, async ({ tabId, url, timeoutMs }) => {
|
|
62
|
-
const attached = requireAttached();
|
|
63
|
-
const { Page, Runtime } = await attached.handles.attachToTab(tabId);
|
|
64
|
-
await Page.enable();
|
|
65
|
-
const loadPromise = new Promise((resolve) => {
|
|
66
|
-
Page.loadEventFired(() => resolve());
|
|
67
|
-
});
|
|
68
|
-
const nav = await Page.navigate({ url });
|
|
69
|
-
if (nav.errorText) {
|
|
70
|
-
return { ok: false, error: nav.errorText };
|
|
71
|
-
}
|
|
72
|
-
const t = timeoutMs ?? 30_000;
|
|
73
|
-
const raced = await Promise.race([
|
|
74
|
-
loadPromise.then(() => 'loaded'),
|
|
75
|
-
new Promise((resolve) => setTimeout(() => resolve('timeout'), t)),
|
|
76
|
-
]);
|
|
77
|
-
const final = await Runtime.evaluate({
|
|
78
|
-
expression: 'location.href',
|
|
79
|
-
returnByValue: true,
|
|
80
|
-
});
|
|
81
|
-
return {
|
|
82
|
-
ok: true,
|
|
83
|
-
loadStatus: raced,
|
|
84
|
-
finalUrl: final.result.value,
|
|
85
|
-
};
|
|
86
|
-
}),
|
|
87
|
-
defineTool({
|
|
88
|
-
name: 'wait_for_page',
|
|
89
|
-
description: 'Poll a JS expression in a tab until it ' +
|
|
90
|
-
'returns truthy (or timeout). ' +
|
|
91
|
-
'Use this for steps that require the ' +
|
|
92
|
-
'developer to do something in the browser — ' +
|
|
93
|
-
'most commonly waiting for them to finish logging in. ' +
|
|
94
|
-
'Pass an expression that ' +
|
|
95
|
-
'evaluates true once the desired state is reached, e.g. ' +
|
|
96
|
-
'`!!document.querySelector' +
|
|
97
|
-
'(\'summary[aria-label*="View profile"]\')`' +
|
|
98
|
-
' for GitHub post-login.',
|
|
99
|
-
inputSchema: {
|
|
100
|
-
type: 'object',
|
|
101
|
-
properties: {
|
|
102
|
-
tabId: { type: 'string' },
|
|
103
|
-
expression: { type: 'string' },
|
|
104
|
-
timeoutMs: { type: 'number' },
|
|
105
|
-
pollMs: { type: 'number' },
|
|
106
|
-
},
|
|
107
|
-
required: ['tabId', 'expression'],
|
|
108
|
-
},
|
|
109
|
-
}, async ({ tabId, expression, timeoutMs, pollMs }) => {
|
|
110
|
-
const attached = requireAttached();
|
|
111
|
-
const { Runtime } = await attached.handles.attachToTab(tabId);
|
|
112
|
-
const deadline = Date.now() + (timeoutMs ?? 120_000);
|
|
113
|
-
const interval = pollMs ?? 1000;
|
|
114
|
-
while (Date.now() < deadline) {
|
|
115
|
-
const r = await Runtime.evaluate({ expression, returnByValue: true });
|
|
116
|
-
if (r.exceptionDetails) {
|
|
117
|
-
return { matched: false, error: r.exceptionDetails.text };
|
|
118
|
-
}
|
|
119
|
-
if (r.result.value) {
|
|
120
|
-
return { matched: true, value: r.result.value };
|
|
121
|
-
}
|
|
122
|
-
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
123
|
-
}
|
|
124
|
-
return { matched: false, reason: 'timeout' };
|
|
125
|
-
}),
|
|
126
|
-
];
|
|
127
|
-
}
|
package/lib/mcp/tools/find.d.ts
DELETED
package/lib/mcp/tools/find.js
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { normalizeCandidates } from "../../provider/normalize.js";
|
|
2
|
-
import { defineTool } from "../server.js";
|
|
3
|
-
export function findTool(captures) {
|
|
4
|
-
return defineTool({
|
|
5
|
-
name: 'find_requests_containing',
|
|
6
|
-
description: 'Search captured responses for any encoding of `value`.' +
|
|
7
|
-
'Returns a ranked candidate list ' +
|
|
8
|
-
'with the JSON path (when applicable), score, and a short snippet.' +
|
|
9
|
-
'Server-side; bodies stay here.',
|
|
10
|
-
inputSchema: {
|
|
11
|
-
type: 'object',
|
|
12
|
-
properties: {
|
|
13
|
-
captureId: { type: 'string' },
|
|
14
|
-
value: { type: 'string' },
|
|
15
|
-
limit: { type: 'number' },
|
|
16
|
-
},
|
|
17
|
-
required: ['captureId', 'value'],
|
|
18
|
-
},
|
|
19
|
-
}, async ({ captureId, value, limit }) => {
|
|
20
|
-
const session = captures.sessions.get(captureId);
|
|
21
|
-
if (!session) {
|
|
22
|
-
throw new Error(`no capture ${captureId}`);
|
|
23
|
-
}
|
|
24
|
-
const variants = normalizeCandidates(value);
|
|
25
|
-
const ranked = [];
|
|
26
|
-
for (const r of session.requests.values()) {
|
|
27
|
-
if (!r.responseBody) {
|
|
28
|
-
continue;
|
|
29
|
-
}
|
|
30
|
-
let hit;
|
|
31
|
-
for (const v of variants) {
|
|
32
|
-
const idx = r.responseBody.indexOf(v);
|
|
33
|
-
if (idx >= 0) {
|
|
34
|
-
const start = Math.max(0, idx - 40);
|
|
35
|
-
const end = Math.min(r.responseBody.length, idx + v.length + 40);
|
|
36
|
-
hit = { snippet: r.responseBody.slice(start, end), variant: v };
|
|
37
|
-
break;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
if (!hit) {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
// Score: prefer JSON responses + smaller bodies (likely API endpoints).
|
|
44
|
-
const score = (r.contentType.includes('json') ? 10 : 0) +
|
|
45
|
-
Math.max(0, 5 - Math.log10(Math.max(r.size, 1)));
|
|
46
|
-
ranked.push({
|
|
47
|
-
requestId: r.requestId,
|
|
48
|
-
url: r.url,
|
|
49
|
-
method: r.method,
|
|
50
|
-
status: r.status,
|
|
51
|
-
contentType: r.contentType,
|
|
52
|
-
matchedVariant: hit.variant,
|
|
53
|
-
snippet: hit.snippet,
|
|
54
|
-
score,
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
ranked.sort((a, b) => b.score - a.score);
|
|
58
|
-
return { candidates: ranked.slice(0, limit ?? 10) };
|
|
59
|
-
});
|
|
60
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { generateOwnerKey, ownerKeyEnvOverrideActive, ownerKeyPath, readOwnerKey, } from "../credentials/owner-key.js";
|
|
2
|
-
import { defineTool } from "../server.js";
|
|
3
|
-
export function ownerKeyTool() {
|
|
4
|
-
return defineTool({
|
|
5
|
-
name: 'generate_owner_key',
|
|
6
|
-
description: 'Generate the owner private key that `run_proof` needs '
|
|
7
|
-
+ '(RECLAIM_AGENT_OWNER_PRIVATE_KEY) and save it to '
|
|
8
|
-
+ '~/.reclaim/owner-key.json (mode 0600). `run_proof` reads it '
|
|
9
|
-
+ 'from there automatically — no env var and no server restart '
|
|
10
|
-
+ 'needed. Call this when `run_proof` reports the owner key is '
|
|
11
|
-
+ 'missing. If a key already exists it is reused; pass '
|
|
12
|
-
+ '`force: true` to replace it (this changes the claim owner '
|
|
13
|
-
+ 'identity for future proofs). An explicit '
|
|
14
|
-
+ 'RECLAIM_AGENT_OWNER_PRIVATE_KEY env var always takes '
|
|
15
|
-
+ 'precedence over the saved file. The private key is never '
|
|
16
|
-
+ 'returned in the response — the saved file is the only copy.',
|
|
17
|
-
inputSchema: {
|
|
18
|
-
type: 'object',
|
|
19
|
-
properties: {
|
|
20
|
-
force: {
|
|
21
|
-
type: 'boolean',
|
|
22
|
-
description: 'Replace an existing saved owner key with a new one. '
|
|
23
|
-
+ 'Default false (reuse the existing key).',
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
}, async (args) => {
|
|
28
|
-
const envActive = ownerKeyEnvOverrideActive();
|
|
29
|
-
const existing = readOwnerKey();
|
|
30
|
-
if (existing && !args.force) {
|
|
31
|
-
return {
|
|
32
|
-
created: false,
|
|
33
|
-
address: existing.address,
|
|
34
|
-
publicKey: existing.publicKey,
|
|
35
|
-
path: ownerKeyPath(),
|
|
36
|
-
envOverrideActive: envActive,
|
|
37
|
-
note: 'An owner key already exists and was reused. run_proof '
|
|
38
|
-
+ 'will use it automatically. Pass force:true to replace it.'
|
|
39
|
-
+ (envActive
|
|
40
|
-
? ' NOTE: RECLAIM_AGENT_OWNER_PRIVATE_KEY is set in the '
|
|
41
|
-
+ 'environment and takes precedence over this file.'
|
|
42
|
-
: ''),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
const key = generateOwnerKey();
|
|
46
|
-
return {
|
|
47
|
-
created: true,
|
|
48
|
-
replaced: Boolean(existing),
|
|
49
|
-
address: key.address,
|
|
50
|
-
publicKey: key.publicKey,
|
|
51
|
-
path: ownerKeyPath(),
|
|
52
|
-
envOverrideActive: envActive,
|
|
53
|
-
note: 'Owner key saved to ~/.reclaim/owner-key.json (0600). '
|
|
54
|
-
+ 'run_proof will use it automatically — no restart needed. '
|
|
55
|
-
+ 'The private key is intentionally omitted from this response.'
|
|
56
|
-
+ (envActive
|
|
57
|
-
? ' NOTE: RECLAIM_AGENT_OWNER_PRIVATE_KEY is set in the '
|
|
58
|
-
+ 'environment and takes precedence over this file, so the '
|
|
59
|
-
+ 'saved key will not be used until that env var is unset.'
|
|
60
|
-
: ''),
|
|
61
|
-
};
|
|
62
|
-
});
|
|
63
|
-
}
|
package/lib/mcp/tools/proof.d.ts
DELETED
package/lib/mcp/tools/proof.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { reclaimHomeDirPath } from "../../paths.js";
|
|
4
|
-
import { runAttestorProof, tailLogs, warnsAndErrors, } from "../../proof/attestor.js";
|
|
5
|
-
import { defineTool } from "../server.js";
|
|
6
|
-
function claimsDir() {
|
|
7
|
-
return join(reclaimHomeDirPath(), 'claims');
|
|
8
|
-
}
|
|
9
|
-
function proofRunsDir() {
|
|
10
|
-
return join(reclaimHomeDirPath(), 'proof-runs');
|
|
11
|
-
}
|
|
12
|
-
/** Persist everything we know about this proof attempt — input provider,
|
|
13
|
-
* sentParams the SDK saw, full captured logs, and the final result — to
|
|
14
|
-
* a file the dev can `cat` directly. This is the source of truth when
|
|
15
|
-
* the LLM's summary disagrees with reality. */
|
|
16
|
-
function writeProofRunDump(payload) {
|
|
17
|
-
try {
|
|
18
|
-
mkdirSync(proofRunsDir(), { recursive: true });
|
|
19
|
-
const path = join(proofRunsDir(), `${Date.now()}.json`);
|
|
20
|
-
writeFileSync(path, JSON.stringify(payload, null, 2), 'utf8');
|
|
21
|
-
return path;
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
// Persistence is best-effort; never fail the proof for it.
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* Walk a claim object for display:
|
|
30
|
-
* - drop any `request` field at any depth (it's huge and only useful
|
|
31
|
-
* for low-level debugging — the on-disk claim still has it)
|
|
32
|
-
* - convert byte-like values (Uint8Array, or arrays where every entry
|
|
33
|
-
* is a number in [0,255]) to base64 strings so they render as
|
|
34
|
-
* readable text instead of `{"0":12,"1":34,...}`
|
|
35
|
-
*
|
|
36
|
-
* The on-disk file at claimPath is the raw, unprettified claim — this
|
|
37
|
-
* function only affects what we return in the MCP tool response.
|
|
38
|
-
*/
|
|
39
|
-
function prettifyClaim(value) {
|
|
40
|
-
if (value === null || value === undefined) {
|
|
41
|
-
return value;
|
|
42
|
-
}
|
|
43
|
-
if (value instanceof Uint8Array) {
|
|
44
|
-
return Buffer.from(value).toString('base64');
|
|
45
|
-
}
|
|
46
|
-
if (Array.isArray(value)) {
|
|
47
|
-
if (isLikelyByteArray(value)) {
|
|
48
|
-
return Buffer.from(value).toString('base64');
|
|
49
|
-
}
|
|
50
|
-
return value.map(prettifyClaim);
|
|
51
|
-
}
|
|
52
|
-
if (typeof value === 'object') {
|
|
53
|
-
const out = {};
|
|
54
|
-
for (const [k, v] of Object.entries(value)) {
|
|
55
|
-
if (k === 'request') {
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
|
-
out[k] = prettifyClaim(v);
|
|
59
|
-
}
|
|
60
|
-
return out;
|
|
61
|
-
}
|
|
62
|
-
return value;
|
|
63
|
-
}
|
|
64
|
-
function isLikelyByteArray(v) {
|
|
65
|
-
if (v.length === 0) {
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
for (const x of v) {
|
|
69
|
-
if (typeof x !== 'number' || !Number.isInteger(x) || x < 0 || x > 255) {
|
|
70
|
-
return false;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return true;
|
|
74
|
-
}
|
|
75
|
-
export function proofTool(secrets) {
|
|
76
|
-
return defineTool({
|
|
77
|
-
name: 'run_proof',
|
|
78
|
-
description: 'Run a full zkTLS proof through the Reclaim attestor SDK. ' +
|
|
79
|
-
'Use only after replay_request ' +
|
|
80
|
-
'returns matchesOriginal=true — attestor calls are expensive. ' +
|
|
81
|
-
'Writes the full claim to ' +
|
|
82
|
-
'~/.reclaim/claims/<timestamp>.json and ' +
|
|
83
|
-
'returns identifier + extractedParameters + ' +
|
|
84
|
-
'claimPath + a prettified `claim` field ' +
|
|
85
|
-
'(request dropped, byte arrays as base64) suitable ' +
|
|
86
|
-
'for displaying directly to the dev. ' +
|
|
87
|
-
'When the MCP server is started with ' +
|
|
88
|
-
'`RECLAIM_AGENT_TRACE=1`, ALSO writes ' +
|
|
89
|
-
'a per-call diagnostic dump (input provider, ' +
|
|
90
|
-
'sentParams the SDK saw post-substitution, ' +
|
|
91
|
-
'FULL attestor log stream, result) to ' +
|
|
92
|
-
'~/.reclaim/proof-runs/<timestamp>.json and ' +
|
|
93
|
-
'returns the path as `runLogPath`. ' +
|
|
94
|
-
'`attestorUrl` overrides the default attestor URL only when the dev ' +
|
|
95
|
-
'supplies a specific ' +
|
|
96
|
-
'alternative — do NOT invent backup URLs ' +
|
|
97
|
-
'(there is one live public attestor right now; ' +
|
|
98
|
-
'surface real errors to the dev instead of guessing). ' +
|
|
99
|
-
'`ownerAddress` (the credential to sign with) is REQUIRED — ' +
|
|
100
|
-
'call resolve_owner_key first to obtain it, then pass it here. ' +
|
|
101
|
-
'errorKind="missing-owner-key" means that address has no known ' +
|
|
102
|
-
'private key; re-run resolve_owner_key or issue/import a credential.',
|
|
103
|
-
inputSchema: {
|
|
104
|
-
type: 'object',
|
|
105
|
-
properties: {
|
|
106
|
-
// `type: 'object'` is required so MCP clients (the LLM)
|
|
107
|
-
// serialize the value as an object, not a JSON-stringified
|
|
108
|
-
// string. `properties: {}` is required so zod-from-json-schema
|
|
109
|
-
// compiles to a passthrough instead of strict-strip — leaving
|
|
110
|
-
// it off makes the server receive `{}`.
|
|
111
|
-
provider: { type: 'object', properties: {} },
|
|
112
|
-
secretParamsRef: { type: 'string' },
|
|
113
|
-
attestorUrl: { type: 'string' },
|
|
114
|
-
ownerAddress: {
|
|
115
|
-
type: 'string',
|
|
116
|
-
pattern: '^0x[0-9a-fA-F]{40}$',
|
|
117
|
-
description: 'ETH address of the credential to sign the claim with. ' +
|
|
118
|
-
'Get it from resolve_owner_key first. The private key is ' +
|
|
119
|
-
'resolved locally (cache / env / .env) — never passed here.',
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
required: ['provider', 'ownerAddress'],
|
|
123
|
-
},
|
|
124
|
-
}, async ({ provider, secretParamsRef, attestorUrl, ownerAddress }) => {
|
|
125
|
-
let resolved = {};
|
|
126
|
-
if (secretParamsRef !== undefined) {
|
|
127
|
-
const r = secrets.resolve(secretParamsRef);
|
|
128
|
-
if (!r) {
|
|
129
|
-
throw new Error(`unknown secretParamsRef "${secretParamsRef}" — ` +
|
|
130
|
-
'the MCP server has restarted or reset_session was called. ' +
|
|
131
|
-
'Re-run propose_provider to mint a fresh ref.');
|
|
132
|
-
}
|
|
133
|
-
resolved = r;
|
|
134
|
-
}
|
|
135
|
-
const result = await runAttestorProof(provider, resolved, attestorUrl, ownerAddress);
|
|
136
|
-
// Persist the full claim to disk for the dev to inspect/share.
|
|
137
|
-
let claimPath;
|
|
138
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
139
|
-
try {
|
|
140
|
-
mkdirSync(claimsDir(), { recursive: true });
|
|
141
|
-
claimPath = join(claimsDir(), `${Date.now()}.json`);
|
|
142
|
-
writeFileSync(claimPath, JSON.stringify(result.proof, null, 2), 'utf8');
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
// Persistence is best-effort; don't fail the proof for it.
|
|
146
|
-
claimPath = undefined;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
const out = {
|
|
150
|
-
verified: result.verified,
|
|
151
|
-
extractedValue: result.extractedValue,
|
|
152
|
-
extractedParameters: result.extractedParameters,
|
|
153
|
-
};
|
|
154
|
-
if (result.identifier !== undefined) {
|
|
155
|
-
out.identifier = result.identifier;
|
|
156
|
-
}
|
|
157
|
-
if (result.owner !== undefined) {
|
|
158
|
-
out.owner = result.owner;
|
|
159
|
-
}
|
|
160
|
-
if (claimPath !== undefined) {
|
|
161
|
-
out.claimPath = claimPath;
|
|
162
|
-
}
|
|
163
|
-
if (result.proof !== undefined && result.proof !== null) {
|
|
164
|
-
out.claim = prettifyClaim(result.proof);
|
|
165
|
-
}
|
|
166
|
-
if (result.error !== undefined) {
|
|
167
|
-
out.error = result.error;
|
|
168
|
-
}
|
|
169
|
-
if (result.errorKind !== undefined) {
|
|
170
|
-
out.errorKind = result.errorKind;
|
|
171
|
-
}
|
|
172
|
-
// Trim the LLM-visible logs — full stream goes to runLogPath.
|
|
173
|
-
if (result.attestorLogs !== undefined && result.attestorLogs.length > 0) {
|
|
174
|
-
out.attestorLogs = result.verified
|
|
175
|
-
? warnsAndErrors(result.attestorLogs)
|
|
176
|
-
: tailLogs(result.attestorLogs);
|
|
177
|
-
if (out.attestorLogs.length === 0) {
|
|
178
|
-
delete out.attestorLogs;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
if (result.sentParams !== undefined) {
|
|
182
|
-
out.sentParams = result.sentParams;
|
|
183
|
-
}
|
|
184
|
-
// Persist a diagnostic dump for forensics — gated behind
|
|
185
|
-
// RECLAIM_AGENT_TRACE=1 (matches the attestor logger capture).
|
|
186
|
-
// Off by default since happy-path runs don't need it; turn on
|
|
187
|
-
// when investigating proof failures and the file at runLogPath
|
|
188
|
-
// will carry the input provider, sentParams, full attestor log
|
|
189
|
-
// stream, and result.
|
|
190
|
-
if (process.env['RECLAIM_AGENT_TRACE'] === '1') {
|
|
191
|
-
const runLogPath = writeProofRunDump({
|
|
192
|
-
provider,
|
|
193
|
-
hasSecretParamsRef: secretParamsRef !== undefined,
|
|
194
|
-
attestorUrl,
|
|
195
|
-
result: {
|
|
196
|
-
verified: result.verified,
|
|
197
|
-
error: result.error,
|
|
198
|
-
errorKind: result.errorKind,
|
|
199
|
-
extractedValue: result.extractedValue,
|
|
200
|
-
extractedParameters: result.extractedParameters,
|
|
201
|
-
identifier: result.identifier,
|
|
202
|
-
owner: result.owner,
|
|
203
|
-
sentParams: result.sentParams,
|
|
204
|
-
attestorLogs: result.attestorLogs,
|
|
205
|
-
claimPath,
|
|
206
|
-
},
|
|
207
|
-
});
|
|
208
|
-
if (runLogPath !== undefined) {
|
|
209
|
-
out.runLogPath = runLogPath;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return out;
|
|
213
|
-
});
|
|
214
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type RegisteredTool } from '../server.ts';
|
|
2
|
-
import type { CaptureStore } from './capture.ts';
|
|
3
|
-
export interface SecretStore {
|
|
4
|
-
put: (values: Record<string, string>) => string;
|
|
5
|
-
resolve: (ref: string) => Record<string, string> | undefined;
|
|
6
|
-
clear: () => void;
|
|
7
|
-
}
|
|
8
|
-
export declare function makeSecretStore(): SecretStore;
|
|
9
|
-
export declare function proposeTool(captures: CaptureStore, secrets: SecretStore): RegisteredTool;
|