@reclaimprotocol/agent 0.1.4 → 0.1.5
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.
- package/README.md +5 -5
- package/lib/authoring/backend.d.ts +95 -0
- package/lib/authoring/backend.js +24 -0
- package/lib/authoring/index.d.ts +4 -0
- package/lib/authoring/index.js +5 -0
- package/lib/authoring/tools.d.ts +9 -0
- package/lib/authoring/tools.js +378 -0
- package/lib/cdp/capture-engine.js +1 -1
- package/lib/mcp/api/operations.gen.js +46 -18
- package/lib/mcp/server.d.ts +18 -2
- package/lib/mcp/server.js +19 -4
- package/lib/mcp/tools/agent/publish.js +2 -2
- package/lib/mcp/tools/agent/shared.d.ts +6 -0
- package/lib/mcp/tools/agent/shared.js +115 -0
- package/lib/old/login-cdp.d.ts +5 -0
- package/lib/old/login-cdp.js +12 -1
- package/lib/old/tools/authenticate.js +7 -3
- package/lib/proof/proof-core.d.ts +1 -1
- package/lib/proof/proof-core.js +1 -1
- package/lib/tools/registry.d.ts +36 -0
- package/lib/tools/registry.js +17 -0
- package/package.json +1 -1
- package/skill/SKILL.builder.md +13 -9
- package/skill/SKILL.old.md +14 -10
- package/src/cdp/capture-engine.ts +1 -1
- package/src/mcp/api/operations.gen.ts +46 -18
- package/src/mcp/server.ts +43 -6
- package/src/mcp/tools/agent/publish.ts +2 -2
- package/src/old/login-cdp.ts +20 -1
- package/src/old/tools/authenticate.ts +11 -3
- package/src/proof/proof-core.ts +1 -1
package/skill/SKILL.builder.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
# Authoring a Reclaim Provider
|
|
2
|
-
|
|
3
|
-
> **Terminology note:**
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
1
|
+
# Authoring a Reclaim Provider
|
|
2
|
+
|
|
3
|
+
> **Terminology note:** A **provider** is the recipe you author here — the
|
|
4
|
+
> instructions for extracting a data point from a website (the
|
|
5
|
+
> `responseMatches` / `responseRedactions` spec, identified by a
|
|
6
|
+
> `providerId`). Always call it a **provider**; never call a provider a
|
|
7
|
+
> "verification." A **verification** (or **verification session**) is the
|
|
8
|
+
> separate runtime act in which an end-user proves a data point *using* a
|
|
9
|
+
> provider — reserve that word for the session/result, never for the recipe.
|
|
10
|
+
> If a developer calls the recipe a "verification," gently use "provider"
|
|
11
|
+
> yourself rather than correcting them.
|
|
8
12
|
|
|
9
13
|
You drive the browser through the capture → draft → replay → prove loop using the `reclaim-agent` MCP server. **Your default stance is driver, not orchestrator.** Only pause to ask the dev for things that genuinely require a human: typing credentials, completing 2FA, solving a captcha, confirming an ambiguous value. Navigation, reloads, DOM inspection, request capture — all yours.
|
|
10
14
|
|
|
@@ -175,7 +179,7 @@ replace with `{{context.<name>}}`. E.g. `https://github.com/Scratch-net/repos`
|
|
|
175
179
|
|
|
176
180
|
13. **Publish the proved provider.** `provider` is the exact JSON from step 9 with the step-10 URL parameterisation applied, and `initialUrl` is the page where the user logs in / the value is displayed (e.g. `https://github.com/Syed`) — **not** the API endpoint URL inside the provider.
|
|
177
181
|
|
|
178
|
-
1. **Create the
|
|
182
|
+
1. **Create the provider if it doesn't exist:** `create_provider(orgId, domain, slug, title, description)` — find `orgId` via `list_orgs`. `domain` e.g. `github.com`; `slug` e.g. `github-username`; `title` e.g. "GitHub Username". Starts PRIVATE with an empty seed version. Skip if the dev already has a `providerId`.
|
|
179
183
|
2. **Persist the version:** `create_provider_version_from_capture(providerId, provider, initialUrl, notes)` — `notes` e.g. `"Initial draft from browser capture"`. The version lands on the `draft` branch.
|
|
180
184
|
3. **`requiredContext` is derived for you.** The publish tool scans the recipe's url/body for `{{context.<name>}}` placeholders (step 10) and emits a JSON Schema requiring each one — the Builder then validates every session-create's `context` against it (a clear 400 instead of a late attestor failure). Extra context fields are always allowed. The derived properties are plain strings; to refine types or add human-readable descriptions, call `update_provider_version` with a `requiredContext` override while the version is on `draft`, e.g.:
|
|
181
185
|
|
|
@@ -183,7 +187,7 @@ replace with `{{context.<name>}}`. E.g. `https://github.com/Scratch-net/repos`
|
|
|
183
187
|
{ "requiredContext": { "type": "object", "required": ["username"], "properties": { "username": { "type": "string", "description": "GitHub username to verify" } } } }
|
|
184
188
|
```
|
|
185
189
|
4. **Go live:** PRIVATE → `publish_provider_version`; PUBLIC → `submit_provider_version_for_review(providerId, version)` and tell the dev it's awaiting admin review.
|
|
186
|
-
5. **Tell the dev how consumers call it:** sessions for this
|
|
190
|
+
5. **Tell the dev how consumers call it:** sessions for this provider must include the context params, e.g. `context: { "username": "..." }` in `POST /verifications/sessions`. Quote the `requiredContext` returned on the created version — a session missing those fields gets a 400, and verification matches the supplied values exactly.
|
|
187
191
|
|
|
188
192
|
When done, tell the developer the version is live (PRIVATE) or submitted for review (PUBLIC), and that they can integrate using the `providerId`.
|
|
189
193
|
|
package/skill/SKILL.old.md
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
# Authoring a Reclaim Provider
|
|
2
|
-
|
|
3
|
-
> **Terminology note:**
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
>
|
|
7
|
-
>
|
|
1
|
+
# Authoring a Reclaim Provider
|
|
2
|
+
|
|
3
|
+
> **Terminology note:** A **provider** is the recipe you author here — the
|
|
4
|
+
> instructions for extracting a data point from a website (the
|
|
5
|
+
> `responseMatches` / `responseRedactions` spec, identified by a
|
|
6
|
+
> `providerId`). Always call it a **provider**; never call a provider a
|
|
7
|
+
> "verification." A **verification** (or **verification session**) is the
|
|
8
|
+
> separate runtime act in which an end-user proves a data point *using* a
|
|
9
|
+
> provider — reserve that word for the session/result, never for the recipe.
|
|
10
|
+
> If a developer calls the recipe a "verification," gently use "provider"
|
|
11
|
+
> yourself rather than correcting them.
|
|
8
12
|
|
|
9
13
|
You drive the browser through the capture → draft → replay → prove loop using the `reclaim-agent` MCP server. **Your default stance is driver, not orchestrator.** Only pause to ask the dev for things that genuinely require a human: typing credentials, completing 2FA, solving a captcha, confirming an ambiguous value. Navigation, reloads, DOM inspection, request capture — all yours.
|
|
10
14
|
|
|
@@ -164,9 +168,9 @@ Call `reclaim_authenticate({})` with no arguments. It opens the Reclaim dashboar
|
|
|
164
168
|
13. **Publish the proved provider.** `provider` is the exact JSON from step 9 with the step-10 URL parameterisation applied, and `initialUrl` is the page where the user logs in / the value is displayed (e.g. `https://github.com/Syed`) — **not** the API endpoint URL inside the provider.
|
|
165
169
|
|
|
166
170
|
Call `create_provider_version_from_capture`:
|
|
167
|
-
- **New
|
|
168
|
-
- **New version of an existing
|
|
169
|
-
- `get_me_providers({ searchQuery? })` lists the
|
|
171
|
+
- **New provider:** omit `providerId`. It registers a new provider (version 1.0.0). Pass `provider`, `initialUrl`, and optionally `description`, `geoLocation`, `providerType` (`PRIVATE` default | `PUBLIC`).
|
|
172
|
+
- **New version of an existing provider:** pass its `providerId` — the patch is auto-bumped above the highest existing version. Pass `notes` (≥10 chars) as the change note.
|
|
173
|
+
- `get_me_providers({ searchQuery? })` lists the providers you own — use it to find a `providerId` or to confirm the result. It's the only provider-listing tool in this mode.
|
|
170
174
|
- There's no separate "create-then-version" step and no org / public-review workflow here.
|
|
171
175
|
- Consumer-supplied params (step 10) keep the `{{context_<name>}}` form in this mode; there is no `requiredContext` declaration on the legacy backend.
|
|
172
176
|
|
|
@@ -75,7 +75,7 @@ export function isStaticAsset(url: string): boolean {
|
|
|
75
75
|
try {
|
|
76
76
|
path = new URL(url).pathname
|
|
77
77
|
} catch{
|
|
78
|
-
path = url.split(/[?#]/)[0]
|
|
78
|
+
path = url.split(/[?#]/)[0] || url
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
// Extension of the last path segment only, so `/v1.2/data` isn't misread.
|
|
@@ -98,7 +98,7 @@ export const MCP_TOOLS = {
|
|
|
98
98
|
}),
|
|
99
99
|
},
|
|
100
100
|
"AdminProviders": {
|
|
101
|
-
description: "All
|
|
101
|
+
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.",
|
|
102
102
|
inputSchema: toZod({
|
|
103
103
|
"type": "object",
|
|
104
104
|
"properties": {
|
|
@@ -485,7 +485,7 @@ export const MCP_TOOLS = {
|
|
|
485
485
|
}),
|
|
486
486
|
},
|
|
487
487
|
"CreateProvider": {
|
|
488
|
-
description: "Create a
|
|
488
|
+
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.",
|
|
489
489
|
inputSchema: toZod({
|
|
490
490
|
"type": "object",
|
|
491
491
|
"properties": {
|
|
@@ -618,7 +618,7 @@ export const MCP_TOOLS = {
|
|
|
618
618
|
}),
|
|
619
619
|
},
|
|
620
620
|
"CreateProviderVersion": {
|
|
621
|
-
description: "Create a new
|
|
621
|
+
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",
|
|
622
622
|
inputSchema: toZod({
|
|
623
623
|
"type": "object",
|
|
624
624
|
"properties": {
|
|
@@ -644,7 +644,7 @@ export const MCP_TOOLS = {
|
|
|
644
644
|
"body": {
|
|
645
645
|
"type": "object",
|
|
646
646
|
"additionalProperties": false,
|
|
647
|
-
"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).
|
|
647
|
+
"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.",
|
|
648
648
|
"required": [
|
|
649
649
|
"initialUrl",
|
|
650
650
|
"requests",
|
|
@@ -652,6 +652,20 @@ export const MCP_TOOLS = {
|
|
|
652
652
|
"webSettings"
|
|
653
653
|
],
|
|
654
654
|
"properties": {
|
|
655
|
+
"verificationType": {
|
|
656
|
+
"type": "string",
|
|
657
|
+
"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.",
|
|
658
|
+
"enum": [
|
|
659
|
+
"llm",
|
|
660
|
+
"structured"
|
|
661
|
+
]
|
|
662
|
+
},
|
|
663
|
+
"prompt": {
|
|
664
|
+
"type": "string",
|
|
665
|
+
"description": "Extraction prompt, used (and required) when `verificationType` is `llm`.",
|
|
666
|
+
"minLength": 0,
|
|
667
|
+
"maxLength": 1000000
|
|
668
|
+
},
|
|
655
669
|
"version": {
|
|
656
670
|
"type": "object",
|
|
657
671
|
"additionalProperties": false,
|
|
@@ -1211,7 +1225,7 @@ export const MCP_TOOLS = {
|
|
|
1211
1225
|
}),
|
|
1212
1226
|
},
|
|
1213
1227
|
"DecideProviderVersionReview": {
|
|
1214
|
-
description: "Record a decision on a
|
|
1228
|
+
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.",
|
|
1215
1229
|
inputSchema: toZod({
|
|
1216
1230
|
"type": "object",
|
|
1217
1231
|
"properties": {
|
|
@@ -1384,7 +1398,7 @@ export const MCP_TOOLS = {
|
|
|
1384
1398
|
}),
|
|
1385
1399
|
},
|
|
1386
1400
|
"DeleteProvider": {
|
|
1387
|
-
description: "Delete a
|
|
1401
|
+
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`.",
|
|
1388
1402
|
inputSchema: toZod({
|
|
1389
1403
|
"type": "object",
|
|
1390
1404
|
"properties": {
|
|
@@ -1429,7 +1443,7 @@ export const MCP_TOOLS = {
|
|
|
1429
1443
|
}),
|
|
1430
1444
|
},
|
|
1431
1445
|
"DeleteProviderVersion": {
|
|
1432
|
-
description: "Delete a
|
|
1446
|
+
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`.",
|
|
1433
1447
|
inputSchema: toZod({
|
|
1434
1448
|
"type": "object",
|
|
1435
1449
|
"properties": {
|
|
@@ -1521,7 +1535,7 @@ export const MCP_TOOLS = {
|
|
|
1521
1535
|
}),
|
|
1522
1536
|
},
|
|
1523
1537
|
"DiscoverResolve": {
|
|
1524
|
-
description: "Resolve a website + data points to
|
|
1538
|
+
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.",
|
|
1525
1539
|
inputSchema: toZod({
|
|
1526
1540
|
"type": "object",
|
|
1527
1541
|
"properties": {
|
|
@@ -1792,7 +1806,7 @@ export const MCP_TOOLS = {
|
|
|
1792
1806
|
}),
|
|
1793
1807
|
},
|
|
1794
1808
|
"GetProvider": {
|
|
1795
|
-
description: "Get a
|
|
1809
|
+
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",
|
|
1796
1810
|
inputSchema: toZod({
|
|
1797
1811
|
"type": "object",
|
|
1798
1812
|
"properties": {
|
|
@@ -1827,7 +1841,7 @@ export const MCP_TOOLS = {
|
|
|
1827
1841
|
}),
|
|
1828
1842
|
},
|
|
1829
1843
|
"GetProviderVersion": {
|
|
1830
|
-
description: "Get a specific
|
|
1844
|
+
description: "Get a specific provider version",
|
|
1831
1845
|
inputSchema: toZod({
|
|
1832
1846
|
"type": "object",
|
|
1833
1847
|
"properties": {
|
|
@@ -2165,7 +2179,7 @@ export const MCP_TOOLS = {
|
|
|
2165
2179
|
}),
|
|
2166
2180
|
},
|
|
2167
2181
|
"ListProviderVersions": {
|
|
2168
|
-
description: "List a
|
|
2182
|
+
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.",
|
|
2169
2183
|
inputSchema: toZod({
|
|
2170
2184
|
"type": "object",
|
|
2171
2185
|
"properties": {
|
|
@@ -2320,7 +2334,7 @@ export const MCP_TOOLS = {
|
|
|
2320
2334
|
}),
|
|
2321
2335
|
},
|
|
2322
2336
|
"Providers": {
|
|
2323
|
-
description: "Search
|
|
2337
|
+
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.",
|
|
2324
2338
|
inputSchema: toZod({
|
|
2325
2339
|
"type": "object",
|
|
2326
2340
|
"properties": {
|
|
@@ -2366,7 +2380,7 @@ export const MCP_TOOLS = {
|
|
|
2366
2380
|
}),
|
|
2367
2381
|
},
|
|
2368
2382
|
"PublishProviderVersion": {
|
|
2369
|
-
description: "Publish a draft version directly (PRIVATE providers only)\n\nPublishes a
|
|
2383
|
+
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).",
|
|
2370
2384
|
inputSchema: toZod({
|
|
2371
2385
|
"type": "object",
|
|
2372
2386
|
"properties": {
|
|
@@ -2615,7 +2629,7 @@ export const MCP_TOOLS = {
|
|
|
2615
2629
|
}),
|
|
2616
2630
|
},
|
|
2617
2631
|
"SubmitProviderVersionForReview": {
|
|
2618
|
-
description: "Submit a
|
|
2632
|
+
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.",
|
|
2619
2633
|
inputSchema: toZod({
|
|
2620
2634
|
"type": "object",
|
|
2621
2635
|
"properties": {
|
|
@@ -2666,7 +2680,7 @@ export const MCP_TOOLS = {
|
|
|
2666
2680
|
}),
|
|
2667
2681
|
},
|
|
2668
2682
|
"TransferProvider": {
|
|
2669
|
-
description: "Transfer a
|
|
2683
|
+
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.",
|
|
2670
2684
|
inputSchema: toZod({
|
|
2671
2685
|
"type": "object",
|
|
2672
2686
|
"properties": {
|
|
@@ -2825,7 +2839,7 @@ export const MCP_TOOLS = {
|
|
|
2825
2839
|
}),
|
|
2826
2840
|
},
|
|
2827
2841
|
"UpdateProvider": {
|
|
2828
|
-
description: "Update a
|
|
2842
|
+
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`.",
|
|
2829
2843
|
inputSchema: toZod({
|
|
2830
2844
|
"type": "object",
|
|
2831
2845
|
"properties": {
|
|
@@ -2962,7 +2976,7 @@ export const MCP_TOOLS = {
|
|
|
2962
2976
|
}),
|
|
2963
2977
|
},
|
|
2964
2978
|
"UpdateProviderVersion": {
|
|
2965
|
-
description: "Update a
|
|
2979
|
+
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`.",
|
|
2966
2980
|
inputSchema: toZod({
|
|
2967
2981
|
"type": "object",
|
|
2968
2982
|
"properties": {
|
|
@@ -3004,13 +3018,27 @@ export const MCP_TOOLS = {
|
|
|
3004
3018
|
"body": {
|
|
3005
3019
|
"type": "object",
|
|
3006
3020
|
"additionalProperties": false,
|
|
3007
|
-
"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`
|
|
3021
|
+
"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.",
|
|
3008
3022
|
"properties": {
|
|
3009
3023
|
"initialUrl": {
|
|
3010
3024
|
"type": "string",
|
|
3011
3025
|
"format": "uri",
|
|
3012
3026
|
"maxLength": 300
|
|
3013
3027
|
},
|
|
3028
|
+
"verificationType": {
|
|
3029
|
+
"type": "string",
|
|
3030
|
+
"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.",
|
|
3031
|
+
"enum": [
|
|
3032
|
+
"llm",
|
|
3033
|
+
"structured"
|
|
3034
|
+
]
|
|
3035
|
+
},
|
|
3036
|
+
"prompt": {
|
|
3037
|
+
"type": "string",
|
|
3038
|
+
"description": "Extraction prompt, used when `verificationType` is `llm`.",
|
|
3039
|
+
"minLength": 0,
|
|
3040
|
+
"maxLength": 1000000
|
|
3041
|
+
},
|
|
3014
3042
|
"requests": {
|
|
3015
3043
|
"type": "array",
|
|
3016
3044
|
"minItems": 0,
|
package/src/mcp/server.ts
CHANGED
|
@@ -9,16 +9,35 @@ export interface ToolDefinition {
|
|
|
9
9
|
inputSchema: JSONSchema.ObjectSchema
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Passed to every tool handler alongside its parsed args. Long-running,
|
|
14
|
+
* human-in-the-loop tools (e.g. a browser login flow that waits for someone
|
|
15
|
+
* to sign in) should call `reportProgress` every few seconds while waiting.
|
|
16
|
+
* MCP clients that attach a progress token to their request (most desktop
|
|
17
|
+
* clients do) treat an incoming `notifications/progress` as proof the call
|
|
18
|
+
* is still alive and reset their own request timeout instead of giving up —
|
|
19
|
+
* the SDK's client-side default is 60s, far shorter than a human can be
|
|
20
|
+
* expected to take to log in. A no-op when the client didn't request
|
|
21
|
+
* progress tracking for this call.
|
|
22
|
+
*/
|
|
23
|
+
export interface ToolContext {
|
|
24
|
+
reportProgress: (message: string) => Promise<void>
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const NOOP_CONTEXT: ToolContext = { reportProgress: async() => {} }
|
|
28
|
+
|
|
12
29
|
export interface RegisteredTool {
|
|
13
30
|
definition: ToolDefinition
|
|
14
31
|
/**
|
|
15
32
|
* @param args Tool arguments
|
|
33
|
+
* @param ctx Progress-reporting context (see {@link ToolContext}).
|
|
34
|
+
* Optional so direct/test callers can omit it.
|
|
16
35
|
* @returns A JSON stringifiable content to be returned to the llm
|
|
17
36
|
* @throws Any error encountered during tool execution will be caught and
|
|
18
37
|
* returned as a response using
|
|
19
38
|
* [remapErrorAsResponse](./src/mcp/remap_errors.ts).
|
|
20
39
|
*/
|
|
21
|
-
handler: (args: unknown) => Promise<unknown>
|
|
40
|
+
handler: (args: unknown, ctx?: ToolContext) => Promise<unknown>
|
|
22
41
|
}
|
|
23
42
|
|
|
24
43
|
/**
|
|
@@ -30,14 +49,14 @@ export interface RegisteredTool {
|
|
|
30
49
|
*/
|
|
31
50
|
export function defineTool<TArgs>(
|
|
32
51
|
definition: ToolDefinition,
|
|
33
|
-
handler: (args: TArgs) => Promise<unknown>,
|
|
52
|
+
handler: (args: TArgs, ctx: ToolContext) => Promise<unknown>,
|
|
34
53
|
): RegisteredTool {
|
|
35
54
|
const schema = toZod(definition.inputSchema)
|
|
36
55
|
return {
|
|
37
56
|
definition,
|
|
38
|
-
handler: async(raw) => {
|
|
57
|
+
handler: async(raw, ctx = NOOP_CONTEXT) => {
|
|
39
58
|
const args = schema.parse(raw) as TArgs
|
|
40
|
-
return await handler(args)
|
|
59
|
+
return await handler(args, ctx)
|
|
41
60
|
},
|
|
42
61
|
}
|
|
43
62
|
}
|
|
@@ -55,13 +74,31 @@ export function registerToolList(server: McpServer, tools: RegisteredTool[]) {
|
|
|
55
74
|
description: tool.definition.description,
|
|
56
75
|
inputSchema: toZod(tool.definition.inputSchema),
|
|
57
76
|
},
|
|
58
|
-
async(args) => {
|
|
77
|
+
async(args, extra) => {
|
|
59
78
|
try {
|
|
79
|
+
const progressToken = extra?._meta?.progressToken
|
|
80
|
+
let progress = 0
|
|
81
|
+
const ctx: ToolContext = {
|
|
82
|
+
reportProgress: async(message) => {
|
|
83
|
+
if(progressToken === undefined) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
progress += 1
|
|
88
|
+
await extra.sendNotification({
|
|
89
|
+
method: 'notifications/progress',
|
|
90
|
+
params: { progressToken, progress, message },
|
|
91
|
+
}).catch(() => {})
|
|
92
|
+
},
|
|
93
|
+
}
|
|
94
|
+
|
|
60
95
|
return {
|
|
61
96
|
content: [
|
|
62
97
|
{
|
|
63
98
|
type: 'text' as const,
|
|
64
|
-
text: JSON.stringify(
|
|
99
|
+
text: JSON.stringify(
|
|
100
|
+
await tool.handler(args, ctx), null, 2,
|
|
101
|
+
),
|
|
65
102
|
},
|
|
66
103
|
],
|
|
67
104
|
}
|
|
@@ -129,7 +129,7 @@ export function createVersionFromCaptureTool(
|
|
|
129
129
|
{
|
|
130
130
|
name: 'create_provider_version_from_capture',
|
|
131
131
|
description:
|
|
132
|
-
'Persist drafted ReclaimProvider(s) as a
|
|
132
|
+
'Persist drafted ReclaimProvider(s) as a provider version. ' +
|
|
133
133
|
'Call this after run_proof succeeds, passing the `provider` ' +
|
|
134
134
|
'object(s) from propose_provider VERBATIM. This tool builds the ' +
|
|
135
135
|
'body (the requests[] array, webSettings, etc.) for you — do NOT ' +
|
|
@@ -160,7 +160,7 @@ export function createVersionFromCaptureTool(
|
|
|
160
160
|
properties: {
|
|
161
161
|
providerId: {
|
|
162
162
|
type: 'string',
|
|
163
|
-
description: 'UUID of the
|
|
163
|
+
description: 'UUID of the provider to publish the version on.',
|
|
164
164
|
},
|
|
165
165
|
provider: PROVIDER_SCHEMA,
|
|
166
166
|
providers: {
|
package/src/old/login-cdp.ts
CHANGED
|
@@ -79,11 +79,18 @@ export async function captureFirebaseTokenViaCdp(opts: {
|
|
|
79
79
|
loginUrl?: string
|
|
80
80
|
timeoutMs?: number
|
|
81
81
|
pollMs?: number
|
|
82
|
+
/** Called every ~10s while waiting for the human to finish signing in, so
|
|
83
|
+
* MCP clients that track progress on this call can reset their own
|
|
84
|
+
* request timeout instead of giving up on a login that's still in
|
|
85
|
+
* flight (see `ToolContext` in `mcp/server.ts`). */
|
|
86
|
+
onProgress?: (message: string) => Promise<void>
|
|
82
87
|
}): Promise<CdpLoginResult> {
|
|
83
88
|
const loginUrl =
|
|
84
89
|
opts.loginUrl || oldLoginUrl() || DEFAULT_LOGIN_URL
|
|
85
90
|
const timeoutMs = opts.timeoutMs ?? 180_000
|
|
86
91
|
const pollMs = opts.pollMs ?? 1000
|
|
92
|
+
const onProgress = opts.onProgress ?? (async() => {})
|
|
93
|
+
const progressIntervalMs = 10_000
|
|
87
94
|
|
|
88
95
|
const cfg = new ConfigStore().read()?.browser_agent
|
|
89
96
|
const mode = cfg?.attachMode ?? 'dedicated'
|
|
@@ -114,7 +121,9 @@ export async function captureFirebaseTokenViaCdp(opts: {
|
|
|
114
121
|
try {
|
|
115
122
|
const session = await handles.attachToTab(targetId)
|
|
116
123
|
const { Runtime } = session
|
|
117
|
-
const
|
|
124
|
+
const startedAt = Date.now()
|
|
125
|
+
const deadline = startedAt + timeoutMs
|
|
126
|
+
let lastProgressAt = startedAt
|
|
118
127
|
while(Date.now() < deadline) {
|
|
119
128
|
const r = await Runtime.evaluate({
|
|
120
129
|
expression: EXTRACT_TOKEN_JS,
|
|
@@ -126,6 +135,16 @@ export async function captureFirebaseTokenViaCdp(opts: {
|
|
|
126
135
|
return { token: value, closedBrowser: launchedByUs }
|
|
127
136
|
}
|
|
128
137
|
|
|
138
|
+
const now = Date.now()
|
|
139
|
+
if(now - lastProgressAt >= progressIntervalMs) {
|
|
140
|
+
lastProgressAt = now
|
|
141
|
+
const remainingSec = Math.round((deadline - now) / 1000)
|
|
142
|
+
await onProgress(
|
|
143
|
+
`Still waiting for sign-in at ${loginUrl} ` +
|
|
144
|
+
`(${remainingSec}s left before this call times out).`,
|
|
145
|
+
)
|
|
146
|
+
}
|
|
147
|
+
|
|
129
148
|
await new Promise((resolve) => setTimeout(resolve, pollMs))
|
|
130
149
|
}
|
|
131
150
|
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { agentDisabled } from '../../consts.ts'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
defineTool,
|
|
4
|
+
type RegisteredTool,
|
|
5
|
+
type ToolContext,
|
|
6
|
+
} from '../../mcp/server.ts'
|
|
3
7
|
import type { OldIdentity, ReclaimOldClient } from '../client.ts'
|
|
4
8
|
import { persistIdentity, toEthUid } from '../identity.ts'
|
|
5
9
|
import { captureFirebaseTokenViaCdp } from '../login-cdp.ts'
|
|
@@ -83,7 +87,7 @@ export function authenticateTool(client: ReclaimOldClient): RegisteredTool {
|
|
|
83
87
|
},
|
|
84
88
|
},
|
|
85
89
|
},
|
|
86
|
-
async({ token, ethAddress, loginUrl, timeoutMs, useBrowser }) => {
|
|
90
|
+
async({ token, ethAddress, loginUrl, timeoutMs, useBrowser }, ctx: ToolContext) => {
|
|
87
91
|
if(token && ethAddress) {
|
|
88
92
|
throw new Error(
|
|
89
93
|
'Provide only ONE of `token` or `ethAddress`, not both.',
|
|
@@ -136,7 +140,11 @@ export function authenticateTool(client: ReclaimOldClient): RegisteredTool {
|
|
|
136
140
|
)
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
const result = await captureFirebaseTokenViaCdp({
|
|
143
|
+
const result = await captureFirebaseTokenViaCdp({
|
|
144
|
+
loginUrl,
|
|
145
|
+
timeoutMs,
|
|
146
|
+
onProgress: ctx.reportProgress,
|
|
147
|
+
})
|
|
140
148
|
const identity: OldIdentity = { kind: 'bearer', token: result.token }
|
|
141
149
|
await validate(identity)
|
|
142
150
|
persistIdentity(identity)
|
package/src/proof/proof-core.ts
CHANGED
|
@@ -38,7 +38,7 @@ export function resolveAttestorUrl(override?: string): string {
|
|
|
38
38
|
)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
/** Map a
|
|
41
|
+
/** Map a provider's recipe straight to the attestor's HTTP
|
|
42
42
|
* params — never synthesized from captured traffic. */
|
|
43
43
|
export function buildHttpParams(
|
|
44
44
|
provider: ReclaimProvider,
|