@reclaimprotocol/agent 0.1.32 → 0.1.33

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.
@@ -26,6 +26,7 @@ export declare const MCP_TOOLS: {
26
26
  BindVerificationSessionTeeNonce: {
27
27
  description: string;
28
28
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
29
+ orgTokenOnly: boolean;
29
30
  };
30
31
  CancelPublicListingRequest: {
31
32
  description: string;
@@ -34,6 +35,7 @@ export declare const MCP_TOOLS: {
34
35
  CreateCallbackSubscription: {
35
36
  description: string;
36
37
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
38
+ orgTokenOnly: boolean;
37
39
  };
38
40
  CreateOrg: {
39
41
  description: string;
@@ -54,6 +56,7 @@ export declare const MCP_TOOLS: {
54
56
  CreateVerificationSession: {
55
57
  description: string;
56
58
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
59
+ orgTokenOnly: boolean;
57
60
  };
58
61
  DecideProviderVersionReview: {
59
62
  description: string;
@@ -62,6 +65,7 @@ export declare const MCP_TOOLS: {
62
65
  DeleteCallbackSubscription: {
63
66
  description: string;
64
67
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
68
+ orgTokenOnly: boolean;
65
69
  };
66
70
  DeleteOrgCallbackSubscription: {
67
71
  description: string;
@@ -122,6 +126,7 @@ export declare const MCP_TOOLS: {
122
126
  GetVerificationSession: {
123
127
  description: string;
124
128
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
129
+ orgTokenOnly: boolean;
125
130
  };
126
131
  ImportDevtoolsProvider: {
127
132
  description: string;
@@ -138,6 +143,7 @@ export declare const MCP_TOOLS: {
138
143
  ListCallbackSubscriptions: {
139
144
  description: string;
140
145
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
146
+ orgTokenOnly: boolean;
141
147
  };
142
148
  ListOrgCallbackSubscriptions: {
143
149
  description: string;
@@ -166,10 +172,12 @@ export declare const MCP_TOOLS: {
166
172
  ListVerificationDeliveries: {
167
173
  description: string;
168
174
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
175
+ orgTokenOnly: boolean;
169
176
  };
170
177
  ListVerificationEvents: {
171
178
  description: string;
172
179
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
180
+ orgTokenOnly: boolean;
173
181
  };
174
182
  MakePrivate: {
175
183
  description: string;
@@ -190,6 +198,7 @@ export declare const MCP_TOOLS: {
190
198
  RetryVerificationCallback: {
191
199
  description: string;
192
200
  inputSchema: import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
201
+ orgTokenOnly: boolean;
193
202
  };
194
203
  RevokeOrgToken: {
195
204
  description: string;
@@ -1,5 +1,5 @@
1
1
  // AUTO-GENERATED by packages/app/scripts/mcp-tools-gen.ts
2
- // from packages/app/openapi.yaml (spec v0.1.0, source sha256:099a5bcf4fba).
2
+ // from packages/app/openapi.yaml (spec v0.1.0, source sha256:3e28ff308da3).
3
3
  // The hash catches drift the version misses (a spec can change without a
4
4
  // version bump) — do not remove it as "redundant" with the version.
5
5
  // Run `npm run openapi:gen --workspace=packages/app` to regenerate. Do not edit by hand.
@@ -7,7 +7,7 @@
7
7
  import { toZod } from "./to-zod.js";
8
8
  export const MCP_TOOLS = {
9
9
  "AddOrgMember": {
10
- description: "Invite a member to an organization\n\nOwner only. Invites a user to the organization by email. The invitee does **not** need to be a registered user — an invite is created in either case, and an invite email with an accept link is dispatched. The new row is returned with `status: PENDING`; it flips to `ACTIVE` only when the invitee explicitly accepts via `POST /orgs/{orgId}/invite`. `PERSONAL` organizations reject this call (409).",
10
+ description: "Invite a member to an organization\n\nOwner only. Invites a user to the organization by email. The invitee does **not** need to be a registered user — an invite is created in either case, and an invite email with an accept link is dispatched. The new row is returned with `status: PENDING`; it flips to `ACTIVE` only when the invitee explicitly accepts via `POST /orgs/{orgId}/invite`.",
11
11
  inputSchema: toZod({
12
12
  "type": "object",
13
13
  "properties": {
@@ -46,7 +46,7 @@ export const MCP_TOOLS = {
46
46
  },
47
47
  "role": {
48
48
  "type": "string",
49
- "description": "Role a user holds in an organization. `OWNER` can invite, promote, demote, and remove members, and delete the org. `MEMBER` has read/write access to resources owned by the org but cannot manage membership. `PERSONAL` orgs have exactly one `OWNER` and reject all member-mutating operations.",
49
+ "description": "Role a user holds in an organization. `OWNER` can invite, promote, demote, and remove members, and delete the org. `MEMBER` has read/write access to resources owned by the org but cannot manage membership.",
50
50
  "enum": [
51
51
  "OWNER",
52
52
  "MEMBER"
@@ -407,6 +407,12 @@ export const MCP_TOOLS = {
407
407
  "maxLength": 132
408
408
  }
409
409
  }
410
+ },
411
+ "orgToken": {
412
+ "type": "string",
413
+ "pattern": "^rorg_",
414
+ "maxLength": 200,
415
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
410
416
  }
411
417
  },
412
418
  "required": [
@@ -416,6 +422,7 @@ export const MCP_TOOLS = {
416
422
  ],
417
423
  "additionalProperties": false
418
424
  }),
425
+ orgTokenOnly: true,
419
426
  },
420
427
  "CancelPublicListingRequest": {
421
428
  description: "Cancel a pending public listing review request\n\nCancels a pending public listing request by moving the version from `in_review` back to `draft`. Only org members can cancel their own review requests. This allows users to withdraw a request before admin review if they change their mind.",
@@ -557,6 +564,12 @@ export const MCP_TOOLS = {
557
564
  }
558
565
  }
559
566
  }
567
+ },
568
+ "orgToken": {
569
+ "type": "string",
570
+ "pattern": "^rorg_",
571
+ "maxLength": 200,
572
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
560
573
  }
561
574
  },
562
575
  "required": [
@@ -566,9 +579,10 @@ export const MCP_TOOLS = {
566
579
  ],
567
580
  "additionalProperties": false
568
581
  }),
582
+ orgTokenOnly: true,
569
583
  },
570
584
  "CreateOrg": {
571
- description: "Create an organization\n\nCreates a new `ORG`-kind organization with the caller as its first `OWNER`. The personal org is created automatically at user signup and is not created via this endpoint.",
585
+ description: "Create an organization\n\nCreates a new `ORG`-kind organization with the caller as its first `OWNER`. Every user gets a default organization at sign-up, and it counts toward their org-creation limit (1 active organization unless Reclaim support raises it). Past the limit this returns `409`; contact support@reclaimprotocol.org to raise the limit or archive an organization.",
572
586
  inputSchema: toZod({
573
587
  "type": "object",
574
588
  "properties": {
@@ -583,7 +597,7 @@ export const MCP_TOOLS = {
583
597
  "body": {
584
598
  "type": "object",
585
599
  "additionalProperties": false,
586
- "description": "Body for `POST /orgs` — just a name. Every org is created keyless, like auto-provisioned personal orgs; its Ethereum (secp256k1) key pair is published separately via `PUT /orgs/{orgId}/keypair`, which is also where `canEncryptResult` is set. Creation deliberately collects nothing else so it never blocks on generating and safeguarding a private key.",
600
+ "description": "Body for `POST /orgs` — just a name. Every org is created keyless, like each user's default org; its Ethereum (secp256k1) key pair is published separately via `PUT /orgs/{orgId}/keypair`, which is also where `canEncryptResult` is set. Creation deliberately collects nothing else so it never blocks on generating and safeguarding a private key.",
587
601
  "required": [
588
602
  "name"
589
603
  ],
@@ -1538,7 +1552,7 @@ export const MCP_TOOLS = {
1538
1552
  }),
1539
1553
  },
1540
1554
  "CreateVerificationSession": {
1541
- description: "Create a verification session\n\nCreates an end-user verification session. Requires an OrgToken and a callback subscription; pass providers, context, and an optional registered verificationClientUrl (omitted: the Portal). Billing refusal returns 402 or 429 with event billing_required and a terminal sessionId.",
1555
+ description: "Create a verification session\n\nCreates an end-user verification session. Requires an OrgToken and a callback subscription; pass providers, context, and an optional registered verificationClientUrl (omitted: the Portal). Send the end user to the returned verificationUrl; that is where they verify. Billing refusal returns 402 or 429 with event billing_required and a terminal sessionId.",
1542
1556
  inputSchema: toZod({
1543
1557
  "type": "object",
1544
1558
  "properties": {
@@ -1592,9 +1606,16 @@ export const MCP_TOOLS = {
1592
1606
  },
1593
1607
  "verificationClientUrl": {
1594
1608
  "type": "string",
1595
- "description": "Optional. Must exactly equal the base URL of a registered verification client (see the `verification_clients` registry / `/admin/verification-clients`). Omit to use the default (`portals`) client. The Builder resolves and stores the registered client UUID, then returns the ready-to-share `verificationUrl` with the session id and `api=2`. A URL that is not a registered client's base is rejected with 400. Consumers append any client-owned redirect parameters after receiving the URL; Builder does not manage them.",
1609
+ "description": "Optional. Must exactly equal the base URL of a registered verification client (see the `verification_clients` registry / `/admin/verification-clients`). Omit to use the default (`portals`) client. The Builder resolves and stores the registered client UUID, then returns the ready-to-share `verificationUrl` with the session id and `api=2`. A URL that is not a registered client's base is rejected with 400. Consumers append any client-owned redirect parameters after receiving the URL; Builder does not manage them. The built-in clients are `{origin}/share/{name}`, listed in the examples.",
1596
1610
  "maxLength": 2000,
1597
- "pattern": "^https?://"
1611
+ "pattern": "^https?://",
1612
+ "examples": [
1613
+ "https://build.reclaimprotocol.org/share/portals",
1614
+ "https://build.reclaimprotocol.org/share/verifier-app",
1615
+ "https://build.reclaimprotocol.org/share/reclaim-browser-extension",
1616
+ "https://build.reclaimprotocol.org/share/builder",
1617
+ "https://build.reclaimprotocol.org/share/inapp-sdk"
1618
+ ]
1598
1619
  },
1599
1620
  "themeId": {
1600
1621
  "type": "string",
@@ -1709,6 +1730,12 @@ export const MCP_TOOLS = {
1709
1730
  }
1710
1731
  }
1711
1732
  }
1733
+ },
1734
+ "orgToken": {
1735
+ "type": "string",
1736
+ "pattern": "^rorg_",
1737
+ "maxLength": 200,
1738
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
1712
1739
  }
1713
1740
  },
1714
1741
  "required": [
@@ -1718,6 +1745,7 @@ export const MCP_TOOLS = {
1718
1745
  ],
1719
1746
  "additionalProperties": false
1720
1747
  }),
1748
+ orgTokenOnly: true,
1721
1749
  },
1722
1750
  "DecideProviderVersionReview": {
1723
1751
  description: "Record a decision on a provider version review\n\nApproves or rejects a provider version awaiting review. Admin only. Approval promotes the version to the live channel; rejection moves it to the rejected branch with a reason. Use admin_reviews to find versions waiting on a decision.",
@@ -1803,6 +1831,12 @@ export const MCP_TOOLS = {
1803
1831
  },
1804
1832
  "body": {
1805
1833
  "type": "object"
1834
+ },
1835
+ "orgToken": {
1836
+ "type": "string",
1837
+ "pattern": "^rorg_",
1838
+ "maxLength": 200,
1839
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
1806
1840
  }
1807
1841
  },
1808
1842
  "required": [
@@ -1811,6 +1845,7 @@ export const MCP_TOOLS = {
1811
1845
  ],
1812
1846
  "additionalProperties": false
1813
1847
  }),
1848
+ orgTokenOnly: true,
1814
1849
  },
1815
1850
  "DeleteOrgCallbackSubscription": {
1816
1851
  description: "Delete an organization's callback subscription\n\nRemoves a callback subscription. Caller must be an active member of the owning org.",
@@ -2092,15 +2127,22 @@ export const MCP_TOOLS = {
2092
2127
  "type": "string",
2093
2128
  "enum": [
2094
2129
  "claude",
2130
+ "copilot",
2095
2131
  "cursor",
2132
+ "omp",
2096
2133
  "opencode",
2097
2134
  "codex",
2135
+ "antigravity",
2098
2136
  "others"
2099
2137
  ]
2100
2138
  },
2101
2139
  "providerId": {
2102
- "type": "string",
2103
- "format": "uuid"
2140
+ "type": "array",
2141
+ "maxItems": 20,
2142
+ "items": {
2143
+ "type": "string",
2144
+ "format": "uuid"
2145
+ }
2104
2146
  },
2105
2147
  "client": {
2106
2148
  "type": "string",
@@ -2495,6 +2537,12 @@ export const MCP_TOOLS = {
2495
2537
  },
2496
2538
  "body": {
2497
2539
  "type": "object"
2540
+ },
2541
+ "orgToken": {
2542
+ "type": "string",
2543
+ "pattern": "^rorg_",
2544
+ "maxLength": 200,
2545
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
2498
2546
  }
2499
2547
  },
2500
2548
  "required": [
@@ -2503,6 +2551,7 @@ export const MCP_TOOLS = {
2503
2551
  ],
2504
2552
  "additionalProperties": false
2505
2553
  }),
2554
+ orgTokenOnly: true,
2506
2555
  },
2507
2556
  "ImportDevtoolsProvider": {
2508
2557
  description: "Import a provider from devtools\n\nImports a public legacy provider into Builder by UUID. Requires human BearerAuth and a target orgId; preserves the provider UUID and is idempotent for seeded providers. Returns 409 if another Builder org owns the UUID.",
@@ -2616,6 +2665,12 @@ export const MCP_TOOLS = {
2616
2665
  },
2617
2666
  "body": {
2618
2667
  "type": "object"
2668
+ },
2669
+ "orgToken": {
2670
+ "type": "string",
2671
+ "pattern": "^rorg_",
2672
+ "maxLength": 200,
2673
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
2619
2674
  }
2620
2675
  },
2621
2676
  "required": [
@@ -2624,6 +2679,7 @@ export const MCP_TOOLS = {
2624
2679
  ],
2625
2680
  "additionalProperties": false
2626
2681
  }),
2682
+ orgTokenOnly: true,
2627
2683
  },
2628
2684
  "ListOrgCallbackSubscriptions": {
2629
2685
  description: "List an organization's callback subscriptions\n\nReturns every callback subscription owned by the organization. Caller must be an active member of the org.",
@@ -2659,7 +2715,7 @@ export const MCP_TOOLS = {
2659
2715
  }),
2660
2716
  },
2661
2717
  "ListOrgs": {
2662
- description: "List organizations the caller belongs to\n\nLists the organizations the caller belongs to, personal and shared. Use it first to find an organization id — most other tools take one.",
2718
+ description: "List organizations the caller belongs to\n\nLists the organizations the caller belongs to. Use it first to find an organization id — most other tools take one.",
2663
2719
  inputSchema: toZod({
2664
2720
  "type": "object",
2665
2721
  "properties": {
@@ -2920,6 +2976,12 @@ export const MCP_TOOLS = {
2920
2976
  },
2921
2977
  "body": {
2922
2978
  "type": "object"
2979
+ },
2980
+ "orgToken": {
2981
+ "type": "string",
2982
+ "pattern": "^rorg_",
2983
+ "maxLength": 200,
2984
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
2923
2985
  }
2924
2986
  },
2925
2987
  "required": [
@@ -2928,6 +2990,7 @@ export const MCP_TOOLS = {
2928
2990
  ],
2929
2991
  "additionalProperties": false
2930
2992
  }),
2993
+ orgTokenOnly: true,
2931
2994
  },
2932
2995
  "ListVerificationEvents": {
2933
2996
  description: "Get the event log for a session\n\nLists append-only lifecycle events for a session. Requires the owning organization's token. Use after get_verification_session to find the first missing or failed milestone; inspect eventData for failure details.",
@@ -2954,6 +3017,12 @@ export const MCP_TOOLS = {
2954
3017
  },
2955
3018
  "body": {
2956
3019
  "type": "object"
3020
+ },
3021
+ "orgToken": {
3022
+ "type": "string",
3023
+ "pattern": "^rorg_",
3024
+ "maxLength": 200,
3025
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
2957
3026
  }
2958
3027
  },
2959
3028
  "required": [
@@ -2962,6 +3031,7 @@ export const MCP_TOOLS = {
2962
3031
  ],
2963
3032
  "additionalProperties": false
2964
3033
  }),
3034
+ orgTokenOnly: true,
2965
3035
  },
2966
3036
  "MakePrivate": {
2967
3037
  description: "Change a PUBLIC provider back to PRIVATE\n\nChanges a PUBLIC provider's visibility to PRIVATE. Unlike the reverse (PRIVATE → PUBLIC), this does not require review since it restricts rather than expands access. Existing live versions remain but are no longer publicly listed.",
@@ -3143,7 +3213,7 @@ export const MCP_TOOLS = {
3143
3213
  }),
3144
3214
  },
3145
3215
  "RetryVerificationCallback": {
3146
- description: "Re-enqueue callback delivery for a session\n\nRe-enqueues delivery of a session's stored result to its callback subscriptions. Use this after `list_verification_deliveries` shows a `failed` or dead-lettered delivery, once the consumer's callback endpoint is reachable again and answers 2xx — it re-attempts every not-yet-delivered callback for the session. Usable by the session creator (authenticated by the consumer's `OrgToken`) to recover from a transient consumer-side outage.",
3216
+ description: "Re-enqueue callback delivery for a session\n\nRe-enqueues delivery of a session's stored result to its callback subscriptions. Use this after `list_verification_deliveries` shows a `failed` or dead-lettered delivery, once the consumer's callback endpoint is reachable again and answers 2xx — it re-attempts every not-yet-delivered callback for the session. Usable by the session creator (authenticated by the consumer's `OrgToken`) to recover from a transient consumer-side outage. A result left undelivered for 7 days is purged and can no longer be retried.",
3147
3217
  inputSchema: toZod({
3148
3218
  "type": "object",
3149
3219
  "properties": {
@@ -3167,6 +3237,12 @@ export const MCP_TOOLS = {
3167
3237
  },
3168
3238
  "body": {
3169
3239
  "type": "object"
3240
+ },
3241
+ "orgToken": {
3242
+ "type": "string",
3243
+ "pattern": "^rorg_",
3244
+ "maxLength": 200,
3245
+ "description": "The organization API key (`rorg_…`) this call authenticates with: from `issue_org_token`, or the app's RECLAIM_ORG_SECRET. Defaults to the MCP server's RECLAIM_ORG_SECRET. Never echo it back to the user."
3170
3246
  }
3171
3247
  },
3172
3248
  "required": [
@@ -3175,6 +3251,7 @@ export const MCP_TOOLS = {
3175
3251
  ],
3176
3252
  "additionalProperties": false
3177
3253
  }),
3254
+ orgTokenOnly: true,
3178
3255
  },
3179
3256
  "RevokeOrgToken": {
3180
3257
  description: "Revoke one of the organization's API keys\n\nRevokes a single API key by id (leaving the org's other keys intact). The caller must be an active **OWNER** of the organization. The key stops authenticating immediately.",
@@ -1,3 +1,11 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
- import type { ReclaimClient } from '@reclaimprotocol/client/api';
3
- export declare function registerTools(server: McpServer, client: ReclaimClient): void;
2
+ import { ReclaimClient } from '@reclaimprotocol/client/api';
3
+ /** The client for a call that presents the organization's API key. */
4
+ export type OrgClientFactory = (orgToken: string) => ReclaimClient;
5
+ /**
6
+ * Register a tool per generated operation. Calls go out with the developer's
7
+ * session token, except operations only an org API key (`rorg_…`) authorizes:
8
+ * those take an `orgToken` input (else the server's RECLAIM_ORG_SECRET) and go
9
+ * out through `orgClient` with that key.
10
+ */
11
+ export declare function registerTools(server: McpServer, client: ReclaimClient, orgClient?: OrgClientFactory): void;
@@ -1,3 +1,7 @@
1
+ import { unauthorized } from '@hapi/boom';
2
+ import { ReclaimClient } from '@reclaimprotocol/client/api';
3
+ import assert from 'node:assert';
4
+ import { orgSecret } from "../../consts.js";
1
5
  import { remapErrorAsResponse } from "../remap_errors.js";
2
6
  import { successResponse } from "../success-response.js";
3
7
  import { MCP_TOOLS } from "./operations.gen.js";
@@ -14,8 +18,22 @@ function toSnakeCase(name) {
14
18
  .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
15
19
  .toLowerCase();
16
20
  }
17
- export function registerTools(server, client) {
18
- for (const [opId, shape] of Object.entries(MCP_TOOLS)) {
21
+ /**
22
+ * Register a tool per generated operation. Calls go out with the developer's
23
+ * session token, except operations only an org API key (`rorg_…`) authorizes:
24
+ * those take an `orgToken` input (else the server's RECLAIM_ORG_SECRET) and go
25
+ * out through `orgClient` with that key.
26
+ */
27
+ export function registerTools(server, client, orgClient = (orgToken) => new ReclaimClient({
28
+ baseUrl: client.baseUrl,
29
+ token: orgToken,
30
+ })) {
31
+ for (const [opId, tool] of Object.entries(MCP_TOOLS)) {
32
+ const orgTokenOnly = 'orgTokenOnly' in tool && tool.orgTokenOnly === true;
33
+ const shape = {
34
+ description: tool.description,
35
+ inputSchema: tool.inputSchema,
36
+ };
19
37
  if (!isOperationId(opId)) {
20
38
  throw new Error(`Generated MCP operation is not in the API client: ${opId}`);
21
39
  }
@@ -23,12 +41,19 @@ export function registerTools(server, client) {
23
41
  // a hand-written tool throws here at startup — intentional: hand-written
24
42
  // and generated names must stay disjoint (see start.ts), so a clash is a
25
43
  // bug to surface, not silently shadow.
26
- server.registerTool(toSnakeCase(opId), shape, async (args) => {
44
+ server.registerTool(toSnakeCase(opId), shape, async (input) => {
27
45
  try {
46
+ if (!isRecord(input)) {
47
+ throw new Error(`Invalid generated MCP arguments for ${opId}`);
48
+ }
49
+ const { orgToken, ...args } = input;
28
50
  if (!isOperationArgs(opId, args)) {
29
51
  throw new Error(`Invalid generated MCP arguments for ${opId}`);
30
52
  }
31
- const result = await client.call(opId, args);
53
+ const caller = orgTokenOnly
54
+ ? orgClient(orgTokenFor(toSnakeCase(opId), orgToken))
55
+ : client;
56
+ const result = await caller.call(opId, args);
32
57
  return successResponse(result.data);
33
58
  }
34
59
  catch (err) {
@@ -56,3 +81,16 @@ function isOperationId(value) {
56
81
  function isOperationArgs(_operationId, value) {
57
82
  return typeof value === 'object' && value !== null && !Array.isArray(value);
58
83
  }
84
+ function isRecord(value) {
85
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
86
+ }
87
+ /** The org API key a call authenticates with: its `orgToken`, else the
88
+ * server's RECLAIM_ORG_SECRET. The session token (the developer's sign-in)
89
+ * can't stand in, since these routes accept only an org key. */
90
+ function orgTokenFor(tool, orgToken) {
91
+ const token = (typeof orgToken === 'string' && orgToken) || orgSecret();
92
+ assert(token, unauthorized(`${tool} authenticates with the organization's API key. Pass `
93
+ + 'orgToken: one from issue_org_token, or the app\'s '
94
+ + 'RECLAIM_ORG_SECRET. Or set RECLAIM_ORG_SECRET for the MCP server.'));
95
+ return token;
96
+ }
package/lib/mcp/start.js CHANGED
@@ -79,7 +79,12 @@ export async function startMcpServer() {
79
79
  registerToolList(server, buildVerificationTools());
80
80
  // Add auto-generated tools with snake_case wrappers
81
81
  // for every MCP-tagged operation.
82
- registerTools(server, client);
82
+ // Org-key-only operations go out with the call's `orgToken` instead.
83
+ registerTools(server, client, (orgToken) => new ReclaimClient({
84
+ baseUrl: apiUrl(),
85
+ token: orgToken,
86
+ headers: { 'User-Agent': `${NAME}/${VERSION}` },
87
+ }));
83
88
  if (agentToolsEnabled) {
84
89
  agentState = buildAgentState();
85
90
  registerToolList(server, buildAgentTools(client, client, agentState));
@@ -11,16 +11,25 @@ const TERMINAL = new Set([
11
11
  'cancelled',
12
12
  'expired',
13
13
  ]);
14
+ /** Events whose delivery is a signed result; the rest are plaintext event
15
+ * notifications. Mirrors `verification_result_events()`. */
16
+ const RESULT_EVENTS = new Set([
17
+ 'verification_success',
18
+ 'verification_rejected',
19
+ 'verification_error',
20
+ 'verification_cancelled',
21
+ ]);
14
22
  /**
15
23
  * Resolve the org secret used to authenticate verification reads. Auth is a
16
- * single per-org bearer secret (`rorg_…`), not an eth signature — read it from
17
- * `RECLAIM_ORG_SECRET`.
24
+ * single per-org bearer secret (`rorg_…`), not an eth signature: the call's
25
+ * `orgToken`, else `RECLAIM_ORG_SECRET`.
18
26
  */
19
- function resolveOrgSecret() {
20
- const secret = orgSecret()?.trim();
21
- assert(secret, new Error('RECLAIM_ORG_SECRET is not set. Verification reads authenticate with ' +
22
- 'the org secret (rorg_…) — issue one from the dashboard ' +
23
- '(POST /orgs/{orgId}/token) and export it as RECLAIM_ORG_SECRET.'));
27
+ function resolveOrgSecret(orgToken) {
28
+ const secret = orgToken?.trim() || orgSecret()?.trim();
29
+ assert(secret, new Error('No organization API key. Verification reads authenticate with the org '
30
+ + 'secret (rorg_…): pass orgToken (from issue_org_token, or the '
31
+ + 'app\'s RECLAIM_ORG_SECRET), or export RECLAIM_ORG_SECRET for the '
32
+ + 'MCP server.'));
24
33
  return secret;
25
34
  }
26
35
  /**
@@ -36,8 +45,11 @@ function resolveOrgSecret() {
36
45
  export function verificationResultTool() {
37
46
  return defineTool({
38
47
  name: 'get_verification_result',
39
- description: 'Fetches and verifies a terminal Builder result for one session. '
40
- + 'Requires `RECLAIM_ORG_SECRET`; encrypted deliveries also require '
48
+ description: 'Fetches and verifies a terminal Builder result for one session, '
49
+ + 'while Builder still holds it: until its callback is delivered, or '
50
+ + '7 days undelivered. The callback is the normal way to get results. '
51
+ + 'Authenticates with the org API key: `orgToken`, else '
52
+ + '`RECLAIM_ORG_SECRET`. Encrypted deliveries also require '
41
53
  + 'the matching ETH decryption key. Returns `ready: false` until a '
42
54
  + 'payload is available. Invalid results fail verification and are not '
43
55
  + 'returned. Use `list_verification_events` to diagnose '
@@ -50,10 +62,19 @@ export function verificationResultTool() {
50
62
  type: 'string',
51
63
  description: 'The verification session id from create_verification_session.',
52
64
  },
65
+ orgToken: {
66
+ type: 'string',
67
+ pattern: '^rorg_',
68
+ maxLength: 200,
69
+ description: 'The organization API key (`rorg_…`): from '
70
+ + '`issue_org_token`, or the app\'s RECLAIM_ORG_SECRET. '
71
+ + 'Defaults to the MCP server\'s RECLAIM_ORG_SECRET. Never echo '
72
+ + 'it back to the user.',
73
+ },
53
74
  },
54
75
  },
55
76
  }, async (args) => {
56
- const secret = resolveOrgSecret();
77
+ const secret = resolveOrgSecret(args.orgToken);
57
78
  // Optional eth decryption key — absent ⇒ plaintext-only.
58
79
  const decryptionKey = await resolveDecryptionKey();
59
80
  const reclaim = ReclaimVerification.create({
@@ -70,13 +91,29 @@ export function verificationResultTool() {
70
91
  const resultRes = await reclaim.api('GetVerificationResult', {
71
92
  params: { sessionId: args.reclaimSessionId },
72
93
  });
73
- const { items } = resultRes.data;
94
+ const signed = resultRes.data.items
95
+ .filter((item) => RESULT_EVENTS.has(item.event));
96
+ if (!signed.length) {
97
+ return {
98
+ reclaimSessionId: args.reclaimSessionId,
99
+ status,
100
+ ready: false,
101
+ note: 'Session is terminal but no result is stored: none submitted '
102
+ + 'yet, or no callback subscription covers its ending event.',
103
+ };
104
+ }
105
+ // Builder keeps a result (which can carry proofs) only until its
106
+ // callback is delivered, or 7 days undelivered.
107
+ const items = signed.flatMap((item) => (item.payload === null ? [] : [{ ...item, payload: item.payload }]));
74
108
  if (!items.length) {
75
109
  return {
76
110
  reclaimSessionId: args.reclaimSessionId,
77
111
  status,
78
112
  ready: false,
79
- note: 'Session is terminal but no result has been submitted yet.',
113
+ delivered: signed.some((item) => (item.deliveryStatus === 'delivered')),
114
+ note: 'Builder no longer holds this result: it was delivered to '
115
+ + 'the callback (read it there), or went undelivered for 7 days. '
116
+ + 'See list_verification_deliveries.',
80
117
  };
81
118
  }
82
119
  // Each item's `payload` is an ECIES ciphertext encrypted to the org's
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@reclaimprotocol/agent",
3
3
  "title": "Reclaim Agent",
4
- "version": "0.1.32",
4
+ "version": "0.1.33",
5
5
  "description": "Reclaim Protocol tools for AI coding agents. Reclaim lets your app verify data points about its users, such as a follower count, an account balance, or an order history. This package is the Reclaim MCP server: it gives your agent the tools to find, build, test, and fix data verification providers by capturing and replaying browser requests, drafting provider recipes, running zkTLS proofs, and publishing provider versions.",
6
6
  "type": "module",
7
7
  "main": "./lib/index.js",
@@ -83,7 +83,7 @@
83
83
  "@modelcontextprotocol/sdk": "^1.29.0",
84
84
  "@noble/hashes": "^2.2.0",
85
85
  "@reclaimprotocol/attestor-core": "^5.1.5",
86
- "@reclaimprotocol/client": "0.1.32",
86
+ "@reclaimprotocol/client": "0.1.33",
87
87
  "@reclaimprotocol/tls": "^0.1.3",
88
88
  "chrome-remote-interface": "^0.33.0",
89
89
  "domhandler": "^6.0.0",
@@ -403,7 +403,8 @@ use, run the same flow the Discover UI does:
403
403
  `create_verification_session({ providers: [{ providerId }, …], context,
404
404
  verificationClientUrl })` with EVERY resolved provider id and the collected
405
405
  context, give them `verificationUrl`, poll `get_verification_session` until
406
- it is terminal, and report the outcome with `get_verification_result`.
406
+ it is terminal, and report the outcome with `get_verification_result`
407
+ (builder-mode instructions cover the org key and temporary callback).
407
408
  Integrate or new app → topic `integration`.
408
409
 
409
410
  `merge.mergeable` only signals the set *could* collapse into one provider — you
@@ -17,14 +17,32 @@ to try it or want it in an app (skip this if they already said):
17
17
  > Want to (1) just try it right now, (2) integrate it into an existing backend
18
18
  > or frontend (this directory or another path), or (3) create a new app for it?
19
19
 
20
- - **Just try it:** no app, callback, or client package. Create the session the
21
- HTTP way (`create_verification_session`, i.e. `POST /verifications/sessions`
22
- with the org secret as `Authorization: Bearer`; `issue_org_token` if there is
23
- none), give the developer `verificationUrl` to open, then check the session
24
- yourself (`get_verification_session`) until it is terminal and report the
25
- outcome with `get_verification_result`.
20
+ - **Just try it:** no app or client package, but the same production API the
21
+ app will use. You need an org API key (`rorg_…`): reuse one the developer
22
+ already has, else `issue_org_token` (owner only; the key is shown once).
23
+ Session creation returns 409 while the org has no callback subscription, and
24
+ the result is only stored for subscriptions to the event the session ends
25
+ with. If the org has none, register a temporary one for all five ending
26
+ events with `create_org_callback_subscription` (for example, a tunnel to a
27
+ local listener that saves the body it receives). Then call
28
+ `create_verification_session` with `orgToken`, give the developer
29
+ `verificationUrl` to open, poll `get_verification_session` (with `orgToken`)
30
+ until it is terminal, and report the outcome: from the body your listener
31
+ received, or with `get_verification_result` (with `orgToken`), which only
32
+ works until the callback is delivered. Delete the temporary subscription with
33
+ `delete_org_callback_subscription` only after that: deleting it also deletes
34
+ its stored results.
26
35
  - **Integrate, or new app:** follow the setup below in the path they named.
27
36
 
37
+ **Org API key vs. sign-in.** Management tools (`list_orgs`,
38
+ `create_org_callback_subscription`, `issue_org_token`, …) use the developer's
39
+ sign-in. Session tools (`create_verification_session`,
40
+ `get_verification_session`, `list_verification_events`,
41
+ `list_verification_deliveries`, `retry_verification_callback`) are the
42
+ production API a backend calls, so they take the org key as `orgToken`
43
+ (defaulting to this server's `RECLAIM_ORG_SECRET`). Never print the key back to
44
+ the developer.
45
+
28
46
  **Prefer the HTTP API over `@reclaimprotocol/client`** for every option:
29
47
  create sessions with `POST /verifications/sessions`, open `verificationUrl`,
30
48
  poll `GET /verifications/sessions/{sessionId}`, and take the result on the