@reclaimprotocol/agent 0.1.34 → 0.1.36
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 +3 -3
- package/lib/mcp/api/operations.gen.js +340 -150
- package/lib/mcp/instructions.js +3 -3
- package/lib/mcp/start.js +8 -7
- package/lib/mcp/tools/agent/build.js +2 -0
- package/lib/mcp/tools/agent/check-attestor.d.ts +5 -0
- package/lib/mcp/tools/agent/check-attestor.js +37 -0
- package/lib/mcp/tools/agent/live-view.js +42 -18
- package/lib/mcp/tools/agent/proof.d.ts +12 -0
- package/lib/mcp/tools/agent/proof.js +32 -0
- package/lib/mcp/tools/agent/shared.d.ts +2 -1
- package/lib/mcp/tools/agent/shared.js +28 -24
- package/lib/mcp/tools/agent/start-integration.js +5 -4
- package/lib/mcp/tools/verification/build.d.ts +3 -1
- package/lib/mcp/tools/verification/build.js +10 -2
- package/lib/mcp/tools/verification/callback-listener.d.ts +51 -0
- package/lib/mcp/tools/verification/callback-listener.js +163 -0
- package/lib/mcp/tools/verification/index.d.ts +2 -0
- package/lib/mcp/tools/verification/index.js +2 -0
- package/lib/mcp/tools/verification/proxy-callback-events.d.ts +77 -0
- package/lib/mcp/tools/verification/proxy-callback-events.js +383 -0
- package/lib/mcp/tools/verification/read-callback-events.d.ts +3 -0
- package/lib/mcp/tools/verification/read-callback-events.js +135 -0
- package/lib/mcp/tools/verification/result.d.ts +6 -0
- package/lib/mcp/tools/verification/result.js +1 -1
- package/lib/proof/check-attestor.d.ts +67 -0
- package/lib/proof/check-attestor.js +156 -0
- package/package.json +2 -2
- package/skill/SKILL.builder.md +7 -1
- package/skill/SKILL.common.md +21 -9
- package/skill/builder-mode.md +25 -12
- package/skill/start-integration.md +37 -11
- package/skill/verification-client-integration.md +81 -18
- package/src/mcp/api/operations.gen.ts +344 -150
- package/src/mcp/instructions.ts +3 -3
- package/src/mcp/start.ts +9 -7
- package/src/mcp/tools/agent/build.ts +2 -0
- package/src/mcp/tools/agent/check-attestor.ts +49 -0
- package/src/mcp/tools/agent/live-view.ts +42 -18
- package/src/mcp/tools/agent/proof.ts +55 -0
- package/src/mcp/tools/agent/shared.ts +33 -23
- package/src/mcp/tools/agent/start-integration.ts +5 -4
- package/src/mcp/tools/verification/build.ts +10 -2
- package/src/mcp/tools/verification/callback-listener.ts +203 -0
- package/src/mcp/tools/verification/index.ts +2 -0
- package/src/mcp/tools/verification/proxy-callback-events.ts +484 -0
- package/src/mcp/tools/verification/read-callback-events.ts +160 -0
- package/src/mcp/tools/verification/result.ts +1 -1
- package/src/proof/check-attestor.ts +209 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Attestor reachability check. Proves a public request with a throwaway owner
|
|
3
|
+
* key to show whether the attestor works from this machine, independent of any
|
|
4
|
+
* developer provider or site.
|
|
5
|
+
*/
|
|
6
|
+
import { createClaimOnAttestor } from '@reclaimprotocol/attestor-core'
|
|
7
|
+
import { generateKeypair } from '@reclaimprotocol/client'
|
|
8
|
+
import './patch-domhandler.ts'
|
|
9
|
+
import {
|
|
10
|
+
claimRejection,
|
|
11
|
+
ensureAttestorCrypto,
|
|
12
|
+
parseClaim,
|
|
13
|
+
resolveAttestorUrl,
|
|
14
|
+
} from './proof-core.ts'
|
|
15
|
+
import { ensureZkFiles } from './zk-files.ts'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Default time budget for one check. A live run takes about 8 s; a longer
|
|
19
|
+
* budget risks the MCP client's own tool-call timeout.
|
|
20
|
+
*/
|
|
21
|
+
export const CHECK_ATTESTOR_TIMEOUT_MS = 45_000
|
|
22
|
+
|
|
23
|
+
/* eslint-disable @stylistic/max-len -- the source URL cannot wrap. */
|
|
24
|
+
/**
|
|
25
|
+
* Request params for the check: the public CoinGecko price request from the
|
|
26
|
+
* attestor-core examples. Source:
|
|
27
|
+
* https://raw.githubusercontent.com/reclaimprotocol/attestor-core/refs/heads/main/example/coin-gecko.json
|
|
28
|
+
*/
|
|
29
|
+
/* eslint-enable @stylistic/max-len */
|
|
30
|
+
export const COIN_GECKO_PARAMS = {
|
|
31
|
+
url: 'https://api.coingecko.com/api/v3/simple/price'
|
|
32
|
+
+ '?ids=cardano,solana&vs_currencies=usd',
|
|
33
|
+
method: 'GET' as const,
|
|
34
|
+
body: '',
|
|
35
|
+
headers: {
|
|
36
|
+
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) '
|
|
37
|
+
+ 'AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Safari/604.1',
|
|
38
|
+
'Sec-Fetch-Mode': 'same-origin',
|
|
39
|
+
'Sec-Fetch-Site': 'same-origin',
|
|
40
|
+
},
|
|
41
|
+
responseMatches: [
|
|
42
|
+
{
|
|
43
|
+
invert: false,
|
|
44
|
+
type: 'regex' as const,
|
|
45
|
+
value: 'cardano":{"usd":(?<cardanoPrice>\\d*\\.*\\d*)}',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
invert: false,
|
|
49
|
+
type: 'regex' as const,
|
|
50
|
+
value: 'solana":{"usd":(?<solanaPrice>\\d*\\.*\\d*)}',
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
responseRedactions: [
|
|
54
|
+
{ jsonPath: '$.cardano', regex: 'cardano":{"usd":(.*?)}', xPath: '' },
|
|
55
|
+
{ jsonPath: '$.solana', regex: 'solana":{"usd":(.*?)}', xPath: '' },
|
|
56
|
+
],
|
|
57
|
+
additionalClientOptions: {},
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** The only secret in the example request. */
|
|
61
|
+
const COIN_GECKO_SECRET_HEADERS = {
|
|
62
|
+
Referer: 'https://www.coingecko.com/en/nft',
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type AttestorCheckErrorKind =
|
|
66
|
+
/** Socket, connection, DNS, TLS, or timeout failure. */
|
|
67
|
+
| 'attestor-unreachable'
|
|
68
|
+
/** The attestor answered and rejected or failed the claim. */
|
|
69
|
+
| 'attestor-error'
|
|
70
|
+
/** Local setup (ZK files) failed before the attestor was contacted. */
|
|
71
|
+
| 'setup-failed'
|
|
72
|
+
|
|
73
|
+
export interface AttestorCheckResult {
|
|
74
|
+
ok: boolean
|
|
75
|
+
attestorUrl: string
|
|
76
|
+
durationMs: number
|
|
77
|
+
extractedParameters?: Record<string, string>
|
|
78
|
+
error?: string
|
|
79
|
+
errorKind?: AttestorCheckErrorKind
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** Creates the claim on the attestor (`createClaimOnAttestor` by default). */
|
|
83
|
+
export type CreateClaim = (
|
|
84
|
+
args: Parameters<typeof createClaimOnAttestor>[0],
|
|
85
|
+
) => Promise<unknown>
|
|
86
|
+
|
|
87
|
+
export interface CheckAttestorOptions {
|
|
88
|
+
attestorUrl?: string
|
|
89
|
+
timeoutMs?: number
|
|
90
|
+
/** Replaces the network call in tests. */
|
|
91
|
+
createClaim?: CreateClaim
|
|
92
|
+
/** Replaces the ZK file download in tests. */
|
|
93
|
+
prepare?: () => Promise<void>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Prefix of the error raised when the check exceeds its time budget. */
|
|
97
|
+
const CHECK_TIMEOUT_MESSAGE = 'attestor check timed out'
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Signals that the attestor connection failed. Bare "timeout", "timed out",
|
|
101
|
+
* and "websocket" are left out: a target site's errors contain them too.
|
|
102
|
+
*/
|
|
103
|
+
const NETWORK_ERROR_PATTERN = new RegExp(
|
|
104
|
+
[
|
|
105
|
+
'connection closed',
|
|
106
|
+
'ERROR_NETWORK_ERROR',
|
|
107
|
+
'ECONNRESET',
|
|
108
|
+
'ECONNREFUSED',
|
|
109
|
+
'ENOTFOUND',
|
|
110
|
+
'EAI_AGAIN',
|
|
111
|
+
'ETIMEDOUT',
|
|
112
|
+
'EHOSTUNREACH',
|
|
113
|
+
'ENETUNREACH',
|
|
114
|
+
'socket hang up',
|
|
115
|
+
'websocket (connection|error|closed|failed)',
|
|
116
|
+
'(failed|unable|could not) to connect',
|
|
117
|
+
CHECK_TIMEOUT_MESSAGE,
|
|
118
|
+
].join('|'),
|
|
119
|
+
'i',
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
/** True when `message` looks like a network failure rather than a rejection. */
|
|
123
|
+
export function isNetworkError(message: string | undefined): boolean {
|
|
124
|
+
return message !== undefined && NETWORK_ERROR_PATTERN.test(message)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Prove the public CoinGecko request once and classify the outcome. */
|
|
128
|
+
export async function checkAttestor(
|
|
129
|
+
opts: CheckAttestorOptions = {},
|
|
130
|
+
): Promise<AttestorCheckResult> {
|
|
131
|
+
const attestorUrl = resolveAttestorUrl(opts.attestorUrl)
|
|
132
|
+
const timeoutMs = opts.timeoutMs ?? CHECK_ATTESTOR_TIMEOUT_MS
|
|
133
|
+
const createClaim = opts.createClaim ?? createClaimOnAttestor
|
|
134
|
+
const prepare = opts.prepare ?? (async() => {
|
|
135
|
+
ensureAttestorCrypto()
|
|
136
|
+
await ensureZkFiles()
|
|
137
|
+
})
|
|
138
|
+
const startedAt = Date.now()
|
|
139
|
+
const finish = (
|
|
140
|
+
outcome: Omit<AttestorCheckResult, 'attestorUrl' | 'durationMs'>,
|
|
141
|
+
): AttestorCheckResult => {
|
|
142
|
+
return { ...outcome, attestorUrl, durationMs: Date.now() - startedAt }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
let timer: NodeJS.Timeout | undefined
|
|
146
|
+
const timeout = new Promise<never>((_, reject) => {
|
|
147
|
+
timer = setTimeout(() => {
|
|
148
|
+
reject(new Error(`${CHECK_TIMEOUT_MESSAGE} after ${timeoutMs} ms`))
|
|
149
|
+
}, timeoutMs)
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
try {
|
|
154
|
+
await Promise.race([prepare(), timeout])
|
|
155
|
+
} catch(err) {
|
|
156
|
+
const error = messageOf(err)
|
|
157
|
+
return finish({
|
|
158
|
+
ok: false,
|
|
159
|
+
error,
|
|
160
|
+
errorKind: error.startsWith(CHECK_TIMEOUT_MESSAGE)
|
|
161
|
+
? 'attestor-unreachable'
|
|
162
|
+
: 'setup-failed',
|
|
163
|
+
})
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const claim = await Promise.race([
|
|
167
|
+
createClaim({
|
|
168
|
+
name: 'http',
|
|
169
|
+
params: COIN_GECKO_PARAMS,
|
|
170
|
+
secretParams: { headers: COIN_GECKO_SECRET_HEADERS },
|
|
171
|
+
ownerPrivateKey: generateKeypair().privateKey,
|
|
172
|
+
client: { url: attestorUrl },
|
|
173
|
+
zkEngine: 'stwo',
|
|
174
|
+
}),
|
|
175
|
+
timeout,
|
|
176
|
+
])
|
|
177
|
+
|
|
178
|
+
const rejection = claimRejection(claim)
|
|
179
|
+
if(rejection !== undefined) {
|
|
180
|
+
return finish({
|
|
181
|
+
ok: false,
|
|
182
|
+
error: rejection,
|
|
183
|
+
errorKind: isNetworkError(rejection)
|
|
184
|
+
? 'attestor-unreachable'
|
|
185
|
+
: 'attestor-error',
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return finish({
|
|
190
|
+
ok: true,
|
|
191
|
+
extractedParameters: parseClaim(claim).extractedParameters,
|
|
192
|
+
})
|
|
193
|
+
} catch(err) {
|
|
194
|
+
const error = messageOf(err)
|
|
195
|
+
return finish({
|
|
196
|
+
ok: false,
|
|
197
|
+
error,
|
|
198
|
+
errorKind: isNetworkError(error)
|
|
199
|
+
? 'attestor-unreachable'
|
|
200
|
+
: 'attestor-error',
|
|
201
|
+
})
|
|
202
|
+
} finally {
|
|
203
|
+
clearTimeout(timer)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function messageOf(err: unknown): string {
|
|
208
|
+
return err instanceof Error ? err.message : String(err)
|
|
209
|
+
}
|