@reclaimprotocol/agent 0.1.10 → 0.1.12
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/lib/authoring/tools.js +67 -0
- package/lib/mcp/tools/agent/find.js +41 -16
- package/lib/mcp/tools/agent/propose.js +4 -4
- package/lib/old/client.d.ts +31 -5
- package/lib/old/client.js +33 -10
- package/lib/old/to-register.d.ts +2 -0
- package/lib/old/to-register.js +9 -5
- package/lib/old/tools/build.js +12 -2
- package/lib/old/tools/check-app-status.d.ts +8 -0
- package/lib/old/tools/check-app-status.js +27 -0
- package/lib/old/tools/get-provider-info.d.ts +10 -7
- package/lib/old/tools/get-provider-info.js +21 -15
- package/lib/old/tools/issue-app-credentials.d.ts +11 -0
- package/lib/old/tools/issue-app-credentials.js +35 -0
- package/lib/old/tools/js-sdk-integration-guide.d.ts +2 -0
- package/lib/old/tools/js-sdk-integration-guide.js +141 -0
- package/lib/old/tools/link-app.d.ts +10 -0
- package/lib/old/tools/link-app.js +72 -0
- package/lib/old/tools/publish.js +89 -126
- package/lib/old/tools/scaffold-demo-server.d.ts +2 -0
- package/lib/old/tools/scaffold-demo-server.js +242 -0
- package/lib/old/tools/verify-sdk-setup.d.ts +9 -0
- package/lib/old/tools/verify-sdk-setup.js +128 -0
- package/lib/provider/dom-xpath.js +178 -25
- package/lib/provider/draft.d.ts +6 -0
- package/lib/provider/draft.js +54 -5
- package/lib/provider/matcher.d.ts +4 -0
- package/lib/provider/matcher.js +6 -0
- package/lib/provider/to-version.d.ts +13 -0
- package/package.json +2 -1
- package/src/authoring/tools.ts +76 -0
- package/src/mcp/tools/agent/find.ts +44 -16
- package/src/mcp/tools/agent/propose.ts +4 -4
- package/src/old/client.ts +60 -18
- package/src/old/to-register.ts +11 -5
- package/src/old/tools/build.ts +12 -2
- package/src/old/tools/check-app-status.ts +33 -0
- package/src/old/tools/get-provider-info.ts +21 -15
- package/src/old/tools/issue-app-credentials.ts +42 -0
- package/src/old/tools/js-sdk-integration-guide.ts +147 -0
- package/src/old/tools/link-app.ts +88 -0
- package/src/old/tools/publish.ts +98 -158
- package/src/old/tools/scaffold-demo-server.ts +265 -0
- package/src/old/tools/verify-sdk-setup.ts +158 -0
- package/src/provider/dom-xpath.ts +227 -27
- package/src/provider/draft.ts +59 -5
- package/src/provider/matcher.ts +7 -0
- package/src/provider/to-version.ts +13 -0
- package/src/old/tools/get-version-config.ts +0 -56
package/lib/authoring/tools.js
CHANGED
|
@@ -135,6 +135,73 @@ export function authoringTools(resolveBackend) {
|
|
|
135
135
|
...(c.httpOnly ? { httpOnly: true } : {}),
|
|
136
136
|
}));
|
|
137
137
|
}),
|
|
138
|
+
defineTool({
|
|
139
|
+
name: 'wait_for_login',
|
|
140
|
+
description: 'Wait for the user to finish logging in. Polls the browser\'s '
|
|
141
|
+
+ 'REAL cookies over CDP (httpOnly INCLUDED) until a NEW session '
|
|
142
|
+
+ 'cookie appears, ignoring analytics/bot cookies. The ONLY '
|
|
143
|
+
+ 'correct login wait — NEVER use wait_for_page for it: page JS '
|
|
144
|
+
+ 'can\'t see the httpOnly session cookie (hangs the whole '
|
|
145
|
+
+ 'timeout), yet DOES see pre-login tracking cookies (a '
|
|
146
|
+
+ 'length/substring check fires instantly, before the user '
|
|
147
|
+
+ 'types). Snapshots the baseline itself — call right after '
|
|
148
|
+
+ 'navigating to the login page. Does NOT navigate (never yanks '
|
|
149
|
+
+ 'the user off login/2FA). Returns { loggedIn, newCookies }.',
|
|
150
|
+
inputSchema: objectSchema({ timeoutMs: { type: 'number' } }),
|
|
151
|
+
}, async (args) => {
|
|
152
|
+
const backend = resolveBackend(args);
|
|
153
|
+
const deadline = Date.now() + (Number(args.timeoutMs) || 180000);
|
|
154
|
+
const cookies = async () => {
|
|
155
|
+
const res = (await backend.sendCdp('Network.getCookies'));
|
|
156
|
+
return res.cookies ?? [];
|
|
157
|
+
};
|
|
158
|
+
// Analytics / bot-protection / pre-auth infra cookies appear (and
|
|
159
|
+
// rotate) without any login — never the signal, even when new.
|
|
160
|
+
const JUNK = new RegExp('^(' + [
|
|
161
|
+
'_ga', '_gid', '_gat', '_ym', '__ddg', '__gads', '__gpi', '__eoi',
|
|
162
|
+
'__utm', '_fbp', 'fbp', 'fr', 'FCCDCF', 'pinLogger',
|
|
163
|
+
'userFirstVisit', 'cf_', '_dd_', 'bcookie', 'bscookie', 'lidc',
|
|
164
|
+
].join('|') + ')', 'i');
|
|
165
|
+
// A real session/auth cookie name. Deliberately NOT bare `token` — a
|
|
166
|
+
// challenge/CSRF token (e.g. LinkedIn `chp_token`) contains it and is
|
|
167
|
+
// set BEFORE auth completes. Any new httpOnly cookie is also a
|
|
168
|
+
// candidate (server-set session cookies are usually httpOnly).
|
|
169
|
+
const SESSION = /sess|sid|jwt|_session|auth|logged.?in|remember|li_at/i;
|
|
170
|
+
// Auth/challenge URL paths — while the page is still on one, login is
|
|
171
|
+
// NOT done (a mid-flow cookie must not count). Cross-site-stable, far
|
|
172
|
+
// more so than cookie names.
|
|
173
|
+
const AUTH_URL = new RegExp([
|
|
174
|
+
'login', 'signin', 'sign-in', 'challenge', 'checkpoint', '\\buas\\b',
|
|
175
|
+
'authorize', '\\bsso\\b', 'mfa', '2fa', 'two-factor', 'otp', 'verify',
|
|
176
|
+
'password',
|
|
177
|
+
].join('|'), 'i');
|
|
178
|
+
const offAuthUrl = async () => {
|
|
179
|
+
const { value } = await evalInPage(backend, 'location.href');
|
|
180
|
+
const href = typeof value === 'string' ? value : '';
|
|
181
|
+
try {
|
|
182
|
+
const u = new URL(href);
|
|
183
|
+
return !AUTH_URL.test(u.pathname + u.search);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const initial = await cookies();
|
|
190
|
+
const baseline = new Set(initial.map((c) => c.name));
|
|
191
|
+
while (Date.now() < deadline) {
|
|
192
|
+
const current = await cookies();
|
|
193
|
+
const fresh = current
|
|
194
|
+
.filter((c) => !baseline.has(c.name) && !JUNK.test(c.name));
|
|
195
|
+
const hit = fresh.filter((c) => c.httpOnly || SESSION.test(c.name));
|
|
196
|
+
// BOTH required: a new session cookie AND the page has left the auth
|
|
197
|
+
// flow. Either alone false-positives (mid-flow token; stray nav).
|
|
198
|
+
if (hit.length && await offAuthUrl()) {
|
|
199
|
+
return { loggedIn: true, newCookies: hit.map((c) => c.name) };
|
|
200
|
+
}
|
|
201
|
+
await sleep(1000);
|
|
202
|
+
}
|
|
203
|
+
return { loggedIn: false, newCookies: [] };
|
|
204
|
+
}),
|
|
138
205
|
defineTool({
|
|
139
206
|
name: 'list_requests',
|
|
140
207
|
description: 'List captured network requests (method/url/status/size), newest '
|
|
@@ -14,38 +14,63 @@ export function findTool(resolveBackend) {
|
|
|
14
14
|
description: 'Search captured responses for any encoding of `value` (raw, '
|
|
15
15
|
+ 'URL/JSON/HTML-escaped, …). Returns a ranked candidate list with '
|
|
16
16
|
+ 'the matched variant, score, and a short snippet — used to locate '
|
|
17
|
-
+ 'the request that returns a target.
|
|
17
|
+
+ 'the request that returns a target. Also finds SPLIT matches: when '
|
|
18
|
+
+ '`value` is multi-word (e.g. a full name), a response that carries '
|
|
19
|
+
+ 'every word SEPARATELY (a JSON profile API with first/last name in '
|
|
20
|
+
+ 'distinct fields) is returned with `splitMatch:true` — prove those '
|
|
21
|
+
+ 'per-field (a redaction per part) rather than as one string. '
|
|
22
|
+
+ 'Server-side; bodies stay here.',
|
|
18
23
|
inputSchema: objectSchema({ value: { type: 'string' }, limit: { type: 'number' } }, ['value']),
|
|
19
24
|
}, async (args) => {
|
|
20
25
|
const backend = resolveBackend(args);
|
|
21
|
-
const
|
|
26
|
+
const value = String(args.value);
|
|
27
|
+
const variants = normalizeCandidates(value);
|
|
28
|
+
// Name-part tokens (≥3 chars) for split-field detection — a JSON API
|
|
29
|
+
// often carries a full name as separate first/last fields, so the whole
|
|
30
|
+
// string never matches even though the value IS there.
|
|
31
|
+
const tokens = value.split(/\s+/).filter((t) => t.length >= 3);
|
|
32
|
+
const snip = (body, idx, len) => {
|
|
33
|
+
const s = Math.max(0, idx - 40);
|
|
34
|
+
return body.slice(s, Math.min(body.length, idx + len + 40));
|
|
35
|
+
};
|
|
22
36
|
const ranked = [];
|
|
23
37
|
for (const r of backend.capture.requests.values()) {
|
|
24
38
|
if (!r.responseBody) {
|
|
25
39
|
continue;
|
|
26
40
|
}
|
|
41
|
+
const body = r.responseBody;
|
|
42
|
+
// Prefer JSON responses + smaller bodies (likely API endpoints).
|
|
43
|
+
const base = (r.contentType.includes('json') ? 10 : 0)
|
|
44
|
+
+ Math.max(0, 5 - Math.log10(Math.max(r.size, 1)));
|
|
27
45
|
let hit;
|
|
28
46
|
for (const v of variants) {
|
|
29
|
-
const idx =
|
|
47
|
+
const idx = body.indexOf(v);
|
|
30
48
|
if (idx >= 0) {
|
|
31
|
-
|
|
32
|
-
const end = Math.min(r.responseBody.length, idx + v.length + 40);
|
|
33
|
-
hit = { snippet: r.responseBody.slice(start, end), variant: v };
|
|
49
|
+
hit = { snippet: snip(body, idx, v.length), variant: v };
|
|
34
50
|
break;
|
|
35
51
|
}
|
|
36
52
|
}
|
|
37
|
-
if (
|
|
53
|
+
if (hit) {
|
|
54
|
+
// Whole-value match — ranked above split matches (+5).
|
|
55
|
+
ranked.push({
|
|
56
|
+
...publicRequest(r),
|
|
57
|
+
matchedVariant: hit.variant,
|
|
58
|
+
snippet: hit.snippet,
|
|
59
|
+
score: base + 5,
|
|
60
|
+
});
|
|
38
61
|
continue;
|
|
39
62
|
}
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
// Split match: every word present separately (e.g. first/last name
|
|
64
|
+
// in distinct JSON fields). Requires ≥2 tokens so it's specific.
|
|
65
|
+
if (tokens.length >= 2 && tokens.every((t) => body.includes(t))) {
|
|
66
|
+
ranked.push({
|
|
67
|
+
...publicRequest(r),
|
|
68
|
+
matchedVariant: `split:${tokens.join('+')}`,
|
|
69
|
+
splitMatch: true,
|
|
70
|
+
snippet: snip(body, body.indexOf(tokens[0]), tokens[0].length),
|
|
71
|
+
score: base,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
49
74
|
}
|
|
50
75
|
ranked.sort((a, b) => b.score - a.score);
|
|
51
76
|
const limit = Number(args.limit) || 10;
|
|
@@ -71,11 +71,11 @@ export function proposeTool(resolveBackend) {
|
|
|
71
71
|
+ '`targets` array');
|
|
72
72
|
}
|
|
73
73
|
for (const t of targets) {
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const bytes = Buffer.byteLength(t.value, 'utf8');
|
|
75
|
+
if ((t.hash ?? defaultHash) !== undefined && bytes > OPRF_MAX_BYTES) {
|
|
76
76
|
throw new Error(`OPRF caps hashed values at ${OPRF_MAX_BYTES} bytes; got `
|
|
77
|
-
+ `${
|
|
78
|
-
+ '
|
|
77
|
+
+ `${bytes}-byte "${t.value}". Use a tighter target or drop `
|
|
78
|
+
+ '`hash`.');
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
const captured = backend.capture.requests.get(requestId);
|
package/lib/old/client.d.ts
CHANGED
|
@@ -71,6 +71,20 @@ export interface MyProvidersQuery {
|
|
|
71
71
|
pageSize?: number;
|
|
72
72
|
searchQuery?: string;
|
|
73
73
|
}
|
|
74
|
+
/** `POST /api/applications/issue-credentials` response — a brand-new,
|
|
75
|
+
* unassociated (sandboxed) app. `appSecret` is the raw eth private key;
|
|
76
|
+
* it's returned once and never stored server-side in recoverable form. */
|
|
77
|
+
export interface IssuedAppCredentials {
|
|
78
|
+
appId: string;
|
|
79
|
+
appSecret: string;
|
|
80
|
+
}
|
|
81
|
+
/** `GET /api/applications/link/nonce` response — a one-time, 5-minute-TTL
|
|
82
|
+
* challenge the caller signs with the app's private key to prove ownership
|
|
83
|
+
* in `linkAppToAccount`. */
|
|
84
|
+
export interface LinkNonce {
|
|
85
|
+
nonce: string;
|
|
86
|
+
expiresInSeconds: number;
|
|
87
|
+
}
|
|
74
88
|
/**
|
|
75
89
|
* Minimal REST client for the OLD devtools Express backend (base `/api`).
|
|
76
90
|
* Deliberately NOT a clone of `@reclaimprotocol/client`'s operationId
|
|
@@ -99,11 +113,6 @@ export declare class ReclaimOldClient {
|
|
|
99
113
|
registerProvider(body: RegisterProviderBody): Promise<unknown>;
|
|
100
114
|
updateProviderConfig(providerId: string, body: UpdateProviderConfigBody): Promise<unknown>;
|
|
101
115
|
listVersions(providerId: string): Promise<unknown>;
|
|
102
|
-
/** Full `providerConfig` (loginUrl, customInjection, requestData, ...) for
|
|
103
|
-
* one version — the latest when `version` is omitted. Readable for ANY
|
|
104
|
-
* non-archived provider (not owner-restricted), same as the dashboard's
|
|
105
|
-
* edit-form prefill fetch. */
|
|
106
|
-
getProviderConfig(providerId: string, version?: string): Promise<unknown>;
|
|
107
116
|
/** Partial update on the PROVIDER document itself — name/description/
|
|
108
117
|
* providerType/tags/isActive, after creation. The backend 403s if you
|
|
109
118
|
* don't own the provider (and aren't admin); other providerConfig-style
|
|
@@ -115,5 +124,22 @@ export declare class ReclaimOldClient {
|
|
|
115
124
|
* `#request`). Attaches the caller identity when one is set; queried
|
|
116
125
|
* anonymously otherwise. */
|
|
117
126
|
getSessionAnalyticsLogs(sessionId: string): Promise<unknown>;
|
|
127
|
+
/** Mint a brand-new, unassociated (sandboxed) app — no auth required. Link
|
|
128
|
+
* it to an account afterwards with `getLinkNonce` + `linkAppToAccount`, or
|
|
129
|
+
* use it as-is within the sandbox session limit. */
|
|
130
|
+
issueCredentials(): Promise<IssuedAppCredentials>;
|
|
131
|
+
/** One-time, 5-minute challenge for `linkAppToAccount`. Requires auth —
|
|
132
|
+
* the nonce is scoped to the authenticated user's uid. */
|
|
133
|
+
getLinkNonce(): Promise<LinkNonce>;
|
|
134
|
+
/** Link an unassociated (`issueCredentials`-minted) app to the
|
|
135
|
+
* authenticated account. `signature` must be an EIP-191 signature, made
|
|
136
|
+
* with the app's private key, over the exact string
|
|
137
|
+
* `` `Link ${appId} to account ${userId} | nonce: ${nonce}` `` — see
|
|
138
|
+
* `buildLinkMessage` in the backend's `application.controller.ts`. Fails
|
|
139
|
+
* with `APP_ALREADY_LINKED` (400) if the app already belongs to someone. */
|
|
140
|
+
linkAppToAccount(appId: string, signature: string, nonce: string): Promise<unknown>;
|
|
141
|
+
/** Public, unauthenticated app status — `isLinked`, sandbox/quota info.
|
|
142
|
+
* Works for any appId, owned or not. */
|
|
143
|
+
getApplicationStatus(appId: string): Promise<unknown>;
|
|
118
144
|
getMyProviders(query?: MyProvidersQuery): Promise<unknown>;
|
|
119
145
|
}
|
package/lib/old/client.js
CHANGED
|
@@ -60,16 +60,6 @@ export class ReclaimOldClient {
|
|
|
60
60
|
listVersions(providerId) {
|
|
61
61
|
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/versions`, { auth: true });
|
|
62
62
|
}
|
|
63
|
-
/** Full `providerConfig` (loginUrl, customInjection, requestData, ...) for
|
|
64
|
-
* one version — the latest when `version` is omitted. Readable for ANY
|
|
65
|
-
* non-archived provider (not owner-restricted), same as the dashboard's
|
|
66
|
-
* edit-form prefill fetch. */
|
|
67
|
-
getProviderConfig(providerId, version) {
|
|
68
|
-
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/providers/${encodeURIComponent(providerId)}/config`, {
|
|
69
|
-
auth: true,
|
|
70
|
-
query: version ? { versionNumber: version } : undefined,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
63
|
/** Partial update on the PROVIDER document itself — name/description/
|
|
74
64
|
* providerType/tags/isActive, after creation. The backend 403s if you
|
|
75
65
|
* don't own the provider (and aren't admin); other providerConfig-style
|
|
@@ -99,6 +89,39 @@ export class ReclaimOldClient {
|
|
|
99
89
|
}
|
|
100
90
|
return json;
|
|
101
91
|
}
|
|
92
|
+
/** Mint a brand-new, unassociated (sandboxed) app — no auth required. Link
|
|
93
|
+
* it to an account afterwards with `getLinkNonce` + `linkAppToAccount`, or
|
|
94
|
+
* use it as-is within the sandbox session limit. */
|
|
95
|
+
async issueCredentials() {
|
|
96
|
+
const res = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/applications/issue-credentials');
|
|
97
|
+
return res.data;
|
|
98
|
+
}
|
|
99
|
+
/** One-time, 5-minute challenge for `linkAppToAccount`. Requires auth —
|
|
100
|
+
* the nonce is scoped to the authenticated user's uid. */
|
|
101
|
+
async getLinkNonce() {
|
|
102
|
+
const res = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', '/applications/link/nonce', {
|
|
103
|
+
auth: true,
|
|
104
|
+
});
|
|
105
|
+
return res.data;
|
|
106
|
+
}
|
|
107
|
+
/** Link an unassociated (`issueCredentials`-minted) app to the
|
|
108
|
+
* authenticated account. `signature` must be an EIP-191 signature, made
|
|
109
|
+
* with the app's private key, over the exact string
|
|
110
|
+
* `` `Link ${appId} to account ${userId} | nonce: ${nonce}` `` — see
|
|
111
|
+
* `buildLinkMessage` in the backend's `application.controller.ts`. Fails
|
|
112
|
+
* with `APP_ALREADY_LINKED` (400) if the app already belongs to someone. */
|
|
113
|
+
linkAppToAccount(appId, signature, nonce) {
|
|
114
|
+
return __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'POST', '/applications/link', {
|
|
115
|
+
body: { appId, signature, nonce },
|
|
116
|
+
auth: true,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
/** Public, unauthenticated app status — `isLinked`, sandbox/quota info.
|
|
120
|
+
* Works for any appId, owned or not. */
|
|
121
|
+
async getApplicationStatus(appId) {
|
|
122
|
+
const res = await __classPrivateFieldGet(this, _ReclaimOldClient_instances, "m", _ReclaimOldClient_request).call(this, 'GET', `/applications/status/${encodeURIComponent(appId)}`);
|
|
123
|
+
return res.data;
|
|
124
|
+
}
|
|
102
125
|
getMyProviders(query = {}) {
|
|
103
126
|
// Every one of these query params is REQUIRED by the backend
|
|
104
127
|
// validator (missing/invalid → 400), so default them all here.
|
package/lib/old/to-register.d.ts
CHANGED
|
@@ -83,6 +83,8 @@ interface OldRequestData {
|
|
|
83
83
|
export interface OldInjectedRequestData extends OldRequestData {
|
|
84
84
|
required?: boolean;
|
|
85
85
|
multiple?: boolean;
|
|
86
|
+
templateParams?: string[];
|
|
87
|
+
templateParamsMode?: 'separate' | 'merge';
|
|
86
88
|
}
|
|
87
89
|
/** Translate fresh `allowedInjectedRequestData` drafts (the author's input
|
|
88
90
|
* shape, `AllowedJsRequest[]` — same shape the builder translator uses for
|
package/lib/old/to-register.js
CHANGED
|
@@ -89,11 +89,15 @@ function requestDataFrom(providers) {
|
|
|
89
89
|
* this shape and should be passed straight through instead — don't run it
|
|
90
90
|
* through this a second time. */
|
|
91
91
|
export function injectedRequestDataFrom(requests) {
|
|
92
|
-
return requests.map((req) =>
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
92
|
+
return requests.map((req) => {
|
|
93
|
+
return {
|
|
94
|
+
...requestDataFromProvider(req),
|
|
95
|
+
required: req.required ?? true,
|
|
96
|
+
multiple: req.multiple ?? true,
|
|
97
|
+
templateParams: req.templateParams,
|
|
98
|
+
templateParamsMode: req.templateParamsMode,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
97
101
|
}
|
|
98
102
|
/** Body for `POST /api/providers/register` — new provider + v1.0.0. Every
|
|
99
103
|
* drafted request becomes a `requestData` entry; provider-level fields (name)
|
package/lib/old/tools/build.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { authenticateTool } from "./authenticate.js";
|
|
2
|
+
import { checkAppStatusTool } from "./check-app-status.js";
|
|
2
3
|
import { getProviderInfoTool } from "./get-provider-info.js";
|
|
3
|
-
import {
|
|
4
|
+
import { issueAppCredentialsTool } from "./issue-app-credentials.js";
|
|
5
|
+
import { getJsSdkIntegrationGuideTool } from "./js-sdk-integration-guide.js";
|
|
6
|
+
import { linkAppTool } from "./link-app.js";
|
|
4
7
|
import { getMeProvidersTool } from "./me-providers.js";
|
|
5
8
|
import { createVersionFromCaptureTool } from "./publish.js";
|
|
9
|
+
import { scaffoldDemoServerTool } from "./scaffold-demo-server.js";
|
|
6
10
|
import { sessionAnalyticsLogsTool } from "./session-analytics-logs.js";
|
|
7
11
|
import { updateProviderMetadataTool } from "./update-provider-metadata.js";
|
|
12
|
+
import { verifySdkSetupTool } from "./verify-sdk-setup.js";
|
|
8
13
|
/**
|
|
9
14
|
* The backend-facing tools for OLD-devtools mode. Mirrors
|
|
10
15
|
* `buildCredentialTools` / `buildAgentTools`: returns a flat `RegisteredTool`
|
|
@@ -20,9 +25,14 @@ export function buildOldBackendTools(client, sdkClient) {
|
|
|
20
25
|
authenticateTool(client),
|
|
21
26
|
createVersionFromCaptureTool(client),
|
|
22
27
|
getMeProvidersTool(client),
|
|
23
|
-
getProviderVersionConfigTool(client),
|
|
24
28
|
getProviderInfoTool(sdkClient),
|
|
25
29
|
updateProviderMetadataTool(client),
|
|
26
30
|
sessionAnalyticsLogsTool(client),
|
|
31
|
+
issueAppCredentialsTool(client),
|
|
32
|
+
linkAppTool(client),
|
|
33
|
+
checkAppStatusTool(client),
|
|
34
|
+
getJsSdkIntegrationGuideTool(),
|
|
35
|
+
scaffoldDemoServerTool(),
|
|
36
|
+
verifySdkSetupTool(client),
|
|
27
37
|
];
|
|
28
38
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type RegisteredTool } from '../../mcp/server.ts';
|
|
2
|
+
import type { ReclaimOldClient } from '../client.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Public, unauthenticated app status lookup — works for any `appId`, owned
|
|
5
|
+
* or not, linked or sandboxed. Mirrors the backend's
|
|
6
|
+
* `GET /api/applications/status/:appId`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function checkAppStatusTool(client: ReclaimOldClient): RegisteredTool;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { defineTool } from "../../mcp/server.js";
|
|
2
|
+
/**
|
|
3
|
+
* Public, unauthenticated app status lookup — works for any `appId`, owned
|
|
4
|
+
* or not, linked or sandboxed. Mirrors the backend's
|
|
5
|
+
* `GET /api/applications/status/:appId`.
|
|
6
|
+
*/
|
|
7
|
+
export function checkAppStatusTool(client) {
|
|
8
|
+
return defineTool({
|
|
9
|
+
name: 'check_app_status',
|
|
10
|
+
description: 'Check a Reclaim app\'s link/sandbox status by appId — no ' +
|
|
11
|
+
'authentication required. Returns whether the app is linked to a ' +
|
|
12
|
+
'dashboard account (`isLinked`), and for linked apps, remaining ' +
|
|
13
|
+
'session quota. A 404 means the appId has never been used yet — ' +
|
|
14
|
+
'it is created lazily on the first ReclaimProofRequest.init() call ' +
|
|
15
|
+
'or via issue_app_credentials.',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
appId: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'The eth-address appId to check.',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
required: ['appId'],
|
|
25
|
+
},
|
|
26
|
+
}, async ({ appId }) => client.getApplicationStatus(appId));
|
|
27
|
+
}
|
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { type RegisteredTool } from '../../mcp/server.ts';
|
|
2
2
|
import type { ReclaimSdkClient } from '../sdk-client.ts';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
* (`api.reclaimprotocol.org`) — the service the
|
|
6
|
-
* itself calls at runtime
|
|
7
|
-
*
|
|
8
|
-
* auth). Both underlying reads are unauthenticated.
|
|
4
|
+
* The single provider-read tool for old-devtools mode. Reads from the PUBLIC
|
|
5
|
+
* production SDK backend (`api.reclaimprotocol.org`) — the service the
|
|
6
|
+
* verification SDK/attestor itself calls at runtime. No auth required, works
|
|
7
|
+
* for ANY provider.
|
|
9
8
|
*
|
|
10
|
-
* Fetches BOTH shapes in one call, since they're complementary
|
|
11
|
-
*
|
|
9
|
+
* Fetches BOTH shapes in one call, since they're complementary and together
|
|
10
|
+
* cover everything a caller needs before re-publishing a new version:
|
|
11
|
+
* - `provider`: the full provider + providerConfig — `customInjection`,
|
|
12
|
+
* `userAgent`, `allowedInjectedRequestData`, `requestData`, everything.
|
|
13
|
+
* This is what you read before create_provider_version_from_capture so
|
|
14
|
+
* you can pass the whole config back (that tool carries nothing forward).
|
|
12
15
|
* - `configs`: the trimmed runtime recipe the attestor actually consumes —
|
|
13
16
|
* `customInjection` deliberately omitted, `isScriptRequestingClaim`
|
|
14
17
|
* computed instead.
|
|
@@ -13,14 +13,17 @@ async function attempt(label, call) {
|
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
17
|
-
* (`api.reclaimprotocol.org`) — the service the
|
|
18
|
-
* itself calls at runtime
|
|
19
|
-
*
|
|
20
|
-
* auth). Both underlying reads are unauthenticated.
|
|
16
|
+
* The single provider-read tool for old-devtools mode. Reads from the PUBLIC
|
|
17
|
+
* production SDK backend (`api.reclaimprotocol.org`) — the service the
|
|
18
|
+
* verification SDK/attestor itself calls at runtime. No auth required, works
|
|
19
|
+
* for ANY provider.
|
|
21
20
|
*
|
|
22
|
-
* Fetches BOTH shapes in one call, since they're complementary
|
|
23
|
-
*
|
|
21
|
+
* Fetches BOTH shapes in one call, since they're complementary and together
|
|
22
|
+
* cover everything a caller needs before re-publishing a new version:
|
|
23
|
+
* - `provider`: the full provider + providerConfig — `customInjection`,
|
|
24
|
+
* `userAgent`, `allowedInjectedRequestData`, `requestData`, everything.
|
|
25
|
+
* This is what you read before create_provider_version_from_capture so
|
|
26
|
+
* you can pass the whole config back (that tool carries nothing forward).
|
|
24
27
|
* - `configs`: the trimmed runtime recipe the attestor actually consumes —
|
|
25
28
|
* `customInjection` deliberately omitted, `isScriptRequestingClaim`
|
|
26
29
|
* computed instead.
|
|
@@ -31,15 +34,18 @@ export function getProviderInfoTool(client) {
|
|
|
31
34
|
description: 'Read a PUBLISHED provider from the public production SDK backend ' +
|
|
32
35
|
'(api.reclaimprotocol.org — what the verification SDK/attestor ' +
|
|
33
36
|
'itself fetches at runtime), for ANY provider, no auth required. ' +
|
|
34
|
-
'
|
|
35
|
-
'devtools DASHBOARD backend and requires auth. \n\n' +
|
|
37
|
+
'This is the provider-read tool for old-devtools mode. \n\n' +
|
|
36
38
|
'Returns two complementary reads for the given version (latest ' +
|
|
37
|
-
'when `versionNumber` is omitted): `provider` (the
|
|
38
|
-
'+ providerConfig
|
|
39
|
-
'
|
|
40
|
-
'
|
|
41
|
-
'`
|
|
42
|
-
'
|
|
39
|
+
'when `versionNumber` is omitted): `provider` (the FULL provider ' +
|
|
40
|
+
'+ providerConfig — `customInjection`, `userAgent`, ' +
|
|
41
|
+
'`allowedInjectedRequestData`, `requestData`, everything) and ' +
|
|
42
|
+
'`configs` (the trimmed recipe the attestor actually consumes — ' +
|
|
43
|
+
'`customInjection` is deliberately OMITTED there, replaced by a ' +
|
|
44
|
+
'computed `isScriptRequestingClaim` flag). Read `provider` here ' +
|
|
45
|
+
'BEFORE create_provider_version_from_capture so you can pass the ' +
|
|
46
|
+
'whole existing config back — that tool always creates a new ' +
|
|
47
|
+
'version and carries nothing forward. One endpoint failing (e.g. ' +
|
|
48
|
+
'an invalid `versionNumber`) is reported under `errors` without ' +
|
|
43
49
|
'hiding a result the other endpoint did return.',
|
|
44
50
|
inputSchema: {
|
|
45
51
|
type: 'object',
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RegisteredTool } from '../../mcp/server.ts';
|
|
2
|
+
import type { ReclaimOldClient } from '../client.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Mint a brand-new eth-keypair APP (as opposed to authenticating as a
|
|
5
|
+
* dashboard user). `appId` is the eth address, `appSecret` the raw private
|
|
6
|
+
* key — this is the pair `@reclaimprotocol/js-sdk`'s `ReclaimProofRequest.init`
|
|
7
|
+
* expects. No auth required: the app starts unassociated (`creatorUid: null`)
|
|
8
|
+
* and sandboxed (`sandboxLimit: 100` sessions). Use `link_app_to_account` to
|
|
9
|
+
* attach it to your dashboard account, or `check_app_status` to inspect it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function issueAppCredentialsTool(client: ReclaimOldClient): RegisteredTool;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { defineTool } from "../../mcp/server.js";
|
|
2
|
+
/**
|
|
3
|
+
* Mint a brand-new eth-keypair APP (as opposed to authenticating as a
|
|
4
|
+
* dashboard user). `appId` is the eth address, `appSecret` the raw private
|
|
5
|
+
* key — this is the pair `@reclaimprotocol/js-sdk`'s `ReclaimProofRequest.init`
|
|
6
|
+
* expects. No auth required: the app starts unassociated (`creatorUid: null`)
|
|
7
|
+
* and sandboxed (`sandboxLimit: 100` sessions). Use `link_app_to_account` to
|
|
8
|
+
* attach it to your dashboard account, or `check_app_status` to inspect it.
|
|
9
|
+
*/
|
|
10
|
+
export function issueAppCredentialsTool(client) {
|
|
11
|
+
return defineTool({
|
|
12
|
+
name: 'issue_app_credentials',
|
|
13
|
+
description: 'Mint a new Reclaim APP (eth keypair) on the old devtools backend — ' +
|
|
14
|
+
'no authentication required. Returns `{ appId, appSecret }`: ' +
|
|
15
|
+
'`appId` is the eth address, `appSecret` the raw private key. This ' +
|
|
16
|
+
'is the appId/appSecret pair for @reclaimprotocol/js-sdk ' +
|
|
17
|
+
'(`ReclaimProofRequest.init(appId, appSecret, providerId)`). The app ' +
|
|
18
|
+
'starts UNLINKED and sandboxed (100 sessions) — call ' +
|
|
19
|
+
'link_app_to_account to attach it to your dashboard account and ' +
|
|
20
|
+
'check_app_status to check its state. Store `appSecret` like a ' +
|
|
21
|
+
'password (e.g. in a gitignored .env as RECLAIM_APP_SECRET) — it ' +
|
|
22
|
+
'is returned once and cannot be recovered from the server.',
|
|
23
|
+
inputSchema: { type: 'object', properties: {} },
|
|
24
|
+
}, async () => {
|
|
25
|
+
const { appId, appSecret } = await client.issueCredentials();
|
|
26
|
+
return {
|
|
27
|
+
appId,
|
|
28
|
+
appSecret,
|
|
29
|
+
note: 'Unlinked, sandboxed app (100 session limit). Set RECLAIM_APP_ID ' +
|
|
30
|
+
'and RECLAIM_APP_SECRET in your .env (gitignored). Run ' +
|
|
31
|
+
'link_app_to_account to attach it to your dashboard account and ' +
|
|
32
|
+
'lift the sandbox limit.',
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
}
|