@reclaimprotocol/agent 0.1.3 → 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 +11 -42
- 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.d.ts +7 -0
- package/lib/cdp/capture-engine.js +78 -0
- package/lib/cdp/capture.d.ts +1 -1
- package/lib/cdp/capture.js +1 -1
- package/lib/consts.d.ts +4 -2
- package/lib/consts.js +6 -2
- package/lib/mcp/api/operations.gen.js +46 -18
- package/lib/mcp/instructions.d.ts +2 -0
- package/lib/mcp/instructions.js +16 -0
- package/lib/mcp/server.d.ts +18 -2
- package/lib/mcp/server.js +19 -4
- package/lib/mcp/start.js +2 -1
- package/lib/mcp/tools/agent/build.js +4 -0
- package/lib/mcp/tools/agent/how-it-works.d.ts +11 -0
- package/lib/mcp/tools/agent/how-it-works.js +24 -0
- 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/client.d.ts +10 -0
- package/lib/old/client.js +27 -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/old/tools/build.d.ts +2 -2
- package/lib/old/tools/build.js +4 -2
- package/lib/old/tools/session-analytics-logs.d.ts +9 -0
- package/lib/old/tools/session-analytics-logs.js +25 -0
- 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 +2 -3
- package/skill/{SKILL.md → SKILL.builder.md} +16 -45
- package/skill/SKILL.old.md +225 -0
- package/skill/old-mode.md +2 -0
- package/src/cdp/capture-engine.ts +89 -0
- package/src/cdp/capture.ts +5 -1
- package/src/consts.ts +7 -2
- package/src/mcp/api/operations.gen.ts +46 -18
- package/src/mcp/instructions.ts +18 -0
- package/src/mcp/server.ts +43 -6
- package/src/mcp/start.ts +2 -0
- package/src/mcp/tools/agent/build.ts +4 -0
- package/src/mcp/tools/agent/how-it-works.ts +32 -0
- package/src/mcp/tools/agent/publish.ts +2 -2
- package/src/old/client.ts +32 -0
- package/src/old/login-cdp.ts +20 -1
- package/src/old/tools/authenticate.ts +11 -3
- package/src/old/tools/build.ts +4 -2
- package/src/old/tools/session-analytics-logs.ts +33 -0
- package/src/proof/proof-core.ts +1 -1
|
@@ -25,6 +25,64 @@ export function stripPseudoHeaders(headers) {
|
|
|
25
25
|
}
|
|
26
26
|
return out;
|
|
27
27
|
}
|
|
28
|
+
/** Extensions for static assets we never prove over — scripts, styles, fonts,
|
|
29
|
+
* images, media, source maps. A real page pulls hundreds of these; tracking
|
|
30
|
+
* them (and fetching their bodies) just bloats the request map and body store
|
|
31
|
+
* with traffic no recipe ever matches. Note: `.json` is deliberately absent —
|
|
32
|
+
* that's the API shape recipes care about. */
|
|
33
|
+
const STATIC_ASSET_EXTENSIONS = new Set([
|
|
34
|
+
'js', 'mjs', 'cjs', 'css', 'map',
|
|
35
|
+
'png', 'jpg', 'jpeg', 'gif', 'svg', 'webp', 'avif', 'ico', 'bmp',
|
|
36
|
+
'woff', 'woff2', 'ttf', 'otf', 'eot',
|
|
37
|
+
'mp4', 'webm', 'mp3', 'ogg', 'wav',
|
|
38
|
+
]);
|
|
39
|
+
/** True when the URL's path names a static asset (by file extension; query and
|
|
40
|
+
* hash are ignored, so `chunk.js?v=1` still counts). The capture engine drops
|
|
41
|
+
* these up front — they never carry JSON/HTML a recipe matches. */
|
|
42
|
+
export function isStaticAsset(url) {
|
|
43
|
+
let path;
|
|
44
|
+
try {
|
|
45
|
+
path = new URL(url).pathname;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
path = url.split(/[?#]/)[0] || url;
|
|
49
|
+
}
|
|
50
|
+
// Extension of the last path segment only, so `/v1.2/data` isn't misread.
|
|
51
|
+
const base = path.slice(path.lastIndexOf('/') + 1);
|
|
52
|
+
const dot = base.lastIndexOf('.');
|
|
53
|
+
if (dot <= 0) {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return STATIC_ASSET_EXTENSIONS.has(base.slice(dot + 1).toLowerCase());
|
|
57
|
+
}
|
|
58
|
+
/** Response Content-Types for static assets. The URL-extension filter misses
|
|
59
|
+
* extension-less bundler/CDN URLs (e.g. `/assets/3b8f1c`), so we also drop by
|
|
60
|
+
* MIME at response time. `text/html`, `application/json`, and `text/plain`
|
|
61
|
+
* are NOT here — those are the document/API shapes recipes match. */
|
|
62
|
+
const STATIC_ASSET_MIME_EXACT = new Set([
|
|
63
|
+
'text/css',
|
|
64
|
+
'application/javascript', 'text/javascript', 'application/x-javascript',
|
|
65
|
+
'application/ecmascript', 'text/ecmascript',
|
|
66
|
+
'application/wasm',
|
|
67
|
+
'application/font-woff', 'application/font-woff2',
|
|
68
|
+
'application/vnd.ms-fontobject', 'application/x-font-ttf',
|
|
69
|
+
]);
|
|
70
|
+
const STATIC_ASSET_MIME_PREFIXES = ['image/', 'font/', 'audio/', 'video/'];
|
|
71
|
+
/** True when a response Content-Type is a static asset (scripts/styles/fonts/
|
|
72
|
+
* images/media). Parameters (`; charset=…`) and case are ignored. */
|
|
73
|
+
export function isStaticAssetMime(mimeType) {
|
|
74
|
+
if (!mimeType) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
const m = mimeType.toLowerCase().split(';')[0].trim();
|
|
78
|
+
if (!m) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
if (STATIC_ASSET_MIME_PREFIXES.some((p) => m.startsWith(p))) {
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return STATIC_ASSET_MIME_EXACT.has(m);
|
|
85
|
+
}
|
|
28
86
|
export function createCaptureEngine(opts) {
|
|
29
87
|
const captureId = randomUUID();
|
|
30
88
|
const requests = new Map();
|
|
@@ -79,6 +137,13 @@ export function createCaptureEngine(opts) {
|
|
|
79
137
|
pendingResponseExtra.set(requestId, { ...buffered, ...clean });
|
|
80
138
|
}
|
|
81
139
|
function onRequestWillBeSent(p) {
|
|
140
|
+
// Static assets never match a recipe — never track them (so we don't
|
|
141
|
+
// fetch their bodies or grow the store). Drop any extra-info that raced
|
|
142
|
+
// ahead of this event so it can't linger.
|
|
143
|
+
if (isStaticAsset(p.request.url)) {
|
|
144
|
+
pendingRequestExtra.delete(p.requestId);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
82
147
|
const f = {
|
|
83
148
|
requestId: p.requestId,
|
|
84
149
|
method: p.request.method,
|
|
@@ -100,6 +165,19 @@ export function createCaptureEngine(opts) {
|
|
|
100
165
|
function onResponseReceived(p) {
|
|
101
166
|
const f = inFlight.get(p.requestId);
|
|
102
167
|
if (!f) {
|
|
168
|
+
// No in-flight entry → the request was skipped (e.g. a static asset)
|
|
169
|
+
// or never seen. Discard any buffered response extra-info so a skipped
|
|
170
|
+
// asset can't leave a dangling entry.
|
|
171
|
+
pendingResponseExtra.delete(p.requestId);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Second-line asset filter by Content-Type: catches extension-less
|
|
175
|
+
// bundler/CDN URLs the request-time URL filter can't. Forget the
|
|
176
|
+
// in-flight entry so it never reaches `requests` and a later
|
|
177
|
+
// loadingFinished/extra-info for it becomes a no-op.
|
|
178
|
+
if (isStaticAssetMime(p.response.mimeType)) {
|
|
179
|
+
inFlight.delete(p.requestId);
|
|
180
|
+
pendingResponseExtra.delete(p.requestId);
|
|
103
181
|
return;
|
|
104
182
|
}
|
|
105
183
|
const captured = {
|
package/lib/cdp/capture.d.ts
CHANGED
|
@@ -6,6 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import type CDP from 'chrome-remote-interface';
|
|
8
8
|
import { type CaptureSession, type StartCaptureOptions } from './capture-engine.ts';
|
|
9
|
-
export { stripPseudoHeaders } from './capture-engine.ts';
|
|
9
|
+
export { isStaticAsset, isStaticAssetMime, stripPseudoHeaders, } from './capture-engine.ts';
|
|
10
10
|
export type { CaptureSession, StartCaptureOptions } from './capture-engine.ts';
|
|
11
11
|
export declare function startCapture(tab: CDP.Client, opts?: StartCaptureOptions): Promise<CaptureSession>;
|
package/lib/cdp/capture.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createCaptureEngine, } from "./capture-engine.js";
|
|
2
|
-
export { stripPseudoHeaders } from "./capture-engine.js";
|
|
2
|
+
export { isStaticAsset, isStaticAssetMime, stripPseudoHeaders, } from "./capture-engine.js";
|
|
3
3
|
export async function startCapture(tab, opts = {}) {
|
|
4
4
|
const engine = createCaptureEngine({
|
|
5
5
|
...(opts.maxBodyBytes !== undefined && { maxBodyBytes: opts.maxBodyBytes }),
|
package/lib/consts.d.ts
CHANGED
|
@@ -16,12 +16,12 @@
|
|
|
16
16
|
* Each var's default/fallback literal is co-located with its getter.
|
|
17
17
|
*/
|
|
18
18
|
import { DEFAULT_BASE_URL } from '@reclaimprotocol/client';
|
|
19
|
-
import { DEFAULT_OLD_API_URL } from './old/client.ts';
|
|
19
|
+
import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from './old/client.ts';
|
|
20
20
|
/** Public attestor websocket URL — fallback for `RECLAIM_ATTESTOR_URL`. */
|
|
21
21
|
export declare const FALLBACK_ATTESTOR_URL = "wss://attestor.reclaimprotocol.org:444/ws";
|
|
22
22
|
/** The devtools dashboard login page — fallback for `RECLAIM_OLD_LOGIN_URL`. */
|
|
23
23
|
export declare const DEFAULT_LOGIN_URL = "https://dev.reclaimprotocol.org";
|
|
24
|
-
export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL };
|
|
24
|
+
export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL };
|
|
25
25
|
/** Pino log level. Read once at logger construction, so an eager const is
|
|
26
26
|
* safe (no test mutates LOG_LEVEL at runtime). */
|
|
27
27
|
export declare const LOG_LEVEL: string;
|
|
@@ -45,6 +45,8 @@ export declare function chromePath(): string | undefined;
|
|
|
45
45
|
export declare function agentDisabled(): boolean;
|
|
46
46
|
/** Old-devtools backend base URL. */
|
|
47
47
|
export declare function oldApiUrl(): string;
|
|
48
|
+
/** Old-devtools analytics-logs service base URL (separate host). */
|
|
49
|
+
export declare function oldLogsUrl(): string;
|
|
48
50
|
/** Builder backend base URL. Shared by mcp/start and the verification tool. */
|
|
49
51
|
export declare function apiUrl(): string;
|
|
50
52
|
/** Explicit builder API token (overrides the cached session token). */
|
package/lib/consts.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { DEFAULT_BASE_URL } from '@reclaimprotocol/client';
|
|
19
19
|
import { homedir } from 'node:os';
|
|
20
20
|
import { join } from 'node:path';
|
|
21
|
-
import { DEFAULT_OLD_API_URL } from "./old/client.js";
|
|
21
|
+
import { DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL } from "./old/client.js";
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
// Default / fallback literals (used only as env fallbacks).
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
@@ -28,7 +28,7 @@ export const FALLBACK_ATTESTOR_URL = 'wss://attestor.reclaimprotocol.org:444/ws'
|
|
|
28
28
|
export const DEFAULT_LOGIN_URL = 'https://dev.reclaimprotocol.org';
|
|
29
29
|
// Re-export the two non-env-fallback defaults so callers can keep importing
|
|
30
30
|
// their URL defaults from a single place if they wish.
|
|
31
|
-
export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL };
|
|
31
|
+
export { DEFAULT_BASE_URL, DEFAULT_OLD_API_URL, DEFAULT_OLD_LOGS_URL };
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
33
|
// Logging.
|
|
34
34
|
// ---------------------------------------------------------------------------
|
|
@@ -79,6 +79,10 @@ export function agentDisabled() {
|
|
|
79
79
|
export function oldApiUrl() {
|
|
80
80
|
return process.env.RECLAIM_OLD_API_URL || DEFAULT_OLD_API_URL;
|
|
81
81
|
}
|
|
82
|
+
/** Old-devtools analytics-logs service base URL (separate host). */
|
|
83
|
+
export function oldLogsUrl() {
|
|
84
|
+
return process.env.RECLAIM_OLD_LOGS_URL || DEFAULT_OLD_LOGS_URL;
|
|
85
|
+
}
|
|
82
86
|
/** Builder backend base URL. Shared by mcp/start and the verification tool. */
|
|
83
87
|
export function apiUrl() {
|
|
84
88
|
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
|
|
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
|
|
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
|
|
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).
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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`
|
|
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,
|
package/lib/mcp/instructions.js
CHANGED
|
@@ -9,3 +9,19 @@
|
|
|
9
9
|
import { readFileSync } from 'node:fs';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
export const BUILDER_MODE_INSTRUCTIONS = readFileSync(fileURLToPath(new URL('../../skill/builder-mode.md', import.meta.url)), 'utf8').trim();
|
|
12
|
+
/**
|
|
13
|
+
* The full provider-authoring guide — the deep capture→prove→publish workflow,
|
|
14
|
+
* decision frameworks, and troubleshooting. Served on demand by the
|
|
15
|
+
* `how_it_works` MCP tool so every client (not just Claude Code, which
|
|
16
|
+
* auto-loads skills) can pull it. There's a guide PER MODE so an agent is never
|
|
17
|
+
* shown auth/publish tools that don't exist in its backend: the server picks
|
|
18
|
+
* one by `oldMode` (see `mcp/start.ts`). Same `../../skill/` path resolution as
|
|
19
|
+
* the instructions above; any leading frontmatter is stripped defensively.
|
|
20
|
+
*/
|
|
21
|
+
function readGuide(file) {
|
|
22
|
+
return readFileSync(fileURLToPath(new URL(file, import.meta.url)), 'utf8')
|
|
23
|
+
.replace(/^---\n[\s\S]*?\n---\n/, '')
|
|
24
|
+
.trim();
|
|
25
|
+
}
|
|
26
|
+
export const PROVIDER_GUIDE_BUILDER = readGuide('../../skill/SKILL.builder.md');
|
|
27
|
+
export const PROVIDER_GUIDE_OLD = readGuide('../../skill/SKILL.old.md');
|
package/lib/mcp/server.d.ts
CHANGED
|
@@ -5,16 +5,32 @@ export interface ToolDefinition {
|
|
|
5
5
|
description: string;
|
|
6
6
|
inputSchema: JSONSchema.ObjectSchema;
|
|
7
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* Passed to every tool handler alongside its parsed args. Long-running,
|
|
10
|
+
* human-in-the-loop tools (e.g. a browser login flow that waits for someone
|
|
11
|
+
* to sign in) should call `reportProgress` every few seconds while waiting.
|
|
12
|
+
* MCP clients that attach a progress token to their request (most desktop
|
|
13
|
+
* clients do) treat an incoming `notifications/progress` as proof the call
|
|
14
|
+
* is still alive and reset their own request timeout instead of giving up —
|
|
15
|
+
* the SDK's client-side default is 60s, far shorter than a human can be
|
|
16
|
+
* expected to take to log in. A no-op when the client didn't request
|
|
17
|
+
* progress tracking for this call.
|
|
18
|
+
*/
|
|
19
|
+
export interface ToolContext {
|
|
20
|
+
reportProgress: (message: string) => Promise<void>;
|
|
21
|
+
}
|
|
8
22
|
export interface RegisteredTool {
|
|
9
23
|
definition: ToolDefinition;
|
|
10
24
|
/**
|
|
11
25
|
* @param args Tool arguments
|
|
26
|
+
* @param ctx Progress-reporting context (see {@link ToolContext}).
|
|
27
|
+
* Optional so direct/test callers can omit it.
|
|
12
28
|
* @returns A JSON stringifiable content to be returned to the llm
|
|
13
29
|
* @throws Any error encountered during tool execution will be caught and
|
|
14
30
|
* returned as a response using
|
|
15
31
|
* [remapErrorAsResponse](./src/mcp/remap_errors.ts).
|
|
16
32
|
*/
|
|
17
|
-
handler: (args: unknown) => Promise<unknown>;
|
|
33
|
+
handler: (args: unknown, ctx?: ToolContext) => Promise<unknown>;
|
|
18
34
|
}
|
|
19
35
|
/**
|
|
20
36
|
* Define a tool with a single inputSchema (JSON Schema) used as the
|
|
@@ -23,7 +39,7 @@ export interface RegisteredTool {
|
|
|
23
39
|
* so the description sent to the MCP client and the validation applied
|
|
24
40
|
* to inbound args cannot drift.
|
|
25
41
|
*/
|
|
26
|
-
export declare function defineTool<TArgs>(definition: ToolDefinition, handler: (args: TArgs) => Promise<unknown>): RegisteredTool;
|
|
42
|
+
export declare function defineTool<TArgs>(definition: ToolDefinition, handler: (args: TArgs, ctx: ToolContext) => Promise<unknown>): RegisteredTool;
|
|
27
43
|
/**
|
|
28
44
|
* Registers a list of RegisteredTool entries on a high-level McpServer.
|
|
29
45
|
* Converts JSON Schema definitions to Zod and provides consistent
|
package/lib/mcp/server.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { toZod } from "./api/to-zod.js";
|
|
2
2
|
import { remapErrorAsResponse } from "./remap_errors.js";
|
|
3
|
+
const NOOP_CONTEXT = { reportProgress: async () => { } };
|
|
3
4
|
/**
|
|
4
5
|
* Define a tool with a single inputSchema (JSON Schema) used as the
|
|
5
6
|
* source of truth. The handler receives args already parsed and
|
|
@@ -11,9 +12,9 @@ export function defineTool(definition, handler) {
|
|
|
11
12
|
const schema = toZod(definition.inputSchema);
|
|
12
13
|
return {
|
|
13
14
|
definition,
|
|
14
|
-
handler: async (raw) => {
|
|
15
|
+
handler: async (raw, ctx = NOOP_CONTEXT) => {
|
|
15
16
|
const args = schema.parse(raw);
|
|
16
|
-
return await handler(args);
|
|
17
|
+
return await handler(args, ctx);
|
|
17
18
|
},
|
|
18
19
|
};
|
|
19
20
|
}
|
|
@@ -27,13 +28,27 @@ export function registerToolList(server, tools) {
|
|
|
27
28
|
server.registerTool(tool.definition.name, {
|
|
28
29
|
description: tool.definition.description,
|
|
29
30
|
inputSchema: toZod(tool.definition.inputSchema),
|
|
30
|
-
}, async (args) => {
|
|
31
|
+
}, async (args, extra) => {
|
|
31
32
|
try {
|
|
33
|
+
const progressToken = extra?._meta?.progressToken;
|
|
34
|
+
let progress = 0;
|
|
35
|
+
const ctx = {
|
|
36
|
+
reportProgress: async (message) => {
|
|
37
|
+
if (progressToken === undefined) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
progress += 1;
|
|
41
|
+
await extra.sendNotification({
|
|
42
|
+
method: 'notifications/progress',
|
|
43
|
+
params: { progressToken, progress, message },
|
|
44
|
+
}).catch(() => { });
|
|
45
|
+
},
|
|
46
|
+
};
|
|
32
47
|
return {
|
|
33
48
|
content: [
|
|
34
49
|
{
|
|
35
50
|
type: 'text',
|
|
36
|
-
text: JSON.stringify(await tool.handler(args), null, 2),
|
|
51
|
+
text: JSON.stringify(await tool.handler(args, ctx), null, 2),
|
|
37
52
|
},
|
|
38
53
|
],
|
|
39
54
|
};
|
package/lib/mcp/start.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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, useOldDevtools, } from "../consts.js";
|
|
4
|
+
import { agentDisabled, apiToken, apiUrl, oldApiUrl, oldLogsUrl, 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";
|
|
@@ -30,6 +30,7 @@ export async function startMcpServer() {
|
|
|
30
30
|
// get_me_providers instead.
|
|
31
31
|
const oldClient = new ReclaimOldClient({
|
|
32
32
|
baseUrl: oldApiUrl(),
|
|
33
|
+
logsBaseUrl: oldLogsUrl(),
|
|
33
34
|
identity: resolveInitialIdentity(),
|
|
34
35
|
});
|
|
35
36
|
registerToolList(server, buildLocalCredentialTools());
|
|
@@ -14,6 +14,7 @@ import { attachTool } from "./attach.js";
|
|
|
14
14
|
import { captureTools } from "./capture.js";
|
|
15
15
|
import { browserTools } from "./eval.js";
|
|
16
16
|
import { findTool } from "./find.js";
|
|
17
|
+
import { howItWorksTool } from "./how-it-works.js";
|
|
17
18
|
import { proofTool } from "./proof.js";
|
|
18
19
|
import { makeSecretStore, proposeTool, } from "./propose.js";
|
|
19
20
|
import { createVersionFromCaptureTool } from "./publish.js";
|
|
@@ -35,6 +36,9 @@ export function buildAgentTools(client) {
|
|
|
35
36
|
const state = buildAgentState();
|
|
36
37
|
ensureAttestorCrypto();
|
|
37
38
|
const tools = [];
|
|
39
|
+
// Stateless docs tool — serve the mode-specific authoring guide to any
|
|
40
|
+
// client. No `client` ⇒ old-devtools mode (see `mcp/start.ts`).
|
|
41
|
+
tools.push(howItWorksTool(!client));
|
|
38
42
|
tools.push(attachTool(state.attach));
|
|
39
43
|
for (const t of captureTools(state.attach, state.captures)) {
|
|
40
44
|
tools.push(t);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RegisteredTool } from '../../server.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Serves the full provider-authoring guide on demand. The MCP server's
|
|
4
|
+
* always-on `instructions` are a terse tool-flow reference; this tool returns
|
|
5
|
+
* the deep version (workflow, decision frameworks, gotchas, "never do" rules)
|
|
6
|
+
* so any MCP client — not just Claude Code, which alone auto-loads skills — can
|
|
7
|
+
* pull it. `oldMode` selects the backend-specific guide so the agent is never
|
|
8
|
+
* told to call auth/publish tools that aren't registered in its mode.
|
|
9
|
+
* Stateless: callable before `attach_chrome`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function howItWorksTool(oldMode: boolean): RegisteredTool;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { PROVIDER_GUIDE_BUILDER, PROVIDER_GUIDE_OLD, } from "../../instructions.js";
|
|
2
|
+
import { defineTool } from "../../server.js";
|
|
3
|
+
/**
|
|
4
|
+
* Serves the full provider-authoring guide on demand. The MCP server's
|
|
5
|
+
* always-on `instructions` are a terse tool-flow reference; this tool returns
|
|
6
|
+
* the deep version (workflow, decision frameworks, gotchas, "never do" rules)
|
|
7
|
+
* so any MCP client — not just Claude Code, which alone auto-loads skills — can
|
|
8
|
+
* pull it. `oldMode` selects the backend-specific guide so the agent is never
|
|
9
|
+
* told to call auth/publish tools that aren't registered in its mode.
|
|
10
|
+
* Stateless: callable before `attach_chrome`.
|
|
11
|
+
*/
|
|
12
|
+
export function howItWorksTool(oldMode) {
|
|
13
|
+
const guide = oldMode ? PROVIDER_GUIDE_OLD : PROVIDER_GUIDE_BUILDER;
|
|
14
|
+
return defineTool({
|
|
15
|
+
name: 'how_it_works',
|
|
16
|
+
description: 'Return the full Reclaim provider-authoring guide for THIS server: '
|
|
17
|
+
+ 'the capture → draft → replay → prove → publish workflow, decision '
|
|
18
|
+
+ 'frameworks (login detection, OPRF privacy, context vs bare params), '
|
|
19
|
+
+ 'multi-request handling, troubleshooting, and what never to do. '
|
|
20
|
+
+ 'Call this BEFORE building a provider unless you are already '
|
|
21
|
+
+ 'fluent in the flow.',
|
|
22
|
+
inputSchema: { type: 'object', properties: {} },
|
|
23
|
+
}, async () => ({ guide }));
|
|
24
|
+
}
|
|
@@ -89,7 +89,7 @@ const ALLOWED_JS_REQUEST_SCHEMA = {
|
|
|
89
89
|
export function createVersionFromCaptureTool(client) {
|
|
90
90
|
return defineTool({
|
|
91
91
|
name: 'create_provider_version_from_capture',
|
|
92
|
-
description: 'Persist drafted ReclaimProvider(s) as a
|
|
92
|
+
description: 'Persist drafted ReclaimProvider(s) as a provider version. ' +
|
|
93
93
|
'Call this after run_proof succeeds, passing the `provider` ' +
|
|
94
94
|
'object(s) from propose_provider VERBATIM. This tool builds the ' +
|
|
95
95
|
'body (the requests[] array, webSettings, etc.) for you — do NOT ' +
|
|
@@ -120,7 +120,7 @@ export function createVersionFromCaptureTool(client) {
|
|
|
120
120
|
properties: {
|
|
121
121
|
providerId: {
|
|
122
122
|
type: 'string',
|
|
123
|
-
description: 'UUID of the
|
|
123
|
+
description: 'UUID of the provider to publish the version on.',
|
|
124
124
|
},
|
|
125
125
|
provider: PROVIDER_SCHEMA,
|
|
126
126
|
providers: {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RegisteredTool } from '../../server.ts';
|
|
2
|
+
import type { CaptureStore } from './capture.ts';
|
|
3
|
+
/** The shared authoring tools as MCP `RegisteredTool`s: each resolves its
|
|
4
|
+
* capture's local backend from `args.captureId`; the schema carries
|
|
5
|
+
* `captureId` plus the rich `run_proof` contract. */
|
|
6
|
+
export declare function sharedAuthoringTools(captures: CaptureStore): RegisteredTool[];
|