@reclaimprotocol/agent 0.1.0 → 0.1.1
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 +1 -1
- package/lib/cdp/capture-engine.d.ts +66 -0
- package/lib/cdp/capture-engine.js +153 -0
- package/lib/cdp/capture.d.ts +9 -20
- package/lib/cdp/capture.js +14 -138
- package/lib/cdp/index.d.ts +3 -0
- package/lib/cdp/index.js +6 -0
- package/lib/config/store.d.ts +7 -6
- package/lib/config/store.js +2 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/mcp/api/operations.gen.d.ts +101 -45
- package/lib/mcp/api/operations.gen.js +996 -126
- package/lib/mcp/api/to-zod.d.ts +24 -0
- package/lib/mcp/api/to-zod.js +94 -0
- package/lib/mcp/api/tools.js +1 -1
- package/lib/mcp/credentials/authenticate.d.ts +3 -0
- package/lib/mcp/{tools/credentials → credentials}/authenticate.js +3 -3
- package/lib/mcp/credentials/build.d.ts +5 -0
- package/lib/mcp/credentials/build.js +18 -0
- package/lib/mcp/{tools/credentials → credentials}/cache.d.ts +9 -9
- package/lib/mcp/{tools/credentials → credentials}/cache.js +36 -19
- package/lib/mcp/credentials/import.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/import.js +2 -2
- package/lib/mcp/credentials/issue.d.ts +2 -0
- package/lib/mcp/{tools/credentials → credentials}/issue.js +4 -4
- package/lib/mcp/credentials/keypair.d.ts +17 -0
- package/lib/mcp/credentials/keypair.js +48 -0
- package/lib/mcp/credentials/link.d.ts +3 -0
- package/lib/mcp/credentials/link.js +107 -0
- package/lib/mcp/{tools/credentials → credentials}/list-cached.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/list-cached.js +5 -5
- package/lib/mcp/credentials/owner-key.d.ts +23 -0
- package/lib/mcp/credentials/owner-key.js +58 -0
- package/lib/mcp/credentials/paths.d.ts +12 -0
- package/lib/mcp/credentials/paths.js +35 -0
- package/lib/mcp/credentials/poll.d.ts +27 -0
- package/lib/mcp/credentials/poll.js +61 -0
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.d.ts +1 -1
- package/lib/mcp/{tools/credentials → credentials}/resolve-owner-key.js +2 -2
- package/lib/mcp/credentials/session-cache.d.ts +14 -0
- package/lib/mcp/credentials/session-cache.js +42 -0
- package/lib/mcp/{tools/credentials → credentials}/status.d.ts +1 -1
- package/lib/mcp/credentials/status.js +76 -0
- package/lib/mcp/instructions.d.ts +1 -0
- package/lib/mcp/instructions.js +11 -0
- package/lib/mcp/register.d.ts +38 -0
- package/lib/mcp/register.js +80 -0
- package/lib/mcp/server.d.ts +2 -2
- package/lib/mcp/server.js +3 -3
- package/lib/mcp/start.js +10 -4
- package/lib/mcp/tools/agent/build.js +2 -15
- package/lib/mcp/tools/agent/index.d.ts +2 -0
- package/lib/mcp/tools/agent/index.js +3 -0
- package/lib/mcp/tools/agent/proof.js +1 -6
- package/lib/mcp/tools/agent/propose.js +13 -2
- package/lib/mcp/tools/agent/publish.js +10 -2
- package/lib/mcp/tools/agent/replay.js +0 -5
- package/lib/mcp/tools/analyze.d.ts +3 -0
- package/lib/mcp/tools/analyze.js +26 -0
- package/lib/mcp/tools/attach.d.ts +11 -0
- package/lib/mcp/tools/attach.js +72 -0
- package/lib/mcp/tools/authenticate/authenticate.js +107 -0
- package/lib/mcp/tools/authenticate/build.d.ts +15 -0
- package/lib/mcp/tools/authenticate/build.js +28 -0
- package/lib/mcp/tools/authenticate/decrypt-key.d.ts +32 -0
- package/lib/mcp/tools/authenticate/decrypt-key.js +49 -0
- package/lib/mcp/tools/authenticate/eth-key.d.ts +38 -0
- package/lib/mcp/tools/authenticate/eth-key.js +130 -0
- package/lib/mcp/tools/authenticate/import.js +57 -0
- package/lib/mcp/tools/authenticate/index.d.ts +2 -0
- package/lib/mcp/tools/authenticate/index.js +4 -0
- package/lib/mcp/tools/authenticate/issue.js +42 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.d.ts +13 -0
- package/lib/mcp/tools/authenticate/resolve-owner-key.js +53 -0
- package/lib/mcp/tools/capture.d.ts +10 -0
- package/lib/mcp/tools/capture.js +142 -0
- package/lib/mcp/tools/eval.d.ts +5 -0
- package/lib/mcp/tools/eval.js +127 -0
- package/lib/mcp/tools/find.d.ts +3 -0
- package/lib/mcp/tools/find.js +60 -0
- package/lib/mcp/tools/index.d.ts +3 -0
- package/lib/mcp/tools/index.js +6 -0
- package/lib/mcp/tools/owner-key.d.ts +2 -0
- package/lib/mcp/tools/owner-key.js +63 -0
- package/lib/mcp/tools/proof.d.ts +3 -0
- package/lib/mcp/tools/proof.js +214 -0
- package/lib/mcp/tools/propose.d.ts +9 -0
- package/lib/mcp/tools/propose.js +75 -0
- package/lib/mcp/tools/publish.d.ts +3 -0
- package/lib/mcp/tools/publish.js +59 -0
- package/lib/mcp/tools/replay.d.ts +3 -0
- package/lib/mcp/tools/replay.js +46 -0
- package/lib/mcp/tools/session.d.ts +10 -0
- package/lib/mcp/tools/session.js +29 -0
- package/lib/mcp/tools/verification/build.d.ts +12 -0
- package/lib/mcp/tools/verification/build.js +14 -0
- package/lib/mcp/tools/verification/diagnose.d.ts +11 -0
- package/lib/mcp/tools/verification/diagnose.js +132 -0
- package/lib/mcp/tools/verification/index.d.ts +1 -0
- package/lib/mcp/tools/verification/index.js +2 -0
- package/lib/mcp/tools/verification/result.d.ts +12 -0
- package/lib/mcp/tools/verification/result.js +126 -0
- package/lib/mcp/verifications/build.d.ts +5 -0
- package/lib/mcp/verifications/build.js +14 -0
- package/lib/mcp/verifications/create.d.ts +3 -0
- package/lib/mcp/verifications/create.js +57 -0
- package/lib/mcp/verifications/find.d.ts +3 -0
- package/lib/mcp/verifications/find.js +37 -0
- package/lib/mcp/verifications/get.d.ts +3 -0
- package/lib/mcp/verifications/get.js +26 -0
- package/lib/mcp/verifications/update.d.ts +3 -0
- package/lib/mcp/verifications/update.js +78 -0
- package/lib/old/client.d.ts +3 -0
- package/lib/old/instructions.d.ts +0 -6
- package/lib/old/instructions.js +6 -24
- package/lib/old/to-register.d.ts +3 -0
- package/lib/old/to-register.js +35 -7
- package/lib/old/tools/publish.js +13 -1
- package/lib/proof/attestor.d.ts +33 -1
- package/lib/proof/attestor.js +67 -61
- package/lib/proof/index.d.ts +5 -0
- package/lib/proof/index.js +6 -0
- package/lib/proof/proof-core.d.ts +35 -0
- package/lib/proof/proof-core.js +73 -0
- package/lib/proof/zk-files.d.ts +14 -0
- package/lib/proof/zk-files.js +73 -0
- package/lib/provider/index.d.ts +5 -0
- package/lib/provider/index.js +9 -0
- package/lib/provider/to-version.d.ts +9 -12
- package/lib/provider/to-version.js +38 -4
- package/lib/provider/verification-checks.d.ts +12 -0
- package/lib/provider/verification-checks.js +30 -0
- package/lib/routes.gen.d.ts +271 -0
- package/lib/routes.gen.js +73 -0
- package/lib/types/openapi.gen.d.ts +3967 -0
- package/lib/types/openapi.gen.js +5 -0
- package/package.json +18 -10
- package/skill/SKILL.md +35 -14
- package/skill/builder-mode.md +9 -0
- package/skill/old-mode.md +13 -0
- package/src/cdp/capture-engine.ts +256 -0
- package/src/cdp/capture.ts +25 -185
- package/src/cdp/index.ts +6 -0
- package/src/config/store.ts +7 -6
- package/src/index.ts +2 -4
- package/src/mcp/api/operations.gen.ts +1023 -121
- package/src/mcp/api/to-zod.ts +115 -0
- package/src/mcp/api/tools.ts +9 -3
- package/src/mcp/instructions.ts +15 -0
- package/src/mcp/server.ts +5 -4
- package/src/mcp/start.ts +14 -4
- package/src/mcp/tools/agent/build.ts +2 -18
- package/src/mcp/tools/agent/index.ts +4 -0
- package/src/mcp/tools/agent/proof.ts +1 -7
- package/src/mcp/tools/agent/propose.ts +13 -2
- package/src/mcp/tools/agent/publish.ts +10 -2
- package/src/mcp/tools/agent/replay.ts +0 -5
- package/src/mcp/tools/{credentials → authenticate}/authenticate.ts +9 -8
- package/src/mcp/tools/authenticate/build.ts +32 -0
- package/src/mcp/tools/authenticate/decrypt-key.ts +64 -0
- package/src/mcp/tools/authenticate/eth-key.ts +182 -0
- package/src/mcp/tools/authenticate/import.ts +73 -0
- package/src/mcp/tools/authenticate/index.ts +4 -0
- package/src/mcp/tools/authenticate/issue.ts +50 -0
- package/src/mcp/tools/authenticate/resolve-owner-key.ts +60 -0
- package/src/mcp/tools/index.ts +6 -0
- package/src/mcp/tools/verification/build.ts +16 -0
- package/src/mcp/tools/verification/index.ts +2 -0
- package/src/mcp/tools/verification/result.ts +155 -0
- package/src/old/client.ts +3 -0
- package/src/old/instructions.ts +10 -25
- package/src/old/to-register.ts +62 -27
- package/src/old/tools/publish.ts +17 -1
- package/src/proof/attestor.ts +115 -69
- package/src/proof/index.ts +21 -0
- package/src/proof/proof-core.ts +109 -0
- package/src/proof/zk-files.ts +83 -0
- package/src/provider/index.ts +20 -0
- package/src/provider/to-version.ts +52 -11
- package/src/provider/verification-checks.ts +36 -0
- package/lib/mcp/tools/credentials/build.d.ts +0 -16
- package/lib/mcp/tools/credentials/build.js +0 -33
- package/lib/mcp/tools/credentials/status.js +0 -62
- package/src/mcp/tools/credentials/build.ts +0 -37
- package/src/mcp/tools/credentials/cache.ts +0 -161
- package/src/mcp/tools/credentials/env-file.ts +0 -101
- package/src/mcp/tools/credentials/import.ts +0 -72
- package/src/mcp/tools/credentials/issue.ts +0 -107
- package/src/mcp/tools/credentials/list-cached.ts +0 -66
- package/src/mcp/tools/credentials/register.ts +0 -49
- package/src/mcp/tools/credentials/resolve-owner-key.ts +0 -78
- package/src/mcp/tools/credentials/status.ts +0 -82
- package/src/types/openapi.ts +0 -7
- /package/lib/mcp/{tools/credentials → credentials}/env-file.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/env-file.js +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.d.ts +0 -0
- /package/lib/mcp/{tools/credentials → credentials}/register.js +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/authenticate.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/import.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/issue.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.d.ts +0 -0
- /package/lib/mcp/tools/{credentials → authenticate}/session-cache.js +0 -0
- /package/src/mcp/tools/{credentials → authenticate}/session-cache.ts +0 -0
package/lib/proof/attestor.js
CHANGED
|
@@ -5,8 +5,11 @@
|
|
|
5
5
|
// responseMatches are the regex/contains checks the attestor runs on the
|
|
6
6
|
// revealed slice; jsonPath/xPath live on responseRedactions (what the prover
|
|
7
7
|
// reveals), never on responseMatches.
|
|
8
|
+
import { bytesToHex } from '@noble/hashes/utils.js';
|
|
8
9
|
import { createClaimOnAttestor, } from '@reclaimprotocol/attestor-core';
|
|
9
|
-
import {
|
|
10
|
+
import { resolveEthKey } from "../mcp/tools/authenticate/eth-key.js";
|
|
11
|
+
import { buildHttpParams, ensureAttestorCrypto, parseClaim, resolveAttestorUrl, } from "./proof-core.js";
|
|
12
|
+
import { ensureZkFiles } from "./zk-files.js";
|
|
10
13
|
/** Trim a captured log stream to the last N entries — for shrinking the
|
|
11
14
|
* LLM-visible response while the full stream stays in the on-disk dump. */
|
|
12
15
|
export function tailLogs(entries, n = LOG_TAIL_LINES) {
|
|
@@ -79,47 +82,55 @@ function makeCaptureLogger() {
|
|
|
79
82
|
};
|
|
80
83
|
return { logger: make({}), entries };
|
|
81
84
|
}
|
|
82
|
-
/** Default public attestor websocket URL. Resolved per-call so an env-var
|
|
83
|
-
* change or per-request override takes effect without restarting the
|
|
84
|
-
* MCP server. */
|
|
85
|
-
const FALLBACK_ATTESTOR_URL = 'wss://attestor.reclaimprotocol.org:444/ws';
|
|
86
|
-
function resolveAttestorUrl(override) {
|
|
87
|
-
return (override ?? process.env['RECLAIM_ATTESTOR_URL'] ?? FALLBACK_ATTESTOR_URL);
|
|
88
|
-
}
|
|
89
85
|
// ---------------------------------------------------------------------------
|
|
90
86
|
// Main entry point
|
|
91
87
|
// ---------------------------------------------------------------------------
|
|
92
|
-
export async function runAttestorProof(provider, secrets,
|
|
93
|
-
//
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
88
|
+
export async function runAttestorProof(provider, secrets, opts = {}) {
|
|
89
|
+
// Sign with the caller-supplied key (the app/VC's ephemeral per-session
|
|
90
|
+
// key) when given; otherwise resolve env/.env/file. `ownerAddress` is a
|
|
91
|
+
// sanity check on the resolved key (ignored when a key is supplied).
|
|
92
|
+
let ownerPrivateKey;
|
|
93
|
+
if (opts.ownerPrivateKey) {
|
|
94
|
+
ownerPrivateKey = opts.ownerPrivateKey;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const resolved = resolveEthKey();
|
|
98
|
+
if (!resolved) {
|
|
99
|
+
return {
|
|
100
|
+
proof: undefined,
|
|
101
|
+
extractedValue: '',
|
|
102
|
+
extractedParameters: {},
|
|
103
|
+
verified: false,
|
|
104
|
+
error: 'No eth proof-owner key available (no RECLAIM_PRIVATE_KEY in env, ' +
|
|
105
|
+
'.env, or RECLAIM_PRIVATE_KEY_FILE). Call resolve_owner_key, then ' +
|
|
106
|
+
'issue_credentials (generate) or import_credentials (provide one), ' +
|
|
107
|
+
'and retry run_proof.',
|
|
108
|
+
errorKind: 'missing-owner-key',
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
if (opts.ownerAddress
|
|
112
|
+
&& opts.ownerAddress.toLowerCase() !== resolved.address) {
|
|
113
|
+
return {
|
|
114
|
+
proof: undefined,
|
|
115
|
+
extractedValue: '',
|
|
116
|
+
extractedParameters: {},
|
|
117
|
+
verified: false,
|
|
118
|
+
error: `Requested ownerAddress "${opts.ownerAddress}" does not match ` +
|
|
119
|
+
`the resolved eth key (${resolved.address}, source: ` +
|
|
120
|
+
`${resolved.source}). ` +
|
|
121
|
+
'Call resolve_owner_key to get the current address, or update the ' +
|
|
122
|
+
'configured key.',
|
|
123
|
+
errorKind: 'missing-owner-key',
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
ownerPrivateKey = resolved.privateKey;
|
|
110
127
|
}
|
|
111
128
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
responseMatches: provider.responseMatches,
|
|
118
|
-
responseRedactions: provider.responseRedactions ?? [],
|
|
119
|
-
...(provider.paramValues !== undefined && {
|
|
120
|
-
paramValues: provider.paramValues,
|
|
121
|
-
}),
|
|
122
|
-
};
|
|
129
|
+
// Init the TLS crypto backend (idempotent), then fetch ZK circuits
|
|
130
|
+
// lazily on the first proof (not at install time).
|
|
131
|
+
ensureAttestorCrypto();
|
|
132
|
+
await ensureZkFiles();
|
|
133
|
+
const params = buildHttpParams(provider);
|
|
123
134
|
// Diagnostic logger capture is gated behind RECLAIM_AGENT_TRACE so the
|
|
124
135
|
// happy path doesn't pay the cost (the attestor SDK emits a *lot* of
|
|
125
136
|
// trace/debug entries during ZK setup). Flip RECLAIM_AGENT_TRACE=1 to
|
|
@@ -137,8 +148,8 @@ export async function runAttestorProof(provider, secrets, attestorUrl, ownerAddr
|
|
|
137
148
|
headers: secrets,
|
|
138
149
|
},
|
|
139
150
|
ownerPrivateKey,
|
|
140
|
-
client: { url: resolveAttestorUrl(attestorUrl) },
|
|
141
|
-
zkEngine: '
|
|
151
|
+
client: { url: resolveAttestorUrl(opts.attestorUrl) },
|
|
152
|
+
zkEngine: opts.zkEngine ?? 'gnark',
|
|
142
153
|
...(capture !== undefined && { logger: capture.logger }),
|
|
143
154
|
});
|
|
144
155
|
}
|
|
@@ -156,38 +167,33 @@ export async function runAttestorProof(provider, secrets, attestorUrl, ownerAddr
|
|
|
156
167
|
}
|
|
157
168
|
return errorResult;
|
|
158
169
|
}
|
|
159
|
-
|
|
160
|
-
const claimRecord = claim;
|
|
161
|
-
const claimData = claimRecord['claim'];
|
|
162
|
-
// claimData.context is a JSON-encoded string carrying
|
|
163
|
-
// { extractedParameters: {...}, providerHash, ... }.
|
|
164
|
-
let context = {};
|
|
165
|
-
const rawContext = claimData?.['context'];
|
|
166
|
-
if (typeof rawContext === 'string') {
|
|
167
|
-
try {
|
|
168
|
-
context = JSON.parse(rawContext);
|
|
169
|
-
}
|
|
170
|
-
catch {
|
|
171
|
-
// Leave context empty if it isn't valid JSON.
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const extractedParameters = context['extractedParameters'] ??
|
|
175
|
-
{};
|
|
176
|
-
const extractedValue = Object.values(extractedParameters)[0] ?? '';
|
|
170
|
+
const { extractedValue, extractedParameters, identifier, owner, claimData } = parseClaim(claim);
|
|
177
171
|
const result = {
|
|
178
172
|
proof: claim,
|
|
179
173
|
extractedValue,
|
|
180
174
|
extractedParameters,
|
|
181
175
|
verified: true,
|
|
182
176
|
};
|
|
183
|
-
|
|
184
|
-
if (typeof identifier === 'string') {
|
|
177
|
+
if (identifier !== undefined) {
|
|
185
178
|
result.identifier = identifier;
|
|
186
179
|
}
|
|
187
|
-
|
|
188
|
-
if (typeof owner === 'string') {
|
|
180
|
+
if (owner !== undefined) {
|
|
189
181
|
result.owner = owner;
|
|
190
182
|
}
|
|
183
|
+
// Structured claim + signature so the result JWS can carry a nested,
|
|
184
|
+
// attestor-signed proof the Consumer verifies independently.
|
|
185
|
+
if (opts.includeAttestorClaim) {
|
|
186
|
+
const sigs = claim.signatures;
|
|
187
|
+
if (claimData
|
|
188
|
+
&& typeof sigs?.attestorAddress === 'string'
|
|
189
|
+
&& sigs.claimSignature instanceof Uint8Array) {
|
|
190
|
+
result.attestorClaim = {
|
|
191
|
+
claim: claimData,
|
|
192
|
+
attestorAddress: sigs.attestorAddress,
|
|
193
|
+
claimSignature: '0x' + bytesToHex(sigs.claimSignature),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
191
197
|
// Only set when RECLAIM_AGENT_TRACE=1. Full stream — the MCP layer
|
|
192
198
|
// trims for the LLM-visible response; the on-disk dump gets it all.
|
|
193
199
|
if (attestorLogs !== undefined && attestorLogs.length > 0) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { AttestorClaim, AttestorLogEntry, ProofResult, RunAttestorProofOptions, } from './attestor.ts';
|
|
2
|
+
export { runAttestorProof, tailLogs, warnsAndErrors } from './attestor.ts';
|
|
3
|
+
export { buildHttpParams, ensureAttestorCrypto, type ParsedClaim, parseClaim, resolveAttestorUrl, } from './proof-core.ts';
|
|
4
|
+
export { ensureZkFiles } from './zk-files.ts';
|
|
5
|
+
export { createClaimOnAttestor } from '@reclaimprotocol/attestor-core';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { runAttestorProof, tailLogs, warnsAndErrors } from "./attestor.js";
|
|
2
|
+
export { buildHttpParams, ensureAttestorCrypto, parseClaim, resolveAttestorUrl, } from "./proof-core.js";
|
|
3
|
+
export { ensureZkFiles } from "./zk-files.js";
|
|
4
|
+
// Re-exported attestor-core claim primitive so the agent is the single
|
|
5
|
+
// integration point with @reclaimprotocol/attestor-core across the builder.
|
|
6
|
+
export { createClaimOnAttestor } from '@reclaimprotocol/attestor-core';
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared attestor-claim plumbing used by both proof callers: the agent's MCP
|
|
3
|
+
* `run_proof` (which resolves the owner key from the credential cache and
|
|
4
|
+
* captures trace logs) and the app's verification runner (which signs with an
|
|
5
|
+
* ephemeral per-session key and builds a nested-proof claim). Only those
|
|
6
|
+
* concerns differ — building the HTTP params, resolving the attestor URL, and
|
|
7
|
+
* parsing the claim response are identical, so they live here.
|
|
8
|
+
*/
|
|
9
|
+
import type { ProviderParams } from '@reclaimprotocol/attestor-core';
|
|
10
|
+
import type { ReclaimProvider } from '../provider/schema.ts';
|
|
11
|
+
/** One-time crypto backend init for `@reclaimprotocol/tls` (idempotent). The
|
|
12
|
+
* package ships with an empty `crypto = {}` and defers the backend to the
|
|
13
|
+
* caller; without this the first proof dies inside the TLS client with
|
|
14
|
+
* `crypto.randomBytes is not a function`. Shared by every attestor caller —
|
|
15
|
+
* the agent MCP `run_proof` tool and the app's verification runner. */
|
|
16
|
+
export declare function ensureAttestorCrypto(): void;
|
|
17
|
+
/** Resolve the attestor websocket URL: explicit override → env → public
|
|
18
|
+
* default. Resolved per-call so an env change or per-request override takes
|
|
19
|
+
* effect without restarting. */
|
|
20
|
+
export declare function resolveAttestorUrl(override?: string): string;
|
|
21
|
+
/** Map a verification's provider recipe straight to the attestor's HTTP
|
|
22
|
+
* params — never synthesized from captured traffic. */
|
|
23
|
+
export declare function buildHttpParams(provider: ReclaimProvider): ProviderParams<'http'>;
|
|
24
|
+
export interface ParsedClaim {
|
|
25
|
+
/** ProviderClaimData: provider, parameters, context, owner, identifier, … */
|
|
26
|
+
claimData?: Record<string, unknown>;
|
|
27
|
+
extractedParameters: Record<string, string>;
|
|
28
|
+
extractedValue: string;
|
|
29
|
+
identifier?: string;
|
|
30
|
+
owner?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Pull claimData + decoded `context.extractedParameters` (plus identifier /
|
|
33
|
+
* owner) out of a `createClaimOnAttestor` result. The full result still
|
|
34
|
+
* carries signatures the caller may need for nested-proof building. */
|
|
35
|
+
export declare function parseClaim(claim: unknown): ParsedClaim;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { setCryptoImplementation } from '@reclaimprotocol/tls';
|
|
2
|
+
import { webcryptoCrypto } from '@reclaimprotocol/tls/webcrypto';
|
|
3
|
+
const FALLBACK_ATTESTOR_URL = 'wss://attestor.reclaimprotocol.org:444/ws';
|
|
4
|
+
let cryptoInitialized = false;
|
|
5
|
+
/** One-time crypto backend init for `@reclaimprotocol/tls` (idempotent). The
|
|
6
|
+
* package ships with an empty `crypto = {}` and defers the backend to the
|
|
7
|
+
* caller; without this the first proof dies inside the TLS client with
|
|
8
|
+
* `crypto.randomBytes is not a function`. Shared by every attestor caller —
|
|
9
|
+
* the agent MCP `run_proof` tool and the app's verification runner. */
|
|
10
|
+
export function ensureAttestorCrypto() {
|
|
11
|
+
if (cryptoInitialized) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
setCryptoImplementation(webcryptoCrypto);
|
|
15
|
+
cryptoInitialized = true;
|
|
16
|
+
}
|
|
17
|
+
/** Resolve the attestor websocket URL: explicit override → env → public
|
|
18
|
+
* default. Resolved per-call so an env change or per-request override takes
|
|
19
|
+
* effect without restarting. */
|
|
20
|
+
export function resolveAttestorUrl(override) {
|
|
21
|
+
return (override ?? process.env['RECLAIM_ATTESTOR_URL'] ?? FALLBACK_ATTESTOR_URL);
|
|
22
|
+
}
|
|
23
|
+
/** Map a verification's provider recipe straight to the attestor's HTTP
|
|
24
|
+
* params — never synthesized from captured traffic. */
|
|
25
|
+
export function buildHttpParams(provider) {
|
|
26
|
+
return {
|
|
27
|
+
url: provider.url,
|
|
28
|
+
method: provider.method,
|
|
29
|
+
...(provider.headers !== undefined && { headers: provider.headers }),
|
|
30
|
+
...(provider.body !== undefined && { body: provider.body }),
|
|
31
|
+
responseMatches: provider.responseMatches,
|
|
32
|
+
responseRedactions: provider.responseRedactions ?? [],
|
|
33
|
+
...(provider.paramValues !== undefined && {
|
|
34
|
+
paramValues: provider.paramValues,
|
|
35
|
+
}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Pull claimData + decoded `context.extractedParameters` (plus identifier /
|
|
39
|
+
* owner) out of a `createClaimOnAttestor` result. The full result still
|
|
40
|
+
* carries signatures the caller may need for nested-proof building. */
|
|
41
|
+
export function parseClaim(claim) {
|
|
42
|
+
const claimRecord = claim;
|
|
43
|
+
const claimData = claimRecord['claim'];
|
|
44
|
+
// claimData.context is a JSON-encoded string carrying
|
|
45
|
+
// { extractedParameters: {...}, providerHash, ... }.
|
|
46
|
+
let context = {};
|
|
47
|
+
const rawContext = claimData?.['context'];
|
|
48
|
+
if (typeof rawContext === 'string') {
|
|
49
|
+
try {
|
|
50
|
+
context = JSON.parse(rawContext);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Leave context empty if it isn't valid JSON.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const extractedParameters = context['extractedParameters'] ?? {};
|
|
57
|
+
const parsed = {
|
|
58
|
+
extractedParameters,
|
|
59
|
+
extractedValue: Object.values(extractedParameters)[0] ?? '',
|
|
60
|
+
};
|
|
61
|
+
if (claimData) {
|
|
62
|
+
parsed.claimData = claimData;
|
|
63
|
+
}
|
|
64
|
+
const identifier = claimData?.['identifier'];
|
|
65
|
+
if (typeof identifier === 'string') {
|
|
66
|
+
parsed.identifier = identifier;
|
|
67
|
+
}
|
|
68
|
+
const owner = claimData?.['owner'];
|
|
69
|
+
if (typeof owner === 'string') {
|
|
70
|
+
parsed.owner = owner;
|
|
71
|
+
}
|
|
72
|
+
return parsed;
|
|
73
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure the zk circuit resources are on disk before a proof runs. Idempotent
|
|
3
|
+
* and concurrency-safe: the download runs at most once per process, and a
|
|
4
|
+
* failed attempt clears the latch so a later proof can retry.
|
|
5
|
+
*
|
|
6
|
+
* Resolves silently when the resources are already present (the warm npx cache,
|
|
7
|
+
* or after a manual `npm run download:zk-files`) and when
|
|
8
|
+
* `@reclaimprotocol/zk-symmetric-crypto` isn't installed at all (SDK-only
|
|
9
|
+
* consumers have nothing to prove).
|
|
10
|
+
*
|
|
11
|
+
* All output goes to stderr (fd 2): the MCP server speaks JSON-RPC over stdout,
|
|
12
|
+
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ensureZkFiles(): Promise<void>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
// Lazy download of the @reclaimprotocol/zk-symmetric-crypto circuit resources
|
|
2
|
+
// that the snarkjs proof engine needs. These are ~280MB and are NOT fetched in
|
|
3
|
+
// a `postinstall` (that blocked the MCP server's first launch past the connect
|
|
4
|
+
// timeout — see the install notes). Instead we fetch them on the first proof,
|
|
5
|
+
// once, so the server starts immediately and only `run_proof` pays the cost.
|
|
6
|
+
import { spawn } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { createRequire } from 'node:module';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
const require = createRequire(import.meta.url);
|
|
11
|
+
let inFlight;
|
|
12
|
+
/**
|
|
13
|
+
* Ensure the zk circuit resources are on disk before a proof runs. Idempotent
|
|
14
|
+
* and concurrency-safe: the download runs at most once per process, and a
|
|
15
|
+
* failed attempt clears the latch so a later proof can retry.
|
|
16
|
+
*
|
|
17
|
+
* Resolves silently when the resources are already present (the warm npx cache,
|
|
18
|
+
* or after a manual `npm run download:zk-files`) and when
|
|
19
|
+
* `@reclaimprotocol/zk-symmetric-crypto` isn't installed at all (SDK-only
|
|
20
|
+
* consumers have nothing to prove).
|
|
21
|
+
*
|
|
22
|
+
* All output goes to stderr (fd 2): the MCP server speaks JSON-RPC over stdout,
|
|
23
|
+
* so a stray write to fd 1 mid-session would corrupt the protocol.
|
|
24
|
+
*/
|
|
25
|
+
export function ensureZkFiles() {
|
|
26
|
+
inFlight ??= download().catch((err) => {
|
|
27
|
+
inFlight = undefined;
|
|
28
|
+
throw err;
|
|
29
|
+
});
|
|
30
|
+
return inFlight;
|
|
31
|
+
}
|
|
32
|
+
async function download() {
|
|
33
|
+
let mainPath;
|
|
34
|
+
try {
|
|
35
|
+
mainPath = require.resolve('@reclaimprotocol/zk-symmetric-crypto');
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// mainPath is <pkg>/lib/index.js → resources live at <pkg>/resources, the
|
|
41
|
+
// downloader at <pkg>/lib/scripts/download-files.js. We only use the snarkjs
|
|
42
|
+
// engine (createClaimOnAttestor zkEngine: 'snarkjs'), so its presence is the
|
|
43
|
+
// signal that the circuits are ready.
|
|
44
|
+
const libDir = dirname(mainPath);
|
|
45
|
+
const pkgDir = dirname(libDir);
|
|
46
|
+
if (existsSync(join(pkgDir, 'resources', 'snarkjs'))) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const downloadScript = join(libDir, 'scripts', 'download-files.js');
|
|
50
|
+
if (!existsSync(downloadScript)) {
|
|
51
|
+
throw new Error('zk circuit downloader not found in '
|
|
52
|
+
+ '@reclaimprotocol/zk-symmetric-crypto; '
|
|
53
|
+
+ 'run `npm run download:zk-files` and retry.');
|
|
54
|
+
}
|
|
55
|
+
process.stderr.write('[reclaim-agent] downloading zkTLS proof circuits '
|
|
56
|
+
+ '(~280MB, one-time)…\n');
|
|
57
|
+
// stdio fd 1→2: send the downloader's stdout to our stderr so its progress
|
|
58
|
+
// never lands on the MCP server's JSON-RPC stdout.
|
|
59
|
+
await new Promise((resolve, reject) => {
|
|
60
|
+
const child = spawn(process.execPath, [downloadScript], {
|
|
61
|
+
stdio: ['ignore', 2, 2],
|
|
62
|
+
});
|
|
63
|
+
child.on('error', reject);
|
|
64
|
+
child.on('exit', (code) => {
|
|
65
|
+
if (code === 0) {
|
|
66
|
+
resolve();
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
reject(new Error(`zk download exited ${code}`));
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { extractGraphqlOp, looksLikeGraphqlEndpoint } from './graphql.ts';
|
|
2
|
+
export type { CapturedRequest, HttpMethod, OprfMode, ReclaimProvider, RequestConcern, ResponseMatch, ResponseRedaction, SecretParamRef, } from './schema.ts';
|
|
3
|
+
export { classifyHeader, splitSecrets } from './secrets.ts';
|
|
4
|
+
export { hashProviderParams, providers } from '@reclaimprotocol/attestor-core';
|
|
5
|
+
export type { ProviderParams } from '@reclaimprotocol/attestor-core';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Provider primitives shared with the app's capture pipeline:
|
|
2
|
+
// the attestor-derived recipe types, secret classification, and the GraphQL
|
|
3
|
+
// op parser. Exposed as `@reclaimprotocol/agent/provider`.
|
|
4
|
+
export { extractGraphqlOp, looksLikeGraphqlEndpoint } from "./graphql.js";
|
|
5
|
+
export { classifyHeader, splitSecrets } from "./secrets.js";
|
|
6
|
+
// Re-exported attestor-core provider primitives (the registry, the param hash,
|
|
7
|
+
// and the param type) so the builder imports them via the agent rather than
|
|
8
|
+
// depending on @reclaimprotocol/attestor-core directly.
|
|
9
|
+
export { hashProviderParams, providers } from '@reclaimprotocol/attestor-core';
|
|
@@ -1,22 +1,19 @@
|
|
|
1
1
|
import type { ReclaimClient } from '@reclaimprotocol/client';
|
|
2
|
-
import type { CreateProviderVersionRequest
|
|
2
|
+
import type { CreateProviderVersionRequest, ProviderVersionRef } from '@reclaimprotocol/client/openapi';
|
|
3
3
|
import type { ReclaimProvider } from './schema.ts';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* API URL the attestor replays.
|
|
11
|
-
*
|
|
12
|
-
* Secrets are NOT persisted — the verification client re-supplies
|
|
13
|
-
* them at runtime via `credentials: 'include'`.
|
|
5
|
+
* Derive the version's `requiredContext` JSON Schema from the
|
|
6
|
+
* `{{context.<name>}}` placeholders in the provider's url/body — mechanical,
|
|
7
|
+
* so a published recipe can never reference a context value the Builder
|
|
8
|
+
* doesn't require. Returns undefined when the recipe has none (the field is
|
|
9
|
+
* optional). Authors can refine types/descriptions in the version editor.
|
|
14
10
|
*/
|
|
15
|
-
export declare function
|
|
11
|
+
export declare function deriveRequiredContext(provider: ReclaimProvider): CreateProviderVersionRequest['requiredContext'];
|
|
12
|
+
export declare function providerToCreateVersionRequest(provider: ReclaimProvider, initialUrl: string, notes?: string, version?: ProviderVersionRef): CreateProviderVersionRequest;
|
|
16
13
|
/**
|
|
17
14
|
* Fetch the current versions for a provider and return the next version above
|
|
18
15
|
* the highest existing one (bumping the patch number), or 1.0.0 when the
|
|
19
16
|
* provider has no versions yet. A failed lookup propagates — silently
|
|
20
17
|
* resetting to 1.0.0 would re-publish a v3 provider as v1.0.0.
|
|
21
18
|
*/
|
|
22
|
-
export declare function nextVersion(client: ReclaimClient, providerId: string): Promise<
|
|
19
|
+
export declare function nextVersion(client: ReclaimClient, providerId: string): Promise<ProviderVersionRef>;
|
|
@@ -9,7 +9,35 @@
|
|
|
9
9
|
* Secrets are NOT persisted — the verification client re-supplies
|
|
10
10
|
* them at runtime via `credentials: 'include'`.
|
|
11
11
|
*/
|
|
12
|
+
/** `{{context.<name>}}` placeholders in a request URL/body: values the
|
|
13
|
+
* CONSUMER supplies at verification time via the session `context`. Bare
|
|
14
|
+
* `{{name}}` placeholders (extraction params) are not consumer-supplied
|
|
15
|
+
* and are ignored. */
|
|
16
|
+
const CONTEXT_PARAM_RE = /\{\{context\.([A-Za-z_][A-Za-z0-9_]*)\}\}/g;
|
|
17
|
+
/**
|
|
18
|
+
* Derive the version's `requiredContext` JSON Schema from the
|
|
19
|
+
* `{{context.<name>}}` placeholders in the provider's url/body — mechanical,
|
|
20
|
+
* so a published recipe can never reference a context value the Builder
|
|
21
|
+
* doesn't require. Returns undefined when the recipe has none (the field is
|
|
22
|
+
* optional). Authors can refine types/descriptions in the version editor.
|
|
23
|
+
*/
|
|
24
|
+
export function deriveRequiredContext(provider) {
|
|
25
|
+
const haystack = `${provider.url}\n${provider.body ?? ''}`;
|
|
26
|
+
const names = new Set();
|
|
27
|
+
for (const m of haystack.matchAll(CONTEXT_PARAM_RE)) {
|
|
28
|
+
names.add(m[1]);
|
|
29
|
+
}
|
|
30
|
+
if (!names.size) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
const properties = {};
|
|
34
|
+
for (const name of names) {
|
|
35
|
+
properties[name] = { type: 'string' };
|
|
36
|
+
}
|
|
37
|
+
return { type: 'object', required: [...names], properties };
|
|
38
|
+
}
|
|
12
39
|
export function providerToCreateVersionRequest(provider, initialUrl, notes, version) {
|
|
40
|
+
const requiredContext = deriveRequiredContext(provider);
|
|
13
41
|
// Inline responseRedactions into matches[*].extract (1-to-1 by index).
|
|
14
42
|
const matches = (provider.responseMatches ?? []).map((match, i) => {
|
|
15
43
|
const redaction = provider.responseRedactions?.[i];
|
|
@@ -33,10 +61,16 @@ export function providerToCreateVersionRequest(provider, initialUrl, notes, vers
|
|
|
33
61
|
},
|
|
34
62
|
],
|
|
35
63
|
allowedJsRequests: [],
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
: {}
|
|
64
|
+
// Mirror the builder openapi defaults explicitly — the server does not
|
|
65
|
+
// apply schema defaults to request bodies.
|
|
66
|
+
webSettings: {
|
|
67
|
+
geoLocation: '{{DYNAMIC_GEO}}',
|
|
68
|
+
clientOptions: { portal: { useProxy: true } },
|
|
69
|
+
},
|
|
70
|
+
// Derived from `{{context.<name>}}` placeholders only — a captured
|
|
71
|
+
// provider's `paramValues` are extracted response parameters, not
|
|
72
|
+
// consumer context, and never become requiredContext.
|
|
73
|
+
...(requiredContext ? { requiredContext } : {}),
|
|
40
74
|
...(notes ? { notes } : {}),
|
|
41
75
|
};
|
|
42
76
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReclaimProvider } from './schema.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Advisory pre-publish lint for a drafted provider — never a gate. Surfaces
|
|
4
|
+
* only what the AUTHOR must decide; everything testable is tested by the
|
|
5
|
+
* verification client itself (CDP capture sees all traffic — navigations,
|
|
6
|
+
* XHRs, fetches — and `checkCandidate` in packages/app src/verify/run.ts
|
|
7
|
+
* selects the captured request that satisfies the recipe, skipping the
|
|
8
|
+
* rest). Interpolation and matching are plain text and work for any
|
|
9
|
+
* captured content; extract selectors apply client-side in spec order
|
|
10
|
+
* xPath → jsonPath → regex, each to the prior selection.
|
|
11
|
+
*/
|
|
12
|
+
export declare function verificationWarnings(provider: ReclaimProvider): string[];
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Advisory pre-publish lint for a drafted provider — never a gate. Surfaces
|
|
3
|
+
* only what the AUTHOR must decide; everything testable is tested by the
|
|
4
|
+
* verification client itself (CDP capture sees all traffic — navigations,
|
|
5
|
+
* XHRs, fetches — and `checkCandidate` in packages/app src/verify/run.ts
|
|
6
|
+
* selects the captured request that satisfies the recipe, skipping the
|
|
7
|
+
* rest). Interpolation and matching are plain text and work for any
|
|
8
|
+
* captured content; extract selectors apply client-side in spec order
|
|
9
|
+
* xPath → jsonPath → regex, each to the prior selection.
|
|
10
|
+
*/
|
|
11
|
+
export function verificationWarnings(provider) {
|
|
12
|
+
const out = [];
|
|
13
|
+
// Untemplated user-specific URL parts: any captured param value baked
|
|
14
|
+
// literally into the URL makes the provider user-specific. Only the dev
|
|
15
|
+
// can decide: consumer-supplied → {{context.<name>}} (declared in
|
|
16
|
+
// requiredContext; consumers then send the exact value and the VC matches
|
|
17
|
+
// only that value), bare {{<name>}} (resolved from the end-user's own
|
|
18
|
+
// traffic), or re-capture a non-user-specific endpoint.
|
|
19
|
+
for (const [name, value] of Object.entries(provider.paramValues ?? {})) {
|
|
20
|
+
if (value.length >= 3 && provider.url.includes(value)) {
|
|
21
|
+
out.push(`The URL contains the captured value "${value}" (param ` +
|
|
22
|
+
`"${name}") as a literal. Decide with the dev: if consumers ` +
|
|
23
|
+
'supply it, replace with {{context.' + name + '}} (published ' +
|
|
24
|
+
'requiredContext will require it; verification matches only ' +
|
|
25
|
+
'the supplied value). Leaving it literal pins the provider ' +
|
|
26
|
+
'to this user.');
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return out;
|
|
30
|
+
}
|