@reclaimprotocol/agent 0.1.4 → 0.1.6

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 (126) hide show
  1. package/README.md +5 -5
  2. package/lib/authoring/backend.d.ts +71 -0
  3. package/lib/authoring/backend.js +24 -0
  4. package/lib/authoring/find.d.ts +3 -0
  5. package/lib/authoring/find.js +54 -0
  6. package/lib/authoring/index.d.ts +4 -0
  7. package/lib/authoring/index.js +6 -0
  8. package/lib/authoring/propose.d.ts +3 -0
  9. package/lib/authoring/propose.js +109 -0
  10. package/lib/authoring/replay.d.ts +10 -0
  11. package/lib/authoring/replay.js +34 -0
  12. package/lib/authoring/tools.d.ts +16 -0
  13. package/lib/authoring/tools.js +193 -0
  14. package/lib/authoring/util.d.ts +27 -0
  15. package/lib/authoring/util.js +21 -0
  16. package/lib/cdp/capture-engine.js +1 -1
  17. package/lib/consts.d.ts +6 -1
  18. package/lib/consts.js +9 -2
  19. package/lib/mcp/api/operations.gen.js +46 -18
  20. package/lib/mcp/server.d.ts +2 -25
  21. package/lib/mcp/server.js +4 -17
  22. package/lib/mcp/start.js +4 -2
  23. package/lib/mcp/tools/agent/analyze.js +3 -3
  24. package/lib/mcp/tools/agent/build.d.ts +4 -4
  25. package/lib/mcp/tools/agent/build.js +13 -15
  26. package/lib/mcp/tools/agent/capture.d.ts +13 -1
  27. package/lib/mcp/tools/agent/capture.js +18 -85
  28. package/lib/mcp/tools/agent/eval.d.ts +5 -2
  29. package/lib/mcp/tools/agent/eval.js +11 -121
  30. package/lib/mcp/tools/agent/find.d.ts +10 -3
  31. package/lib/mcp/tools/agent/find.js +25 -31
  32. package/lib/mcp/tools/agent/proof.d.ts +13 -3
  33. package/lib/mcp/tools/agent/proof.js +81 -132
  34. package/lib/mcp/tools/agent/propose.d.ts +10 -9
  35. package/lib/mcp/tools/agent/propose.js +87 -64
  36. package/lib/mcp/tools/agent/publish.js +2 -2
  37. package/lib/mcp/tools/agent/replay.d.ts +10 -3
  38. package/lib/mcp/tools/agent/replay.js +29 -36
  39. package/lib/mcp/tools/agent/session.d.ts +1 -3
  40. package/lib/mcp/tools/agent/session.js +5 -5
  41. package/lib/mcp/tools/agent/shared.d.ts +8 -0
  42. package/lib/mcp/tools/agent/shared.js +125 -0
  43. package/lib/old/client.d.ts +35 -0
  44. package/lib/old/client.js +18 -0
  45. package/lib/old/login-cdp.d.ts +24 -0
  46. package/lib/old/login-cdp.js +28 -3
  47. package/lib/old/sdk-client.d.ts +39 -0
  48. package/lib/old/sdk-client.js +85 -0
  49. package/lib/old/to-register.d.ts +69 -0
  50. package/lib/old/to-register.js +52 -2
  51. package/lib/old/tools/build.d.ts +6 -1
  52. package/lib/old/tools/build.js +11 -1
  53. package/lib/old/tools/get-provider-info.d.ts +16 -0
  54. package/lib/old/tools/get-provider-info.js +73 -0
  55. package/lib/old/tools/get-version-config.d.ts +17 -0
  56. package/lib/old/tools/get-version-config.js +47 -0
  57. package/lib/old/tools/publish.js +189 -2
  58. package/lib/old/tools/update-provider-metadata.d.ts +16 -0
  59. package/lib/old/tools/update-provider-metadata.js +61 -0
  60. package/lib/proof/attestor.d.ts +6 -3
  61. package/lib/proof/attestor.js +10 -1
  62. package/lib/proof/debug-response-dump.d.ts +4 -0
  63. package/lib/proof/debug-response-dump.js +55 -0
  64. package/lib/proof/patch-domhandler.d.ts +1 -0
  65. package/lib/proof/patch-domhandler.js +59 -0
  66. package/lib/proof/proof-core.d.ts +1 -1
  67. package/lib/proof/proof-core.js +1 -1
  68. package/lib/proof/zk-files.js +7 -6
  69. package/lib/provider/dom-xpath.d.ts +17 -0
  70. package/lib/provider/dom-xpath.js +187 -0
  71. package/lib/provider/draft.d.ts +30 -2
  72. package/lib/provider/draft.js +117 -28
  73. package/lib/provider/index.d.ts +4 -0
  74. package/lib/provider/index.js +7 -0
  75. package/lib/provider/injection-doc.js +6 -0
  76. package/lib/provider/matcher.d.ts +17 -20
  77. package/lib/provider/matcher.js +394 -280
  78. package/lib/provider/schema.d.ts +7 -5
  79. package/lib/tools/registry.d.ts +50 -0
  80. package/lib/tools/registry.js +49 -0
  81. package/package.json +9 -1
  82. package/skill/SKILL.builder.md +55 -32
  83. package/skill/SKILL.old.md +20 -12
  84. package/skill/builder-mode.md +1 -1
  85. package/skill/injection-api.md +117 -0
  86. package/src/authoring/backend.ts +98 -0
  87. package/src/authoring/index.ts +20 -0
  88. package/src/authoring/tools.ts +273 -0
  89. package/src/authoring/util.ts +42 -0
  90. package/src/cdp/capture-engine.ts +1 -1
  91. package/src/consts.ts +15 -2
  92. package/src/mcp/api/operations.gen.ts +46 -18
  93. package/src/mcp/server.ts +9 -39
  94. package/src/mcp/start.ts +4 -1
  95. package/src/mcp/tools/agent/analyze.ts +3 -3
  96. package/src/mcp/tools/agent/build.ts +13 -21
  97. package/src/mcp/tools/agent/capture.ts +31 -115
  98. package/src/mcp/tools/agent/eval.ts +19 -155
  99. package/src/mcp/tools/agent/find.ts +33 -36
  100. package/src/mcp/tools/agent/proof.ts +87 -160
  101. package/src/mcp/tools/agent/propose.ts +93 -85
  102. package/src/mcp/tools/agent/publish.ts +2 -2
  103. package/src/mcp/tools/agent/replay.ts +32 -42
  104. package/src/mcp/tools/agent/session.ts +4 -5
  105. package/src/mcp/tools/agent/shared.ts +152 -0
  106. package/src/old/client.ts +56 -0
  107. package/src/old/login-cdp.ts +28 -3
  108. package/src/old/sdk-client.ts +105 -0
  109. package/src/old/to-register.ts +98 -6
  110. package/src/old/tools/build.ts +12 -0
  111. package/src/old/tools/get-provider-info.ts +91 -0
  112. package/src/old/tools/get-version-config.ts +56 -0
  113. package/src/old/tools/publish.ts +244 -1
  114. package/src/old/tools/update-provider-metadata.ts +72 -0
  115. package/src/proof/attestor.ts +16 -4
  116. package/src/proof/debug-response-dump.ts +70 -0
  117. package/src/proof/patch-domhandler.ts +68 -0
  118. package/src/proof/proof-core.ts +1 -1
  119. package/src/proof/zk-files.ts +7 -6
  120. package/src/provider/dom-xpath.ts +225 -0
  121. package/src/provider/draft.ts +168 -35
  122. package/src/provider/index.ts +8 -0
  123. package/src/provider/injection-doc.ts +6 -0
  124. package/src/provider/matcher.ts +477 -357
  125. package/src/provider/schema.ts +7 -5
  126. package/src/tools/registry.ts +92 -0
package/lib/consts.d.ts CHANGED
@@ -17,11 +17,12 @@
17
17
  */
18
18
  import { DEFAULT_BASE_URL } from '@reclaimprotocol/client';
19
19
  import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from './old/client.ts';
20
+ import { DEFAULT_SDK_API_URL } from './old/sdk-client.ts';
20
21
  /** Public attestor websocket URL — fallback for `RECLAIM_ATTESTOR_URL`. */
21
22
  export declare const FALLBACK_ATTESTOR_URL = "wss://attestor.reclaimprotocol.org:444/ws";
22
23
  /** The devtools dashboard login page — fallback for `RECLAIM_OLD_LOGIN_URL`. */
23
24
  export declare const DEFAULT_LOGIN_URL = "https://dev.reclaimprotocol.org";
24
- export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL };
25
+ export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL, DEFAULT_SDK_API_URL, };
25
26
  /** Pino log level. Read once at logger construction, so an eager const is
26
27
  * safe (no test mutates LOG_LEVEL at runtime). */
27
28
  export declare const LOG_LEVEL: string;
@@ -47,6 +48,10 @@ export declare function agentDisabled(): boolean;
47
48
  export declare function oldApiUrl(): string;
48
49
  /** Old-devtools analytics-logs service base URL (separate host). */
49
50
  export declare function oldLogsUrl(): string;
51
+ /** Public production SDK-backend base URL — the service the verification
52
+ * SDK/attestor itself reads a provider's recipe from at runtime. A
53
+ * DIFFERENT host from the old-devtools dashboard backend (`oldApiUrl`). */
54
+ export declare function sdkApiUrl(): string;
50
55
  /** Builder backend base URL. Shared by mcp/start and the verification tool. */
51
56
  export declare function apiUrl(): string;
52
57
  /** Explicit builder API token (overrides the cached session token). */
package/lib/consts.js CHANGED
@@ -19,6 +19,7 @@ import { DEFAULT_BASE_URL } from '@reclaimprotocol/client';
19
19
  import { homedir } from 'node:os';
20
20
  import { join } from 'node:path';
21
21
  import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from "./old/client.js";
22
+ import { DEFAULT_SDK_API_URL } from "./old/sdk-client.js";
22
23
  // ---------------------------------------------------------------------------
23
24
  // Default / fallback literals (used only as env fallbacks).
24
25
  // ---------------------------------------------------------------------------
@@ -26,9 +27,9 @@ import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from "./old/client.js";
26
27
  export const FALLBACK_ATTESTOR_URL = 'wss://attestor.reclaimprotocol.org:444/ws';
27
28
  /** The devtools dashboard login page — fallback for `RECLAIM_OLD_LOGIN_URL`. */
28
29
  export const DEFAULT_LOGIN_URL = 'https://dev.reclaimprotocol.org';
29
- // Re-export the two non-env-fallback defaults so callers can keep importing
30
+ // Re-export the non-env-fallback defaults so callers can keep importing
30
31
  // their URL defaults from a single place if they wish.
31
- export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL };
32
+ export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL, DEFAULT_SDK_API_URL, };
32
33
  // ---------------------------------------------------------------------------
33
34
  // Logging.
34
35
  // ---------------------------------------------------------------------------
@@ -83,6 +84,12 @@ export function oldApiUrl() {
83
84
  export function oldLogsUrl() {
84
85
  return process.env.RECLAIM_OLD_LOGS_URL || DEFAULT_OLD_LOGS_URL;
85
86
  }
87
+ /** Public production SDK-backend base URL — the service the verification
88
+ * SDK/attestor itself reads a provider's recipe from at runtime. A
89
+ * DIFFERENT host from the old-devtools dashboard backend (`oldApiUrl`). */
90
+ export function sdkApiUrl() {
91
+ return process.env.RECLAIM_SDK_API_URL || DEFAULT_SDK_API_URL;
92
+ }
86
93
  /** Builder backend base URL. Shared by mcp/start and the verification tool. */
87
94
  export function apiUrl() {
88
95
  return process.env.RECLAIM_API_URL || DEFAULT_BASE_URL;
@@ -92,7 +92,7 @@ export const MCP_TOOLS = {
92
92
  }),
93
93
  },
94
94
  "AdminProviders": {
95
- description: "All verifications (admin-only)\n\nAdmin only. Lists all verifications across all organizations. Supports filtering by visibility, status, and free-text search on title/domain/slug.",
95
+ description: "All providers (admin-only)\n\nAdmin only. Lists all providers across all organizations. Supports filtering by visibility, status, and free-text search on title/domain/slug.",
96
96
  inputSchema: toZod({
97
97
  "type": "object",
98
98
  "properties": {
@@ -455,7 +455,7 @@ export const MCP_TOOLS = {
455
455
  }),
456
456
  },
457
457
  "CreateProvider": {
458
- description: "Create a verification\n\nCreate a new Reclaim verification. Use this only after `providers` returned nothing useful for the domain. The caller must be an active member of the target organization.\nCreates a new verification in the specified organization. `visibility` is coerced to `PRIVATE` at creation regardless of what's sent; the author may toggle to `PUBLIC` later via `PATCH /providers/{id}`. While `PRIVATE`, versions go to the go live freely; once `PUBLIC`, non-admin versions need admin review. See `Provider.visibility`.\nThe server also seeds an initial `0.1.0` version on the `draft` branch in the same transaction so the verification is immediately editable. Its `initialUrl` defaults to `https://<domain>`; all other version fields fall back to their schema-declared defaults (structured verification, empty requests, empty web settings). `Provider.latestVersion` stays `null` until the draft is promoted to the live channel.",
458
+ description: "Create a provider\n\nCreate a new Reclaim provider. Use this only after `providers` returned nothing useful for the domain. The caller must be an active member of the target organization.\nCreates a new provider in the specified organization. `visibility` is coerced to `PRIVATE` at creation regardless of what's sent; the author may toggle to `PUBLIC` later via `PATCH /providers/{id}`. While `PRIVATE`, versions go to the go live freely; once `PUBLIC`, non-admin versions need admin review. See `Provider.visibility`.\nThe server also seeds an initial `0.1.0` version on the `draft` branch in the same transaction so the provider is immediately editable. Its `initialUrl` defaults to `https://<domain>`; all other version fields fall back to their schema-declared defaults (a `structured` verificationType, empty requests, empty web settings). `Provider.latestVersion` stays `null` until the draft is promoted to the live channel.",
459
459
  inputSchema: toZod({
460
460
  "type": "object",
461
461
  "properties": {
@@ -582,7 +582,7 @@ export const MCP_TOOLS = {
582
582
  }),
583
583
  },
584
584
  "CreateProviderVersion": {
585
- description: "Create a new verification version\n\nCreates a new version of the verification. The starting branch\ndepends on the verification's `visibility` and the caller's role:\n\n- `PRIVATE` verification (any caller): the live channel (no review).\n\n- `PUBLIC` verification, admin caller (Reclaim staff): the live channel\n (no review).\n\n- `PUBLIC` verification, non-admin caller: `draft` (or `ai` if\n authored by the AI assistant). Must pass review (see\n `POST /providers/{id}/versions/{version}/review`) before\n reaching the live channel.\n",
585
+ description: "Create a new provider version\n\nCreates a new version of the provider. The starting branch\ndepends on the provider's `visibility` and the caller's role:\n\n- `PRIVATE` provider (any caller): the live channel (no review).\n\n- `PUBLIC` provider, admin caller (Reclaim staff): the live channel\n (no review).\n\n- `PUBLIC` provider, non-admin caller: `draft` (or `ai` if\n authored by the AI assistant). Must pass review (see\n `POST /providers/{id}/versions/{version}/review`) before\n reaching the live channel.\n",
586
586
  inputSchema: toZod({
587
587
  "type": "object",
588
588
  "properties": {
@@ -606,7 +606,7 @@ export const MCP_TOOLS = {
606
606
  "body": {
607
607
  "type": "object",
608
608
  "additionalProperties": false,
609
- "description": "Body for creating a new version of a provider. Every new version starts on the `draft` branch — see `CreateProviderVersion`. The request body never sets `branch` directly; going live is a separate, explicit step (publish for PRIVATE, submit-for-review → approve for PUBLIC). The version's `verificationType` is always `structured` and is not settable here; a `prompt` field is reserved for a future AI authoring flow and is also not accepted on this surface.",
609
+ "description": "Body for creating a new version of a provider. Every new version starts on the `draft` branch — see `CreateProviderVersion`. The request body never sets `branch` directly; going live is a separate, explicit step (publish for PRIVATE, submit-for-review → approve for PUBLIC). `verificationType` defaults to `structured`; pass `llm` with a `prompt` to author an AI-verification provider.",
610
610
  "required": [
611
611
  "initialUrl",
612
612
  "requests",
@@ -614,6 +614,20 @@ export const MCP_TOOLS = {
614
614
  "webSettings"
615
615
  ],
616
616
  "properties": {
617
+ "verificationType": {
618
+ "type": "string",
619
+ "description": "How a provider version verifies a claim. `structured` uses the explicit match rules on this version (the `matches` / `allowedJsMatches` and related settings). `llm` defers the verification decision to a language model and requires `prompt` to be set.",
620
+ "enum": [
621
+ "llm",
622
+ "structured"
623
+ ]
624
+ },
625
+ "prompt": {
626
+ "type": "string",
627
+ "description": "Extraction prompt, used (and required) when `verificationType` is `llm`.",
628
+ "minLength": 0,
629
+ "maxLength": 1000000
630
+ },
617
631
  "version": {
618
632
  "type": "object",
619
633
  "additionalProperties": false,
@@ -1165,7 +1179,7 @@ export const MCP_TOOLS = {
1165
1179
  }),
1166
1180
  },
1167
1181
  "DecideProviderVersionReview": {
1168
- description: "Record a decision on a verification version review\n\nAdmin only (Reclaim staff). Approves or rejects a verification version currently on the `in_review` branch. `APPROVED` clears the branch tag and promotes the version to the live channel; `REJECTED` moves it to the `rejected` branch where the author can address feedback and resubmit. A rejected version stays rejected — the author either fixes and resubmits, or abandons it.\nUntil RBAC is designed, \"admin\" is detected via the user's email domain (`@reclaimprotocol.org`). Non-admin callers receive a 403.",
1182
+ description: "Record a decision on a provider version review\n\nAdmin only (Reclaim staff). Approves or rejects a provider version currently on the `in_review` branch. `APPROVED` clears the branch tag and promotes the version to the live channel; `REJECTED` moves it to the `rejected` branch where the author can address feedback and resubmit. A rejected version stays rejected — the author either fixes and resubmits, or abandons it.\nUntil RBAC is designed, \"admin\" is detected via the user's email domain (`@reclaimprotocol.org`). Non-admin callers receive a 403.",
1169
1183
  inputSchema: toZod({
1170
1184
  "type": "object",
1171
1185
  "properties": {
@@ -1330,7 +1344,7 @@ export const MCP_TOOLS = {
1330
1344
  }),
1331
1345
  },
1332
1346
  "DeleteProvider": {
1333
- description: "Delete a verification\n\nOwner of the verification's organization only. Soft-archives the verification (sets `status` to `ARCHIVED`) so historical references remain resolvable. Supports optimistic concurrency via `If-Match`.",
1347
+ description: "Delete a provider\n\nOwner of the provider's organization only. Soft-archives the provider (sets `status` to `ARCHIVED`) so historical references remain resolvable. Supports optimistic concurrency via `If-Match`.",
1334
1348
  inputSchema: toZod({
1335
1349
  "type": "object",
1336
1350
  "properties": {
@@ -1373,7 +1387,7 @@ export const MCP_TOOLS = {
1373
1387
  }),
1374
1388
  },
1375
1389
  "DeleteProviderVersion": {
1376
- description: "Delete a verification version\n\nSoft-archives a version on the `draft`, `ai`, or `rejected` branch — sets `status` to `ARCHIVED` so history is preserved. Trunk (live) and `in_review` versions cannot be archived this way; archive the parent verification instead. Supports optimistic concurrency via `If-Match`.",
1390
+ description: "Delete a provider version\n\nSoft-archives a version on the `draft`, `ai`, or `rejected` branch — sets `status` to `ARCHIVED` so history is preserved. Trunk (live) and `in_review` versions cannot be archived this way; archive the parent provider instead. Supports optimistic concurrency via `If-Match`.",
1377
1391
  inputSchema: toZod({
1378
1392
  "type": "object",
1379
1393
  "properties": {
@@ -1461,7 +1475,7 @@ export const MCP_TOOLS = {
1461
1475
  }),
1462
1476
  },
1463
1477
  "DiscoverResolve": {
1464
- description: "Resolve a website + data points to verification providers\n\nProvider resolution: given a website and the data points the user wants their users to prove, return the smallest set of existing providers whose data points COVER the selection (greedy combine), the `requiredContext` inputs the consumer must supply, and any `uncovered` points no provider exposes yet (`needsCreation` is true then — author a provider with the agent tools). When the chosen providers can be fused into one (same start page, no clashing page scripts) `merge.mergeable` is true.\n\nAgent flow: pick a website (`GET /discover/data-points` lists what's verifiable there), confirm the data points with the user, call this to get the `providers` + `requiredContext`, collect those context values from the user, then `POST /verifications/sessions` with `providers` (pass every id) and `context` to mint a verification.",
1478
+ description: "Resolve a website + data points to providers\n\nProvider resolution: given a website and the data points the user wants their users to prove, return the smallest set of existing providers whose data points COVER the selection (greedy combine), the `requiredContext` inputs the consumer must supply, and any `uncovered` points no provider exposes yet (`needsCreation` is true then — author a provider with the agent tools). When the chosen providers can be fused into one (same start page, no clashing page scripts) `merge.mergeable` is true.\n\nAgent flow: pick a website (`GET /discover/data-points` lists what's verifiable there), confirm the data points with the user, call this to get the `providers` + `requiredContext`, collect those context values from the user, then `POST /verifications/sessions` with `providers` (pass every id) and `context` to mint a verification.",
1465
1479
  inputSchema: toZod({
1466
1480
  "type": "object",
1467
1481
  "properties": {
@@ -1718,7 +1732,7 @@ export const MCP_TOOLS = {
1718
1732
  }),
1719
1733
  },
1720
1734
  "GetProvider": {
1721
- description: "Get a verification\n\nFetch a single Reclaim verification by id. Returns every field needed\nto integrate it into a flow: domain, the live version (initialUrl + requests),\nand the data points it can prove. Use `providers` first if you only\nhave a query string.\n\nReturns the verification record.\n\n**Canonical URL.** For SEO and stable sharing, the canonical\nHTML URL for a verification is `/providers/{providerId}/{slug}`\n(see `GetProviderBySlug`). HTML callers (`Accept: text/html`)\nthat hit this route — which omits the slug — receive a `301`\nredirect to the slugged URL. JSON callers\n(`Accept: application/json`) receive the body directly without\nredirect; the slug is on the response.\n",
1735
+ description: "Get a provider\n\nFetch a single Reclaim provider by id. Returns every field needed\nto integrate it into a flow: domain, the live version (initialUrl + requests),\nand the data points it can prove. Use `providers` first if you only\nhave a query string.\n\nReturns the provider record.\n\n**Canonical URL.** For SEO and stable sharing, the canonical\nHTML URL for a provider is `/providers/{providerId}/{slug}`\n(see `GetProviderBySlug`). HTML callers (`Accept: text/html`)\nthat hit this route — which omits the slug — receive a `301`\nredirect to the slugged URL. JSON callers\n(`Accept: application/json`) receive the body directly without\nredirect; the slug is on the response.\n",
1722
1736
  inputSchema: toZod({
1723
1737
  "type": "object",
1724
1738
  "properties": {
@@ -1751,7 +1765,7 @@ export const MCP_TOOLS = {
1751
1765
  }),
1752
1766
  },
1753
1767
  "GetProviderVersion": {
1754
- description: "Get a specific verification version",
1768
+ description: "Get a specific provider version",
1755
1769
  inputSchema: toZod({
1756
1770
  "type": "object",
1757
1771
  "properties": {
@@ -2069,7 +2083,7 @@ export const MCP_TOOLS = {
2069
2083
  }),
2070
2084
  },
2071
2085
  "ListProviderVersions": {
2072
- description: "List a verification's versions\n\nLists versions visible to the caller. Non-public branches (`ai`, `draft`, `in_review`, `rejected`) are only visible to members of the verification's owning organization.",
2086
+ description: "List a provider's versions\n\nLists versions visible to the caller. Non-public branches (`ai`, `draft`, `in_review`, `rejected`) are only visible to members of the provider's owning organization.",
2073
2087
  inputSchema: toZod({
2074
2088
  "type": "object",
2075
2089
  "properties": {
@@ -2218,7 +2232,7 @@ export const MCP_TOOLS = {
2218
2232
  }),
2219
2233
  },
2220
2234
  "Providers": {
2221
- description: "Search verifications\n\nSearch published Reclaim verifications by domain or data point. A verification is the recipe an end-user follows to prove something about themselves (e.g. \"I have N followers on Twitter\"). Returns a list of matches. Call this BEFORE `create_provider` — most popular domains already have a public verification you can reuse.\nCatalog page listing all verifications. Returns a paginated list of verifications the caller can see. Public verifications are visible to everyone; private verifications are only visible to org members.",
2235
+ description: "Search providers\n\nSearch published Reclaim providers by domain or data point. A provider is the recipe an end-user follows to prove something about themselves (e.g. \"I have N followers on Twitter\"). Returns a list of matches. Call this BEFORE `create_provider` — most popular domains already have a public provider you can reuse.\nCatalog page listing all providers. Returns a paginated list of providers the caller can see. Public providers are visible to everyone; private providers are only visible to org members.",
2222
2236
  inputSchema: toZod({
2223
2237
  "type": "object",
2224
2238
  "properties": {
@@ -2262,7 +2276,7 @@ export const MCP_TOOLS = {
2262
2276
  }),
2263
2277
  },
2264
2278
  "PublishProviderVersion": {
2265
- description: "Publish a draft version directly (PRIVATE providers only)\n\nPublishes a verification version on the `draft` branch directly to the live channel (trunk). Only allowed for PRIVATE providers — PUBLIC providers must use the review flow (`POST .../review` → admin decision). On success the version's branch transitions from `draft` to `null` (trunk/live).",
2279
+ description: "Publish a draft version directly (PRIVATE providers only)\n\nPublishes a provider version on the `draft` branch directly to the live channel (trunk). Only allowed for PRIVATE providers — PUBLIC providers must use the review flow (`POST .../review` → admin decision). On success the version's branch transitions from `draft` to `null` (trunk/live).",
2266
2280
  inputSchema: toZod({
2267
2281
  "type": "object",
2268
2282
  "properties": {
@@ -2503,7 +2517,7 @@ export const MCP_TOOLS = {
2503
2517
  }),
2504
2518
  },
2505
2519
  "SubmitProviderVersionForReview": {
2506
- description: "Submit a verification version for review\n\nSubmits a verification version (currently on the `draft` or `rejected` branch) for admin review. On success the version's branch transitions to `in_review`. Callable by any authenticated member of the verification's owning org. Meaningful only on `PUBLIC` verifications — on `PRIVATE` verifications new versions go to the live channel directly and never need review.",
2520
+ description: "Submit a provider version for review\n\nSubmits a provider version (currently on the `draft` or `rejected` branch) for admin review. On success the version's branch transitions to `in_review`. Callable by any authenticated member of the provider's owning org. Meaningful only on `PUBLIC` providers — on `PRIVATE` providers new versions go to the live channel directly and never need review.",
2507
2521
  inputSchema: toZod({
2508
2522
  "type": "object",
2509
2523
  "properties": {
@@ -2552,7 +2566,7 @@ export const MCP_TOOLS = {
2552
2566
  }),
2553
2567
  },
2554
2568
  "TransferProvider": {
2555
- description: "Transfer a verification to a different workspace\n\nAdmin-only. Moves the verification's `orgId` to the supplied workspace; preserves slug, versions, members. SQL function `builder.transfer_provider` enforces the admin gate and target existence atomically.",
2569
+ description: "Transfer a provider to a different workspace\n\nAdmin-only. Moves the provider's `orgId` to the supplied workspace; preserves slug, versions, members. SQL function `builder.transfer_provider` enforces the admin gate and target existence atomically.",
2556
2570
  inputSchema: toZod({
2557
2571
  "type": "object",
2558
2572
  "properties": {
@@ -2705,7 +2719,7 @@ export const MCP_TOOLS = {
2705
2719
  }),
2706
2720
  },
2707
2721
  "UpdateProvider": {
2708
- description: "Update a verification\n\nUpdate a Reclaim verification's metadata. Partial PATCH — pass only fields you want to change. The caller must be an active member of the owning organization. To change the verification's recipe (initialUrl, requests, …) cut a new version via the dashboard. Use `seo` to control how the verification appears in search results and social shares; omit a subfield to keep the server default.\nCaller must be a member of the verification's owning organization. `id`, `orgId`, and `slug` are immutable. Supports optimistic concurrency via `If-Match`.",
2722
+ description: "Update a provider\n\nUpdate a Reclaim provider's metadata. Partial PATCH — pass only fields you want to change. The caller must be an active member of the owning organization. To change the provider's recipe (initialUrl, requests, …) cut a new version via the dashboard. Use `seo` to control how the provider appears in search results and social shares; omit a subfield to keep the server default.\nCaller must be a member of the provider's owning organization. `id`, `orgId`, and `slug` are immutable. Supports optimistic concurrency via `If-Match`.",
2709
2723
  inputSchema: toZod({
2710
2724
  "type": "object",
2711
2725
  "properties": {
@@ -2840,7 +2854,7 @@ export const MCP_TOOLS = {
2840
2854
  }),
2841
2855
  },
2842
2856
  "UpdateProviderVersion": {
2843
- description: "Update a verification version\n\nMutable only while the version is on the `draft` or `rejected` branch. Versions on `in_review` or the live channel reject all writes here. Caller must be a member of the verification's owning organization. Supports optimistic concurrency via `If-Match`.",
2857
+ description: "Update a provider version\n\nMutable only while the version is on the `draft` or `rejected` branch. Versions on `in_review` or the live channel reject all writes here. Caller must be a member of the provider's owning organization. Supports optimistic concurrency via `If-Match`.",
2844
2858
  inputSchema: toZod({
2845
2859
  "type": "object",
2846
2860
  "properties": {
@@ -2880,13 +2894,27 @@ export const MCP_TOOLS = {
2880
2894
  "body": {
2881
2895
  "type": "object",
2882
2896
  "additionalProperties": false,
2883
- "description": "Partial update of a provider version. Mutable only while the version is on the `draft` or `rejected` branch; versions on `in_review` or the live channel reject all writes here. The semver does not change on update — `build_number` increments instead, giving callers a monotonic revision counter without touching the (major, minor, patch) PK. `verificationType` / `prompt` are not accepted; see `ProviderVersion` for why.",
2897
+ "description": "Partial update of a provider version. Mutable only while the version is on the `draft` or `rejected` branch; versions on `in_review` or the live channel reject all writes here. The semver does not change on update — `build_number` increments instead, giving callers a monotonic revision counter without touching the (major, minor, patch) PK. `verificationType` and `prompt` may be updated; omit either to carry the prior build's value forward.",
2884
2898
  "properties": {
2885
2899
  "initialUrl": {
2886
2900
  "type": "string",
2887
2901
  "format": "uri",
2888
2902
  "maxLength": 300
2889
2903
  },
2904
+ "verificationType": {
2905
+ "type": "string",
2906
+ "description": "How a provider version verifies a claim. `structured` uses the explicit match rules on this version (the `matches` / `allowedJsMatches` and related settings). `llm` defers the verification decision to a language model and requires `prompt` to be set.",
2907
+ "enum": [
2908
+ "llm",
2909
+ "structured"
2910
+ ]
2911
+ },
2912
+ "prompt": {
2913
+ "type": "string",
2914
+ "description": "Extraction prompt, used when `verificationType` is `llm`.",
2915
+ "minLength": 0,
2916
+ "maxLength": 1000000
2917
+ },
2890
2918
  "requests": {
2891
2919
  "type": "array",
2892
2920
  "minItems": 0,
@@ -1,29 +1,6 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { JSONSchema } from 'zod/v4/core';
3
- export interface ToolDefinition {
4
- name: string;
5
- description: string;
6
- inputSchema: JSONSchema.ObjectSchema;
7
- }
8
- export interface RegisteredTool {
9
- definition: ToolDefinition;
10
- /**
11
- * @param args Tool arguments
12
- * @returns A JSON stringifiable content to be returned to the llm
13
- * @throws Any error encountered during tool execution will be caught and
14
- * returned as a response using
15
- * [remapErrorAsResponse](./src/mcp/remap_errors.ts).
16
- */
17
- handler: (args: unknown) => Promise<unknown>;
18
- }
19
- /**
20
- * Define a tool with a single inputSchema (JSON Schema) used as the
21
- * source of truth. The handler receives args already parsed and
22
- * type-narrowed via a Zod schema derived from that same JSON Schema —
23
- * so the description sent to the MCP client and the validation applied
24
- * to inbound args cannot drift.
25
- */
26
- export declare function defineTool<TArgs>(definition: ToolDefinition, handler: (args: TArgs) => Promise<unknown>): RegisteredTool;
2
+ import { type RegisteredTool } from '../tools/registry.ts';
3
+ export { defineTool, type RegisteredTool, type ToolDefinition, } from '../tools/registry.ts';
27
4
  /**
28
5
  * Registers a list of RegisteredTool entries on a high-level McpServer.
29
6
  * Converts JSON Schema definitions to Zod and provides consistent
package/lib/mcp/server.js CHANGED
@@ -1,22 +1,9 @@
1
1
  import { toZod } from "./api/to-zod.js";
2
2
  import { remapErrorAsResponse } from "./remap_errors.js";
3
- /**
4
- * Define a tool with a single inputSchema (JSON Schema) used as the
5
- * source of truth. The handler receives args already parsed and
6
- * type-narrowed via a Zod schema derived from that same JSON Schema —
7
- * so the description sent to the MCP client and the validation applied
8
- * to inbound args cannot drift.
9
- */
10
- export function defineTool(definition, handler) {
11
- const schema = toZod(definition.inputSchema);
12
- return {
13
- definition,
14
- handler: async (raw) => {
15
- const args = schema.parse(raw);
16
- return await handler(args);
17
- },
18
- };
19
- }
3
+ // The tool primitive lives in `../tools/registry.ts` (SDK-free, so the cloud
4
+ // loop can use it too). Re-exported here so the MCP-side tool files can keep
5
+ // importing `defineTool`/`RegisteredTool` from the server module.
6
+ export { defineTool, } from "../tools/registry.js";
20
7
  /**
21
8
  * Registers a list of RegisteredTool entries on a high-level McpServer.
22
9
  * Converts JSON Schema definitions to Zod and provides consistent
package/lib/mcp/start.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
3
  import { ReclaimClient } from '@reclaimprotocol/client';
4
- import { agentDisabled, apiToken, apiUrl, oldApiUrl, oldLogsUrl, useOldDevtools, } from "../consts.js";
4
+ import { agentDisabled, apiToken, apiUrl, oldApiUrl, oldLogsUrl, sdkApiUrl, useOldDevtools, } from "../consts.js";
5
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
+ import { ReclaimSdkClient } from "../old/sdk-client.js";
8
9
  import { buildOldBackendTools } from "../old/tools/build.js";
9
10
  import { NAME, VERSION } from "../pkg.js";
10
11
  import { registerTools } from "./api/tools.js";
@@ -33,8 +34,9 @@ export async function startMcpServer() {
33
34
  logsBaseUrl: oldLogsUrl(),
34
35
  identity: resolveInitialIdentity(),
35
36
  });
37
+ const sdkClient = new ReclaimSdkClient({ baseUrl: sdkApiUrl() });
36
38
  registerToolList(server, buildLocalCredentialTools());
37
- registerToolList(server, buildOldBackendTools(oldClient));
39
+ registerToolList(server, buildOldBackendTools(oldClient, sdkClient));
38
40
  if (agentToolsEnabled) {
39
41
  // No builder client → no builder publish tool (old mode has its own).
40
42
  registerToolList(server, buildAgentTools());
@@ -13,11 +13,11 @@ export function analyzeTool(captures) {
13
13
  required: ['captureId', 'requestId'],
14
14
  },
15
15
  }, async ({ captureId, requestId }) => {
16
- const session = captures.sessions.get(captureId);
17
- if (!session) {
16
+ const entry = captures.sessions.get(captureId);
17
+ if (!entry) {
18
18
  throw new Error(`no capture ${captureId}`);
19
19
  }
20
- const r = session.requests.get(requestId);
20
+ const r = entry.session.requests.get(requestId);
21
21
  if (!r) {
22
22
  throw new Error(`no request ${requestId} in capture ${captureId}`);
23
23
  }
@@ -4,22 +4,22 @@
4
4
  * `@modelcontextprotocol/sdk` `McpServer`. Folds the agent's tools
5
5
  * alongside the auto-generated API tools.
6
6
  *
7
- * Shared state — Chrome attach state, capture store, secret store — is
8
- * built once per server and threaded through every tool factory.
7
+ * Shared state — Chrome attach state + capture store — is built once per
8
+ * server and threaded through every tool factory. Per-capture drafts (and the
9
+ * secrets they hold) live inside each capture entry, so a capture IS the
10
+ * session for the shared authoring tools.
9
11
  */
10
12
  import type { ReclaimClient } from '@reclaimprotocol/client';
11
13
  import { ConfigStore } from '../../../config/store.ts';
12
14
  import { type RegisteredTool } from '../../server.ts';
13
15
  import { type AttachState } from './attach.ts';
14
16
  import { type CaptureStore } from './capture.ts';
15
- import { type SecretStore } from './propose.ts';
16
17
  export interface AgentState {
17
18
  attach: {
18
19
  current?: AttachState;
19
20
  config: ConfigStore;
20
21
  };
21
22
  captures: CaptureStore;
22
- secrets: SecretStore;
23
23
  }
24
24
  /** Build the flat list of `RegisteredTool` entries, ready for
25
25
  * `registerToolList`.
@@ -4,27 +4,25 @@
4
4
  * `@modelcontextprotocol/sdk` `McpServer`. Folds the agent's tools
5
5
  * alongside the auto-generated API tools.
6
6
  *
7
- * Shared state — Chrome attach state, capture store, secret store — is
8
- * built once per server and threaded through every tool factory.
7
+ * Shared state — Chrome attach state + capture store — is built once per
8
+ * server and threaded through every tool factory. Per-capture drafts (and the
9
+ * secrets they hold) live inside each capture entry, so a capture IS the
10
+ * session for the shared authoring tools.
9
11
  */
10
12
  import { ConfigStore } from "../../../config/store.js";
11
13
  import { ensureAttestorCrypto } from "../../../proof/proof-core.js";
12
14
  import { analyzeTool } from "./analyze.js";
13
15
  import { attachTool } from "./attach.js";
14
16
  import { captureTools } from "./capture.js";
15
- import { browserTools } from "./eval.js";
16
- import { findTool } from "./find.js";
17
+ import { listTabsTool } from "./eval.js";
17
18
  import { howItWorksTool } from "./how-it-works.js";
18
- import { proofTool } from "./proof.js";
19
- import { makeSecretStore, proposeTool, } from "./propose.js";
20
19
  import { createVersionFromCaptureTool } from "./publish.js";
21
- import { replayTool } from "./replay.js";
22
20
  import { sessionTools } from "./session.js";
21
+ import { sharedAuthoringTools } from "./shared.js";
23
22
  function buildAgentState() {
24
23
  return {
25
24
  attach: { config: new ConfigStore() },
26
25
  captures: { sessions: new Map() },
27
- secrets: makeSecretStore(),
28
26
  };
29
27
  }
30
28
  /** Build the flat list of `RegisteredTool` entries, ready for
@@ -40,20 +38,20 @@ export function buildAgentTools(client) {
40
38
  // client. No `client` ⇒ old-devtools mode (see `mcp/start.ts`).
41
39
  tools.push(howItWorksTool(!client));
42
40
  tools.push(attachTool(state.attach));
41
+ tools.push(listTabsTool(state.attach));
43
42
  for (const t of captureTools(state.attach, state.captures)) {
44
43
  tools.push(t);
45
44
  }
46
- tools.push(findTool(state.captures));
47
- for (const t of browserTools(state.attach)) {
45
+ for (const t of sessionTools(state.attach, state.captures)) {
48
46
  tools.push(t);
49
47
  }
50
- for (const t of sessionTools(state.attach, state.captures, state.secrets)) {
48
+ tools.push(analyzeTool(state.captures));
49
+ // navigate / eval_in_page / wait_for_page / get_cookies / list_requests /
50
+ // find_requests_containing / propose_provider / replay_request / run_proof —
51
+ // shared with the cloud loop, bound to each capture's local backend.
52
+ for (const t of sharedAuthoringTools(state.captures)) {
51
53
  tools.push(t);
52
54
  }
53
- tools.push(analyzeTool(state.captures));
54
- tools.push(proposeTool(state.captures, state.secrets));
55
- tools.push(replayTool(state.secrets));
56
- tools.push(proofTool(state.secrets));
57
55
  if (client) {
58
56
  tools.push(createVersionFromCaptureTool(client));
59
57
  }
@@ -1,8 +1,20 @@
1
+ import { type DraftStore } from '../../../authoring/index.ts';
1
2
  import { type CaptureSession } from '../../../cdp/capture.ts';
2
3
  import { type RegisteredTool } from '../../server.ts';
3
4
  import type { AttachState } from './attach.ts';
5
+ /**
6
+ * One capture == a session (network requests) + the tab CDP client it runs on +
7
+ * a draft store. Bundling the tab client is what lets the shared authoring
8
+ * tools treat a `captureId` as a full session (drive the browser AND read
9
+ * capture AND hold drafts) behind one id.
10
+ */
11
+ export interface CaptureEntry {
12
+ session: CaptureSession;
13
+ tabClient: Awaited<ReturnType<AttachState['handles']['attachToTab']>>;
14
+ drafts: DraftStore;
15
+ }
4
16
  export interface CaptureStore {
5
- sessions: Map<string, CaptureSession>;
17
+ sessions: Map<string, CaptureEntry>;
6
18
  activeTab?: string;
7
19
  }
8
20
  export declare function captureTools(attachRef: {
@@ -1,3 +1,4 @@
1
+ import { makeDraftStore } from "../../../authoring/index.js";
1
2
  import { startCapture } from "../../../cdp/capture.js";
2
3
  import { defineTool } from "../../server.js";
3
4
  export function captureTools(attachRef, captures) {
@@ -9,8 +10,9 @@ export function captureTools(attachRef, captures) {
9
10
  };
10
11
  const startTool = defineTool({
11
12
  name: 'start_capture',
12
- description: 'Begin recording network requests on the specified tab. ' +
13
- 'Returns a captureId.',
13
+ description: 'Begin recording network requests on the specified tab. '
14
+ + 'Returns a captureId — the session handle the authoring tools '
15
+ + '(navigate, propose_provider, run_proof, …) all take.',
14
16
  inputSchema: {
15
17
  type: 'object',
16
18
  properties: { tabId: { type: 'string' } },
@@ -20,91 +22,28 @@ export function captureTools(attachRef, captures) {
20
22
  const attached = requireAttached();
21
23
  const tabClient = await attached.handles.attachToTab(tabId);
22
24
  const session = await startCapture(tabClient);
23
- captures.sessions.set(session.captureId, session);
25
+ captures.sessions.set(session.captureId, {
26
+ session, tabClient, drafts: makeDraftStore(),
27
+ });
24
28
  captures.activeTab = tabId;
25
29
  return { captureId: session.captureId };
26
30
  });
27
31
  const stopTool = defineTool({
28
32
  name: 'stop_capture',
29
- description: 'Stop recording on the given capture. ' +
30
- 'Captured data remains queryable until reset_session.',
33
+ description: 'Stop recording on the given capture. '
34
+ + 'Captured data remains queryable until reset_session.',
31
35
  inputSchema: {
32
36
  type: 'object',
33
37
  properties: { captureId: { type: 'string' } },
34
38
  required: ['captureId'],
35
39
  },
36
40
  }, async ({ captureId }) => {
37
- const session = captures.sessions.get(captureId);
38
- if (!session) {
41
+ const entry = captures.sessions.get(captureId);
42
+ if (!entry) {
39
43
  throw new Error(`no capture ${captureId}`);
40
44
  }
41
- await session.stop();
42
- return { stopped: true, requestCount: session.requests.size };
43
- });
44
- const listTool = defineTool({
45
- name: 'list_requests',
46
- description: 'List metadata for captured requests. ' +
47
- 'Filter by method, URL glob, status, content-type, ' +
48
- 'or graphqlOp. Returns only metadata, never bodies — ' +
49
- 'use get_request for those.',
50
- inputSchema: {
51
- type: 'object',
52
- properties: {
53
- captureId: { type: 'string' },
54
- filter: {
55
- type: 'object',
56
- properties: {
57
- method: { type: 'string' },
58
- urlGlob: { type: 'string' },
59
- statusMin: { type: 'number' },
60
- statusMax: { type: 'number' },
61
- contentType: { type: 'string' },
62
- graphqlOp: { type: 'string' },
63
- },
64
- },
65
- },
66
- required: ['captureId'],
67
- },
68
- }, async ({ captureId, filter }) => {
69
- const session = captures.sessions.get(captureId);
70
- if (!session) {
71
- throw new Error(`no capture ${captureId}`);
72
- }
73
- const out = [];
74
- for (const r of session.requests.values()) {
75
- if (filter?.method && r.method !== filter.method.toUpperCase()) {
76
- continue;
77
- }
78
- if (filter?.urlGlob && !globMatch(filter.urlGlob, r.url)) {
79
- continue;
80
- }
81
- if (filter?.statusMin !== undefined && r.status < filter.statusMin) {
82
- continue;
83
- }
84
- if (filter?.statusMax !== undefined && r.status > filter.statusMax) {
85
- continue;
86
- }
87
- if (filter?.contentType &&
88
- !r.contentType.includes(filter.contentType)) {
89
- continue;
90
- }
91
- if (filter?.graphqlOp && r.graphqlOp !== filter.graphqlOp) {
92
- continue;
93
- }
94
- const item = {
95
- requestId: r.requestId,
96
- method: r.method,
97
- url: r.url,
98
- status: r.status,
99
- contentType: r.contentType,
100
- size: r.size,
101
- };
102
- if (r.graphqlOp !== undefined) {
103
- item.graphqlOp = r.graphqlOp;
104
- }
105
- out.push(item);
106
- }
107
- return { requests: out };
45
+ await entry.session.stop();
46
+ return { stopped: true, requestCount: entry.session.requests.size };
108
47
  });
109
48
  const getTool = defineTool({
110
49
  name: 'get_request',
@@ -118,25 +57,19 @@ export function captureTools(attachRef, captures) {
118
57
  required: ['captureId', 'requestId'],
119
58
  },
120
59
  }, async ({ captureId, requestId }) => {
121
- const session = captures.sessions.get(captureId);
122
- if (!session) {
60
+ const entry = captures.sessions.get(captureId);
61
+ if (!entry) {
123
62
  throw new Error(`no capture ${captureId}`);
124
63
  }
125
- const r = session.requests.get(requestId);
64
+ const r = entry.session.requests.get(requestId);
126
65
  if (!r) {
127
66
  throw new Error(`no request ${requestId} in capture ${captureId}`);
128
67
  }
129
- const body = session.bodies.get(requestId);
68
+ const body = entry.session.bodies.get(requestId);
130
69
  if (!body.available) {
131
70
  return { ...r, bodyAvailable: false, reason: body.reason };
132
71
  }
133
72
  return { ...r, responseBody: body.body, bodyAvailable: true };
134
73
  });
135
- return [startTool, stopTool, listTool, getTool];
136
- }
137
- function globMatch(pattern, str) {
138
- const re = new RegExp('^' +
139
- pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*') +
140
- '$');
141
- return re.test(str);
74
+ return [startTool, stopTool, getTool];
142
75
  }