@reclaimprotocol/agent 0.1.22 → 0.1.24

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 (163) hide show
  1. package/README.md +55 -20
  2. package/lib/authoring/backend.d.ts +13 -10
  3. package/lib/authoring/tools.js +106 -9
  4. package/lib/cdp/browser-proxy.d.ts +78 -0
  5. package/lib/cdp/browser-proxy.js +186 -0
  6. package/lib/cdp/capture-engine.js +8 -7
  7. package/lib/cdp/client.d.ts +10 -0
  8. package/lib/cdp/geo.d.ts +10 -0
  9. package/lib/cdp/geo.js +36 -0
  10. package/lib/cdp/index.d.ts +1 -0
  11. package/lib/cdp/index.js +1 -0
  12. package/lib/live/cloudflared.d.ts +15 -0
  13. package/lib/live/cloudflared.js +268 -0
  14. package/lib/live/page.d.ts +20 -0
  15. package/lib/live/page.js +134 -0
  16. package/lib/live/tunnel.d.ts +23 -0
  17. package/lib/live/tunnel.js +120 -0
  18. package/lib/live/viewer.d.ts +28 -0
  19. package/lib/live/viewer.js +232 -0
  20. package/lib/mcp/api/operations.gen.js +34 -26
  21. package/lib/mcp/api/to-zod.d.ts +1 -1
  22. package/lib/mcp/api/to-zod.js +1 -1
  23. package/lib/mcp/api/tools.js +1 -1
  24. package/lib/mcp/instructions.d.ts +15 -2
  25. package/lib/mcp/instructions.js +101 -38
  26. package/lib/mcp/start.js +4 -3
  27. package/lib/mcp/tools/agent/analyze.js +5 -1
  28. package/lib/mcp/tools/agent/attach.d.ts +8 -1
  29. package/lib/mcp/tools/agent/attach.js +166 -22
  30. package/lib/mcp/tools/agent/build.d.ts +13 -8
  31. package/lib/mcp/tools/agent/build.js +22 -11
  32. package/lib/mcp/tools/agent/capture.js +5 -1
  33. package/lib/mcp/tools/agent/eval.js +3 -1
  34. package/lib/mcp/tools/agent/find.js +6 -5
  35. package/lib/mcp/tools/agent/how-it-works.d.ts +15 -7
  36. package/lib/mcp/tools/agent/how-it-works.js +57 -17
  37. package/lib/mcp/tools/agent/live-view.d.ts +21 -0
  38. package/lib/mcp/tools/agent/live-view.js +153 -0
  39. package/lib/mcp/tools/agent/pod-proof.d.ts +8 -0
  40. package/lib/mcp/tools/agent/pod-proof.js +64 -0
  41. package/lib/mcp/tools/agent/propose.js +29 -3
  42. package/lib/mcp/tools/agent/proxy.d.ts +3 -0
  43. package/lib/mcp/tools/agent/proxy.js +199 -0
  44. package/lib/mcp/tools/agent/publish.js +49 -77
  45. package/lib/mcp/tools/agent/session.d.ts +2 -1
  46. package/lib/mcp/tools/agent/session.js +26 -7
  47. package/lib/mcp/tools/agent/shared.js +17 -8
  48. package/lib/mcp/tools/authenticate/authenticate.d.ts +11 -0
  49. package/lib/mcp/tools/authenticate/authenticate.js +143 -121
  50. package/lib/mcp/tools/authenticate/builder-access.d.ts +8 -3
  51. package/lib/mcp/tools/authenticate/builder-access.js +8 -3
  52. package/lib/mcp/tools/mode/mode.d.ts +1 -1
  53. package/lib/mcp/tools/mode/mode.js +26 -7
  54. package/lib/old/client.d.ts +9 -0
  55. package/lib/old/client.js +19 -1
  56. package/lib/old/instructions.d.ts +9 -1
  57. package/lib/old/instructions.js +4 -6
  58. package/lib/old/login-cdp.d.ts +2 -2
  59. package/lib/old/login-cdp.js +46 -6
  60. package/lib/old/to-register.d.ts +20 -8
  61. package/lib/old/to-register.js +7 -1
  62. package/lib/old/tools/authenticate.js +9 -1
  63. package/lib/old/tools/get-provider-info.js +6 -5
  64. package/lib/old/tools/issue-app-credentials.js +3 -2
  65. package/lib/old/tools/me-providers.js +3 -1
  66. package/lib/old/tools/publish.d.ts +1 -1
  67. package/lib/old/tools/publish.js +132 -129
  68. package/lib/old/tools/update-provider-metadata.d.ts +1 -1
  69. package/lib/old/tools/update-provider-metadata.js +1 -1
  70. package/lib/old/tools/verify-sdk-setup.js +1 -1
  71. package/lib/proof/attestor.d.ts +3 -3
  72. package/lib/proof/debug-response-dump.js +4 -4
  73. package/lib/proof/index.d.ts +1 -0
  74. package/lib/proof/index.js +1 -0
  75. package/lib/proof/page-replay.d.ts +36 -0
  76. package/lib/proof/page-replay.js +76 -0
  77. package/lib/proof/pod-prover.d.ts +47 -0
  78. package/lib/proof/pod-prover.js +155 -0
  79. package/lib/proof/replay.d.ts +28 -0
  80. package/lib/proof/replay.js +39 -18
  81. package/lib/provider/dom-xpath.js +11 -9
  82. package/lib/provider/draft.d.ts +13 -8
  83. package/lib/provider/draft.js +47 -13
  84. package/lib/provider/injection-doc.d.ts +23 -1
  85. package/lib/provider/injection-doc.js +34 -21
  86. package/lib/provider/match-redaction-warning.d.ts +2 -2
  87. package/lib/provider/match-redaction-warning.js +3 -3
  88. package/lib/provider/matcher.js +122 -12
  89. package/lib/provider/secrets.d.ts +3 -3
  90. package/lib/provider/secrets.js +3 -3
  91. package/lib/provider/to-version.d.ts +12 -9
  92. package/lib/provider/to-version.js +16 -4
  93. package/lib/tools/registry.d.ts +5 -5
  94. package/lib/tools/registry.js +5 -5
  95. package/package.json +4 -3
  96. package/samples/demo-server/README.md +7 -6
  97. package/skill/SKILL.builder.md +356 -189
  98. package/skill/SKILL.common.md +314 -79
  99. package/skill/SKILL.old.md +340 -155
  100. package/skill/builder-mode.md +58 -17
  101. package/skill/hash-validation.md +170 -0
  102. package/skill/interception.md +235 -0
  103. package/skill/js-sdk-integration.md +13 -7
  104. package/skill/old-mode.md +53 -12
  105. package/skill/user-script.md +61 -0
  106. package/src/authoring/backend.ts +13 -10
  107. package/src/authoring/tools.ts +128 -9
  108. package/src/cdp/capture-engine.ts +8 -7
  109. package/src/cdp/client.ts +8 -0
  110. package/src/cdp/geo.ts +52 -0
  111. package/src/cdp/index.ts +1 -0
  112. package/src/consts.ts +1 -0
  113. package/src/live/cloudflared.ts +348 -0
  114. package/src/live/page.ts +145 -0
  115. package/src/live/tunnel.ts +157 -0
  116. package/src/live/viewer.ts +293 -0
  117. package/src/mcp/api/operations.gen.ts +34 -26
  118. package/src/mcp/api/to-zod.ts +1 -1
  119. package/src/mcp/api/tools.ts +1 -1
  120. package/src/mcp/instructions.ts +121 -48
  121. package/src/mcp/start.ts +4 -3
  122. package/src/mcp/tools/agent/analyze.ts +5 -1
  123. package/src/mcp/tools/agent/attach.ts +194 -22
  124. package/src/mcp/tools/agent/build.ts +26 -15
  125. package/src/mcp/tools/agent/capture.ts +5 -1
  126. package/src/mcp/tools/agent/eval.ts +4 -1
  127. package/src/mcp/tools/agent/find.ts +6 -5
  128. package/src/mcp/tools/agent/how-it-works.ts +62 -21
  129. package/src/mcp/tools/agent/live-view.ts +198 -0
  130. package/src/mcp/tools/agent/pod-proof.ts +90 -0
  131. package/src/mcp/tools/agent/propose.ts +31 -3
  132. package/src/mcp/tools/agent/publish.ts +54 -78
  133. package/src/mcp/tools/agent/session.ts +26 -5
  134. package/src/mcp/tools/agent/shared.ts +19 -8
  135. package/src/mcp/tools/authenticate/authenticate.ts +167 -165
  136. package/src/mcp/tools/authenticate/builder-access.ts +8 -3
  137. package/src/mcp/tools/mode/mode.ts +28 -7
  138. package/src/old/client.ts +30 -1
  139. package/src/old/instructions.ts +4 -10
  140. package/src/old/login-cdp.ts +50 -6
  141. package/src/old/to-register.ts +28 -8
  142. package/src/old/tools/authenticate.ts +9 -1
  143. package/src/old/tools/get-provider-info.ts +6 -5
  144. package/src/old/tools/issue-app-credentials.ts +3 -2
  145. package/src/old/tools/me-providers.ts +3 -1
  146. package/src/old/tools/publish.ts +140 -130
  147. package/src/old/tools/update-provider-metadata.ts +1 -1
  148. package/src/old/tools/verify-sdk-setup.ts +1 -1
  149. package/src/proof/attestor.ts +3 -3
  150. package/src/proof/debug-response-dump.ts +4 -4
  151. package/src/proof/index.ts +8 -0
  152. package/src/proof/page-replay.ts +131 -0
  153. package/src/proof/pod-prover.ts +231 -0
  154. package/src/proof/replay.ts +60 -19
  155. package/src/provider/dom-xpath.ts +11 -9
  156. package/src/provider/draft.ts +56 -13
  157. package/src/provider/injection-doc.ts +37 -24
  158. package/src/provider/match-redaction-warning.ts +3 -3
  159. package/src/provider/matcher.ts +151 -10
  160. package/src/provider/secrets.ts +3 -3
  161. package/src/provider/to-version.ts +30 -13
  162. package/src/tools/registry.ts +5 -5
  163. package/skill/injection-api.md +0 -335
@@ -26,7 +26,8 @@ export interface OldProviderOpts {
26
26
  /** Page-injection script — the devtools name for the builder's
27
27
  * `webSettings.jsUserScripts`. Top-level on register, nested under
28
28
  * `providerConfig` on config (add-version). The backend rejects a few
29
- * deprecated injection APIs (e.g. `window.payloadData`) with a 400. */
29
+ * deprecated injection APIs (for example, `window.payloadData`) with a
30
+ * 400. */
30
31
  customInjection?: string;
31
32
  /** Accepted at register too (unlike the four fields below, which the
32
33
  * backend only accepts on config/add-version). */
@@ -51,13 +52,24 @@ export interface OldProviderOpts {
51
52
  * field from the request body. Free-form JSON. */
52
53
  extensionConfig?: unknown;
53
54
  /** Provider-level `disableRequestReplay` (HAWKEYE document replay skip).
54
- * Config (add-version) ONLY: the register endpoint hardcodes it to false
55
- * — the publish tool follows a register up with an add-version call to
56
- * apply it for new providers (see `old/tools/publish.ts`). NOTE the
57
- * builder backend has NO equivalent; its inverse is
58
- * `webSettings.clientOptions.inapp.interceptorOptions
59
- * .isDocumentRequestReplayEnabled`. */
55
+ * The publish tool always forces this `true` — there is no author-facing
56
+ * way to enable document replay. Config (add-version) ONLY: the register
57
+ * endpoint hardcodes it to false regardless of what's sent, so the
58
+ * publish tool always follows a register up with an add-version call to
59
+ * actually apply it (see `old/tools/publish.ts`). The builder backend's
60
+ * inverse-named equivalent, `webSettings.clientOptions.inapp
61
+ * .interceptorOptions.isDocumentRequestReplayEnabled`, is likewise always
62
+ * force-disabled by `providerToCreateVersionRequest`. */
60
63
  disableRequestReplay?: boolean;
64
+ /** Interception mechanism — `NONE` (the publish tool's default) for the
65
+ * standard capture→replay flow; `HAWKEYE`/`MSWJS`/`XHOOK`/`CDP` for a
66
+ * genuine live-interception provider. Old-devtools calls this
67
+ * `injectionType`; builder's equivalent is `webSettings.clientOptions
68
+ * .inapp.interceptorOptions.interceptorType` (no `NONE` value there —
69
+ * omitting the whole object is builder's no-interception signal
70
+ * instead). See `old/client.ts`'s `RegisterProviderBody.injectionType`
71
+ * doc for the register-persistence caveat. */
72
+ injectionType?: 'NONE' | 'MSWJS' | 'XHOOK' | 'CDP' | 'HAWKEYE';
61
73
  }
62
74
  interface OldResponseMatch {
63
75
  value: string;
@@ -118,7 +130,7 @@ export interface SemverTriplet {
118
130
  /**
119
131
  * Pull `{major,minor,patch}` triplets out of a `/versions` response, tolerant
120
132
  * of the exact envelope (array, `{ providerVersions: [...] }`, `{ items }`,
121
- * etc.). Each entry's `version` is the triplet.
133
+ *, and so on). Each entry's `version` is the triplet.
122
134
  */
123
135
  export declare function extractVersions(resp: unknown): SemverTriplet[];
124
136
  /**
@@ -133,6 +133,9 @@ export function providerToRegisterBody(providers, opts) {
133
133
  if (opts.stepsToFollow !== undefined) {
134
134
  body.stepsToFollow = opts.stepsToFollow;
135
135
  }
136
+ if (opts.injectionType !== undefined) {
137
+ body.injectionType = opts.injectionType;
138
+ }
136
139
  return body;
137
140
  }
138
141
  /** Body for `POST /api/providers/:providerId/config` — adds a new version to
@@ -173,12 +176,15 @@ export function providerToConfigBody(providers, opts, version, versionInfo) {
173
176
  if (opts.disableRequestReplay !== undefined) {
174
177
  providerConfig.disableRequestReplay = opts.disableRequestReplay;
175
178
  }
179
+ if (opts.injectionType !== undefined) {
180
+ providerConfig.injectionType = opts.injectionType;
181
+ }
176
182
  return { providerConfig, version, versionInfo };
177
183
  }
178
184
  /**
179
185
  * Pull `{major,minor,patch}` triplets out of a `/versions` response, tolerant
180
186
  * of the exact envelope (array, `{ providerVersions: [...] }`, `{ items }`,
181
- * etc.). Each entry's `version` is the triplet.
187
+ *, and so on). Each entry's `version` is the triplet.
182
188
  */
183
189
  export function extractVersions(resp) {
184
190
  const list = pickArray(resp);
@@ -36,6 +36,11 @@ export function authenticateTool(client) {
36
36
  'and closes the tab. A previously stored identity that is still ' +
37
37
  'valid is reused first (pass `useBrowser: true` to force a fresh ' +
38
38
  'login). \n\n' +
39
+ 'EXPECT THIS TO TAKE A WHILE ON A FIRST RUN: a fresh Chrome ' +
40
+ 'profile downloads the dashboard cold, so tell the developer it is ' +
41
+ 'loading and that the window is waiting for them — do not re-run ' +
42
+ 'the tool while it is still waiting. It polls for up to 6 minutes ' +
43
+ 'and reports whether the page ever became interactive.\n\n' +
39
44
  'Manual overrides:\n' +
40
45
  '- `token`: paste a Firebase ID token (skips the browser).\n' +
41
46
  '- `ethAddress`: an `eth:0x…` / `0x…` uid for an already-provisioned ' +
@@ -61,7 +66,10 @@ export function authenticateTool(client) {
61
66
  },
62
67
  timeoutMs: {
63
68
  type: 'number',
64
- description: 'How long to wait for sign-in, in ms (default 180000).',
69
+ description: 'How long to wait for sign-in, in ms (default 360000, i.e. 6 '
70
+ + 'minutes). A fresh Chrome profile loads the dashboard cold, '
71
+ + 'which can take tens of seconds before the form is usable — '
72
+ + 'that time comes out of this budget.',
65
73
  },
66
74
  useBrowser: {
67
75
  type: 'boolean',
@@ -1,8 +1,8 @@
1
1
  import { isBoom } from '@hapi/boom';
2
2
  import { defineTool } from "../../mcp/server.js";
3
3
  /** Best-effort call: resolve to the response, or to an error string instead
4
- * of throwing — one endpoint 404ing (e.g. a bad `versionNumber`) shouldn't
5
- * hide a result the other endpoint DID have. */
4
+ * of throwing — one endpoint 404ing (for example, a bad `versionNumber`)
5
+ * shouldn't hide a result the other endpoint DID have. */
6
6
  async function attempt(label, call) {
7
7
  try {
8
8
  return { ok: true, value: await call() };
@@ -44,8 +44,9 @@ export function getProviderInfoTool(client) {
44
44
  'computed `isScriptRequestingClaim` flag). Read `provider` here ' +
45
45
  'BEFORE create_provider_version_from_capture so you can pass the ' +
46
46
  'whole existing config back — that tool always creates a new ' +
47
- 'version and carries nothing forward. One endpoint failing (e.g. ' +
48
- 'an invalid `versionNumber`) is reported under `errors` without ' +
47
+ 'version and carries nothing forward. One endpoint failing (for ' +
48
+ 'example, an invalid `versionNumber`) is reported under `errors` ' +
49
+ 'without ' +
49
50
  'hiding a result the other endpoint did return.',
50
51
  inputSchema: {
51
52
  type: 'object',
@@ -56,7 +57,7 @@ export function getProviderInfoTool(client) {
56
57
  },
57
58
  versionNumber: {
58
59
  type: 'string',
59
- description: 'Specific version, e.g. "1.0.2". Omit for the ' +
60
+ description: 'Specific version, for example, "1.0.2". Omit for the ' +
60
61
  "provider's current latest version.",
61
62
  },
62
63
  },
@@ -18,8 +18,9 @@ export function issueAppCredentialsTool(client) {
18
18
  'starts UNLINKED and sandboxed (100 sessions) — call ' +
19
19
  'link_app_to_account to attach it to your dashboard account and ' +
20
20
  'check_app_status to check its state. Store `appSecret` like a ' +
21
- 'password (e.g. in a gitignored .env as RECLAIM_APP_SECRET) — it ' +
22
- 'is returned once and cannot be recovered from the server.',
21
+ 'password (for example, in a gitignored .env as ' +
22
+ 'RECLAIM_APP_SECRET) — it is returned once and cannot be ' +
23
+ 'recovered from the server.',
23
24
  inputSchema: { type: 'object', properties: {} },
24
25
  }, async () => {
25
26
  const { appId, appSecret } = await client.issueCredentials();
@@ -13,7 +13,9 @@ export function getMeProvidersTool(client) {
13
13
  'first). Returns provider metadata including each `providerId` — ' +
14
14
  'pass one back to create_provider_version_from_capture to publish a ' +
15
15
  'new version of that provider instead of creating a duplicate. ' +
16
- 'Requires reclaim_authenticate first.',
16
+ 'Requires reclaim_authenticate (old-devtools login) first — this ' +
17
+ 'is separate from authenticate_builder/Builder auth, which does ' +
18
+ 'not authorize this call. Check status with get_devtools_mode.',
17
19
  inputSchema: {
18
20
  type: 'object',
19
21
  properties: {
@@ -4,7 +4,7 @@ import type { ReclaimOldClient } from '../client.ts';
4
4
  /**
5
5
  * Publish a drafted provider to the OLD devtools backend. Keeps the builder
6
6
  * tool NAME (`create_provider_version_from_capture`) so the skill flow is
7
- * unchanged, but the behaviour differs:
7
+ * unchanged, but the behavior differs:
8
8
  *
9
9
  * - WITHOUT `providerId` → `POST /api/providers/register`: creates a
10
10
  * brand-new provider + version 1.0.0. Re-running creates a DUPLICATE.
@@ -1,6 +1,6 @@
1
1
  import { Boom, isBoom } from '@hapi/boom';
2
2
  import { defineTool } from "../../mcp/server.js";
3
- import { INJECTION_GUIDE } from "../../provider/injection-doc.js";
3
+ import { ALLOWED_REQUESTS_HINT, USER_SCRIPT_HINT, } from "../../provider/injection-doc.js";
4
4
  import { countsFor, matchRedactionWarnings, } from "../../provider/match-redaction-warning.js";
5
5
  import { bumpPatchString, extractVersions, injectedRequestDataFrom, providerToConfigBody, providerToRegisterBody, } from "../to-register.js";
6
6
  const DEFAULT_VERSION_INFO = 'Updated from MCP browser capture';
@@ -15,8 +15,8 @@ function extractProviderId(resp) {
15
15
  * `providerId` for a public provider (or anyone else's) comes back as
16
16
  * 401/403/404 — the dev's likely intent is to publish their OWN version of that
17
17
  * site, which on this backend means registering a separate copy. Rethrow those
18
- * failures with that actionable suggestion; leave other errors (e.g. a 400
19
- * version collision) untouched so their real detail surfaces.
18
+ * failures with that actionable suggestion; leave other errors (for example, a
19
+ * 400 version collision) untouched so their real detail surfaces.
20
20
  */
21
21
  function rethrowOwnershipError(err, providerId) {
22
22
  const status = isBoom(err) ? err.output.statusCode : undefined;
@@ -37,7 +37,7 @@ function rethrowOwnershipError(err, providerId) {
37
37
  /**
38
38
  * Publish a drafted provider to the OLD devtools backend. Keeps the builder
39
39
  * tool NAME (`create_provider_version_from_capture`) so the skill flow is
40
- * unchanged, but the behaviour differs:
40
+ * unchanged, but the behavior differs:
41
41
  *
42
42
  * - WITHOUT `providerId` → `POST /api/providers/register`: creates a
43
43
  * brand-new provider + version 1.0.0. Re-running creates a DUPLICATE.
@@ -56,54 +56,38 @@ function rethrowOwnershipError(err, providerId) {
56
56
  export function createVersionFromCaptureTool(client, attachRef) {
57
57
  return defineTool({
58
58
  name: 'create_provider_version_from_capture',
59
- description: 'Publish drafted ReclaimProvider(s) to the devtools backend. ' +
60
- 'Pass the `provider` object from propose_provider VERBATIM and the ' +
61
- '`initialUrl` the user landed on (the login/landing page, NOT the ' +
62
- 'API url). \n\n' +
63
- 'For a MULTI-REQUEST provider, pass `providers: [...]` (each entry a ' +
64
- 'proven draft from propose_provider) — every entry becomes one ' +
65
- '`requestData` entry on the SAME version, and all are verified ' +
66
- 'together. Pass a single `provider` for the one-request case ' +
67
- '(provide exactly one of `provider` / `providers`). \n\n' +
68
- 'Omit `providerId` to REGISTER A NEW provider (creates it + version ' +
69
- '1.0.0; re-running creates a duplicate). Pass `providerId` (from ' +
70
- 'get_me_providers) to add a NEW VERSION to that existing provider ' +
71
- '(the patch is auto-bumped). \n\n' +
72
- 'You can only add versions to a provider YOU own — the `providerId` ' +
73
- 'must come from get_me_providers. To publish your own version of a ' +
74
- "PUBLIC provider you don't own, omit `providerId` to register your " +
75
- 'own copy (you cannot edit someone else\'s provider here). \n\n' +
76
- 'For data gated behind login/navigation, pass `customInjection` — a ' +
77
- 'page-injection script (the devtools name for the builder\'s ' +
78
- 'jsUserScripts) that drives the page to where the request fires. \n\n' +
79
- 'BY DESIGN, this backend only ever CREATES A NEW VERSION (POST) — ' +
80
- 'there is no partial-patch/edit endpoint, and this tool does NOT ' +
81
- 'read or carry anything forward from the previous version. Every ' +
82
- 'new version replaces the WHOLE providerConfig with exactly what ' +
83
- 'you pass in THIS call. Therefore any field you want present in the ' +
84
- 'new version MUST be supplied here — `customInjection`, `userAgent`, ' +
85
- '`pageTitle`, `allowedInjectedRequestData`, `stepsToFollow`, ' +
86
- '`useIncognitoWebview`, `extensionConfig`, and `requestData` (via ' +
87
- '`provider`/`providers`). Anything you OMIT is published blank/' +
88
- 'default in the new version, NOT preserved. To change one field ' +
89
- 'while keeping the rest, first read the current version with ' +
90
- 'get_provider_info, then pass the full desired config (the existing ' +
91
- 'values plus your change) back into this call. ' +
92
- '`allowedInjectedRequestData`/`useIncognitoWebview`/' +
93
- '`extensionConfig` only take effect on add-version — the register ' +
94
- 'endpoint (no `providerId`) ignores them. `disableRequestReplay` ' +
95
- 'is also add-version-only, but when it is true the tool follows ' +
96
- 'a register up with an add-version call automatically so it takes ' +
97
- 'effect on new providers too. Per-request fields you may set on ' +
98
- '`provider`/`providers`: `credentials` (omit/same-origin/include, ' +
99
- 'default include), `urlType` (REGEX/CONSTANT/TEMPLATE, default ' +
100
- 'derived from {{placeholders}}), and `isOptional` on each ' +
101
- 'responseMatch (default false). \n\n' +
102
- 'Captured requests must be GET/POST. OPRF redactions are supported. ' +
103
- 'On success, if a browser is still attached, the response\'s ' +
104
- '`_notes` reminds you to confirm with the developer before ' +
105
- 'calling `dispose_browser` — never close it unprompted, they ' +
106
- 'may want it for further edits.',
59
+ description: 'Publish drafted ReclaimProvider(s) to the devtools backend. Needs '
60
+ + 'its OWN reclaim_authenticate login — authenticate_builder does NOT '
61
+ + 'authorize this call. Pass the `provider` object(s) from '
62
+ + 'propose_provider VERBATIM, plus the `initialUrl` the user landed '
63
+ + 'on (the login/landing page, NOT the API url). Exactly one of '
64
+ + '`provider` (one request) or `providers` (a multi-request '
65
+ + 'provider — every entry becomes a parallel requestData entry, all '
66
+ + 'verified together). Captured requests must be GET/POST; OPRF '
67
+ + 'redactions are supported.\n\n'
68
+ + 'Omit `providerId` to REGISTER A NEW provider (creates it + '
69
+ + 'version 1.0.0 — re-running creates a DUPLICATE). Pass '
70
+ + '`providerId` (from get_me_providers) to add a NEW VERSION to it; '
71
+ + 'the patch auto-bumps. You can only version a provider YOU own — '
72
+ + 'to publish your own take on one you don\'t own, omit '
73
+ + '`providerId` to register your own copy.\n\n'
74
+ + 'THIS BACKEND ONLY EVER CREATES A NEW VERSION — there is no '
75
+ + 'partial-patch endpoint, and this tool carries NOTHING forward '
76
+ + 'from the previous version: every version replaces the WHOLE '
77
+ + 'providerConfig with exactly what you pass in THIS call. Any '
78
+ + 'field you want to survive must be re-supplied here '
79
+ + '(`customInjection`, `userAgent`, `pageTitle`, '
80
+ + '`allowedInjectedRequestData`, `stepsToFollow`, '
81
+ + '`useIncognitoWebview`, `extensionConfig`, `requestData`); '
82
+ + 'anything omitted is published blank. To change one field, read '
83
+ + 'the current config with get_provider_info first and pass it back '
84
+ + 'with your edit. `allowedInjectedRequestData`/'
85
+ + '`useIncognitoWebview`/`extensionConfig` apply on add-version '
86
+ + 'only, so a fresh register auto-follows with an add-version call '
87
+ + 'that applies them (and disables document replay — see '
88
+ + '`disableRequestReplay`).\n\n'
89
+ + 'Always read the response\'s `_notes`. '
90
+ + 'Full walkthrough: how_it_works({ topic: "publish" }).',
107
91
  inputSchema: {
108
92
  type: 'object',
109
93
  properties: {
@@ -205,15 +189,11 @@ export function createVersionFromCaptureTool(client, attachRef) {
205
189
  },
206
190
  customInjection: {
207
191
  type: 'string',
208
- description: 'Plain JavaScript injected into the provider page before every ' +
209
- 'page load — old-devtools\' name for what the builder calls ' +
210
- '`webSettings.jsUserScripts`. Use standard browser APIs ' +
211
- '(window.location, element.click(), forms) to drive login/' +
212
- 'navigation so the target request fires — window.Reclaim is ' +
213
- 'only for rare edge cases, not navigation. The backend rejects ' +
214
- 'a few deprecated injection APIs (e.g. window.payloadData, ' +
215
- 'window.ReclaimInjected) with a 400. Guide:\n\n' +
216
- INJECTION_GUIDE,
192
+ description: USER_SCRIPT_HINT
193
+ + ' Old-devtools\' name for what the builder calls '
194
+ + 'webSettings.jsUserScripts. The backend rejects a few '
195
+ + 'deprecated injection APIs (window.payloadData, '
196
+ + 'window.ReclaimInjected) with a 400.',
217
197
  },
218
198
  userAgent: {
219
199
  type: 'object',
@@ -230,39 +210,15 @@ export function createVersionFromCaptureTool(client, attachRef) {
230
210
  },
231
211
  allowedInjectedRequestData: {
232
212
  type: 'array',
233
- description: 'Extra requests the customInjection script is allowed to ' +
234
- 'fire (e.g. pagination) — add-version ONLY, the register ' +
235
- 'endpoint ignores this. Each item has the same shape as ' +
236
- '`provider`, plus `multiple`/`required` (default true). ' +
237
- 'IMPORTANT whenever a claim\'s request HAS a body: set `body` ' +
238
- 'here (see its own description below) — if only a small part ' +
239
- 'of the real body varies per user/run (e.g. one id field, not ' +
240
- 'the whole payload), template just that part with ' +
241
- '`{{paramName}}` and keep the rest as fixed literal text; see ' +
242
- 'the "bodySniff" section of the customInjection field\'s guide ' +
243
- 'for the exact mechanics and a worked example. ' +
244
- '⚠️ BEFORE populating this to gate ' +
245
- '`verifyProof(proof, { providerId })`: this whole entry (url, ' +
246
- 'method, body, responseMatches, responseRedactions) feeds a ' +
247
- 'client-side hash-equality check, and `url` is hashed VERBATIM ' +
248
- '— no regex/template resolution, even with `urlType: REGEX` or ' +
249
- '`TEMPLATE`. If the real captured URL contains ANY per-session ' +
250
- 'part (a tracking nonce, CSRF token, cache-busting timestamp), ' +
251
- 'no declared spec can EVER hash-match a real proof, no matter ' +
252
- 'how correct the rest of this entry is — populating' +
253
- 'it for such ' +
254
- 'a provider makes verifyProof reject every real proof,' +
255
- 'which is ' +
256
- 'worse than leaving this field empty. Diff the same endpoint\'s' +
257
- ' captured URL across two separate sessions before wiring this ' +
258
- 'up. If provider-hash validation keeps causing problems ' +
259
- '(unstable url, or any other persistent mismatch), the ' +
260
- 'fallback on the verifying side is `verifyProof(proof, { ' +
261
- 'dangerouslyDisableContentValidation: true })` — trusts only ' +
262
- 'the attestor\'s signature, skips the hash-equality check ' +
263
- 'entirely; see the "Provider-hash validation" section of the ' +
264
- 'customInjection field\'s guide for the full mechanics and ' +
265
- 'when to reach for it.',
213
+ description: 'Extra requests the customInjection user script is allowed to '
214
+ + 'fire (for example, pagination) — add-version ONLY, the '
215
+ + 'register '
216
+ + 'endpoint ignores it. Each item has the same shape as '
217
+ + '`provider`, plus `multiple`/`required` (default true). Set '
218
+ + '`body` whenever the request has one (see its own description '
219
+ + 'below). The builder calls the same concept '
220
+ + '`allowedJsRequests`. '
221
+ + ALLOWED_REQUESTS_HINT,
266
222
  items: {
267
223
  type: 'object',
268
224
  properties: {
@@ -282,7 +238,8 @@ export function createVersionFromCaptureTool(client, attachRef) {
282
238
  'body at all (skip only for a genuinely bodyless ' +
283
239
  'request, typically GET). If the real body is FIXED ' +
284
240
  '(identical for every user/run), put that literal body ' +
285
- 'text here verbatim. If only PART of it varies (e.g. ' +
241
+ 'text here verbatim. If only PART of it varies (for ' +
242
+ 'example, ' +
286
243
  '`{"request":1,"type":"user_info","id":"12345"}` where ' +
287
244
  'only `id` differs per user), template ONLY that part: ' +
288
245
  '`{"request":1,"type":"user_info",' +
@@ -305,7 +262,7 @@ export function createVersionFromCaptureTool(client, attachRef) {
305
262
  'reproduces the real captured request body ' +
306
263
  'byte-for-byte. Fallback if per-field templating keeps ' +
307
264
  'mismatching (more fields vary than expected, unstable ' +
308
- 'key order, etc.) and you can\'t pin down every ' +
265
+ 'key order, and so on) and you can\'t pin down every ' +
309
266
  'variable field: template the WHOLE body as one ' +
310
267
  'placeholder instead, `{{REQ_BODY_GRD}}` — the `GRD` ' +
311
268
  'suffix makes it a greedy match (captures everything) ' +
@@ -322,7 +279,7 @@ export function createVersionFromCaptureTool(client, attachRef) {
322
279
  '`value` must literally appear (or match, if `regex`) ' +
323
280
  'somewhere in the response body for the claim to be ' +
324
281
  'accepted; it commonly embeds one or more ' +
325
- '`{{paramName}}` extraction placeholders (e.g. ' +
282
+ '`{{paramName}}` extraction placeholders (for example, ' +
326
283
  '`"name":"{{name_0}}"`) whose real value is redacted ' +
327
284
  'out and supplied separately as a witness/extracted ' +
328
285
  'param. Use `${var}` (not `{{var}}`) inside this string ' +
@@ -337,7 +294,8 @@ export function createVersionFromCaptureTool(client, attachRef) {
337
294
  description: 'Each item: `{ jsonPath?: string, xPath?: string, ' +
338
295
  'regex?: string, hash?: string }`. Identifies WHICH ' +
339
296
  'part of the response the matching `{{paramName}}` in ' +
340
- '`responseMatches` actually redacts/extracts — e.g. ' +
297
+ '`responseMatches` actually redacts or extracts — for ' +
298
+ 'example, ' +
341
299
  '`jsonPath: "$.data.items[0].name"` for a JSON response. ' +
342
300
  'Order/count should line up with `responseMatches`\' ' +
343
301
  'placeholders one-to-one for a typical claim.',
@@ -388,13 +346,34 @@ export function createVersionFromCaptureTool(client, attachRef) {
388
346
  description: 'Free-form JSON passed through to the client. Add-version ' +
389
347
  'ONLY.',
390
348
  },
349
+ injectionType: {
350
+ type: 'string',
351
+ enum: ['NONE', 'MSWJS', 'XHOOK', 'CDP', 'HAWKEYE'],
352
+ description: 'Interception mechanism for this version. Omit to leave it ' +
353
+ 'unset — the devtools backend\'s own column default ' +
354
+ '(`HAWKEYE`) applies, which is inert and harmless for the ' +
355
+ 'standard capture→replay flow with no interceptor script ' +
356
+ 'installed. Only set `HAWKEYE`/`MSWJS`/`XHOOK` when you are ' +
357
+ 'ALSO supplying a `customInjection` script that calls ' +
358
+ '`window.reclaimInterceptor.addResponseMiddleware(...)` for ' +
359
+ 'genuine live interception, or set `NONE` explicitly to be ' +
360
+ 'certain none is configured. Builder calls the equivalent ' +
361
+ 'concept `interceptorType` (no `NONE` there — omitting the ' +
362
+ 'whole `interceptorOptions` object is its no-interception ' +
363
+ 'signal instead). What each value actually does: ' +
364
+ 'how_it_works({ topic: "interception" }).',
365
+ },
391
366
  disableRequestReplay: {
392
367
  type: 'boolean',
393
- description: 'Skip replaying the main document request (HAWKEYE ' +
394
- 'provider-level flag). Honored on add-version; for a ' +
395
- 'provider (no `providerId`) the register endpoint ignores ' +
396
- 'it, so when true the tool automatically follows the ' +
397
- 'register up with an add-version call that applies it.',
368
+ description: 'Whether the page\'s own document/navigation request is ' +
369
+ 'skipped (constructed locally) instead of genuinely replayed ' +
370
+ 'through the interceptor. Defaults to `true` (disabled) when ' +
371
+ 'omitted. Only meaningful for `injectionType` ' +
372
+ 'HAWKEYE/MSWJS/XHOOK — pass `false` to enable real document ' +
373
+ 'replay for those (for example, the target value is embedded ' +
374
+ 'in the page\'s own HTML). Inert when `injectionType` is ' +
375
+ '`CDP` or ' +
376
+ 'unset.',
398
377
  },
399
378
  },
400
379
  required: ['initialUrl'],
@@ -429,7 +408,13 @@ export function createVersionFromCaptureTool(client, attachRef) {
429
408
  stepsToFollow: args.stepsToFollow,
430
409
  useIncognitoWebview: args.useIncognitoWebview,
431
410
  extensionConfig: args.extensionConfig,
432
- disableRequestReplay: args.disableRequestReplay,
411
+ // Author-settable, no forced default — the backend's own HAWKEYE
412
+ // column default applies when omitted, same as before this field
413
+ // existed at all.
414
+ injectionType: args.injectionType,
415
+ // Author-settable; defaults to disabled (see tool description).
416
+ // Only meaningful for HAWKEYE/MSWJS/XHOOK — inert for CDP.
417
+ disableRequestReplay: args.disableRequestReplay ?? true,
433
418
  allowedInjectedRequestData: args.allowedInjectedRequestData
434
419
  ? injectedRequestDataFrom(args.allowedInjectedRequestData)
435
420
  : undefined
@@ -468,11 +453,12 @@ export function createVersionFromCaptureTool(client, attachRef) {
468
453
  'every page load (before navigating to initialUrl), matching ' +
469
454
  'the builder\'s jsUserScripts.');
470
455
  }
471
- // disableRequestReplay is honored ONLY on add-version, so a
472
- // register can't set it — when true we immediately follow the
473
- // register with an add-version call (which also lands any other
474
- // register-ignored fields).
475
- const followUp = args.disableRequestReplay === true;
456
+ // disableRequestReplay is honored ONLY on add-version — so every
457
+ // register is immediately followed by an add-version call that
458
+ // actually applies it (whatever value — default or author-set;
459
+ // which also lands an explicit injectionType, when passed —
460
+ // unverified whether register persists it — and any other
461
+ // register-ignored fields the caller passed).
476
462
  const REGISTER_IGNORED_KEYS = [
477
463
  'allowedInjectedRequestData',
478
464
  'useIncognitoWebview',
@@ -484,38 +470,55 @@ export function createVersionFromCaptureTool(client, attachRef) {
484
470
  notes.push(`${ignoredOnRegister.join(', ')} ` +
485
471
  `${ignoredOnRegister.length > 1 ? 'are' : 'is'} ` +
486
472
  'ignored on register (no providerId) — the devtools backend only ' +
487
- 'reads them when adding a version. ' +
488
- (followUp
489
- ? 'They were applied by the follow-up version the tool ' +
490
- 'created to set disableRequestReplay.'
491
- : 'Publish once to create the provider, then call this ' +
492
- 'again WITH the returned providerId to set them.'));
473
+ 'reads them when adding a version. They were applied by the ' +
474
+ 'automatic follow-up version this tool always creates to apply ' +
475
+ 'disableRequestReplay.');
493
476
  }
494
477
  const body = providerToRegisterBody(providers, opts);
495
478
  const registered = await client.registerProvider(body);
496
- if (followUp) {
497
- const newProviderId = extractProviderId(registered);
498
- if (newProviderId) {
479
+ const newProviderId = extractProviderId(registered);
480
+ if (newProviderId) {
481
+ // The provider already exists as of the register call above —
482
+ // a failure past this point must NOT reject the tool and
483
+ // discard `registered`/`newProviderId`, or a retry without
484
+ // `providerId` would register a DUPLICATE provider. Catch and
485
+ // warn instead, telling the caller to resume WITH this
486
+ // providerId.
487
+ try {
499
488
  const versionsResp = await client.listVersions(newProviderId);
500
489
  const followVersion = bumpPatchString(extractVersions(versionsResp));
501
- const configBody = providerToConfigBody(providers, { ...opts, disableRequestReplay: true }, followVersion, DEFAULT_VERSION_INFO);
490
+ const configBody = providerToConfigBody(providers, opts, followVersion, DEFAULT_VERSION_INFO);
502
491
  await client.updateProviderConfig(newProviderId, configBody);
503
- notes.push('disableRequestReplay is ignored by the register endpoint — ' +
504
- `applied it via a follow-up version (${followVersion}) on ` +
505
- 'the new provider, which also lands any register-ignored ' +
506
- 'fields you passed.');
492
+ notes.push(`Created an automatic follow-up version (${followVersion}) to ` +
493
+ `apply disableRequestReplay (${opts.disableRequestReplay})` +
494
+ (opts.injectionType !== undefined
495
+ ? ` and set injectionType (${opts.injectionType})`
496
+ : '') +
497
+ ' — the register endpoint ignores/may ignore those fields, so ' +
498
+ 'every fresh register gets one. It also landed any other ' +
499
+ 'register-ignored fields you passed.');
507
500
  }
508
- else {
509
- notes.push('Could not apply disableRequestReplay: the register ' +
510
- 'response did not include the new providerId. Call this ' +
511
- 'tool again WITH `providerId` and `disableRequestReplay: ' +
512
- 'true` to set it.');
501
+ catch (err) {
502
+ const detail = isBoom(err) ? err.message : String(err);
503
+ notes.push(`Provider ${newProviderId} WAS created, but the automatic ` +
504
+ `follow-up version (to force-disable document replay${opts.injectionType !== undefined
505
+ ? ' and set injectionType'
506
+ : ''}) failed: ${detail}. Do NOT retry without providerId — that ` +
507
+ 'would register a duplicate. Instead, re-run ' +
508
+ 'create_provider_version_from_capture WITH ' +
509
+ `providerId: "${newProviderId}" to add the follow-up version.`);
513
510
  }
514
511
  }
512
+ else {
513
+ notes.push('Could not apply disableRequestReplay: the ' +
514
+ 'register response did not include the new providerId. Call ' +
515
+ 'this tool again WITH `providerId` to create a version that ' +
516
+ 'applies them.');
517
+ }
515
518
  return withNotes(registered);
516
519
  }
517
520
  // New version of an existing provider — pick the next patch above
518
- // the highest existing version. A provider you don't own (e.g. a
521
+ // the highest existing version. A provider you don't own (for example, a
519
522
  // public one) fails here with 401/403/404; surface the register-a-copy
520
523
  // workaround instead of a bare permission error.
521
524
  const providerId = args.providerId;
@@ -7,7 +7,7 @@ import type { ReclaimOldClient } from '../client.ts';
7
7
  * `create_provider_version_from_capture` paths: it does NOT touch
8
8
  * `providerConfig`/versions at all, and only the fields you pass here
9
9
  * change — everything else on the provider is left untouched (no need to
10
- * re-supply `requestData`/`customInjection`/etc., and
10
+ * re-supply `requestData`/`customInjection`, and so on, and
11
11
  * no new version is created).
12
12
  *
13
13
  * The backend 403s if you don't own the provider (and aren't an admin) —
@@ -6,7 +6,7 @@ import { defineTool } from "../../mcp/server.js";
6
6
  * `create_provider_version_from_capture` paths: it does NOT touch
7
7
  * `providerConfig`/versions at all, and only the fields you pass here
8
8
  * change — everything else on the provider is left untouched (no need to
9
- * re-supply `requestData`/`customInjection`/etc., and
9
+ * re-supply `requestData`/`customInjection`, and so on, and
10
10
  * no new version is created).
11
11
  *
12
12
  * The backend 403s if you don't own the provider (and aren't an admin) —
@@ -101,7 +101,7 @@ export function verifySdkSetupTool(client) {
101
101
  : 'PUBLIC_URL not set — fine if you only read the proof from the ' +
102
102
  'frontend flow, but the async webhook callback needs a ' +
103
103
  'publicly-reachable URL or it will never fire. Get one via a ' +
104
- 'tunnel (e.g. `ngrok http <port>`) or by deploying to a ' +
104
+ 'tunnel (for example, `ngrok http <port>`) or by deploying to a ' +
105
105
  'dev/staging server you already have — ask the user which they ' +
106
106
  'prefer.',
107
107
  });
@@ -24,13 +24,13 @@ export interface RunAttestorProofOptions {
24
24
  /** When resolving the key from env/.env/file, the address the caller expects
25
25
  * to sign with (sanity check). Ignored when `ownerPrivateKey` is given. */
26
26
  ownerAddress?: string;
27
- /** Sign with this key directly (e.g. the app/VC's ephemeral per-session key)
28
- * instead of resolving from env/.env/file. */
27
+ /** Sign with this key directly (for example, the app or VC's ephemeral
28
+ * per-session key) instead of resolving from env/.env/file. */
29
29
  ownerPrivateKey?: string;
30
30
  /** ZK engine for `createClaimOnAttestor`. Defaults to `'stwo'` — a pure-WASM
31
31
  * prover that runs everywhere (no native shared library, so it works on
32
32
  * Windows where `'gnark'` fails to load its `.dll`). Server-side paths that
33
- * want gnark's speed pin it explicitly (e.g. the verify runner). */
33
+ * want gnark's speed pin it explicitly (for example, the verify runner). */
34
34
  zkEngine?: 'gnark' | 'snarkjs' | 'stwo';
35
35
  /** Extract the structured {@link AttestorClaim} (claim + attestor signature)
36
36
  * onto the result for nested-proof construction. */