@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,182 @@
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 X25519 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 { findProjectRoot } from '../../../paths.ts'
21
+
22
+ const ENV_VAR = 'RECLAIM_PRIVATE_KEY'
23
+ /** The dotenv file the agent reads from / writes the key to. */
24
+ export const ENV_FILE = '.env'
25
+
26
+ /** Where the resolved eth key came from. */
27
+ export type EthKeySource = 'env' | 'dotenv' | 'file'
28
+
29
+ export type ResolvedEthKey = {
30
+ /** Raw 0x-hex 32-byte scalar. */
31
+ privateKey: string
32
+ /** Lowercase eth address derived from the scalar. */
33
+ address: string
34
+ source: EthKeySource
35
+ /** Absolute path the key was read from (for `dotenv` / `file` sources). */
36
+ path?: string
37
+ }
38
+
39
+ /** Validate + normalize a raw Ethereum private key to lowercase 0x-hex. */
40
+ export function normalizeEthHex(value: string): string {
41
+ const v = value.trim().replace(/^['"]|['"]$/g, '')
42
+ if(!/^(0x)?[0-9a-fA-F]{64}$/.test(v)) {
43
+ throw new Error(
44
+ 'not a valid Ethereum private key (expected a 32-byte / 64-hex scalar)',
45
+ )
46
+ }
47
+
48
+ return '0x' + v.replace(/^0x/, '').toLowerCase()
49
+ }
50
+
51
+ /** Read `RECLAIM_PRIVATE_KEY` from a dotenv file (simple KEY=VALUE parse). */
52
+ function readDotenvKey(path: string): string | undefined {
53
+ if(!existsSync(path)) {
54
+ return undefined
55
+ }
56
+
57
+ for(const line of readFileSync(path, 'utf8').split('\n')) {
58
+ const m = line.match(/^\s*RECLAIM_PRIVATE_KEY\s*=\s*(.+?)\s*$/)
59
+ if(m) {
60
+ return m[1]
61
+ }
62
+ }
63
+
64
+ return undefined
65
+ }
66
+
67
+ /** The explicit raw-hex key-file path, if `RECLAIM_PRIVATE_KEY_FILE` is set. */
68
+ export function ethKeyFilePath(
69
+ projectDir = findProjectRoot(process.cwd()),
70
+ ): string | undefined {
71
+ const p = process.env.RECLAIM_PRIVATE_KEY_FILE
72
+ if(!p) {
73
+ return undefined
74
+ }
75
+
76
+ return isAbsolute(p) ? p : join(projectDir, p)
77
+ }
78
+
79
+ function resolved(
80
+ privateKey: string,
81
+ source: EthKeySource,
82
+ path?: string,
83
+ ): ResolvedEthKey {
84
+ return {
85
+ privateKey,
86
+ address: deriveFromPrivateKey(privateKey).address,
87
+ source,
88
+ ...(path ? { path } : {}),
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Resolve the eth proof-owner key without prompting. Returns `undefined` when
94
+ * no key is configured anywhere — the caller decides whether to generate or
95
+ * ask for one (see `resolve_owner_key`).
96
+ */
97
+ export function resolveEthKey(
98
+ projectDir = findProjectRoot(process.cwd()),
99
+ ): ResolvedEthKey | undefined {
100
+ const env = process.env.RECLAIM_PRIVATE_KEY
101
+ if(env?.trim()) {
102
+ return resolved(normalizeEthHex(env), 'env')
103
+ }
104
+
105
+ const envPath = join(projectDir, ENV_FILE)
106
+ const fromDotenv = readDotenvKey(envPath)
107
+ if(fromDotenv) {
108
+ return resolved(normalizeEthHex(fromDotenv), 'dotenv', envPath)
109
+ }
110
+
111
+ const keyFile = ethKeyFilePath(projectDir)
112
+ if(keyFile && existsSync(keyFile)) {
113
+ return resolved(
114
+ normalizeEthHex(readFileSync(keyFile, 'utf8')),
115
+ 'file',
116
+ keyFile,
117
+ )
118
+ }
119
+
120
+ return undefined
121
+ }
122
+
123
+ /**
124
+ * Resolve the eth proof-owner private key (0x-hex) or throw a clear, actionable
125
+ * error. Used by the proof flow that can't proceed without a signing key.
126
+ */
127
+ export function requireEthPrivateKey(
128
+ projectDir = findProjectRoot(process.cwd()),
129
+ ): string {
130
+ const r = resolveEthKey(projectDir)
131
+ if(!r) {
132
+ throw new Error(
133
+ 'No eth proof-owner key found. Set RECLAIM_PRIVATE_KEY (0x-hex), add a '
134
+ + `RECLAIM_PRIVATE_KEY=0x… line to ${join(projectDir, ENV_FILE)}, or `
135
+ + 'point RECLAIM_PRIVATE_KEY_FILE at a file holding the raw hex. Run '
136
+ + 'issue_credentials to generate one, or import_credentials to use a '
137
+ + 'key you already hold.',
138
+ )
139
+ }
140
+
141
+ return r.privateKey
142
+ }
143
+
144
+ /** Append `entry` to the project `.gitignore` if not already present. */
145
+ function ensureGitignored(projectDir: string, entry: string): void {
146
+ const path = join(projectDir, '.gitignore')
147
+ const current = existsSync(path) ? readFileSync(path, 'utf8') : ''
148
+ if(current.split('\n').some((l) => l.trim() === entry)) {
149
+ return
150
+ }
151
+
152
+ const prefix = current && !current.endsWith('\n') ? '\n' : ''
153
+ writeFileSync(path, current + prefix + entry + '\n')
154
+ }
155
+
156
+ /**
157
+ * Persist a raw eth private key to the project `.env` as
158
+ * `RECLAIM_PRIVATE_KEY=0x…` (upsert; mode 0600; `.env` added to `.gitignore`).
159
+ * Used by `issue_credentials` (generate) and `import_credentials` (supplied
160
+ * hex). Returns the derived address and the `.env` path.
161
+ */
162
+ export function writeEthKey(
163
+ privateKeyHex: string,
164
+ projectDir = findProjectRoot(process.cwd()),
165
+ ): { path: string, address: string } {
166
+ const hex = normalizeEthHex(privateKeyHex)
167
+ const envPath = join(projectDir, ENV_FILE)
168
+ const line = `${ENV_VAR}=${hex}`
169
+ const existing = existsSync(envPath) ? readFileSync(envPath, 'utf8') : ''
170
+ const re = new RegExp(`^\\s*${ENV_VAR}\\s*=.*$`, 'm')
171
+ let next: string
172
+ if(re.test(existing)) {
173
+ next = existing.replace(re, line)
174
+ } else {
175
+ const prefix = existing && !existing.endsWith('\n') ? '\n' : ''
176
+ next = existing + prefix + line + '\n'
177
+ }
178
+
179
+ writeFileSync(envPath, next, { mode: 0o600 })
180
+ ensureGitignored(projectDir, ENV_FILE)
181
+ return { path: envPath, address: deriveFromPrivateKey(hex).address }
182
+ }
@@ -0,0 +1,73 @@
1
+ import { readFileSync } from 'node:fs'
2
+ import { findProjectRoot } from '../../../paths.ts'
3
+ import { defineTool, type RegisteredTool } from '../../server.ts'
4
+ import { writeEthKey } from './eth-key.ts'
5
+
6
+ export function importTool(): RegisteredTool {
7
+ return defineTool<{
8
+ privateKey?: string
9
+ keyFile?: string
10
+ projectDir?: string
11
+ }>(
12
+ {
13
+ name: 'import_credentials',
14
+ description:
15
+ 'Import an eth proof-owner key the dev already holds and persist it ' +
16
+ 'to the project `.env` as RECLAIM_PRIVATE_KEY=0x… (mode 0600; `.env` ' +
17
+ 'added to .gitignore). Provide EITHER `privateKey` (raw 0x-hex, 64 ' +
18
+ 'chars) OR `keyFile` (path to a file holding the raw 0x-hex key). ' +
19
+ 'The address is derived locally; the private key is never ' +
20
+ 'returned. This is a local signing key only (not registered ' +
21
+ 'with any server, ' +
22
+ 'unrelated to org auth or encryption).',
23
+ inputSchema: {
24
+ type: 'object',
25
+ properties: {
26
+ privateKey: {
27
+ type: 'string',
28
+ pattern: '^0x?[0-9a-fA-F]{64}$',
29
+ description:
30
+ 'Raw Ethereum private key, 0x-prefixed hex (64 hex chars).',
31
+ },
32
+ keyFile: {
33
+ type: 'string',
34
+ description:
35
+ 'Path to a file containing the raw 0x-hex private key ' +
36
+ '(absolute or project-relative).',
37
+ },
38
+ projectDir: {
39
+ type: 'string',
40
+ description:
41
+ 'Project directory whose `.env` the key is written to. ' +
42
+ 'Defaults to the closest ancestor of cwd containing .git or ' +
43
+ 'package.json.',
44
+ },
45
+ },
46
+ },
47
+ },
48
+ async(args) => {
49
+ if(!args.privateKey && !args.keyFile) {
50
+ throw new Error('Provide either `privateKey` (0x-hex) or `keyFile`.')
51
+ }
52
+
53
+ if(args.privateKey && args.keyFile) {
54
+ throw new Error('Provide only one of `privateKey` or `keyFile`.')
55
+ }
56
+
57
+ const projectDir = findProjectRoot(args.projectDir || process.cwd())
58
+ const privateKeyHex = args.keyFile
59
+ ? readFileSync(args.keyFile, 'utf8')
60
+ : args.privateKey!
61
+ const { path, address } = writeEthKey(privateKeyHex, projectDir)
62
+
63
+ return {
64
+ address,
65
+ path,
66
+ note:
67
+ 'Eth proof-owner key written to .env as RECLAIM_PRIVATE_KEY ' +
68
+ '(mode 0600). resolve_owner_key resolves it from .env. Keep .env ' +
69
+ 'secret — it has been added to .gitignore.',
70
+ }
71
+ },
72
+ )
73
+ }
@@ -0,0 +1,4 @@
1
+ // Barrel for the credential tool group: local eth proof-owner key (env/PEM)
2
+ // and the org-token-authenticated builder tools. Import from here.
3
+ export { buildCredentialTools, buildLocalCredentialTools } from './build.ts'
4
+ export { readSession } from './session-cache.ts'
@@ -0,0 +1,50 @@
1
+ import { generateKeypair } from '@reclaimprotocol/client'
2
+ import { findProjectRoot } from '../../../paths.ts'
3
+ import { defineTool, type RegisteredTool } from '../../server.ts'
4
+ import { writeEthKey } from './eth-key.ts'
5
+
6
+ export function issueTool(): RegisteredTool {
7
+ return defineTool<{ projectDir?: string }>(
8
+ {
9
+ name: 'issue_credentials',
10
+ description:
11
+ 'Generate a fresh secp256k1 eth proof-owner key-pair (the key ' +
12
+ 'that signs local claim creation) and write the raw private key to ' +
13
+ 'the project `.env` as RECLAIM_PRIVATE_KEY=0x… (mode 0600; `.env` ' +
14
+ 'added to .gitignore). This is a LOCAL signing key only — it is NOT ' +
15
+ 'registered with any server and is unrelated to org auth (the org ' +
16
+ 'secret) or encryption (the X25519 decrypt key). ALWAYS confirm with ' +
17
+ 'the dev before generating a new key. After writing, run_proof picks ' +
18
+ 'it up automatically via resolve_owner_key. The private key is never ' +
19
+ 'returned in the response.',
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ projectDir: {
24
+ type: 'string',
25
+ description:
26
+ 'Project directory whose `.env` the key is written to. ' +
27
+ 'Defaults to the closest ancestor of cwd containing .git or ' +
28
+ 'package.json.',
29
+ },
30
+ },
31
+ },
32
+ },
33
+ async(args) => {
34
+ const projectDir = findProjectRoot(args.projectDir || process.cwd())
35
+ const keypair = generateKeypair()
36
+ const { path, address } = writeEthKey(keypair.privateKey, projectDir)
37
+
38
+ return {
39
+ address,
40
+ path,
41
+ note:
42
+ 'Eth proof-owner key written to .env as RECLAIM_PRIVATE_KEY ' +
43
+ '(mode 0600); the private key is NOT in this response on purpose. ' +
44
+ 'resolve_owner_key will now resolve it from .env (or set ' +
45
+ 'RECLAIM_PRIVATE_KEY in the environment to override). Keep .env ' +
46
+ 'secret — it has been added to .gitignore.',
47
+ }
48
+ },
49
+ )
50
+ }
@@ -0,0 +1,60 @@
1
+ import { join } from 'node:path'
2
+ import { findProjectRoot } from '../../../paths.ts'
3
+ import { defineTool, type RegisteredTool } from '../../server.ts'
4
+ import { ENV_FILE, resolveEthKey } from './eth-key.ts'
5
+
6
+ /**
7
+ * Decide which eth proof-owner key `run_proof` should sign with, BEFORE
8
+ * calling it. The key is a raw 0x-hex Ethereum private key, resolved (no
9
+ * `~/.reclaim` cache) from:
10
+ * 1. `RECLAIM_PRIVATE_KEY` in the MCP env
11
+ * 2. a `RECLAIM_PRIVATE_KEY=0x…` line in the project `.env`
12
+ * 3. a file at `RECLAIM_PRIVATE_KEY_FILE` holding the raw hex
13
+ * 4. none → ask the dev to generate (issue_credentials) or provide one
14
+ * (import_credentials), then call again.
15
+ * Never returns the private key — only the derived address.
16
+ */
17
+ export function resolveOwnerKeyTool(): RegisteredTool {
18
+ return defineTool<Record<string, never>>(
19
+ {
20
+ name: 'resolve_owner_key',
21
+ description:
22
+ 'Resolve which eth proof-owner key run_proof should sign with — ' +
23
+ 'call this BEFORE run_proof. Checks, in order: RECLAIM_PRIVATE_KEY ' +
24
+ 'in the MCP env, a RECLAIM_PRIVATE_KEY=0x… line in the project .env, ' +
25
+ 'then a file at RECLAIM_PRIVATE_KEY_FILE holding the raw hex. ' +
26
+ 'Returns { ready: true, address, source } when one is ' +
27
+ 'available — pass `address` to run_proof as `ownerAddress`. ' +
28
+ 'Returns { ready: false } ' +
29
+ 'when none exists: then ask the dev to generate one ' +
30
+ '(issue_credentials) or import one they already hold ' +
31
+ '(import_credentials, accepts 0x-hex or a key-file path), and call ' +
32
+ 'resolve_owner_key again. Never exposes the private key.',
33
+ inputSchema: { type: 'object', properties: {} },
34
+ },
35
+ async() => {
36
+ const projectDir = findProjectRoot(process.cwd())
37
+ const resolved = resolveEthKey(projectDir)
38
+ if(resolved) {
39
+ return {
40
+ ready: true,
41
+ address: resolved.address,
42
+ source: resolved.source,
43
+ ...(resolved.path ? { path: resolved.path } : {}),
44
+ }
45
+ }
46
+
47
+ return {
48
+ ready: false,
49
+ message:
50
+ 'No eth proof-owner key available — no RECLAIM_PRIVATE_KEY in the ' +
51
+ `env, no RECLAIM_PRIVATE_KEY in ${join(projectDir, ENV_FILE)}, and ` +
52
+ 'no RECLAIM_PRIVATE_KEY_FILE. Ask the dev to generate one via ' +
53
+ 'issue_credentials, or import one they already hold via ' +
54
+ 'import_credentials (0x-hex or a key-file path). Then call ' +
55
+ 'resolve_owner_key again and pass its address to run_proof as ' +
56
+ 'ownerAddress.',
57
+ }
58
+ },
59
+ )
60
+ }
@@ -0,0 +1,6 @@
1
+ // Top-level barrel for every MCP tool group. The MCP server (start.ts) and the
2
+ // package entry (src/index.ts) import tool builders from here, never from the
3
+ // individual tool files.
4
+ export * from './agent/index.ts'
5
+ export * from './authenticate/index.ts'
6
+ export * from './verification/index.ts'
@@ -0,0 +1,16 @@
1
+ import type { RegisteredTool } from '../../server.ts'
2
+ import { verificationResultTool } from './result.ts'
3
+
4
+ /**
5
+ * Builder-mode verification tools: higher-level orchestrations over the
6
+ * generated API surface. `get_verification_result` authenticates with the org
7
+ * token, checks status, pulls the stored payload, and decrypts it locally with
8
+ * the optional X25519 key — a flow the generated raw-API tools can't express
9
+ * (the decryption key never leaves the consumer). Diagnosis is left to the
10
+ * agent over the generated tools (`get_verification_session`,
11
+ * `list_verification_events`, `list_verification_deliveries`), whose
12
+ * descriptions carry the lifecycle and delivery semantics.
13
+ */
14
+ export function buildVerificationTools(): RegisteredTool[] {
15
+ return [verificationResultTool()]
16
+ }
@@ -0,0 +1,2 @@
1
+ // Barrel for the verification tool group (result retrieval + decryption).
2
+ export { buildVerificationTools } from './build.ts'
@@ -0,0 +1,155 @@
1
+ import {
2
+ createReclaim,
3
+ decryptCallback,
4
+ type DecryptionKey,
5
+ DEFAULT_BASE_URL,
6
+ verifyResultFull,
7
+ } from '@reclaimprotocol/client'
8
+ import assert from 'node:assert'
9
+ import { defineTool, type RegisteredTool } from '../../server.ts'
10
+ import { resolveDecryptionKey } from '../authenticate/decrypt-key.ts'
11
+
12
+ /** Statuses that can carry a submitted (terminal) result. `expired`/`pending`
13
+ * never have one. */
14
+ const TERMINAL = new Set(['success', 'rejected', 'error'])
15
+
16
+ /**
17
+ * Resolve the org secret used to authenticate verification reads. Auth is a
18
+ * single per-org bearer secret (`rorg_…`), not an eth signature — read it from
19
+ * `RECLAIM_ORG_SECRET`.
20
+ */
21
+ function resolveOrgSecret(): string {
22
+ const secret = process.env.RECLAIM_ORG_SECRET?.trim()
23
+ assert(
24
+ secret,
25
+ new Error(
26
+ 'RECLAIM_ORG_SECRET is not set. Verification reads authenticate with ' +
27
+ 'the org secret (rorg_…) — issue one from the dashboard ' +
28
+ '(POST /orgs/{orgId}/token) and export it as RECLAIM_ORG_SECRET.',
29
+ ),
30
+ )
31
+ return secret
32
+ }
33
+
34
+ /**
35
+ * `get_verification_result` — check a session's status and, once a result has
36
+ * been submitted, pull the stored payload(s) and verify locally. Auth is the
37
+ * org token; delivery is org-scoped. Each stored payload is either the
38
+ * plaintext signed JWS (when the org has no encryption credential) or a compact
39
+ * JWE (RFC 7516, ECDH-ES+A256GCM over X25519) that we decrypt here with the
40
+ * optional X25519 key (the `reclaim-decrypt.pem` PEM in the project). The
41
+ * Builder only ever relays the payload — decryption, when needed, happens
42
+ * here.
43
+ */
44
+ export function verificationResultTool(): RegisteredTool {
45
+ return defineTool<{ sessionId: string }>(
46
+ {
47
+ name: 'get_verification_result',
48
+ description:
49
+ 'Check a verification session and return its result when ready. ' +
50
+ 'Authenticates with the org secret (RECLAIM_ORG_SECRET). Fetches the ' +
51
+ 'session status; if it is terminal and a result has been submitted, ' +
52
+ 'pulls the stored result(s) and verifies them locally. Encrypted ' +
53
+ 'deliveries (compact JWE over X25519) are decrypted with your ' +
54
+ 'optional decryption key (the reclaim-decrypt.pem PEM in the ' +
55
+ 'project); plaintext deliveries are read directly. Returns ' +
56
+ '`ready: false` while the session is still pending or no result has ' +
57
+ 'been delivered yet. Use list_verification_events for the full ' +
58
+ 'lifecycle log.',
59
+ inputSchema: {
60
+ type: 'object',
61
+ required: ['sessionId'],
62
+ properties: {
63
+ sessionId: {
64
+ type: 'string',
65
+ description:
66
+ 'The verification session id from create_verification_session.',
67
+ },
68
+ },
69
+ },
70
+ },
71
+ async(args) => {
72
+ const orgSecret = resolveOrgSecret()
73
+ // Optional X25519 decryption key — absent ⇒ plaintext-only.
74
+ const decryptionKey: DecryptionKey | undefined =
75
+ await resolveDecryptionKey()
76
+
77
+ const reclaim = createReclaim({
78
+ baseUrl: process.env.RECLAIM_API_URL || DEFAULT_BASE_URL,
79
+ orgSecret,
80
+ })
81
+
82
+ const sessionRes = await reclaim.api('GetVerificationSession', {
83
+ params: { sessionId: args.sessionId },
84
+ })
85
+ const status = sessionRes.data.status
86
+
87
+ if(!TERMINAL.has(status)) {
88
+ return { sessionId: args.sessionId, status, ready: false }
89
+ }
90
+
91
+ const resultRes = await reclaim.api('GetVerificationResult', {
92
+ params: { sessionId: args.sessionId },
93
+ })
94
+ const { items } = resultRes.data
95
+
96
+ if(!items.length) {
97
+ return {
98
+ sessionId: args.sessionId,
99
+ status,
100
+ ready: false,
101
+ note: 'Session is terminal but no result has been submitted yet.',
102
+ }
103
+ }
104
+
105
+ // Each item's `payload` is a compact JWE (encrypted to the org's
106
+ // credential) or the plaintext signed JWS, as raw text. `decryptCallback`
107
+ // branches on the body shape; an encrypted delivery with no key throws
108
+ // a clear error, which we surface per-subscription rather than skip.
109
+ const results: unknown[] = []
110
+ const undecryptable: string[] = []
111
+ for(const item of items) {
112
+ let jws
113
+ try {
114
+ jws = await decryptCallback(decryptionKey, item.payload)
115
+ } catch(err) {
116
+ undecryptable.push(item.subscriptionId)
117
+ void err
118
+ continue
119
+ }
120
+
121
+ const outcome = await verifyResultFull(jws, {
122
+ expectedReclaimSessionId: args.sessionId,
123
+ })
124
+ results.push({
125
+ subscriptionId: item.subscriptionId,
126
+ valid: outcome.valid,
127
+ reason: outcome.reason,
128
+ payload: outcome.payload,
129
+ proofs: outcome.proofs,
130
+ })
131
+ }
132
+
133
+ if(!results.length) {
134
+ return {
135
+ sessionId: args.sessionId,
136
+ status,
137
+ ready: false,
138
+ note:
139
+ 'A result was stored, but no payload could be read — it is ' +
140
+ 'corrupt, or encrypted (JWE) to a key this consumer does not ' +
141
+ 'hold. Place an X25519 PEM (reclaim-decrypt.pem) in the ' +
142
+ 'project matching the org credential.',
143
+ }
144
+ }
145
+
146
+ return {
147
+ sessionId: args.sessionId,
148
+ status,
149
+ ready: true,
150
+ results,
151
+ ...(undecryptable.length ? { undecryptable } : {}),
152
+ }
153
+ },
154
+ )
155
+ }
package/src/old/client.ts CHANGED
@@ -25,6 +25,9 @@ export interface RegisterProviderBody {
25
25
  description?: string
26
26
  loginUrl: string
27
27
  geoLocation?: string
28
+ /** Provider-level flag on the old backend (defaults false there; the
29
+ * translator sends `true` to match the builder default). */
30
+ useProxy?: boolean
28
31
  providerType?: 'PRIVATE' | 'PUBLIC'
29
32
  requestData: unknown[]
30
33
  }
@@ -2,29 +2,14 @@
2
2
  * MCP server instructions shown to the LLM when running in OLD-devtools mode
3
3
  * (`USE_OLD_DEVTOOLS` unset or not `false`). Describes the REDUCED tool
4
4
  * surface — there are no org/credential-link/review flows and no generated
5
- * API tools here. Must not mention disabled tools.
5
+ * API tools here. The prose lives in `skill/old-mode.md` (published via the
6
+ * `files` array); the path resolves identically from `src/old` (dev) and
7
+ * `lib/old` (published).
6
8
  */
7
- export const OLD_MODE_INSTRUCTIONS =
8
- 'This server is running against the LEGACY Reclaim devtools backend ' +
9
- '(temporary, while the new builder backend is in development), so its ' +
10
- 'capabilities are intentionally limited.\n\n' +
11
- 'Provider-authoring flow:\n' +
12
- '1. `reclaim_authenticate` — by default opens the dashboard in Chrome, ' +
13
- 'waits for you to sign in, captures the token automatically, and closes ' +
14
- 'the tab (or paste a `token` / pass an eth `ethAddress` to skip the ' +
15
- 'browser). Do this once before publishing or listing.\n' +
16
- '2. `attach_chrome` → `start_capture` → drive the page (`navigate`, ' +
17
- '`wait_for_page`) → inspect (`list_requests`, `get_request`, ' +
18
- '`find_requests_containing`).\n' +
19
- '3. `propose_provider` to draft a provider, `replay_request` to ' +
20
- 'pre-flight, `run_proof` to verify with the attestor. OPRF/`hash` ' +
21
- 'redactions are optional and supported.\n' +
22
- '4. `create_provider_version_from_capture` to publish. With NO ' +
23
- '`providerId` it REGISTERS A NEW provider (re-running creates a ' +
24
- 'duplicate); pass a ' +
25
- '`providerId` from `get_me_providers` to add a new version to an existing ' +
26
- 'provider instead.\n' +
27
- '5. `get_me_providers` lists the providers you own (the only ' +
28
- 'provider-listing tool available in this mode).\n\n' +
29
- 'Only GET/POST endpoints can be captured into providers here. There is no ' +
30
- 'organization, credential-linking, or public-review workflow in this mode.'
9
+ import { readFileSync } from 'node:fs'
10
+ import { fileURLToPath } from 'node:url'
11
+
12
+ export const OLD_MODE_INSTRUCTIONS = readFileSync(
13
+ fileURLToPath(new URL('../../skill/old-mode.md', import.meta.url)),
14
+ 'utf8',
15
+ ).trim()