@reclaimprotocol/agent 0.1.0 → 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 (204) hide show
  1. package/README.md +1 -1
  2. package/lib/cdp/capture-engine.d.ts +66 -0
  3. package/lib/cdp/capture-engine.js +153 -0
  4. package/lib/cdp/capture.d.ts +9 -20
  5. package/lib/cdp/capture.js +14 -138
  6. package/lib/cdp/index.d.ts +3 -0
  7. package/lib/cdp/index.js +6 -0
  8. package/lib/config/store.d.ts +7 -6
  9. package/lib/config/store.js +2 -2
  10. package/lib/index.d.ts +2 -2
  11. package/lib/index.js +1 -1
  12. package/lib/mcp/api/operations.gen.d.ts +101 -45
  13. package/lib/mcp/api/operations.gen.js +996 -126
  14. package/lib/mcp/api/to-zod.d.ts +24 -0
  15. package/lib/mcp/api/to-zod.js +94 -0
  16. package/lib/mcp/api/tools.js +1 -1
  17. package/lib/mcp/credentials/authenticate.d.ts +3 -0
  18. package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
  19. package/lib/mcp/credentials/build.d.ts +5 -0
  20. package/lib/mcp/credentials/build.js +18 -0
  21. package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
  22. package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
  23. package/lib/mcp/credentials/import.d.ts +2 -0
  24. package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
  25. package/lib/mcp/credentials/issue.d.ts +2 -0
  26. package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
  27. package/lib/mcp/credentials/keypair.d.ts +17 -0
  28. package/lib/mcp/credentials/keypair.js +48 -0
  29. package/lib/mcp/credentials/link.d.ts +3 -0
  30. package/lib/mcp/credentials/link.js +107 -0
  31. package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
  32. package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
  33. package/lib/mcp/credentials/owner-key.d.ts +23 -0
  34. package/lib/mcp/credentials/owner-key.js +58 -0
  35. package/lib/mcp/credentials/paths.d.ts +12 -0
  36. package/lib/mcp/credentials/paths.js +35 -0
  37. package/lib/mcp/credentials/poll.d.ts +27 -0
  38. package/lib/mcp/credentials/poll.js +61 -0
  39. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
  40. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
  41. package/lib/mcp/credentials/session-cache.d.ts +14 -0
  42. package/lib/mcp/credentials/session-cache.js +42 -0
  43. package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
  44. package/lib/mcp/credentials/status.js +76 -0
  45. package/lib/mcp/instructions.d.ts +1 -0
  46. package/lib/mcp/instructions.js +11 -0
  47. package/lib/mcp/register.d.ts +38 -0
  48. package/lib/mcp/register.js +80 -0
  49. package/lib/mcp/server.d.ts +2 -2
  50. package/lib/mcp/server.js +3 -3
  51. package/lib/mcp/start.js +10 -4
  52. package/lib/mcp/tools/agent/build.js +2 -15
  53. package/lib/mcp/tools/agent/index.d.ts +2 -0
  54. package/lib/mcp/tools/agent/index.js +3 -0
  55. package/lib/mcp/tools/agent/proof.js +1 -6
  56. package/lib/mcp/tools/agent/propose.js +13 -2
  57. package/lib/mcp/tools/agent/publish.js +10 -2
  58. package/lib/mcp/tools/agent/replay.js +0 -5
  59. package/lib/mcp/tools/analyze.d.ts +3 -0
  60. package/lib/mcp/tools/analyze.js +26 -0
  61. package/lib/mcp/tools/attach.d.ts +11 -0
  62. package/lib/mcp/tools/attach.js +72 -0
  63. package/lib/mcp/tools/authenticate/authenticate.js +107 -0
  64. package/lib/mcp/tools/authenticate/build.d.ts +15 -0
  65. package/lib/mcp/tools/authenticate/build.js +28 -0
  66. package/lib/mcp/tools/authenticate/decrypt-key.d.ts +32 -0
  67. package/lib/mcp/tools/authenticate/decrypt-key.js +49 -0
  68. package/lib/mcp/tools/authenticate/eth-key.d.ts +38 -0
  69. package/lib/mcp/tools/authenticate/eth-key.js +130 -0
  70. package/lib/mcp/tools/authenticate/import.js +57 -0
  71. package/lib/mcp/tools/authenticate/index.d.ts +2 -0
  72. package/lib/mcp/tools/authenticate/index.js +4 -0
  73. package/lib/mcp/tools/authenticate/issue.js +42 -0
  74. package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
  75. package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
  76. package/lib/mcp/tools/capture.d.ts +10 -0
  77. package/lib/mcp/tools/capture.js +142 -0
  78. package/lib/mcp/tools/eval.d.ts +5 -0
  79. package/lib/mcp/tools/eval.js +127 -0
  80. package/lib/mcp/tools/find.d.ts +3 -0
  81. package/lib/mcp/tools/find.js +60 -0
  82. package/lib/mcp/tools/index.d.ts +3 -0
  83. package/lib/mcp/tools/index.js +6 -0
  84. package/lib/mcp/tools/owner-key.d.ts +2 -0
  85. package/lib/mcp/tools/owner-key.js +63 -0
  86. package/lib/mcp/tools/proof.d.ts +3 -0
  87. package/lib/mcp/tools/proof.js +214 -0
  88. package/lib/mcp/tools/propose.d.ts +9 -0
  89. package/lib/mcp/tools/propose.js +75 -0
  90. package/lib/mcp/tools/publish.d.ts +3 -0
  91. package/lib/mcp/tools/publish.js +59 -0
  92. package/lib/mcp/tools/replay.d.ts +3 -0
  93. package/lib/mcp/tools/replay.js +46 -0
  94. package/lib/mcp/tools/session.d.ts +10 -0
  95. package/lib/mcp/tools/session.js +29 -0
  96. package/lib/mcp/tools/verification/build.d.ts +12 -0
  97. package/lib/mcp/tools/verification/build.js +14 -0
  98. package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
  99. package/lib/mcp/tools/verification/diagnose.js +132 -0
  100. package/lib/mcp/tools/verification/index.d.ts +1 -0
  101. package/lib/mcp/tools/verification/index.js +2 -0
  102. package/lib/mcp/tools/verification/result.d.ts +12 -0
  103. package/lib/mcp/tools/verification/result.js +126 -0
  104. package/lib/mcp/verifications/build.d.ts +5 -0
  105. package/lib/mcp/verifications/build.js +14 -0
  106. package/lib/mcp/verifications/create.d.ts +3 -0
  107. package/lib/mcp/verifications/create.js +57 -0
  108. package/lib/mcp/verifications/find.d.ts +3 -0
  109. package/lib/mcp/verifications/find.js +37 -0
  110. package/lib/mcp/verifications/get.d.ts +3 -0
  111. package/lib/mcp/verifications/get.js +26 -0
  112. package/lib/mcp/verifications/update.d.ts +3 -0
  113. package/lib/mcp/verifications/update.js +78 -0
  114. package/lib/old/client.d.ts +3 -0
  115. package/lib/old/instructions.d.ts +0 -6
  116. package/lib/old/instructions.js +6 -24
  117. package/lib/old/to-register.d.ts +3 -0
  118. package/lib/old/to-register.js +35 -7
  119. package/lib/old/tools/publish.js +13 -1
  120. package/lib/proof/attestor.d.ts +33 -1
  121. package/lib/proof/attestor.js +67 -61
  122. package/lib/proof/index.d.ts +5 -0
  123. package/lib/proof/index.js +6 -0
  124. package/lib/proof/proof-core.d.ts +35 -0
  125. package/lib/proof/proof-core.js +73 -0
  126. package/lib/proof/zk-files.d.ts +14 -0
  127. package/lib/proof/zk-files.js +73 -0
  128. package/lib/provider/index.d.ts +5 -0
  129. package/lib/provider/index.js +9 -0
  130. package/lib/provider/to-version.d.ts +9 -12
  131. package/lib/provider/to-version.js +38 -4
  132. package/lib/provider/verification-checks.d.ts +12 -0
  133. package/lib/provider/verification-checks.js +30 -0
  134. package/lib/routes.gen.d.ts +271 -0
  135. package/lib/routes.gen.js +73 -0
  136. package/lib/types/openapi.gen.d.ts +3967 -0
  137. package/lib/types/openapi.gen.js +5 -0
  138. package/package.json +18 -10
  139. package/skill/SKILL.md +35 -14
  140. package/skill/builder-mode.md +9 -0
  141. package/skill/old-mode.md +13 -0
  142. package/src/cdp/capture-engine.ts +256 -0
  143. package/src/cdp/capture.ts +25 -185
  144. package/src/cdp/index.ts +6 -0
  145. package/src/config/store.ts +7 -6
  146. package/src/index.ts +2 -4
  147. package/src/mcp/api/operations.gen.ts +1023 -121
  148. package/src/mcp/api/to-zod.ts +115 -0
  149. package/src/mcp/api/tools.ts +9 -3
  150. package/src/mcp/instructions.ts +15 -0
  151. package/src/mcp/server.ts +5 -4
  152. package/src/mcp/start.ts +14 -4
  153. package/src/mcp/tools/agent/build.ts +2 -18
  154. package/src/mcp/tools/agent/index.ts +4 -0
  155. package/src/mcp/tools/agent/proof.ts +1 -7
  156. package/src/mcp/tools/agent/propose.ts +13 -2
  157. package/src/mcp/tools/agent/publish.ts +10 -2
  158. package/src/mcp/tools/agent/replay.ts +0 -5
  159. package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
  160. package/src/mcp/tools/authenticate/build.ts +32 -0
  161. package/src/mcp/tools/authenticate/decrypt-key.ts +64 -0
  162. package/src/mcp/tools/authenticate/eth-key.ts +182 -0
  163. package/src/mcp/tools/authenticate/import.ts +73 -0
  164. package/src/mcp/tools/authenticate/index.ts +4 -0
  165. package/src/mcp/tools/authenticate/issue.ts +50 -0
  166. package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
  167. package/src/mcp/tools/index.ts +6 -0
  168. package/src/mcp/tools/verification/build.ts +16 -0
  169. package/src/mcp/tools/verification/index.ts +2 -0
  170. package/src/mcp/tools/verification/result.ts +155 -0
  171. package/src/old/client.ts +3 -0
  172. package/src/old/instructions.ts +10 -25
  173. package/src/old/to-register.ts +62 -27
  174. package/src/old/tools/publish.ts +17 -1
  175. package/src/proof/attestor.ts +115 -69
  176. package/src/proof/index.ts +21 -0
  177. package/src/proof/proof-core.ts +109 -0
  178. package/src/proof/zk-files.ts +83 -0
  179. package/src/provider/index.ts +20 -0
  180. package/src/provider/to-version.ts +52 -11
  181. package/src/provider/verification-checks.ts +36 -0
  182. package/lib/mcp/tools/credentials/build.d.ts +0 -16
  183. package/lib/mcp/tools/credentials/build.js +0 -33
  184. package/lib/mcp/tools/credentials/status.js +0 -62
  185. package/src/mcp/tools/credentials/build.ts +0 -37
  186. package/src/mcp/tools/credentials/cache.ts +0 -161
  187. package/src/mcp/tools/credentials/env-file.ts +0 -101
  188. package/src/mcp/tools/credentials/import.ts +0 -72
  189. package/src/mcp/tools/credentials/issue.ts +0 -107
  190. package/src/mcp/tools/credentials/list-cached.ts +0 -66
  191. package/src/mcp/tools/credentials/register.ts +0 -49
  192. package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
  193. package/src/mcp/tools/credentials/status.ts +0 -82
  194. package/src/types/openapi.ts +0 -7
  195. /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
  196. /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
  197. /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
  198. /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
  199. /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
  200. /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
  201. /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
  202. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
  203. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
  204. /package/src/mcp/tools/{credentials → authenticate}/session-cache.ts +0 -0
@@ -0,0 +1,214 @@
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
+ }
@@ -0,0 +1,9 @@
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;
@@ -0,0 +1,75 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { draftProvider } from "../../provider/draft.js";
3
+ import { OPRF_MAX_BYTES } from "../../provider/matcher.js";
4
+ import { defineTool } from "../server.js";
5
+ export function makeSecretStore() {
6
+ const map = new Map();
7
+ return {
8
+ put: (values) => {
9
+ const id = `sref_${randomUUID()}`;
10
+ map.set(id, values);
11
+ return id;
12
+ },
13
+ resolve: (ref) => map.get(ref),
14
+ clear: () => map.clear(),
15
+ };
16
+ }
17
+ export function proposeTool(captures, secrets) {
18
+ return defineTool({
19
+ name: 'propose_provider',
20
+ description: 'Draft a Reclaim provider JSON from a captured request + ' +
21
+ 'a target value. ' +
22
+ 'Secret header values are stored server-side and replaced with an ' +
23
+ 'opaque secretParamsRef ' +
24
+ 'in the response — raw secret values never appear in tool output. ' +
25
+ "`hash` is opt-in: when set, the captured value is OPRF'd so " +
26
+ 'the attestor never sees ' +
27
+ 'cleartext. Skill should ask the dev first. `oprf-raw` ' +
28
+ 'is the only variant that runs ' +
29
+ 'without external deps; `oprf` needs gnark (Linux/macOS), ' +
30
+ '`oprf-mpc` needs a TEE attestor.',
31
+ inputSchema: {
32
+ type: 'object',
33
+ properties: {
34
+ captureId: { type: 'string' },
35
+ requestId: { type: 'string' },
36
+ target: { type: 'string' },
37
+ name: { type: 'string' },
38
+ hash: { type: 'string', enum: ['oprf-raw', 'oprf', 'oprf-mpc'] },
39
+ },
40
+ required: ['captureId', 'requestId', 'target', 'name'],
41
+ },
42
+ }, async ({ captureId, requestId, target, name, hash }) => {
43
+ if (hash !== undefined && target.length > OPRF_MAX_BYTES) {
44
+ throw new Error(`OPRF caps hashed values at ${OPRF_MAX_BYTES} bytes; ` +
45
+ `got ${target.length}-byte target ` +
46
+ `"${target}". Try a tighter target ` +
47
+ '(e.g. just the relevant substring) or call ' +
48
+ 'propose_provider without `hash`.');
49
+ }
50
+ const session = captures.sessions.get(captureId);
51
+ if (!session) {
52
+ throw new Error(`no capture ${captureId}`);
53
+ }
54
+ const r = session.requests.get(requestId);
55
+ if (!r) {
56
+ throw new Error(`no request ${requestId}`);
57
+ }
58
+ const body = session.bodies.get(requestId);
59
+ if (!body.available) {
60
+ throw new Error(`request body unavailable: ${body.reason}`);
61
+ }
62
+ const reqWithBody = { ...r, responseBody: body.body };
63
+ const { provider, secretRefs } = draftProvider(reqWithBody, target, name, hash);
64
+ // Stash real secret values for later replay/proof.
65
+ const realSecrets = {};
66
+ for (const ref of secretRefs) {
67
+ const real = r.requestHeaders[ref.name];
68
+ if (real !== undefined) {
69
+ realSecrets[ref.name] = real;
70
+ }
71
+ }
72
+ const secretParamsRef = secrets.put(realSecrets);
73
+ return { provider, secretRefs, secretParamsRef };
74
+ });
75
+ }
@@ -0,0 +1,3 @@
1
+ import type { ReclaimClient } from '@reclaimprotocol/client';
2
+ import { type RegisteredTool } from '../server.ts';
3
+ export declare function createVersionFromCaptureTool(client: ReclaimClient): RegisteredTool;
@@ -0,0 +1,59 @@
1
+ import { nextVersion, providerToCreateVersionRequest, } from "../../provider/to-version.js";
2
+ import { defineTool } from "../server.js";
3
+ export function createVersionFromCaptureTool(client) {
4
+ return defineTool({
5
+ name: 'create_provider_version_from_capture',
6
+ description: 'Translate a drafted ReclaimProvider (from propose_provider) into a ' +
7
+ 'verification version and persist it via create_provider_version. ' +
8
+ 'Call this after run_proof succeeds. ' +
9
+ 'Omit `version` to have the tool auto-select the next available ' +
10
+ 'version (it lists existing versions and bumps past the highest). ' +
11
+ 'For PRIVATE verifications the version goes live immediately; ' +
12
+ 'for PUBLIC ones call submit_provider_version_for_review afterwards.',
13
+ inputSchema: {
14
+ type: 'object',
15
+ properties: {
16
+ providerId: {
17
+ type: 'string',
18
+ description: 'UUID of the verification to publish the version on.',
19
+ },
20
+ provider: {
21
+ type: 'object',
22
+ description: 'The ReclaimProvider JSON from propose_provider ' +
23
+ '(with URL parameterisation applied).',
24
+ },
25
+ initialUrl: {
26
+ type: 'string',
27
+ description: 'The website URL the user landed on to trigger the request ' +
28
+ '(e.g. https://github.com/Syed). The URL the verification ' +
29
+ 'flow opens for end-users — NOT the API URL inside the provider.',
30
+ },
31
+ notes: {
32
+ type: 'string',
33
+ description: 'Short change note (e.g. "Initial draft from browser capture").',
34
+ },
35
+ version: {
36
+ type: 'object',
37
+ description: 'Semver to publish as. Omit to auto-pick the next ' +
38
+ 'version above the highest existing one.',
39
+ properties: {
40
+ major: { type: 'number', minimum: 0 },
41
+ minor: { type: 'number', minimum: 0 },
42
+ patch: { type: 'number', minimum: 0 },
43
+ },
44
+ required: ['major', 'minor', 'patch'],
45
+ },
46
+ },
47
+ required: ['providerId', 'provider', 'initialUrl'],
48
+ },
49
+ }, async (args) => {
50
+ // Auto-pick the next version if not explicit
51
+ const ver = args.version ?? (await nextVersion(client, args.providerId));
52
+ const body = providerToCreateVersionRequest(args.provider, args.initialUrl, args.notes, ver);
53
+ const result = (await client.call('CreateProviderVersion', {
54
+ params: { providerId: args.providerId },
55
+ body,
56
+ }));
57
+ return result.data;
58
+ });
59
+ }
@@ -0,0 +1,3 @@
1
+ import { type RegisteredTool } from '../server.ts';
2
+ import type { SecretStore } from './propose.ts';
3
+ export declare function replayTool(secrets: SecretStore): RegisteredTool;
@@ -0,0 +1,46 @@
1
+ import { replayProvider } from "../../proof/replay.js";
2
+ import { defineTool } from "../server.js";
3
+ export function replayTool(secrets) {
4
+ return defineTool({
5
+ name: 'replay_request',
6
+ description: 'Replay a drafted provider against the live endpoint ' +
7
+ 'using Node fetch (no attestor). ' +
8
+ 'Pre-flight gate before run_proof — ' +
9
+ 'diagnoses CSRF / token-rotation / matcher-too-tight ' +
10
+ 'issues with richer hints than the attestor would produce.',
11
+ inputSchema: {
12
+ type: 'object',
13
+ properties: {
14
+ // `type: 'object'` is required so MCP clients (the LLM)
15
+ // serialize the value as an object, not a JSON-stringified
16
+ // string. `properties: {}` is required so zod-from-json-schema
17
+ // compiles to a passthrough instead of strict-strip — leaving
18
+ // it off makes the server receive `{}`.
19
+ provider: { type: 'object', properties: {} },
20
+ secretParamsRef: { type: 'string' },
21
+ },
22
+ required: ['provider'],
23
+ },
24
+ }, async ({ provider, secretParamsRef }) => {
25
+ let resolved = {};
26
+ if (secretParamsRef !== undefined) {
27
+ const r = secrets.resolve(secretParamsRef);
28
+ if (!r) {
29
+ throw new Error(`unknown secretParamsRef "${secretParamsRef}" — ` +
30
+ 'the MCP server has restarted or reset_session was called. ' +
31
+ 'Re-run propose_provider to mint a fresh ref.');
32
+ }
33
+ resolved = r;
34
+ }
35
+ const result = await replayProvider(provider, resolved);
36
+ const out = {
37
+ status: result.status,
38
+ matchesOriginal: result.matchesOriginal,
39
+ bodySnippet: result.body.slice(0, 256),
40
+ };
41
+ if (result.hints !== undefined) {
42
+ out.hints = result.hints;
43
+ }
44
+ return out;
45
+ });
46
+ }
@@ -0,0 +1,10 @@
1
+ import type { ConfigStore } from '../../config/store.ts';
2
+ import { type RegisteredTool } from '../server.ts';
3
+ import type { AttachState } from './attach.ts';
4
+ import type { CaptureStore } from './capture.ts';
5
+ export declare function sessionTools(attachRef: {
6
+ current?: AttachState;
7
+ config: ConfigStore;
8
+ }, captures: CaptureStore, secrets: {
9
+ clear: () => void;
10
+ }): RegisteredTool[];
@@ -0,0 +1,29 @@
1
+ import { defineTool } from "../server.js";
2
+ export function sessionTools(attachRef, captures, secrets) {
3
+ return [
4
+ defineTool({
5
+ name: 'get_session',
6
+ description: 'Return current attach state, active captures, and persisted config.',
7
+ inputSchema: { type: 'object', properties: {} },
8
+ }, async () => ({
9
+ config: attachRef.config.read(),
10
+ attached: Boolean(attachRef.current),
11
+ port: attachRef.current?.port,
12
+ captures: [...captures.sessions.keys()],
13
+ activeTab: captures.activeTab,
14
+ })),
15
+ defineTool({
16
+ name: 'reset_session',
17
+ description: 'Stop all captures, drop in-memory secrets, and clear capture state.',
18
+ inputSchema: { type: 'object', properties: {} },
19
+ }, async () => {
20
+ for (const s of captures.sessions.values()) {
21
+ await s.stop().catch(() => { });
22
+ }
23
+ captures.sessions.clear();
24
+ delete captures.activeTab;
25
+ secrets.clear();
26
+ return { reset: true };
27
+ }),
28
+ ];
29
+ }
@@ -0,0 +1,12 @@
1
+ import type { RegisteredTool } from '../../server.ts';
2
+ /**
3
+ * Builder-mode verification tools: higher-level orchestrations over the
4
+ * generated API surface. `get_verification_result` authenticates with the org
5
+ * token, checks status, pulls the stored payload, and decrypts it locally with
6
+ * the optional X25519 key — a flow the generated raw-API tools can't express
7
+ * (the decryption key never leaves the consumer). Diagnosis is left to the
8
+ * agent over the generated tools (`get_verification_session`,
9
+ * `list_verification_events`, `list_verification_deliveries`), whose
10
+ * descriptions carry the lifecycle and delivery semantics.
11
+ */
12
+ export declare function buildVerificationTools(): RegisteredTool[];
@@ -0,0 +1,14 @@
1
+ import { verificationResultTool } from "./result.js";
2
+ /**
3
+ * Builder-mode verification tools: higher-level orchestrations over the
4
+ * generated API surface. `get_verification_result` authenticates with the org
5
+ * token, checks status, pulls the stored payload, and decrypts it locally with
6
+ * the optional X25519 key — a flow the generated raw-API tools can't express
7
+ * (the decryption key never leaves the consumer). Diagnosis is left to the
8
+ * agent over the generated tools (`get_verification_session`,
9
+ * `list_verification_events`, `list_verification_deliveries`), whose
10
+ * descriptions carry the lifecycle and delivery semantics.
11
+ */
12
+ export function buildVerificationTools() {
13
+ return [verificationResultTool()];
14
+ }
@@ -0,0 +1,11 @@
1
+ import { type ReclaimClient } from '@reclaimprotocol/client';
2
+ import { type RegisteredTool } from '../../server.ts';
3
+ /**
4
+ * `diagnose_verification_session` — one call that answers "what's wrong
5
+ * with this session?". Pulls the session, its full event log, and its
6
+ * callback-delivery diagnostics, then derives findings (where the flow
7
+ * stalled or failed) and concrete suggestions (what to check or do next).
8
+ * Read-only; authenticates with the active eth credential like
9
+ * `get_verification_result`.
10
+ */
11
+ export declare function verificationDiagnoseTool(client: ReclaimClient): RegisteredTool;
@@ -0,0 +1,132 @@
1
+ import { buildAuthHeaders } from '@reclaimprotocol/client';
2
+ import { defineTool } from "../../server.js";
3
+ import { resolveActivePrivateKey } from "./result.js";
4
+ const TERMINAL = new Set(['success', 'rejected', 'error']);
5
+ /**
6
+ * `diagnose_verification_session` — one call that answers "what's wrong
7
+ * with this session?". Pulls the session, its full event log, and its
8
+ * callback-delivery diagnostics, then derives findings (where the flow
9
+ * stalled or failed) and concrete suggestions (what to check or do next).
10
+ * Read-only; authenticates with the active eth credential like
11
+ * `get_verification_result`.
12
+ */
13
+ export function verificationDiagnoseTool(client) {
14
+ return defineTool({
15
+ name: 'diagnose_verification_session',
16
+ description: 'Diagnose a verification session: fetches its status, event ' +
17
+ 'timeline, and callback-delivery state, then reports findings ' +
18
+ '(where the flow stalled or failed — link never opened, proof ' +
19
+ 'failed, callback endpoint erroring, dead-lettered delivery, ' +
20
+ 'expiry) and suggested next steps. Read-only. Use ' +
21
+ 'get_verification_result to fetch and decrypt the actual result.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ required: ['sessionId'],
25
+ properties: {
26
+ sessionId: {
27
+ type: 'string',
28
+ description: 'The verification session id to diagnose.',
29
+ },
30
+ },
31
+ },
32
+ }, async (args) => {
33
+ const privateKey = resolveActivePrivateKey();
34
+ const auth = () => buildAuthHeaders(privateKey, 'VerificationAuth');
35
+ const params = { sessionId: args.sessionId };
36
+ const [session, events, deliveries] = await Promise.all([
37
+ client.call('GetVerificationSession', { params, headers: auth() })
38
+ .then((r) => r.data),
39
+ client.call('ListVerificationEvents', { params, headers: auth() })
40
+ .then((r) => r.data.items),
41
+ client.call('ListVerificationDeliveries', { params, headers: auth() })
42
+ .then((r) => r.data.items),
43
+ ]);
44
+ const seen = new Set(events.map((e) => e.event));
45
+ const last = events[events.length - 1];
46
+ const findings = [];
47
+ const suggestions = [];
48
+ // Where did the flow get to?
49
+ if (session.status === 'pending') {
50
+ if (new Date(session.expiresAt).getTime() < Date.now()) {
51
+ findings.push('Session is past expiresAt — it will flip to expired on the ' +
52
+ 'next sweep; the end-user can no longer complete it.');
53
+ suggestions.push('Create a new session and share a fresh link.');
54
+ }
55
+ else if (!seen.has('verification_client_opened')) {
56
+ findings.push('The end-user has not opened the verification link yet.');
57
+ suggestions.push(`Re-share the link (${session.verificationUrl}) before ` +
58
+ `it expires at ${session.expiresAt}.`);
59
+ }
60
+ else if (!seen.has('request_matched')) {
61
+ findings.push('The page was opened but the target request was never ' +
62
+ 'captured — the end-user likely has not completed the ' +
63
+ 'login/journey on the provider site.');
64
+ }
65
+ else {
66
+ findings.push('Proof flow is in progress — the target request was ' +
67
+ 'captured and the run has not reached a terminal event.');
68
+ }
69
+ }
70
+ if (session.status === 'expired') {
71
+ findings.push(seen.has('verification_client_opened')
72
+ ? 'Session expired mid-flow — the end-user started but did ' +
73
+ 'not finish before expiresAt.'
74
+ : 'Session expired without the link ever being opened.');
75
+ suggestions.push('Create a new session and share a fresh link.');
76
+ }
77
+ // Surface failure detail from the event log.
78
+ for (const e of events) {
79
+ if (e.event === 'request_claim_failed' ||
80
+ e.event === 'request_claim_rejected' ||
81
+ e.event === 'verification_error' ||
82
+ e.event === 'verification_rejected') {
83
+ findings.push(`${e.event} at ${e.createdAt}` +
84
+ (e.eventData ? `: ${JSON.stringify(e.eventData)}` : ''));
85
+ }
86
+ }
87
+ // Callback delivery health (only meaningful after a terminal event).
88
+ for (const d of deliveries) {
89
+ if (d.deliveryStatus === 'delivered') {
90
+ continue;
91
+ }
92
+ findings.push(`Callback to ${d.callbackUrl} is ${d.deliveryStatus} after ` +
93
+ `${d.attempts} attempt(s)` +
94
+ (d.lastError ? ` — last error: ${d.lastError}` : '') +
95
+ (d.deadLettered ? ' (dead-lettered; retries exhausted)' : ''));
96
+ suggestions.push(`Check that ${d.callbackUrl} is reachable and answers 2xx.`);
97
+ if (d.deadLettered) {
98
+ suggestions.push('Once the endpoint is fixed, re-deliver via ' +
99
+ 'POST /verifications/sessions/{sessionId}/retry-callback ' +
100
+ '(or ask an admin to retry it from the Callback DLQ).');
101
+ }
102
+ }
103
+ if (TERMINAL.has(session.status) &&
104
+ deliveries.every((d) => d.deliveryStatus === 'delivered')) {
105
+ suggestions.push('Result delivered. Use get_verification_result to fetch and ' +
106
+ 'decrypt it locally.');
107
+ }
108
+ if (!findings.length) {
109
+ findings.push('No problems detected.');
110
+ }
111
+ return {
112
+ sessionId: session.id,
113
+ status: session.status,
114
+ callbackDeliveryStatus: session.callbackDeliveryStatus,
115
+ mode: session.mode,
116
+ createdAt: session.createdAt,
117
+ expiresAt: session.expiresAt,
118
+ completedAt: session.completedAt,
119
+ lastEvent: last
120
+ ? { event: last.event, at: last.createdAt }
121
+ : undefined,
122
+ events: events.map((e) => ({
123
+ event: e.event,
124
+ at: e.createdAt,
125
+ ...(e.eventData ? { data: e.eventData } : {}),
126
+ })),
127
+ deliveries,
128
+ findings,
129
+ suggestions,
130
+ };
131
+ });
132
+ }
@@ -0,0 +1 @@
1
+ export { buildVerificationTools } from './build.ts';
@@ -0,0 +1,2 @@
1
+ // Barrel for the verification tool group (result retrieval + decryption).
2
+ export { buildVerificationTools } from "./build.js";
@@ -0,0 +1,12 @@
1
+ import { type RegisteredTool } from '../../server.ts';
2
+ /**
3
+ * `get_verification_result` — check a session's status and, once a result has
4
+ * been submitted, pull the stored payload(s) and verify locally. Auth is the
5
+ * org token; delivery is org-scoped. Each stored payload is either the
6
+ * plaintext signed JWS (when the org has no encryption credential) or a compact
7
+ * JWE (RFC 7516, ECDH-ES+A256GCM over X25519) that we decrypt here with the
8
+ * optional X25519 key (the `reclaim-decrypt.pem` PEM in the project). The
9
+ * Builder only ever relays the payload — decryption, when needed, happens
10
+ * here.
11
+ */
12
+ export declare function verificationResultTool(): RegisteredTool;