@reclaimprotocol/agent 0.1.33 → 0.1.34

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 (88) hide show
  1. package/lib/authoring/backend.d.ts +13 -0
  2. package/lib/authoring/index.d.ts +1 -1
  3. package/lib/authoring/tools.js +78 -42
  4. package/lib/config/store.d.ts +10 -0
  5. package/lib/mcp/api/operations.gen.d.ts +238 -4
  6. package/lib/mcp/api/operations.gen.js +6433 -328
  7. package/lib/mcp/api/tools.js +21 -8
  8. package/lib/mcp/instructions.js +11 -11
  9. package/lib/mcp/server.d.ts +1 -1
  10. package/lib/mcp/server.js +3 -0
  11. package/lib/mcp/success-response.js +5 -1
  12. package/lib/mcp/tools/agent/analyze.js +5 -4
  13. package/lib/mcp/tools/agent/attach.js +11 -7
  14. package/lib/mcp/tools/agent/build.js +3 -1
  15. package/lib/mcp/tools/agent/capture.d.ts +2 -2
  16. package/lib/mcp/tools/agent/capture.js +15 -11
  17. package/lib/mcp/tools/agent/eval.js +4 -3
  18. package/lib/mcp/tools/agent/find.js +9 -10
  19. package/lib/mcp/tools/agent/how-it-works.js +1 -0
  20. package/lib/mcp/tools/agent/live-view.js +10 -7
  21. package/lib/mcp/tools/agent/pod-proof.js +7 -11
  22. package/lib/mcp/tools/agent/propose.js +4 -3
  23. package/lib/mcp/tools/agent/publish.d.ts +2 -1
  24. package/lib/mcp/tools/agent/publish.js +12 -6
  25. package/lib/mcp/tools/agent/replay.js +10 -7
  26. package/lib/mcp/tools/agent/session.js +16 -8
  27. package/lib/mcp/tools/agent/shared.js +3 -2
  28. package/lib/mcp/tools/agent/start-integration.d.ts +15 -0
  29. package/lib/mcp/tools/agent/start-integration.js +61 -0
  30. package/lib/mcp/tools/authenticate/authenticate.js +9 -11
  31. package/lib/mcp/tools/authenticate/build.js +2 -0
  32. package/lib/mcp/tools/authenticate/builder-access.js +1 -0
  33. package/lib/mcp/tools/authenticate/eth-key.d.ts +8 -0
  34. package/lib/mcp/tools/authenticate/eth-key.js +27 -15
  35. package/lib/mcp/tools/authenticate/import.js +18 -31
  36. package/lib/mcp/tools/authenticate/issue-org-token.d.ts +8 -0
  37. package/lib/mcp/tools/authenticate/issue-org-token.js +60 -0
  38. package/lib/mcp/tools/authenticate/issue.js +9 -9
  39. package/lib/mcp/tools/authenticate/org-key-store.d.ts +10 -0
  40. package/lib/mcp/tools/authenticate/org-key-store.js +23 -0
  41. package/lib/mcp/tools/authenticate/resolve-owner-key.js +10 -12
  42. package/lib/mcp/tools/mode/mode.js +2 -0
  43. package/lib/mcp/tools/verification/result.js +10 -7
  44. package/lib/tools/registry.d.ts +12 -0
  45. package/lib/tools/registry.js +1 -0
  46. package/package.json +2 -2
  47. package/skill/SKILL.builder.md +77 -74
  48. package/skill/SKILL.common.md +2 -1
  49. package/skill/builder-mode.md +135 -138
  50. package/skill/start-integration.md +49 -0
  51. package/skill/user-script.md +64 -0
  52. package/skill/verification-client-integration.md +28 -22
  53. package/src/authoring/backend.ts +15 -0
  54. package/src/authoring/index.ts +2 -0
  55. package/src/authoring/tools.ts +86 -42
  56. package/src/config/store.ts +11 -0
  57. package/src/mcp/api/operations.gen.ts +6477 -364
  58. package/src/mcp/api/tools.ts +21 -8
  59. package/src/mcp/instructions.ts +11 -11
  60. package/src/mcp/server.ts +4 -0
  61. package/src/mcp/success-response.ts +5 -1
  62. package/src/mcp/tools/agent/analyze.ts +5 -4
  63. package/src/mcp/tools/agent/attach.ts +11 -7
  64. package/src/mcp/tools/agent/build.ts +5 -1
  65. package/src/mcp/tools/agent/capture.ts +20 -12
  66. package/src/mcp/tools/agent/eval.ts +4 -3
  67. package/src/mcp/tools/agent/find.ts +9 -10
  68. package/src/mcp/tools/agent/how-it-works.ts +1 -0
  69. package/src/mcp/tools/agent/live-view.ts +10 -7
  70. package/src/mcp/tools/agent/pod-proof.ts +7 -11
  71. package/src/mcp/tools/agent/propose.ts +4 -3
  72. package/src/mcp/tools/agent/publish.ts +12 -4
  73. package/src/mcp/tools/agent/replay.ts +10 -7
  74. package/src/mcp/tools/agent/session.ts +16 -8
  75. package/src/mcp/tools/agent/shared.ts +7 -2
  76. package/src/mcp/tools/agent/start-integration.ts +83 -0
  77. package/src/mcp/tools/authenticate/authenticate.ts +9 -11
  78. package/src/mcp/tools/authenticate/build.ts +2 -0
  79. package/src/mcp/tools/authenticate/builder-access.ts +1 -0
  80. package/src/mcp/tools/authenticate/eth-key.ts +48 -18
  81. package/src/mcp/tools/authenticate/import.ts +21 -36
  82. package/src/mcp/tools/authenticate/issue-org-token.ts +84 -0
  83. package/src/mcp/tools/authenticate/issue.ts +9 -9
  84. package/src/mcp/tools/authenticate/org-key-store.ts +25 -0
  85. package/src/mcp/tools/authenticate/resolve-owner-key.ts +10 -12
  86. package/src/mcp/tools/mode/mode.ts +2 -0
  87. package/src/mcp/tools/verification/result.ts +10 -7
  88. package/src/tools/registry.ts +14 -0
@@ -47,6 +47,70 @@ Do not clear cookies or force another sign-in; inconclusive coverage must not
47
47
  block publication. This browser check does not emulate a client-specific
48
48
  interceptor.
49
49
 
50
+ ## Write the navigation script first
51
+
52
+ Write the navigation script as soon as the developer is signed in, or as soon
53
+ as you know the sign-in page. Then capture through it, so authoring, testing,
54
+ and verification follow the same path.
55
+
56
+ The script does two things:
57
+
58
+ 1. **Signed out:** send the user to the sign-in page.
59
+ 2. **Signed in:** visit each page that holds a data point, in order. Data
60
+ points can live on different pages. Keep a step index in `sessionStorage` so
61
+ the script survives reloads and repeated runs.
62
+
63
+ Loop: `test_user_script({ script, keep: true })` → fix → retest. With `keep:
64
+ true` the script stays installed for every later navigation in the authoring
65
+ browser, as it does at verification. `create_provider_version_from_capture`
66
+ publishes it as `webSettings.jsUserScripts` unless you pass your own.
67
+
68
+ ```js
69
+ (() => {
70
+ const SIGN_IN = '/login'
71
+ const STEPS = [
72
+ { path: '/account', ready: () => document.querySelector('#dob') },
73
+ { path: '/settings/profile', ready: () => document.querySelector('#plan') },
74
+ ]
75
+ const signedIn = () => document.querySelector('[data-user-menu]')
76
+ && !document.querySelector('a[href="/login"]')
77
+ let tries = 0
78
+ const timer = setInterval(() => {
79
+ if(++tries > 120) {
80
+ return clearInterval(timer)
81
+ }
82
+
83
+ if(!signedIn()) {
84
+ // stay put on the sign-in page; also covers unknown pages
85
+ if(location.pathname !== SIGN_IN) {
86
+ clearInterval(timer)
87
+ location.assign(SIGN_IN)
88
+ }
89
+
90
+ return
91
+ }
92
+
93
+ const i = Number(sessionStorage.getItem('rc-step') || 0)
94
+ const step = STEPS[i]
95
+ if(!step) {
96
+ return clearInterval(timer)
97
+ }
98
+
99
+ if(location.pathname !== step.path) {
100
+ clearInterval(timer)
101
+ return location.assign(step.path)
102
+ }
103
+
104
+ if(step.ready()) {
105
+ sessionStorage.setItem('rc-step', String(i + 1))
106
+ }
107
+ }, 500)
108
+ })()
109
+ ```
110
+
111
+ Adapt the selectors to the site. Each new tab starts at the first step, and a
112
+ reload resumes at the current step.
113
+
50
114
  ## `window.Reclaim` — rarely needed
51
115
 
52
116
  `window.Reclaim` is an optional bridge for a handful of edge cases. Most
@@ -2,31 +2,38 @@
2
2
 
3
3
  ## Set up an application with the coding agent
4
4
 
5
- When asked to integrate Reclaim into an app, inspect that app's frontend,
6
- backend, package manager, configuration, and callback conventions. Complete
7
- the integration in its codebase and run its relevant checks. The MCP tools
8
- configure Builder resources; the coding agent's file tools edit the app.
5
+ For "add Reclaim to my app", call `start_integration` first and follow its
6
+ plan. Don't ask whether to try, integrate, or create an app. Ask one short
7
+ question only when intent is unclear. The steps below are the detail behind
8
+ that plan.
9
+
10
+ Inspect the app's frontend, backend, package manager, configuration, and
11
+ callback conventions. Complete the integration in its codebase and run its
12
+ relevant checks. The MCP tools configure Builder resources; your file tools
13
+ edit the app.
9
14
 
10
15
  If the app depends on `@reclaimprotocol/js-sdk`, ask the developer first:
11
- keep it (call `set_devtools_mode({ mode: "old" })` and have them restart the MCP
12
- server), or migrate to the Builder session flow below. When
13
- migrating, remove `@reclaimprotocol/js-sdk` and replace its
14
- `ReclaimProofRequest` and `verifyProof` calls with the session flow below.
15
-
16
- 1. Use `get_devtools_mode` to confirm Builder mode and `get_me` or
17
- `authenticate` to sign in as the developer. Find the intended organization
18
- with `list_orgs`; call `create_org` only when a new organization is wanted.
16
+ keep it (`set_devtools_mode({ mode: "old" })`, then they restart the MCP
17
+ server), or migrate to the session flow below. When migrating, remove
18
+ `@reclaimprotocol/js-sdk` and replace its `ReclaimProofRequest` and
19
+ `verifyProof` calls.
20
+
21
+ 1. `get_devtools_mode` confirms Builder mode. `get_me` or `authenticate` signs
22
+ in the developer. Find the organization with `list_orgs`; call `create_org`
23
+ only when they want a new one.
19
24
  2. Register a callback URL owned by the app's backend with
20
25
  `create_org_callback_subscription`. Include terminal success, rejection,
21
26
  error, cancellation, and expiry events. If the app needs encrypted results,
22
- register its public key with `set_org_keypair`; retain the private key only
23
- in the backend.
24
- 3. Reuse a `RECLAIM_ORG_SECRET` the app already has. Otherwise an organization
25
- owner calls `issue_org_token`; its `orgSecret` is shown once. Write it with
26
- your file tools into the backend's env file (for example
27
- `RECLAIM_ORG_SECRET=rorg_…` in `.env`) and make sure that file is
28
- gitignored. Keep it out of frontend bundles, logs, source control, and the
29
- final response.
27
+ register its public key with `set_org_keypair`; keep the private key only in
28
+ the backend. `set_org_keypair` refuses to replace an existing key unless you
29
+ pass `replace: true`; pass it only when the developer asks.
30
+ 3. Org key: reuse the `RECLAIM_ORG_SECRET` the app already has. Otherwise an
31
+ organization owner calls `issue_org_token`. It writes the key to the
32
+ project's env file (default `.env`, variable `RECLAIM_ORG_SECRET`) and
33
+ returns only the last four characters and the file path. Make sure that file
34
+ is gitignored. Never print the key, put it in the conversation, or ask the
35
+ developer to paste it. Keep it out of frontend bundles, logs, and source
36
+ control.
30
37
  4. Prefer plain HTTP from the backend (see [Code to write](#code-to-write)).
31
38
  Create sessions with `POST /verifications/sessions`
32
39
  (`Authorization: Bearer $RECLAIM_ORG_SECRET`), save each returned session ID
@@ -60,8 +67,7 @@ The MCP session tools (`create_verification_session`,
60
67
  `delete_callback_subscription`, `bind_verification_session_tee_nonce`, and
61
68
  `get_verification_result`) call these same production endpoints with the org
62
69
  key: pass it as `orgToken`, or let them fall back to the MCP server's
63
- `RECLAIM_ORG_SECRET`. Use them, or `curl` with the key from `.env`, to test the
64
- integration end to end.
70
+ `RECLAIM_ORG_SECRET`. Use them to test the integration end to end.
65
71
 
66
72
  ## Code to write
67
73
 
@@ -37,6 +37,18 @@ export interface Draft {
37
37
  extractions: Extraction[]
38
38
  }
39
39
 
40
+ /** A navigation script installed for every later page load of the authoring
41
+ * session. `identifier` is the CDP registration, so it can be removed. */
42
+ export interface KeptScript {
43
+ script: string
44
+ identifier?: string
45
+ }
46
+
47
+ /** Holds the session's kept script, replaced by each `keep` call. */
48
+ export interface KeptScriptRef {
49
+ keptScript?: KeptScript
50
+ }
51
+
40
52
  /** Per-session draft store: `propose` puts, `replay`/`run_proof` get by id. */
41
53
  export interface DraftStore {
42
54
  put(draft: Draft): string
@@ -75,6 +87,9 @@ export interface AuthoringBackend {
75
87
  * out. Cloud authoring enables this; local MCP keeps its existing
76
88
  * behavior. */
77
89
  readonly readOnlyPageEval?: boolean
90
+ /** Where `test_user_script` keeps its script. Absent for hosts that do not
91
+ * publish it (the cloud loop synthesizes its own navigation script). */
92
+ readonly kept?: KeptScriptRef
78
93
  /** Send a raw CDP command scoped to this session's page. */
79
94
  sendCdp(method: string, params?: Record<string, unknown>): Promise<unknown>
80
95
  /** Resolve once `method` (a CDP event) fires on this session's page, or
@@ -4,6 +4,8 @@ export type {
4
4
  AuthoringBackend,
5
5
  Draft,
6
6
  DraftStore,
7
+ KeptScript,
8
+ KeptScriptRef,
7
9
  ProveOptions,
8
10
  SecretParams,
9
11
  } from './backend.ts'
@@ -14,6 +14,7 @@
14
14
  * draft (recipe + secrets) is held server-side; the model only sees an opaque
15
15
  * `draftId` and the secret-free provider.
16
16
  */
17
+ import assert from 'node:assert'
17
18
  import { findTool } from '../mcp/tools/agent/find.ts'
18
19
  import { proposeTool } from '../mcp/tools/agent/propose.ts'
19
20
  import { replayTool } from '../mcp/tools/agent/replay.ts'
@@ -117,13 +118,15 @@ export function authoringTools(
117
118
  {
118
119
  name: 'navigate',
119
120
  description:
120
- 'Navigate the captured tab to a URL and wait for its load event. '
121
- + 'Returns the URL the tab actually landed on, so you can detect a '
122
- + 'redirect to a login page.',
121
+ 'Navigates the captured tab to a URL and waits for its load event. '
122
+ + 'Returns the URL the tab landed on, to detect a redirect to a '
123
+ + 'sign-in page. Any navigation script kept by `test_user_script` '
124
+ + 'runs on the page.',
123
125
  inputSchema: objectSchema(
124
126
  { url: { type: 'string' }, timeoutMs: { type: 'number' } },
125
127
  ['url'],
126
128
  ),
129
+ annotations: { openWorldHint: true, destructiveHint: false },
127
130
  },
128
131
  async(args) => {
129
132
  const backend = resolveBackend(args)
@@ -147,13 +150,16 @@ export function authoringTools(
147
150
  {
148
151
  name: 'eval_in_page',
149
152
  description:
150
- 'Evaluate a JavaScript expression in the page and return its value. '
151
- + 'Use it to read the value being proven out of the DOM, to check '
152
- + 'login state, or to trigger the target request (for example, '
153
- + '`location.reload()`).',
153
+ 'Evaluates a JavaScript expression in the page of the remote '
154
+ + 'authoring browser, not on this machine, and returns its value. '
155
+ + 'Use it to read a data point from the DOM, check sign-in state, '
156
+ + 'or trigger the target request (for example, `location.reload()`). '
157
+ + 'The page cannot reach files or processes on this machine. Return '
158
+ + 'only the values you need, never cookies or tokens.',
154
159
  inputSchema: objectSchema(
155
160
  { expression: { type: 'string' } }, ['expression'],
156
161
  ),
162
+ annotations: { openWorldHint: true, destructiveHint: false },
157
163
  },
158
164
  (args) => evalInPage(resolveBackend(args), String(args.expression)),
159
165
  ),
@@ -161,14 +167,16 @@ export function authoringTools(
161
167
  {
162
168
  name: 'wait_for_page',
163
169
  description:
164
- 'Poll a JavaScript expression once a second until it is truthy or '
165
- + 'the timeout elapses. Use it to wait for content to appear. To '
166
- + 'wait for a login, use wait_for_login instead — page JavaScript '
167
- + 'cannot see the httpOnly session cookie.',
170
+ 'Evaluates a JavaScript expression in the remote authoring browser '
171
+ + 'once a second until it is truthy or the timeout elapses. Returns '
172
+ + '{ ready }. Use it to wait for content to appear. To wait for a '
173
+ + 'sign-in, use `wait_for_login`: page JavaScript cannot see the '
174
+ + 'httpOnly session cookie.',
168
175
  inputSchema: objectSchema(
169
176
  { expression: { type: 'string' }, timeoutMs: { type: 'number' } },
170
177
  ['expression'],
171
178
  ),
179
+ annotations: { readOnlyHint: true, openWorldHint: true },
172
180
  },
173
181
  async(args) => {
174
182
  const backend = resolveBackend(args)
@@ -190,27 +198,34 @@ export function authoringTools(
190
198
  {
191
199
  name: 'test_user_script',
192
200
  description:
193
- 'Dry-run a USER SCRIPT (the `jsUserScripts` / `customInjection` '
194
- + 'field) in the LIVE attached tab while authoring or after provider '
195
- + 'creation. Installs '
196
- + '`script` via CDP so it runs on the next navigation exactly as '
197
- + 'the real field would, then reports whether it ran and what it '
198
- + 'threw. With `navigateUrl`, it navigates there and removes the '
199
- + 'script once the result is read — self-cleaning, safe to repeat. '
200
- + 'WITHOUT `navigateUrl` the script stays installed (navigate '
201
- + 'yourself, then re-call this tool or read '
202
- + '`window.__reclaimUserScriptResult` via eval_in_page) and keeps '
203
- + 'running on every later navigation until a call WITH '
204
- + '`navigateUrl` removes it — so don\'t stack manual-mode calls. '
205
- + 'Guide: how_it_works({ topic: "user-script" }).',
201
+ 'Installs a navigation script (the `jsUserScripts` field) in the '
202
+ + 'remote authoring browser, not on this machine, so it runs before '
203
+ + 'each page load, as it does at verification. Reports whether it '
204
+ + 'ran and what it threw. With `navigateUrl`, navigates there and '
205
+ + 'removes the script after reading the result, unless `keep` is '
206
+ + 'true. Without `navigateUrl`, the script stays installed for '
207
+ + 'later navigations until a call with `navigateUrl` removes it. '
208
+ + 'With `keep: true`, the script stays installed for every later '
209
+ + 'navigation in this session, replaces any earlier kept script, and '
210
+ + '`create_provider_version_from_capture` publishes it as '
211
+ + '`jsUserScripts` unless that call passes its own. '
212
+ + 'See how_it_works({ topic: "user-script" }).',
206
213
  inputSchema: objectSchema(
207
214
  {
208
215
  script: { type: 'string' },
209
216
  navigateUrl: { type: 'string' },
210
217
  timeoutMs: { type: 'number' },
218
+ keep: {
219
+ type: 'boolean',
220
+ description:
221
+ 'Keep the script installed for every later navigation in '
222
+ + 'this session and use it as the published navigation '
223
+ + 'script.',
224
+ },
211
225
  },
212
226
  ['script'],
213
227
  ),
228
+ annotations: { openWorldHint: true, destructiveHint: false },
214
229
  },
215
230
  async(args) => {
216
231
  const backend = resolveBackend(args)
@@ -235,13 +250,37 @@ export function authoringTools(
235
250
  );
236
251
  }
237
252
  `
253
+ const keep = args.keep === true
254
+ const kept = keep ? backend.kept : undefined
255
+ assert(
256
+ !keep || kept,
257
+ new Error('This host does not support `keep`.'),
258
+ )
259
+ // Replace, never stack: only one kept script runs.
260
+ const previous = kept?.keptScript?.identifier
261
+ if(previous) {
262
+ await backend.sendCdp(
263
+ 'Page.removeScriptToEvaluateOnNewDocument',
264
+ { identifier: previous },
265
+ ).catch(() => {})
266
+ }
267
+
238
268
  const installed = (await backend.sendCdp(
239
269
  'Page.addScriptToEvaluateOnNewDocument', { source: wrapped },
240
270
  )) as { identifier?: string }
271
+ if(kept) {
272
+ kept.keptScript = {
273
+ script,
274
+ ...(installed.identifier
275
+ ? { identifier: installed.identifier }
276
+ : {}),
277
+ }
278
+ }
241
279
 
242
280
  if(typeof args.navigateUrl !== 'string') {
243
281
  return {
244
282
  installed: true,
283
+ ...(keep ? { kept: true } : {}),
245
284
  note:
246
285
  'Installed for the NEXT navigation only — it did not run on '
247
286
  + 'the current page, and stays installed (runs on every later '
@@ -276,6 +315,7 @@ export function authoringTools(
276
315
  value as { ran?: boolean, errors?: string[] } | undefined
277
316
  return {
278
317
  installed: true,
318
+ ...(keep ? { kept: true } : {}),
279
319
  navigated: true,
280
320
  ran: result?.ran ?? false,
281
321
  errors: result?.errors ?? [],
@@ -283,7 +323,7 @@ export function authoringTools(
283
323
  } finally {
284
324
  // One-shot test: remove it so it doesn't keep running (and
285
325
  // potentially redirecting the tab) on every later navigation.
286
- if(installed.identifier) {
326
+ if(installed.identifier && !keep) {
287
327
  await backend.sendCdp(
288
328
  'Page.removeScriptToEvaluateOnNewDocument',
289
329
  { identifier: installed.identifier },
@@ -296,13 +336,14 @@ export function authoringTools(
296
336
  {
297
337
  name: 'get_cookies',
298
338
  description:
299
- 'List the NAMES of cookies currently set for the page (values are '
300
- + 'NEVER returned). The most reliable, language- and DOM-independent '
301
- + 'login signal: after the user logs in, an auth/session cookie '
302
- + 'appears (for example, session, sid, token, auth, jwt, _user, '
303
- + 'logged_in). '
304
- + 'Includes httpOnly cookies the page JS cannot see.',
339
+ 'Returns the names, domains, and flags of the cookies set in the '
340
+ + 'remote authoring browser. Values are never returned; they stay '
341
+ + 'in the browser and on the server. A new auth or session cookie '
342
+ + '(for example, session, sid, auth, jwt) is a reliable sign-in '
343
+ + 'signal that does not depend on the page language or DOM. '
344
+ + 'Includes httpOnly cookies that page JavaScript cannot see.',
305
345
  inputSchema: objectSchema({}),
346
+ annotations: { readOnlyHint: true, openWorldHint: true },
306
347
  },
307
348
  async(args) => {
308
349
  const backend = resolveBackend(args)
@@ -337,6 +378,7 @@ export function authoringTools(
337
378
  + 'navigating to the login page. Does NOT navigate (never yanks '
338
379
  + 'the user off login/2FA). Returns { loggedIn, newCookies }.',
339
380
  inputSchema: objectSchema({ timeoutMs: { type: 'number' } }),
381
+ annotations: { readOnlyHint: true, openWorldHint: true },
340
382
  },
341
383
  async(args) => {
342
384
  const backend = resolveBackend(args)
@@ -402,9 +444,10 @@ export function authoringTools(
402
444
  {
403
445
  name: 'list_requests',
404
446
  description:
405
- 'List captured network requests (method/url/status/size), newest '
406
- + 'last. Optionally filter by method / urlGlob / status range / '
407
- + 'contentType / graphqlOp. Metadata only — secrets never included.',
447
+ 'Lists captured network requests (method, URL, status, size), '
448
+ + 'newest last. Filter by method, urlGlob, status range, '
449
+ + 'contentType, or graphqlOp. Returns metadata only, never '
450
+ + 'secrets.',
408
451
  inputSchema: objectSchema({
409
452
  filter: {
410
453
  type: 'object',
@@ -418,6 +461,7 @@ export function authoringTools(
418
461
  },
419
462
  },
420
463
  }),
464
+ annotations: { readOnlyHint: true, openWorldHint: false },
421
465
  },
422
466
  async(args) => {
423
467
  const backend = resolveBackend(args)
@@ -434,15 +478,15 @@ export function authoringTools(
434
478
  {
435
479
  name: 'run_proof',
436
480
  description:
437
- 'Prove the drafted recipe (zkTLS). Only call after replay_request '
438
- + 'looks right. Returns the proof result. NOTE: unlike '
439
- + 'replay_request (which re-issues from inside the live attached '
440
- + 'browser tab), the ATTESTOR calls the target from its OWN '
441
- + 'network/IP, separate from the browser\'s. A request that '
442
- + 'replayed fine can still fail here for geo/IP-bound content '
443
- + '(country-locked pages, IP-allowlisted APIs) — if that happens, '
444
- + 'it\'s a property of the site, not a bug in the draft.',
481
+ 'Proves the drafted recipe (zkTLS). Call it after `replay_request` '
482
+ + 'looks right. Returns the proof result. Unlike `replay_request`, '
483
+ + 'which re-sends from inside the attached browser tab, the '
484
+ + 'attestor calls the target from its own network and IP. A request '
485
+ + 'that replayed can still fail here for geo- or IP-bound content '
486
+ + '(country-locked pages, IP-allowlisted APIs); that is a property '
487
+ + 'of the site, not a bug in the draft.',
445
488
  inputSchema: objectSchema({ draftId: { type: 'string' } }, ['draftId']),
489
+ annotations: { openWorldHint: true, destructiveHint: false },
446
490
  },
447
491
  // The backend shapes its own result: the cloud returns a lean,
448
492
  // secret-free summary (and records the proven recipe for publish); the
@@ -27,6 +27,8 @@ export interface ReclaimAgentConfig {
27
27
  * - `old_devtools` — externally-supplied identity for OLD-devtools mode
28
28
  * (USE_OLD_DEVTOOLS); independent of `session`'s
29
29
  * builder token. Deletable with the rest of `src/old/`.
30
+ * - `org_keys` — organization API keys saved by `issue_org_token`, so
31
+ * the org-key tools work without the key in a transcript
30
32
  * Sections are persisted independently via `ConfigStore.write`, which
31
33
  * merges rather than replaces, so one subsystem never clobbers another's.
32
34
  *
@@ -40,6 +42,15 @@ export interface ReclaimConfig {
40
42
  browser_agent?: ReclaimAgentConfig
41
43
  session?: CachedSession
42
44
  old_devtools?: OldIdentity
45
+ org_keys?: SavedOrgKeys
46
+ }
47
+
48
+ /** Organization API keys (`rorg_…`) saved by `issue_org_token`. */
49
+ export interface SavedOrgKeys {
50
+ /** Key by organization ID. */
51
+ byOrg: Record<string, string>
52
+ /** The organization whose key was saved last. */
53
+ recent?: string
43
54
  }
44
55
 
45
56
  /** Which backend the MCP server targets. See `resolveOldMode` in consts.ts. */