@reclaimprotocol/agent 0.1.1-dev.1 → 0.1.2

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 (232) 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/cdp/launcher.js +4 -3
  9. package/lib/config/store.d.ts +7 -6
  10. package/lib/config/store.js +2 -2
  11. package/lib/consts.d.ts +68 -0
  12. package/lib/consts.js +134 -0
  13. package/lib/index.d.ts +2 -2
  14. package/lib/index.js +1 -1
  15. package/lib/logger.js +2 -1
  16. package/lib/mcp/api/operations.gen.d.ts +100 -48
  17. package/lib/mcp/api/operations.gen.js +1129 -194
  18. package/lib/mcp/api/to-zod.d.ts +24 -0
  19. package/lib/mcp/api/to-zod.js +94 -0
  20. package/lib/mcp/api/tools.js +1 -1
  21. package/lib/mcp/credentials/authenticate.d.ts +3 -0
  22. package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
  23. package/lib/mcp/credentials/build.d.ts +5 -0
  24. package/lib/mcp/credentials/build.js +18 -0
  25. package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
  26. package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
  27. package/lib/mcp/credentials/import.d.ts +2 -0
  28. package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
  29. package/lib/mcp/credentials/issue.d.ts +2 -0
  30. package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
  31. package/lib/mcp/credentials/keypair.d.ts +17 -0
  32. package/lib/mcp/credentials/keypair.js +48 -0
  33. package/lib/mcp/credentials/link.d.ts +3 -0
  34. package/lib/mcp/credentials/link.js +107 -0
  35. package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
  36. package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
  37. package/lib/mcp/credentials/owner-key.d.ts +23 -0
  38. package/lib/mcp/credentials/owner-key.js +58 -0
  39. package/lib/mcp/credentials/paths.d.ts +12 -0
  40. package/lib/mcp/credentials/paths.js +35 -0
  41. package/lib/mcp/credentials/poll.d.ts +27 -0
  42. package/lib/mcp/credentials/poll.js +61 -0
  43. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
  44. package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
  45. package/lib/mcp/credentials/session-cache.d.ts +14 -0
  46. package/lib/mcp/credentials/session-cache.js +42 -0
  47. package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
  48. package/lib/mcp/credentials/status.js +76 -0
  49. package/lib/mcp/instructions.d.ts +1 -0
  50. package/lib/mcp/instructions.js +11 -0
  51. package/lib/mcp/register.d.ts +38 -0
  52. package/lib/mcp/register.js +80 -0
  53. package/lib/mcp/server.d.ts +2 -8
  54. package/lib/mcp/server.js +3 -33
  55. package/lib/mcp/start.js +17 -11
  56. package/lib/mcp/tools/agent/build.d.ts +5 -9
  57. package/lib/mcp/tools/agent/build.js +7 -24
  58. package/lib/mcp/tools/agent/index.d.ts +2 -0
  59. package/lib/mcp/tools/agent/index.js +3 -0
  60. package/lib/mcp/tools/agent/proof.js +3 -7
  61. package/lib/mcp/tools/agent/propose.js +13 -2
  62. package/lib/mcp/tools/agent/publish.js +172 -75
  63. package/lib/mcp/tools/agent/replay.js +0 -5
  64. package/lib/mcp/tools/analyze.d.ts +3 -0
  65. package/lib/mcp/tools/analyze.js +26 -0
  66. package/lib/mcp/tools/attach.d.ts +11 -0
  67. package/lib/mcp/tools/attach.js +72 -0
  68. package/lib/mcp/tools/authenticate/authenticate.js +107 -0
  69. package/lib/mcp/tools/authenticate/build.d.ts +15 -0
  70. package/lib/mcp/tools/authenticate/build.js +28 -0
  71. package/lib/mcp/tools/authenticate/decrypt-key.d.ts +19 -0
  72. package/lib/mcp/tools/authenticate/decrypt-key.js +46 -0
  73. package/lib/mcp/tools/authenticate/eth-key.d.ts +31 -0
  74. package/lib/mcp/tools/authenticate/eth-key.js +116 -0
  75. package/lib/mcp/tools/authenticate/import.js +57 -0
  76. package/lib/mcp/tools/authenticate/index.d.ts +2 -0
  77. package/lib/mcp/tools/authenticate/index.js +4 -0
  78. package/lib/mcp/tools/authenticate/issue.js +42 -0
  79. package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
  80. package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
  81. package/lib/mcp/tools/capture.d.ts +10 -0
  82. package/lib/mcp/tools/capture.js +142 -0
  83. package/lib/mcp/tools/eval.d.ts +5 -0
  84. package/lib/mcp/tools/eval.js +127 -0
  85. package/lib/mcp/tools/find.d.ts +3 -0
  86. package/lib/mcp/tools/find.js +60 -0
  87. package/lib/mcp/tools/index.d.ts +3 -0
  88. package/lib/mcp/tools/index.js +6 -0
  89. package/lib/mcp/tools/owner-key.d.ts +2 -0
  90. package/lib/mcp/tools/owner-key.js +63 -0
  91. package/lib/mcp/tools/proof.d.ts +3 -0
  92. package/lib/mcp/tools/proof.js +214 -0
  93. package/lib/mcp/tools/propose.d.ts +9 -0
  94. package/lib/mcp/tools/propose.js +75 -0
  95. package/lib/mcp/tools/publish.d.ts +3 -0
  96. package/lib/mcp/tools/publish.js +59 -0
  97. package/lib/mcp/tools/replay.d.ts +3 -0
  98. package/lib/mcp/tools/replay.js +46 -0
  99. package/lib/mcp/tools/session.d.ts +10 -0
  100. package/lib/mcp/tools/session.js +29 -0
  101. package/lib/mcp/tools/verification/build.d.ts +12 -0
  102. package/lib/mcp/tools/verification/build.js +14 -0
  103. package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
  104. package/lib/mcp/tools/verification/diagnose.js +132 -0
  105. package/lib/mcp/tools/verification/index.d.ts +1 -0
  106. package/lib/mcp/tools/verification/index.js +2 -0
  107. package/lib/mcp/tools/verification/result.d.ts +11 -0
  108. package/lib/mcp/tools/verification/result.js +126 -0
  109. package/lib/mcp/verifications/build.d.ts +5 -0
  110. package/lib/mcp/verifications/build.js +14 -0
  111. package/lib/mcp/verifications/create.d.ts +3 -0
  112. package/lib/mcp/verifications/create.js +57 -0
  113. package/lib/mcp/verifications/find.d.ts +3 -0
  114. package/lib/mcp/verifications/find.js +37 -0
  115. package/lib/mcp/verifications/get.d.ts +3 -0
  116. package/lib/mcp/verifications/get.js +26 -0
  117. package/lib/mcp/verifications/update.d.ts +3 -0
  118. package/lib/mcp/verifications/update.js +78 -0
  119. package/lib/old/client.d.ts +3 -0
  120. package/lib/old/flag.d.ts +4 -1
  121. package/lib/old/flag.js +4 -3
  122. package/lib/old/identity.d.ts +0 -10
  123. package/lib/old/identity.js +8 -7
  124. package/lib/old/instructions.d.ts +0 -6
  125. package/lib/old/instructions.js +6 -24
  126. package/lib/old/login-cdp.d.ts +0 -3
  127. package/lib/old/login-cdp.js +2 -4
  128. package/lib/old/to-register.d.ts +3 -0
  129. package/lib/old/to-register.js +32 -7
  130. package/lib/old/tools/authenticate.js +2 -1
  131. package/lib/old/tools/publish.js +71 -10
  132. package/lib/paths.js +2 -2
  133. package/lib/proof/attestor.d.ts +33 -1
  134. package/lib/proof/attestor.js +67 -64
  135. package/lib/proof/index.d.ts +5 -0
  136. package/lib/proof/index.js +6 -0
  137. package/lib/proof/proof-core.d.ts +35 -0
  138. package/lib/proof/proof-core.js +84 -0
  139. package/lib/provider/index.d.ts +5 -0
  140. package/lib/provider/index.js +9 -0
  141. package/lib/provider/injection-doc.d.ts +1 -0
  142. package/lib/provider/injection-doc.js +17 -0
  143. package/lib/provider/match-redaction-warning.d.ts +25 -0
  144. package/lib/provider/match-redaction-warning.js +35 -0
  145. package/lib/provider/schema.d.ts +16 -0
  146. package/lib/provider/schema.js +11 -1
  147. package/lib/provider/to-version.d.ts +61 -12
  148. package/lib/provider/to-version.js +109 -24
  149. package/lib/provider/verification-checks.d.ts +12 -0
  150. package/lib/provider/verification-checks.js +30 -0
  151. package/lib/routes.gen.d.ts +271 -0
  152. package/lib/routes.gen.js +73 -0
  153. package/lib/types/openapi.gen.d.ts +3967 -0
  154. package/lib/types/openapi.gen.js +5 -0
  155. package/package.json +16 -7
  156. package/skill/SKILL.md +35 -14
  157. package/skill/builder-mode.md +13 -0
  158. package/skill/injection-api.md +42 -0
  159. package/skill/old-mode.md +15 -0
  160. package/src/cdp/capture-engine.ts +256 -0
  161. package/src/cdp/capture.ts +25 -185
  162. package/src/cdp/index.ts +6 -0
  163. package/src/cdp/launcher.ts +5 -4
  164. package/src/config/store.ts +7 -6
  165. package/src/consts.ts +164 -0
  166. package/src/index.ts +2 -4
  167. package/src/logger.ts +2 -1
  168. package/src/mcp/api/operations.gen.ts +1155 -194
  169. package/src/mcp/api/to-zod.ts +115 -0
  170. package/src/mcp/api/tools.ts +9 -3
  171. package/src/mcp/instructions.ts +15 -0
  172. package/src/mcp/server.ts +5 -50
  173. package/src/mcp/start.ts +27 -11
  174. package/src/mcp/tools/agent/build.ts +7 -27
  175. package/src/mcp/tools/agent/index.ts +4 -0
  176. package/src/mcp/tools/agent/proof.ts +3 -8
  177. package/src/mcp/tools/agent/propose.ts +13 -2
  178. package/src/mcp/tools/agent/publish.ts +218 -92
  179. package/src/mcp/tools/agent/replay.ts +0 -5
  180. package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
  181. package/src/mcp/tools/authenticate/build.ts +32 -0
  182. package/src/mcp/tools/authenticate/decrypt-key.ts +59 -0
  183. package/src/mcp/tools/authenticate/eth-key.ts +162 -0
  184. package/src/mcp/tools/authenticate/import.ts +73 -0
  185. package/src/mcp/tools/authenticate/index.ts +4 -0
  186. package/src/mcp/tools/authenticate/issue.ts +50 -0
  187. package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
  188. package/src/mcp/tools/index.ts +6 -0
  189. package/src/mcp/tools/verification/build.ts +16 -0
  190. package/src/mcp/tools/verification/index.ts +2 -0
  191. package/src/mcp/tools/verification/result.ts +154 -0
  192. package/src/old/client.ts +3 -0
  193. package/src/old/flag.ts +4 -3
  194. package/src/old/identity.ts +8 -7
  195. package/src/old/instructions.ts +10 -25
  196. package/src/old/login-cdp.ts +2 -5
  197. package/src/old/to-register.ts +58 -26
  198. package/src/old/tools/authenticate.ts +2 -1
  199. package/src/old/tools/publish.ts +92 -16
  200. package/src/paths.ts +2 -2
  201. package/src/proof/attestor.ts +114 -72
  202. package/src/proof/index.ts +21 -0
  203. package/src/proof/proof-core.ts +119 -0
  204. package/src/provider/index.ts +20 -0
  205. package/src/provider/injection-doc.ts +21 -0
  206. package/src/provider/match-redaction-warning.ts +53 -0
  207. package/src/provider/schema.ts +23 -0
  208. package/src/provider/to-version.ts +180 -33
  209. package/src/provider/verification-checks.ts +36 -0
  210. package/lib/mcp/tools/credentials/build.d.ts +0 -16
  211. package/lib/mcp/tools/credentials/build.js +0 -33
  212. package/lib/mcp/tools/credentials/status.js +0 -62
  213. package/src/mcp/tools/credentials/build.ts +0 -37
  214. package/src/mcp/tools/credentials/cache.ts +0 -161
  215. package/src/mcp/tools/credentials/env-file.ts +0 -101
  216. package/src/mcp/tools/credentials/import.ts +0 -72
  217. package/src/mcp/tools/credentials/issue.ts +0 -107
  218. package/src/mcp/tools/credentials/list-cached.ts +0 -66
  219. package/src/mcp/tools/credentials/register.ts +0 -49
  220. package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
  221. package/src/mcp/tools/credentials/status.ts +0 -82
  222. package/src/types/openapi.ts +0 -7
  223. /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
  224. /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
  225. /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
  226. /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
  227. /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
  228. /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
  229. /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
  230. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
  231. /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
  232. /package/src/mcp/tools/{credentials → authenticate}/session-cache.ts +0 -0
@@ -1,33 +1,160 @@
1
1
  import type { ReclaimClient } from '@reclaimprotocol/client'
2
+ import type { JSONSchema } from 'zod/v4/core'
3
+ import { INJECTION_GUIDE } from '../../../provider/injection-doc.ts'
4
+ import {
5
+ countsFor,
6
+ matchRedactionWarnings,
7
+ } from '../../../provider/match-redaction-warning.ts'
2
8
  import type { ReclaimProvider } from '../../../provider/schema.ts'
9
+ import type { AllowedJsRequest } from '../../../provider/to-version.ts'
3
10
  import {
4
11
  nextVersion,
5
12
  providerToCreateVersionRequest,
6
13
  } from '../../../provider/to-version.ts'
7
14
  import { defineTool, type RegisteredTool } from '../../server.ts'
8
15
 
16
+ /** Schemas shared by the top-level `provider`/`providers` and the lighter
17
+ * `allowedJsRequests` drafts — keeps the request shape from drifting between
18
+ * them. */
19
+ const RESPONSE_MATCHES_SCHEMA: JSONSchema.Schema = {
20
+ type: 'array',
21
+ description: 'What the attestor checks on the revealed response slice.',
22
+ items: {
23
+ type: 'object',
24
+ properties: {
25
+ type: { type: 'string', enum: ['regex', 'contains'] },
26
+ value: { type: 'string' },
27
+ },
28
+ required: ['type', 'value'],
29
+ },
30
+ }
31
+
32
+ const RESPONSE_REDACTIONS_SCHEMA: JSONSchema.Schema = {
33
+ type: 'array',
34
+ description:
35
+ 'Which portions of the response the prover reveals ' +
36
+ '(xPath / jsonPath / regex; hash to OPRF the value). Paired with ' +
37
+ 'responseMatches by index — keep them aligned 1-to-1. If you list more ' +
38
+ 'redactions than matches, the tool pads matches with no-op optional ' +
39
+ 'entries so older index-paired claim creators stay happy.',
40
+ items: {
41
+ type: 'object',
42
+ properties: {
43
+ xPath: { type: 'string' },
44
+ jsonPath: { type: 'string' },
45
+ regex: { type: 'string' },
46
+ hash: { type: 'string', enum: ['oprf', 'oprf-mpc', 'oprf-raw'] },
47
+ },
48
+ },
49
+ }
50
+
51
+ /** Properties every drafted request shares (top-level providers and the
52
+ * injected `allowedJsRequests`). */
53
+ const REQUEST_DRAFT_PROPERTIES: Record<string, JSONSchema.Schema> = {
54
+ url: {
55
+ type: 'string',
56
+ description:
57
+ 'Exact API URL the attestor replays, with {{param}} placeholders ' +
58
+ 'for any templated values.',
59
+ },
60
+ method: { type: 'string', enum: ['GET', 'POST', 'PUT', 'PATCH'] },
61
+ body: { type: 'string', description: 'Request body template, if any.' },
62
+ responseMatches: RESPONSE_MATCHES_SCHEMA,
63
+ responseRedactions: RESPONSE_REDACTIONS_SCHEMA,
64
+ }
65
+
66
+ /** A full provider draft (from propose_provider), passed through verbatim. */
67
+ const PROVIDER_SCHEMA: JSONSchema.Schema = {
68
+ type: 'object',
69
+ description:
70
+ 'A `provider` object from propose_provider, passed through verbatim — ' +
71
+ 'the tool builds the version body (the requests[] entry etc.) for you.',
72
+ properties: {
73
+ name: { type: 'string', description: 'Verification name.' },
74
+ ...REQUEST_DRAFT_PROPERTIES,
75
+ headers: {
76
+ type: 'object',
77
+ description:
78
+ 'Request headers from the capture. Secret headers are stripped ' +
79
+ 'before persistence; the client re-supplies them at runtime.',
80
+ },
81
+ paramValues: {
82
+ type: 'object',
83
+ description:
84
+ 'Real values for the {{param}} placeholders, e.g. ' +
85
+ '{ "username": "Syed" }.',
86
+ },
87
+ },
88
+ required: ['name', 'url', 'method', 'responseMatches'],
89
+ }
90
+
91
+ /** One `allowedJsRequests` template: a request the injection script may fire,
92
+ * plus pagination/optionality flags. */
93
+ const ALLOWED_JS_REQUEST_SCHEMA: JSONSchema.Schema = {
94
+ type: 'object',
95
+ properties: {
96
+ ...REQUEST_DRAFT_PROPERTIES,
97
+ multiple: {
98
+ type: 'boolean',
99
+ description:
100
+ 'Allow the template to match many requests (e.g. pagination). ' +
101
+ 'Default true.',
102
+ },
103
+ required: {
104
+ type: 'boolean',
105
+ description:
106
+ 'Fail validation if no request matches this template. Default true.',
107
+ },
108
+ },
109
+ required: ['url', 'method'],
110
+ }
111
+
112
+ interface PublishArgs {
113
+ providerId: string
114
+ /** Single-provider back-compat input; normalized to `[provider]`. */
115
+ provider?: ReclaimProvider
116
+ /** Multi-request input — one version carrying every request. */
117
+ providers?: ReclaimProvider[]
118
+ initialUrl: string
119
+ notes?: string
120
+ version?: { major: number, minor: number, patch: number }
121
+ jsUserScripts?: string
122
+ allowedJsRequests?: AllowedJsRequest[]
123
+ }
124
+
9
125
  export function createVersionFromCaptureTool(
10
126
  client: ReclaimClient,
11
127
  ): RegisteredTool {
12
- return defineTool<{
13
- providerId: string
14
- provider: ReclaimProvider
15
- initialUrl: string
16
- notes?: string
17
- version?: { major: number, minor: number, patch: number }
18
- }>(
128
+ return defineTool<PublishArgs>(
19
129
  {
20
130
  name: 'create_provider_version_from_capture',
21
131
  description:
22
- 'Persist a drafted ReclaimProvider as a verification version. ' +
23
- 'Call this after run_proof succeeds, passing the `provider` object ' +
24
- 'from propose_provider VERBATIM. This tool builds the full version ' +
132
+ 'Persist drafted ReclaimProvider(s) as a verification version. ' +
133
+ 'Call this after run_proof succeeds, passing the `provider` ' +
134
+ 'object(s) from propose_provider VERBATIM. This tool builds the ' +
25
135
  'body (the requests[] array, webSettings, etc.) for you — do NOT ' +
26
136
  'hand-construct that shape or call create_provider_version directly. ' +
137
+ 'For a MULTI-REQUEST provider, pass `providers: [...]` (each entry a ' +
138
+ 'proven draft) — every entry becomes one request in the version, and ' +
139
+ 'all are required at verification time. Pass a single `provider` ' +
140
+ 'for the one-request case (exactly one of `provider`/`providers`). ' +
141
+ 'For data gated behind login/navigation, supply `jsUserScripts` (a ' +
142
+ 'page-injection script that drives the page to where the request ' +
143
+ 'fires) and/or `allowedJsRequests` (extra requests the script may ' +
144
+ 'fire, e.g. pagination). ' +
27
145
  'Omit `version` to have the tool auto-select the next available ' +
28
146
  'version (it lists existing versions and bumps past the highest). ' +
29
- 'For PRIVATE verifications the version goes live immediately; ' +
30
- 'for PUBLIC ones call submit_provider_version_for_review afterwards.',
147
+ 'The version lands on the draft branch — to go live, call ' +
148
+ '`publish_provider_version` (PRIVATE) or ' +
149
+ '`submit_provider_version_for_review` (PUBLIC) afterwards. ' +
150
+ '`requiredContext` is derived from any {{context.<name>}} ' +
151
+ 'placeholders across ALL requests (plus injected requests / script) ' +
152
+ 'and returned on the created version — when present, tell the dev ' +
153
+ 'verbatim which context fields consumers MUST send when creating ' +
154
+ 'sessions (verification matches those values exactly; a missing ' +
155
+ 'field is a 400 at session create). ' +
156
+ 'Refine types/descriptions via `update_provider_version` while ' +
157
+ 'still on draft.',
31
158
  inputSchema: {
32
159
  type: 'object',
33
160
  properties: {
@@ -35,77 +162,15 @@ export function createVersionFromCaptureTool(
35
162
  type: 'string',
36
163
  description: 'UUID of the verification to publish the version on.',
37
164
  },
38
- provider: {
39
- type: 'object',
165
+ provider: PROVIDER_SCHEMA,
166
+ providers: {
167
+ type: 'array',
40
168
  description:
41
- 'The `provider` object from propose_provider, passed ' +
42
- 'through verbatim — the tool builds the version body ' +
43
- '(the requests[] array etc.) for you.',
44
- properties: {
45
- name: { type: 'string', description: 'Verification name.' },
46
- url: {
47
- type: 'string',
48
- description:
49
- 'Exact API URL the attestor replays, with {{param}} ' +
50
- 'placeholders for any templated values.',
51
- },
52
- method: {
53
- type: 'string',
54
- enum: ['GET', 'POST', 'PUT', 'PATCH'],
55
- },
56
- headers: {
57
- type: 'object',
58
- description:
59
- 'Request headers from the capture. Secret headers are ' +
60
- 'stripped before persistence; the client re-supplies them ' +
61
- 'at runtime.',
62
- },
63
- body: {
64
- type: 'string',
65
- description: 'Request body template, if any.',
66
- },
67
- responseMatches: {
68
- type: 'array',
69
- description:
70
- 'What the attestor checks on the revealed response slice.',
71
- items: {
72
- type: 'object',
73
- properties: {
74
- type: { type: 'string', enum: ['regex', 'contains'] },
75
- value: { type: 'string' },
76
- },
77
- required: ['type', 'value'],
78
- },
79
- },
80
- responseRedactions: {
81
- type: 'array',
82
- description:
83
- 'Which portions of the response the prover reveals ' +
84
- '(xPath / jsonPath / regex; hash to OPRF the value). ' +
85
- 'Paired with responseMatches by index — the tool folds ' +
86
- 'each one into the matching entry\'s `extract` in the ' +
87
- 'persisted version, so keep them aligned 1-to-1.',
88
- items: {
89
- type: 'object',
90
- properties: {
91
- xPath: { type: 'string' },
92
- jsonPath: { type: 'string' },
93
- regex: { type: 'string' },
94
- hash: {
95
- type: 'string',
96
- enum: ['oprf', 'oprf-mpc', 'oprf-raw'],
97
- },
98
- },
99
- },
100
- },
101
- paramValues: {
102
- type: 'object',
103
- description:
104
- 'Real values for the {{param}} placeholders, ' +
105
- 'e.g. { "username": "Syed" }.',
106
- },
107
- },
108
- required: ['name', 'url', 'method', 'responseMatches'],
169
+ 'Multiple proven drafts → one multi-request version. Each ' +
170
+ 'entry has the same shape as `provider`. Pass this OR ' +
171
+ '`provider`, not both.',
172
+ items: PROVIDER_SCHEMA,
173
+ minItems: 1,
109
174
  },
110
175
  initialUrl: {
111
176
  type: 'string',
@@ -131,25 +196,86 @@ export function createVersionFromCaptureTool(
131
196
  },
132
197
  required: ['major', 'minor', 'patch'],
133
198
  },
199
+ jsUserScripts: {
200
+ type: 'string',
201
+ description:
202
+ 'Plain JavaScript injected into the provider page before every ' +
203
+ 'page load (stored as webSettings.jsUserScripts). Use standard ' +
204
+ 'browser APIs (window.location, element.click(), forms) to ' +
205
+ 'drive login/navigation so the target request fires — the ' +
206
+ 'client already intercepts page requests, and window.Reclaim ' +
207
+ 'is only for rare edge cases, not navigation. The Builder ' +
208
+ 'verification client installs this to run before every page ' +
209
+ 'load (before navigating to initialUrl), matching old-devtool ' +
210
+ 'customInjection; window.Reclaim itself is not yet exposed ' +
211
+ 'there, so prefer plain browser JS. Guide:\n\n' +
212
+ INJECTION_GUIDE,
213
+ },
214
+ allowedJsRequests: {
215
+ type: 'array',
216
+ description:
217
+ 'Extra requests the injection script is allowed to fire ' +
218
+ '(e.g. paginated API calls), as RequestSelectionTemplates. ' +
219
+ '`multiple`/`required` default to true.',
220
+ items: ALLOWED_JS_REQUEST_SCHEMA,
221
+ },
134
222
  },
135
- required: ['providerId', 'provider', 'initialUrl'],
223
+ required: ['providerId', 'initialUrl'],
136
224
  },
137
225
  },
138
226
  async(args) => {
227
+ // Exactly one of `provider` / `providers` — normalize to an array.
228
+ const hasMany = Array.isArray(args.providers) && args.providers.length > 0
229
+ const hasOne = !!args.provider
230
+ if(hasMany === hasOne) {
231
+ throw new Error(
232
+ 'Pass exactly one of `provider` (a single draft) or ' +
233
+ '`providers` (an array of 1+ drafts).',
234
+ )
235
+ }
236
+
237
+ const providers = hasMany ? args.providers! : [args.provider!]
238
+
139
239
  // Auto-pick the next version if not explicit
140
240
  const ver = args.version ?? (await nextVersion(client, args.providerId))
141
241
 
142
- const body = providerToCreateVersionRequest(
143
- args.provider,
144
- args.initialUrl,
145
- args.notes,
146
- ver,
147
- )
148
- const result = (await client.call('CreateProviderVersion', {
242
+ const body = providerToCreateVersionRequest(providers, args.initialUrl, {
243
+ notes: args.notes,
244
+ version: ver,
245
+ jsUserScripts: args.jsUserScripts,
246
+ allowedJsRequests: args.allowedJsRequests,
247
+ })
248
+ const result = await client.call('CreateProviderVersion', {
149
249
  params: { providerId: args.providerId },
150
250
  body,
151
- }))
152
- return result.data
251
+ })
252
+
253
+ const created = result.data
254
+
255
+ // Aggregate non-blocking advisories for the dev — nothing here blocks
256
+ // or alters what was published; the author keeps full control.
257
+ const notes: string[] = []
258
+
259
+ // Match/redaction advisory across every request (+ injected requests).
260
+ const requestCounts = [
261
+ ...providers.map((p, i) => countsFor(`Request ${i + 1}`, p)),
262
+ ...(args.allowedJsRequests ?? []).map(
263
+ (r, i) => countsFor(`Injected request ${i + 1}`, r),
264
+ ),
265
+ ]
266
+ notes.push(...matchRedactionWarnings(requestCounts))
267
+
268
+ // Let the dev know how/when the script runs (and the window.Reclaim gap).
269
+ if(args.jsUserScripts?.trim()) {
270
+ notes.push(
271
+ 'jsUserScripts will run in the Builder verification client before ' +
272
+ 'every page load (before navigating to initialUrl), matching ' +
273
+ 'old-devtool customInjection. window.Reclaim is not yet exposed ' +
274
+ 'there, so prefer plain browser JS for navigation/interaction.',
275
+ )
276
+ }
277
+
278
+ return notes.length ? { ...created, _notes: notes } : created
153
279
  },
154
280
  )
155
281
  }
@@ -16,11 +16,6 @@ export function replayTool(secrets: SecretStore): RegisteredTool {
16
16
  inputSchema: {
17
17
  type: 'object',
18
18
  properties: {
19
- // `type: 'object'` is required so MCP clients (the LLM)
20
- // serialize the value as an object, not a JSON-stringified
21
- // string. `properties: {}` is required so zod-from-json-schema
22
- // compiles to a passthrough instead of strict-strip — leaving
23
- // it off makes the server receive `{}`.
24
19
  provider: { type: 'object', properties: {} },
25
20
  secretParamsRef: { type: 'string' },
26
21
  },
@@ -1,7 +1,7 @@
1
1
  import type { ReclaimClient } from '@reclaimprotocol/client'
2
2
  import type {
3
- CredentialAttachSession as Session
4
- } from '../../../types/openapi.ts'
3
+ CredentialAttachSession
4
+ } from '@reclaimprotocol/client/openapi'
5
5
  import { defineTool, type RegisteredTool } from '../../server.ts'
6
6
  import { writeSession } from './session-cache.ts'
7
7
 
@@ -21,10 +21,9 @@ export function authenticateTool(client: ReclaimClient): RegisteredTool {
21
21
  'Returns `LINKED` with a 2-day bearer token when confirmed, ' +
22
22
  '`PENDING` if not yet, or `EXPIRED` if too long has passed.\n\n' +
23
23
  'The token is cached in ~/.reclaim/config.json automatically.\n\n' +
24
- 'To then link a credential to an org (needed only to use it ' +
25
- 'for verification in production), use the token with the ' +
26
- 'generated tools: `list_orgs` → `link_credential` with the ' +
27
- "credential's `address` and the target `orgId`.",
24
+ 'This bearer token authenticates dashboard/org-management calls ' +
25
+ '(e.g. list_orgs, issuing an org secret). Programmatic verification ' +
26
+ 'calls use a separate org secret (rorg_…, set as RECLAIM_ORG_SECRET).',
28
27
  inputSchema: {
29
28
  type: 'object',
30
29
  properties: {
@@ -68,7 +67,7 @@ async function checkSession(
68
67
  client: ReclaimClient,
69
68
  code: string,
70
69
  ): Promise<unknown> {
71
- let session: Session
70
+ let session: CredentialAttachSession
72
71
  try {
73
72
  const sessionResult = (await client.call('GetAttachSession', {
74
73
  params: { code }
@@ -93,7 +92,9 @@ async function checkSession(
93
92
  if(token) {
94
93
  writeSession({
95
94
  token,
96
- expiresAt: new Date(Date.now() + 2 * 24 * 60 * 60 * 1000).toISOString(),
95
+ expiresAt: new Date(
96
+ Date.now() + 2 * 24 * 60 * 60 * 1000
97
+ ).toISOString(),
97
98
  })
98
99
  client.setToken(token)
99
100
  return {
@@ -0,0 +1,32 @@
1
+ import type { ReclaimClient } from '@reclaimprotocol/client'
2
+ import type { RegisteredTool } from '../../server.ts'
3
+ import { authenticateTool } from './authenticate.ts'
4
+ import { importTool } from './import.ts'
5
+ import { issueTool } from './issue.ts'
6
+ import { resolveOwnerKeyTool } from './resolve-owner-key.ts'
7
+
8
+ /**
9
+ * Local-only key tools — no backend client needed. These manage the eth
10
+ * proof-owner key entirely on disk (as a secp256k1 PEM) or via env: generate,
11
+ * import, and resolve which key to sign proofs with. No `~/.reclaim` caching;
12
+ * useful in BOTH builder and OLD-devtools mode.
13
+ */
14
+ export function buildLocalCredentialTools(): RegisteredTool[] {
15
+ return [
16
+ resolveOwnerKeyTool(),
17
+ issueTool(),
18
+ importTool(),
19
+ ]
20
+ }
21
+
22
+ /**
23
+ * Full builder-mode credential set: the local key tools plus the backend
24
+ * `reclaim_authenticate` device-code flow. Old mode does NOT use the
25
+ * authenticate tool — it has its own.
26
+ */
27
+ export function buildCredentialTools(client: ReclaimClient): RegisteredTool[] {
28
+ return [
29
+ authenticateTool(client),
30
+ ...buildLocalCredentialTools(),
31
+ ]
32
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Optional eth decryption key — only needed when testing ENCRYPTED callback
3
+ * payloads in the consumer role. The org's results are ECIES-encrypted to its
4
+ * eth public key; this is the matching eth PRIVATE key (`0x`-hex). Resolution:
5
+ *
6
+ * 1. The `RECLAIM_DECRYPT_KEY` env var (a `0x`-prefixed 32-byte hex key), or
7
+ * 2. A file named `reclaim-decrypt.key` in the project root holding that hex.
8
+ * 3. Absent — plaintext-only testing (no decryption key; encrypted
9
+ * deliveries surface a clear error).
10
+ *
11
+ * The hex is loaded via the client's `loadDecryptionKey` and passed straight
12
+ * through as `ReclaimConfig.credential` / to `decryptCallback`.
13
+ */
14
+ import {
15
+ type DecryptionKey,
16
+ loadDecryptionKey,
17
+ } from '@reclaimprotocol/client'
18
+ import { existsSync, readFileSync } from 'node:fs'
19
+ import { join } from 'node:path'
20
+ import { findProjectRoot } from '../../../paths.ts'
21
+
22
+ /** Default eth decrypt-key filename the agent looks for in the project root. */
23
+ const DEFAULT_DECRYPT_KEY_FILE = 'reclaim-decrypt.key'
24
+
25
+ /**
26
+ * Read the raw eth decryption-key hex — from `RECLAIM_DECRYPT_KEY` or the
27
+ * default file — without loading it. Returns `undefined` when neither is
28
+ * present (plaintext-only).
29
+ */
30
+ function resolveDecryptKeyInput(
31
+ projectDir = findProjectRoot(process.cwd()),
32
+ ): string | undefined {
33
+ const fromEnv = process.env.RECLAIM_DECRYPT_KEY?.trim()
34
+ if(fromEnv) {
35
+ return fromEnv
36
+ }
37
+
38
+ const keyPath = join(projectDir, DEFAULT_DECRYPT_KEY_FILE)
39
+ if(existsSync(keyPath)) {
40
+ return readFileSync(keyPath, 'utf8').trim()
41
+ }
42
+
43
+ return undefined
44
+ }
45
+
46
+ /**
47
+ * Load the optional decryption key. Returns `undefined` when no key is
48
+ * configured (the consumer then handles only plaintext deliveries).
49
+ */
50
+ export async function resolveDecryptionKey(
51
+ projectDir = findProjectRoot(process.cwd()),
52
+ ): Promise<DecryptionKey | undefined> {
53
+ const input = resolveDecryptKeyInput(projectDir)
54
+ if(input === undefined) {
55
+ return undefined
56
+ }
57
+
58
+ return loadDecryptionKey(input)
59
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Eth proof-owner key resolution — the raw secp256k1 private key passed to
3
+ * attestor-core when the agent creates a local claim. It's a plain 0x-hex
4
+ * Ethereum private key (no PEM), resolved from, in order:
5
+ *
6
+ * 1. `process.env.RECLAIM_PRIVATE_KEY` — a 0x-hex 32-byte scalar.
7
+ * 2. A `.env` file in the project root — its `RECLAIM_PRIVATE_KEY=0x…` line.
8
+ * 3. A key file holding the raw 0x-hex scalar, at `RECLAIM_PRIVATE_KEY_FILE`
9
+ * (absolute or project-relative).
10
+ * 4. Absent — the caller offers to generate one or asks the dev for a key.
11
+ *
12
+ * Generated/imported keys are written to the project `.env` (mode 0600, and the
13
+ * file is added to `.gitignore`). NO `~/.reclaim` caching. This is a LOCAL
14
+ * signing key only — unrelated to org auth (the org secret) or encryption
15
+ * (the eth decrypt key).
16
+ */
17
+ import { deriveFromPrivateKey } from '@reclaimprotocol/client'
18
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs'
19
+ import { isAbsolute, join } from 'node:path'
20
+ import { privateKey, privateKeyFile } from '../../../consts.ts'
21
+ import { findProjectRoot } from '../../../paths.ts'
22
+
23
+ const ENV_VAR = 'RECLAIM_PRIVATE_KEY'
24
+ /** The dotenv file the agent reads from / writes the key to. */
25
+ export const ENV_FILE = '.env'
26
+
27
+ /** Where the resolved eth key came from. */
28
+ export type EthKeySource = 'env' | 'dotenv' | 'file'
29
+
30
+ export type ResolvedEthKey = {
31
+ /** Raw 0x-hex 32-byte scalar. */
32
+ privateKey: string
33
+ /** Lowercase eth address derived from the scalar. */
34
+ address: string
35
+ source: EthKeySource
36
+ /** Absolute path the key was read from (for `dotenv` / `file` sources). */
37
+ path?: string
38
+ }
39
+
40
+ /** Validate + normalize a raw Ethereum private key to lowercase 0x-hex. */
41
+ export function normalizeEthHex(value: string): string {
42
+ const v = value.trim().replace(/^['"]|['"]$/g, '')
43
+ if(!/^(0x)?[0-9a-fA-F]{64}$/.test(v)) {
44
+ throw new Error(
45
+ 'not a valid Ethereum private key (expected a 32-byte / 64-hex scalar)',
46
+ )
47
+ }
48
+
49
+ return '0x' + v.replace(/^0x/, '').toLowerCase()
50
+ }
51
+
52
+ /** Read `RECLAIM_PRIVATE_KEY` from a dotenv file (simple KEY=VALUE parse). */
53
+ function readDotenvKey(path: string): string | undefined {
54
+ if(!existsSync(path)) {
55
+ return undefined
56
+ }
57
+
58
+ for(const line of readFileSync(path, 'utf8').split('\n')) {
59
+ const m = line.match(/^\s*RECLAIM_PRIVATE_KEY\s*=\s*(.+?)\s*$/)
60
+ if(m) {
61
+ return m[1]
62
+ }
63
+ }
64
+
65
+ return undefined
66
+ }
67
+
68
+ /** The explicit raw-hex key-file path, if `RECLAIM_PRIVATE_KEY_FILE` is set. */
69
+ function ethKeyFilePath(
70
+ projectDir = findProjectRoot(process.cwd()),
71
+ ): string | undefined {
72
+ const p = privateKeyFile()
73
+ if(!p) {
74
+ return undefined
75
+ }
76
+
77
+ return isAbsolute(p) ? p : join(projectDir, p)
78
+ }
79
+
80
+ function resolved(
81
+ privateKey: string,
82
+ source: EthKeySource,
83
+ path?: string,
84
+ ): ResolvedEthKey {
85
+ return {
86
+ privateKey,
87
+ address: deriveFromPrivateKey(privateKey).address,
88
+ source,
89
+ ...(path ? { path } : {}),
90
+ }
91
+ }
92
+
93
+ /**
94
+ * Resolve the eth proof-owner key without prompting. Returns `undefined` when
95
+ * no key is configured anywhere — the caller decides whether to generate or
96
+ * ask for one (see `resolve_owner_key`).
97
+ */
98
+ export function resolveEthKey(
99
+ projectDir = findProjectRoot(process.cwd()),
100
+ ): ResolvedEthKey | undefined {
101
+ const env = privateKey()
102
+ if(env?.trim()) {
103
+ return resolved(normalizeEthHex(env), 'env')
104
+ }
105
+
106
+ const envPath = join(projectDir, ENV_FILE)
107
+ const fromDotenv = readDotenvKey(envPath)
108
+ if(fromDotenv) {
109
+ return resolved(normalizeEthHex(fromDotenv), 'dotenv', envPath)
110
+ }
111
+
112
+ const keyFile = ethKeyFilePath(projectDir)
113
+ if(keyFile && existsSync(keyFile)) {
114
+ return resolved(
115
+ normalizeEthHex(readFileSync(keyFile, 'utf8')),
116
+ 'file',
117
+ keyFile,
118
+ )
119
+ }
120
+
121
+ return undefined
122
+ }
123
+
124
+ /** Append `entry` to the project `.gitignore` if not already present. */
125
+ function ensureGitignored(projectDir: string, entry: string): void {
126
+ const path = join(projectDir, '.gitignore')
127
+ const current = existsSync(path) ? readFileSync(path, 'utf8') : ''
128
+ if(current.split('\n').some((l) => l.trim() === entry)) {
129
+ return
130
+ }
131
+
132
+ const prefix = current && !current.endsWith('\n') ? '\n' : ''
133
+ writeFileSync(path, current + prefix + entry + '\n')
134
+ }
135
+
136
+ /**
137
+ * Persist a raw eth private key to the project `.env` as
138
+ * `RECLAIM_PRIVATE_KEY=0x…` (upsert; mode 0600; `.env` added to `.gitignore`).
139
+ * Used by `issue_credentials` (generate) and `import_credentials` (supplied
140
+ * hex). Returns the derived address and the `.env` path.
141
+ */
142
+ export function writeEthKey(
143
+ privateKeyHex: string,
144
+ projectDir = findProjectRoot(process.cwd()),
145
+ ): { path: string, address: string } {
146
+ const hex = normalizeEthHex(privateKeyHex)
147
+ const envPath = join(projectDir, ENV_FILE)
148
+ const line = `${ENV_VAR}=${hex}`
149
+ const existing = existsSync(envPath) ? readFileSync(envPath, 'utf8') : ''
150
+ const re = new RegExp(`^\\s*${ENV_VAR}\\s*=.*$`, 'm')
151
+ let next: string
152
+ if(re.test(existing)) {
153
+ next = existing.replace(re, line)
154
+ } else {
155
+ const prefix = existing && !existing.endsWith('\n') ? '\n' : ''
156
+ next = existing + prefix + line + '\n'
157
+ }
158
+
159
+ writeFileSync(envPath, next, { mode: 0o600 })
160
+ ensureGitignored(projectDir, ENV_FILE)
161
+ return { path: envPath, address: deriveFromPrivateKey(hex).address }
162
+ }