@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
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Resolve the Reclaim cache directory (`~/.reclaim`). Honours the
3
+ * `RECLAIM_HOME` env var as an override so tests can sandbox writes.
4
+ */
5
+ export declare function reclaimHome(): string;
6
+ export declare function credentialsCachePath(): string;
7
+ /**
8
+ * Walk up from `start` until we find a directory containing one of
9
+ * the project-root markers, then return that directory. Falls back
10
+ * to `start` if no marker is found within 8 levels.
11
+ */
12
+ export declare function findProjectRoot(start?: string): string;
@@ -0,0 +1,35 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ /**
5
+ * Resolve the Reclaim cache directory (`~/.reclaim`). Honours the
6
+ * `RECLAIM_HOME` env var as an override so tests can sandbox writes.
7
+ */
8
+ export function reclaimHome() {
9
+ return process.env.RECLAIM_HOME || join(homedir(), '.reclaim');
10
+ }
11
+ export function credentialsCachePath() {
12
+ return join(reclaimHome(), 'credentials.json');
13
+ }
14
+ /**
15
+ * Walk up from `start` until we find a directory containing one of
16
+ * the project-root markers, then return that directory. Falls back
17
+ * to `start` if no marker is found within 8 levels.
18
+ */
19
+ export function findProjectRoot(start = process.cwd()) {
20
+ const markers = ['.git', 'package.json', 'pyproject.toml', 'Cargo.toml'];
21
+ let dir = resolve(start);
22
+ for (let i = 0; i < 8; i++) {
23
+ for (const m of markers) {
24
+ if (existsSync(join(dir, m))) {
25
+ return dir;
26
+ }
27
+ }
28
+ const parent = dirname(dir);
29
+ if (parent === dir) {
30
+ break;
31
+ }
32
+ dir = parent;
33
+ }
34
+ return start;
35
+ }
@@ -0,0 +1,27 @@
1
+ import type { ReclaimClient } from '@reclaimprotocol/client';
2
+ import type { components } from '../../types/openapi.gen.ts';
3
+ type Session = components['schemas']['CredentialAttachSession'];
4
+ type PollResult = {
5
+ outcome: 'linked';
6
+ token?: string;
7
+ orgId?: string;
8
+ } | {
9
+ outcome: 'expired';
10
+ } | {
11
+ outcome: 'timeout';
12
+ elapsed: number;
13
+ attachUrl: string;
14
+ } | {
15
+ outcome: 'error';
16
+ message: string;
17
+ };
18
+ /**
19
+ * Poll GET /credentials/attach/sessions/{code} until the session is
20
+ * LINKED or we give up, whichever comes first.
21
+ *
22
+ * Errors inside the loop are surfaced immediately after MAX_CONSECUTIVE_ERRORS
23
+ * rather than being silently swallowed — this is what tells the agent that
24
+ * e.g. the confirmation POST failed or the server restarted.
25
+ */
26
+ export declare function pollUntilLinked(client: ReclaimClient, session: Pick<Session, 'code' | 'attachUrl' | 'expiresAt'>, onToken?: (token: string) => void): Promise<PollResult>;
27
+ export {};
@@ -0,0 +1,61 @@
1
+ // How long to poll before giving up and telling the user what to do.
2
+ // Shorter than the 15-min server TTL on purpose — agents can't block long.
3
+ const POLL_TIMEOUT_MS = 3 * 60_000; // 3 minutes
4
+ const POLL_INTERVAL_MS = 5_000; // 5 seconds
5
+ const MAX_CONSECUTIVE_ERRORS = 5;
6
+ /**
7
+ * Poll GET /credentials/attach/sessions/{code} until the session is
8
+ * LINKED or we give up, whichever comes first.
9
+ *
10
+ * Errors inside the loop are surfaced immediately after MAX_CONSECUTIVE_ERRORS
11
+ * rather than being silently swallowed — this is what tells the agent that
12
+ * e.g. the confirmation POST failed or the server restarted.
13
+ */
14
+ export async function pollUntilLinked(client, session, onToken) {
15
+ const sessionExpiry = new Date(session.expiresAt).getTime();
16
+ const deadline = Math.min(sessionExpiry, Date.now() + POLL_TIMEOUT_MS);
17
+ const startedAt = Date.now();
18
+ let consecutiveErrors = 0;
19
+ while (Date.now() < deadline) {
20
+ await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
21
+ let polled;
22
+ try {
23
+ polled = await client.call('GetAttachSession', {
24
+ params: { code: session.code },
25
+ query: {}, body: {},
26
+ });
27
+ consecutiveErrors = 0;
28
+ }
29
+ catch (err) {
30
+ consecutiveErrors++;
31
+ if (consecutiveErrors >= MAX_CONSECUTIVE_ERRORS) {
32
+ return {
33
+ outcome: 'error',
34
+ message: `Polling failed ${consecutiveErrors} times in a row: `
35
+ + err.message
36
+ + '. The session confirmation may have failed — try opening '
37
+ + session.attachUrl
38
+ + ' again and confirming, then retry.',
39
+ };
40
+ }
41
+ continue; // transient error, retry
42
+ }
43
+ if (polled.status === 'LINKED') {
44
+ const token = polled.token?.trim();
45
+ if (token) {
46
+ onToken?.(token);
47
+ }
48
+ return {
49
+ outcome: 'linked',
50
+ token,
51
+ orgId: polled.linkedOrgId,
52
+ };
53
+ }
54
+ if (polled.status === 'EXPIRED') {
55
+ return { outcome: 'expired' };
56
+ }
57
+ // status === 'PENDING' → keep polling
58
+ }
59
+ const elapsed = Math.round((Date.now() - startedAt) / 60_000);
60
+ return { outcome: 'timeout', elapsed, attachUrl: session.attachUrl };
61
+ }
@@ -1,4 +1,4 @@
1
- import { type RegisteredTool } from '../../server.ts';
1
+ import { type RegisteredTool } from '../server.ts';
2
2
  /**
3
3
  * Decide which app credential `run_proof` should sign with, BEFORE
4
4
  * calling it. `run_proof` requires an `ownerAddress` and does no
@@ -1,6 +1,6 @@
1
1
  import { deriveFromPrivateKey } from '@reclaimprotocol/client';
2
- import { findProjectRoot } from "../../../paths.js";
3
- import { defineTool } from "../../server.js";
2
+ import { findProjectRoot } from "../../paths.js";
3
+ import { defineTool } from "../server.js";
4
4
  import { suggestCredentialForDir } from "./cache.js";
5
5
  import { readPrivateKeyFromEnvFile } from "./env-file.js";
6
6
  /**
@@ -0,0 +1,14 @@
1
+ export type CachedSession = {
2
+ token: string;
3
+ /** ISO timestamp when the token expires (2 days from issue). */
4
+ expiresAt: string;
5
+ /** Email of the user who authorized (if available). */
6
+ email?: string;
7
+ };
8
+ /** Persist a session token to ~/.reclaim/session.json (0600). */
9
+ export declare function writeSession(session: CachedSession): void;
10
+ /**
11
+ * Read the cached session, returning it only if the token is still
12
+ * valid (not yet expired). Returns undefined on any error.
13
+ */
14
+ export declare function readSession(): CachedSession | undefined;
@@ -0,0 +1,42 @@
1
+ import { chmodSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { reclaimHomeDirPath } from "../../paths.js";
4
+ // Separate from credentials.json — sessions expire, credentials don't.
5
+ function sessionCachePath() {
6
+ return join(reclaimHomeDirPath(), 'session.json');
7
+ }
8
+ /** Persist a session token to ~/.reclaim/session.json (0600). */
9
+ export function writeSession(session) {
10
+ const dir = reclaimHomeDirPath();
11
+ if (!existsSync(dir)) {
12
+ mkdirSync(dir, { recursive: true, mode: 0o700 });
13
+ }
14
+ chmodSync(dir, 0o700);
15
+ const path = sessionCachePath();
16
+ writeFileSync(path, JSON.stringify(session, null, 2) + '\n', { mode: 0o600 });
17
+ chmodSync(path, 0o600);
18
+ }
19
+ /**
20
+ * Read the cached session, returning it only if the token is still
21
+ * valid (not yet expired). Returns undefined on any error.
22
+ */
23
+ export function readSession() {
24
+ const path = sessionCachePath();
25
+ if (!existsSync(path)) {
26
+ return undefined;
27
+ }
28
+ try {
29
+ const raw = readFileSync(path, 'utf8');
30
+ const s = JSON.parse(raw);
31
+ if (!s.token || !s.expiresAt) {
32
+ return undefined;
33
+ }
34
+ if (new Date(s.expiresAt) <= new Date()) {
35
+ return undefined; // expired
36
+ }
37
+ return s;
38
+ }
39
+ catch {
40
+ return undefined;
41
+ }
42
+ }
@@ -1,3 +1,3 @@
1
1
  import { type ReclaimClient } from '@reclaimprotocol/client';
2
- import { type RegisteredTool } from '../../server.ts';
2
+ import { type RegisteredTool } from '../server.ts';
3
3
  export declare function statusTool(client: ReclaimClient): RegisteredTool;
@@ -0,0 +1,76 @@
1
+ import { deriveFromPrivateKey, } from '@reclaimprotocol/client';
2
+ import { findProjectRoot } from "../../paths.js";
3
+ import { defineTool } from "../server.js";
4
+ import { findCached, suggestCredentialForDir } from "./cache.js";
5
+ export function statusTool(client) {
6
+ return defineTool({
7
+ name: 'reclaim_status',
8
+ description: 'Report the live mode (SANDBOX | PRODUCTION | REVOKED) ' +
9
+ 'of a Reclaim app credential. Pass `address` — or omit it ' +
10
+ 'to derive the address from RECLAIM_PRIVATE_KEY, falling ' +
11
+ 'back to the best cached credential for this directory. ' +
12
+ 'Useful to confirm a credential is linked to an org ' +
13
+ 'with billing before running a production flow.',
14
+ inputSchema: {
15
+ type: 'object',
16
+ properties: {
17
+ address: {
18
+ type: 'string',
19
+ pattern: '^0x[0-9a-fA-F]{40}$',
20
+ description: 'Lowercase ETH address. Defaults to the address ' +
21
+ 'derived from RECLAIM_PRIVATE_KEY, then the cached ' +
22
+ 'credential suggested for the current directory.',
23
+ },
24
+ },
25
+ },
26
+ }, async (args) => {
27
+ let address = args.address?.toLowerCase();
28
+ if (!address && process.env.RECLAIM_PRIVATE_KEY) {
29
+ address = deriveFromPrivateKey(process.env.RECLAIM_PRIVATE_KEY).address;
30
+ }
31
+ if (!address) {
32
+ address = suggestCredentialForDir(findProjectRoot(process.cwd()))
33
+ ?.credential.address;
34
+ }
35
+ if (!address) {
36
+ throw new Error('No address given, RECLAIM_PRIVATE_KEY is not set, and the ' +
37
+ 'cache is empty. Run issue_credentials or import_credentials ' +
38
+ 'first.');
39
+ }
40
+ try {
41
+ const credResult = (await client.call('GetCredentialByAddress', {
42
+ params: { address },
43
+ }));
44
+ const cred = credResult.data;
45
+ return {
46
+ address: cred.address,
47
+ mode: cred.mode,
48
+ orgId: cred.orgId,
49
+ label: cred.label,
50
+ revokedAt: cred.revokedAt,
51
+ lastUsedAt: cred.lastUsedAt,
52
+ };
53
+ }
54
+ catch (err) {
55
+ // Anonymous credentials are not registered server-side, so a
56
+ // 404 just means "local-only" — which is SANDBOX. Report what
57
+ // the local cache knows. Other errors propagate. The client
58
+ // throws a Boom-style ProblemError, so the status lives on
59
+ // `output.statusCode` / `problem.status`, not `status`.
60
+ const e = err;
61
+ const code = e.status ?? e.output?.statusCode ?? e.problem?.status;
62
+ if (code !== 404) {
63
+ throw err;
64
+ }
65
+ const cached = findCached(address);
66
+ return {
67
+ address,
68
+ mode: 'SANDBOX',
69
+ ...(cached?.label ? { label: cached.label } : {}),
70
+ note: 'Local-only credential — not registered with the server. ' +
71
+ 'It operates in SANDBOX. Link it to an org with billing ' +
72
+ '(via link_credential) to reach PRODUCTION.',
73
+ };
74
+ }
75
+ });
76
+ }
@@ -0,0 +1 @@
1
+ export declare const BUILDER_MODE_INSTRUCTIONS: string;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * MCP server instructions shown to the LLM when running in BUILDER mode
3
+ * (`USE_OLD_DEVTOOLS=false`). The prose lives in `skill/builder-mode.md`
4
+ * (published via the `files` array) so it can be edited as markdown without
5
+ * touching code. The path resolves identically from `src/mcp` (dev) and
6
+ * `lib/mcp` (published) — both are two levels below the package root.
7
+ * Old-devtools mode has its own reduced set in `../old/instructions.ts`.
8
+ */
9
+ import { readFileSync } from 'node:fs';
10
+ import { fileURLToPath } from 'node:url';
11
+ export const BUILDER_MODE_INSTRUCTIONS = readFileSync(fileURLToPath(new URL('../../skill/builder-mode.md', import.meta.url)), 'utf8').trim();
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Factory entry-point for embedding the reclaim-agent's MCP tools into
3
+ * a host MCP server. Two consumers:
4
+ *
5
+ * - The agent's own standalone `src/index.ts` (uses `ReclaimMcpServer`,
6
+ * the low-level wrapper around `@modelcontextprotocol/sdk`'s Server).
7
+ * - `@reclaimprotocol/client`'s MCP server (uses `McpServer`, the
8
+ * high-level SDK wrapper). Calls `registerAgentTools` to fold the
9
+ * agent's 16 tools alongside its auto-generated API tools.
10
+ *
11
+ * Shared state — Chrome attach state, capture store, secret store — is
12
+ * built once per server and threaded through every tool factory.
13
+ */
14
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
+ import type { ReclaimClient } from '@reclaimprotocol/client';
16
+ import { ConfigStore } from '../config/store.ts';
17
+ import { type AttachState } from './tools/attach.ts';
18
+ import { type CaptureStore } from './tools/capture.ts';
19
+ import { type SecretStore } from './tools/propose.ts';
20
+ import { type RegisteredTool } from './server.ts';
21
+ export interface AgentState {
22
+ attach: {
23
+ current?: AttachState;
24
+ config: ConfigStore;
25
+ };
26
+ captures: CaptureStore;
27
+ secrets: SecretStore;
28
+ }
29
+ export declare function buildAgentState(): AgentState;
30
+ /** Build the flat list of `RegisteredTool` entries. Useful when the host
31
+ * uses our internal `ReclaimMcpServer` interface (`.register(tool)`).
32
+ * Pass `client` to include `create_provider_version_from_capture`. */
33
+ export declare function buildAgentTools(state: AgentState, client?: ReclaimClient): RegisteredTool[];
34
+ /** Register agent tools on `@reclaimprotocol/client`'s McpServer. Mirrors
35
+ * the same shape as builder's auto-generated `registerTools(server, client)`
36
+ * in `mcp/api/tools.ts`.
37
+ * Pass `client` to include `create_provider_version_from_capture`. */
38
+ export declare function registerAgentTools(server: McpServer, state?: AgentState, client?: ReclaimClient): void;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Factory entry-point for embedding the reclaim-agent's MCP tools into
3
+ * a host MCP server. Two consumers:
4
+ *
5
+ * - The agent's own standalone `src/index.ts` (uses `ReclaimMcpServer`,
6
+ * the low-level wrapper around `@modelcontextprotocol/sdk`'s Server).
7
+ * - `@reclaimprotocol/client`'s MCP server (uses `McpServer`, the
8
+ * high-level SDK wrapper). Calls `registerAgentTools` to fold the
9
+ * agent's 16 tools alongside its auto-generated API tools.
10
+ *
11
+ * Shared state — Chrome attach state, capture store, secret store — is
12
+ * built once per server and threaded through every tool factory.
13
+ */
14
+ import { setCryptoImplementation } from '@reclaimprotocol/tls';
15
+ import { webcryptoCrypto } from '@reclaimprotocol/tls/webcrypto';
16
+ import { ConfigStore } from "../config/store.js";
17
+ import { analyzeTool } from "./tools/analyze.js";
18
+ import { attachTool } from "./tools/attach.js";
19
+ import { captureTools } from "./tools/capture.js";
20
+ import { browserTools } from "./tools/eval.js";
21
+ import { findTool } from "./tools/find.js";
22
+ import { proofTool } from "./tools/proof.js";
23
+ import { makeSecretStore, proposeTool, } from "./tools/propose.js";
24
+ import { createVersionFromCaptureTool } from "./tools/publish.js";
25
+ import { replayTool } from "./tools/replay.js";
26
+ import { sessionTools } from "./tools/session.js";
27
+ import { registerToolList } from "./server.js";
28
+ let cryptoInitialized = false;
29
+ /** One-time crypto backend init for @reclaimprotocol/tls. The package
30
+ * ships with an empty `crypto = {}` and defers backend choice to the
31
+ * caller; without this, the first proof call dies inside the SDK with
32
+ * `crypto.randomBytes is not a function`. */
33
+ function ensureCryptoInit() {
34
+ if (cryptoInitialized) {
35
+ return;
36
+ }
37
+ setCryptoImplementation(webcryptoCrypto);
38
+ cryptoInitialized = true;
39
+ }
40
+ export function buildAgentState() {
41
+ return {
42
+ attach: { config: new ConfigStore() },
43
+ captures: { sessions: new Map() },
44
+ secrets: makeSecretStore(),
45
+ };
46
+ }
47
+ /** Build the flat list of `RegisteredTool` entries. Useful when the host
48
+ * uses our internal `ReclaimMcpServer` interface (`.register(tool)`).
49
+ * Pass `client` to include `create_provider_version_from_capture`. */
50
+ export function buildAgentTools(state, client) {
51
+ ensureCryptoInit();
52
+ const tools = [];
53
+ tools.push(attachTool(state.attach));
54
+ for (const t of captureTools(state.attach, state.captures)) {
55
+ tools.push(t);
56
+ }
57
+ tools.push(findTool(state.captures));
58
+ for (const t of browserTools(state.attach)) {
59
+ tools.push(t);
60
+ }
61
+ for (const t of sessionTools(state.attach, state.captures, state.secrets)) {
62
+ tools.push(t);
63
+ }
64
+ tools.push(analyzeTool(state.captures));
65
+ tools.push(proposeTool(state.captures, state.secrets));
66
+ tools.push(replayTool(state.secrets));
67
+ tools.push(proofTool(state.secrets));
68
+ if (client) {
69
+ tools.push(createVersionFromCaptureTool(client));
70
+ }
71
+ return tools;
72
+ }
73
+ /** Register agent tools on `@reclaimprotocol/client`'s McpServer. Mirrors
74
+ * the same shape as builder's auto-generated `registerTools(server, client)`
75
+ * in `mcp/api/tools.ts`.
76
+ * Pass `client` to include `create_provider_version_from_capture`. */
77
+ export function registerAgentTools(server, state, client) {
78
+ const s = state ?? buildAgentState();
79
+ registerToolList(server, buildAgentTools(s, client));
80
+ }
@@ -1,9 +1,9 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import { type JSONSchema } from 'zod-from-json-schema';
2
+ import type { JSONSchema } from 'zod/v4/core';
3
3
  export interface ToolDefinition {
4
4
  name: string;
5
5
  description: string;
6
- inputSchema: JSONSchema;
6
+ inputSchema: JSONSchema.ObjectSchema;
7
7
  }
8
8
  export interface RegisteredTool {
9
9
  definition: ToolDefinition;
@@ -30,9 +30,3 @@ export declare function defineTool<TArgs>(definition: ToolDefinition, handler: (
30
30
  * stringification and error catching for tool execution.
31
31
  */
32
32
  export declare function registerToolList(server: McpServer, tools: RegisteredTool[]): void;
33
- export declare class ReclaimMcpServer {
34
- #private;
35
- constructor();
36
- register(tool: RegisteredTool): void;
37
- listen(): Promise<void>;
38
- }
package/lib/mcp/server.js CHANGED
@@ -1,7 +1,4 @@
1
- import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
- import { convertJsonSchemaToZod } from 'zod-from-json-schema';
1
+ import { toZod } from "./api/to-zod.js";
5
2
  import { remapErrorAsResponse } from "./remap_errors.js";
6
3
  /**
7
4
  * Define a tool with a single inputSchema (JSON Schema) used as the
@@ -11,7 +8,7 @@ import { remapErrorAsResponse } from "./remap_errors.js";
11
8
  * to inbound args cannot drift.
12
9
  */
13
10
  export function defineTool(definition, handler) {
14
- const schema = convertJsonSchemaToZod(definition.inputSchema);
11
+ const schema = toZod(definition.inputSchema);
15
12
  return {
16
13
  definition,
17
14
  handler: async (raw) => {
@@ -29,7 +26,7 @@ export function registerToolList(server, tools) {
29
26
  for (const tool of tools) {
30
27
  server.registerTool(tool.definition.name, {
31
28
  description: tool.definition.description,
32
- inputSchema: convertJsonSchemaToZod(tool.definition.inputSchema),
29
+ inputSchema: toZod(tool.definition.inputSchema),
33
30
  }, async (args) => {
34
31
  try {
35
32
  return {
@@ -47,30 +44,3 @@ export function registerToolList(server, tools) {
47
44
  });
48
45
  }
49
46
  }
50
- export class ReclaimMcpServer {
51
- #tools = new Map();
52
- #server;
53
- constructor() {
54
- this.#server = new Server({ name: 'reclaim-agent', version: '0.1.0' }, { capabilities: { tools: {} } });
55
- this.#server.setRequestHandler(ListToolsRequestSchema, async () => ({
56
- // Double-cast: our `ToolDefinition` carries the same fields as the
57
- // SDK's `Tool` but the SDK's type is strict-narrowed and won't
58
- // accept ours without going through `unknown`.
59
- tools: [...this.#tools.values()].map((t) => t.definition),
60
- }));
61
- this.#server.setRequestHandler(CallToolRequestSchema, async (req) => {
62
- const tool = this.#tools.get(req.params.name);
63
- if (!tool) {
64
- throw new Error(`unknown tool: ${req.params.name}`);
65
- }
66
- const result = await tool.handler(req.params.arguments ?? {});
67
- return { content: [{ type: 'text', text: JSON.stringify(result) }] };
68
- });
69
- }
70
- register(tool) {
71
- this.#tools.set(tool.definition.name, tool);
72
- }
73
- async listen() {
74
- await this.#server.connect(new StdioServerTransport());
75
- }
76
- }
package/lib/mcp/start.js CHANGED
@@ -1,32 +1,35 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { DEFAULT_BASE_URL, ReclaimClient } from '@reclaimprotocol/client';
4
- import { DEFAULT_OLD_API_URL, ReclaimOldClient } from "../old/client.js";
5
- import { useOldDevtools } from "../old/flag.js";
3
+ import { ReclaimClient } from '@reclaimprotocol/client';
4
+ import { agentDisabled, apiToken, apiUrl, oldApiUrl, useOldDevtools, } from "../consts.js";
5
+ import { ReclaimOldClient } from "../old/client.js";
6
6
  import { resolveInitialIdentity } from "../old/identity.js";
7
7
  import { OLD_MODE_INSTRUCTIONS } from "../old/instructions.js";
8
8
  import { buildOldBackendTools } from "../old/tools/build.js";
9
9
  import { NAME, VERSION } from "../pkg.js";
10
10
  import { registerTools } from "./api/tools.js";
11
- import { buildAgentTools } from "./tools/agent/build.js";
12
- import { buildCredentialTools, buildLocalCredentialTools, } from "./tools/credentials/build.js";
13
- import { readSession } from "./tools/credentials/session-cache.js";
11
+ import { buildAgentTools, buildCredentialTools, buildLocalCredentialTools, buildVerificationTools, readSession, } from "./tools/index.js";
12
+ import { BUILDER_MODE_INSTRUCTIONS } from "./instructions.js";
14
13
  import { registerToolList } from "./server.js";
15
14
  export async function startMcpServer() {
16
15
  const oldMode = useOldDevtools();
17
- const server = new McpServer({ name: NAME, version: VERSION }, oldMode ? { instructions: OLD_MODE_INSTRUCTIONS } : undefined);
16
+ const server = new McpServer({ name: NAME, version: VERSION }, {
17
+ instructions: oldMode
18
+ ? OLD_MODE_INSTRUCTIONS
19
+ : BUILDER_MODE_INSTRUCTIONS,
20
+ });
18
21
  // Agent tools (Chrome CDP capture, provider synthesis, replay, proof) are
19
22
  // backend-independent and registered in both modes. Skipped in hosted
20
23
  // deployments — set RECLAIM_AGENT_DISABLED=1 to register only the API
21
24
  // surface.
22
- const agentToolsEnabled = process.env.RECLAIM_AGENT_DISABLED !== '1';
25
+ const agentToolsEnabled = !agentDisabled();
23
26
  if (oldMode) {
24
27
  // OLD-devtools mode (the default): the legacy backend is still in
25
28
  // production while builder is built. All auto-generated builder tools
26
29
  // are disabled; a small ReclaimOldClient serves authenticate / publish /
27
30
  // get_me_providers instead.
28
31
  const oldClient = new ReclaimOldClient({
29
- baseUrl: process.env.RECLAIM_OLD_API_URL || DEFAULT_OLD_API_URL,
32
+ baseUrl: oldApiUrl(),
30
33
  identity: resolveInitialIdentity(),
31
34
  });
32
35
  registerToolList(server, buildLocalCredentialTools());
@@ -39,9 +42,9 @@ export async function startMcpServer() {
39
42
  }
40
43
  else {
41
44
  const client = new ReclaimClient({
42
- baseUrl: process.env.RECLAIM_API_URL || DEFAULT_BASE_URL,
45
+ baseUrl: apiUrl(),
43
46
  // Priority: explicit env var → cached session token → unauthenticated
44
- token: process.env.RECLAIM_API_TOKEN || readSession()?.token,
47
+ token: apiToken() || readSession()?.token,
45
48
  headers: { 'User-Agent': `${NAME}/${VERSION}` },
46
49
  });
47
50
  // Tool names must stay disjoint across these three groups: hand-written
@@ -51,6 +54,9 @@ export async function startMcpServer() {
51
54
  // collision instead of one tool silently shadowing the other.
52
55
  // Register credential tools for ETH credential management.
53
56
  registerToolList(server, buildCredentialTools(client));
57
+ // Higher-level verification orchestrations (e.g. fetch + decrypt result).
58
+ // Authenticates with RECLAIM_ORG_SECRET, not the session client.
59
+ registerToolList(server, buildVerificationTools());
54
60
  // Add auto-generated tools with snake_case wrappers
55
61
  // for every MCP-tagged operation.
56
62
  registerTools(server, client);
@@ -1,12 +1,8 @@
1
1
  /**
2
2
  * Factory entry-point for embedding the reclaim-agent's MCP tools into
3
- * a host MCP server. Two consumers:
4
- *
5
- * - The agent's own standalone `src/index.ts` (uses `ReclaimMcpServer`,
6
- * the low-level wrapper around `@modelcontextprotocol/sdk`'s Server).
7
- * - `@reclaimprotocol/client`'s MCP server (uses `McpServer`, the
8
- * high-level SDK wrapper). Calls `registerAgentTools` to fold the
9
- * agent's 16 tools alongside its auto-generated API tools.
3
+ * a host MCP server via `registerToolList` (server.ts) on the high-level
4
+ * `@modelcontextprotocol/sdk` `McpServer`. Folds the agent's tools
5
+ * alongside the auto-generated API tools.
10
6
  *
11
7
  * Shared state — Chrome attach state, capture store, secret store — is
12
8
  * built once per server and threaded through every tool factory.
@@ -25,8 +21,8 @@ export interface AgentState {
25
21
  captures: CaptureStore;
26
22
  secrets: SecretStore;
27
23
  }
28
- /** Build the flat list of `RegisteredTool` entries. Useful when the host
29
- * uses our internal `ReclaimMcpServer` interface (`.register(tool)`).
24
+ /** Build the flat list of `RegisteredTool` entries, ready for
25
+ * `registerToolList`.
30
26
  * Pass `client` to include the builder `create_provider_version_from_capture`;
31
27
  * omit it (e.g. OLD-devtools mode) to register only the backend-independent
32
28
  * capture/proof tools — old mode supplies its own publish tool. */