@reclaimprotocol/agent 0.1.34 → 0.1.35

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.
Files changed (49) hide show
  1. package/README.md +3 -3
  2. package/lib/mcp/api/operations.gen.js +340 -150
  3. package/lib/mcp/instructions.js +3 -3
  4. package/lib/mcp/start.js +8 -7
  5. package/lib/mcp/tools/agent/build.js +2 -0
  6. package/lib/mcp/tools/agent/check-attestor.d.ts +5 -0
  7. package/lib/mcp/tools/agent/check-attestor.js +37 -0
  8. package/lib/mcp/tools/agent/live-view.js +42 -18
  9. package/lib/mcp/tools/agent/proof.d.ts +12 -0
  10. package/lib/mcp/tools/agent/proof.js +32 -0
  11. package/lib/mcp/tools/agent/shared.d.ts +2 -1
  12. package/lib/mcp/tools/agent/shared.js +28 -24
  13. package/lib/mcp/tools/agent/start-integration.js +5 -4
  14. package/lib/mcp/tools/verification/build.d.ts +3 -1
  15. package/lib/mcp/tools/verification/build.js +10 -2
  16. package/lib/mcp/tools/verification/callback-listener.d.ts +51 -0
  17. package/lib/mcp/tools/verification/callback-listener.js +163 -0
  18. package/lib/mcp/tools/verification/index.d.ts +2 -0
  19. package/lib/mcp/tools/verification/index.js +2 -0
  20. package/lib/mcp/tools/verification/proxy-callback-events.d.ts +59 -0
  21. package/lib/mcp/tools/verification/proxy-callback-events.js +300 -0
  22. package/lib/mcp/tools/verification/read-callback-events.d.ts +3 -0
  23. package/lib/mcp/tools/verification/read-callback-events.js +135 -0
  24. package/lib/mcp/tools/verification/result.d.ts +6 -0
  25. package/lib/mcp/tools/verification/result.js +1 -1
  26. package/lib/proof/check-attestor.d.ts +67 -0
  27. package/lib/proof/check-attestor.js +156 -0
  28. package/package.json +2 -2
  29. package/skill/SKILL.builder.md +7 -1
  30. package/skill/SKILL.common.md +21 -9
  31. package/skill/builder-mode.md +17 -12
  32. package/skill/start-integration.md +36 -11
  33. package/skill/verification-client-integration.md +15 -9
  34. package/src/mcp/api/operations.gen.ts +344 -150
  35. package/src/mcp/instructions.ts +3 -3
  36. package/src/mcp/start.ts +9 -7
  37. package/src/mcp/tools/agent/build.ts +2 -0
  38. package/src/mcp/tools/agent/check-attestor.ts +49 -0
  39. package/src/mcp/tools/agent/live-view.ts +42 -18
  40. package/src/mcp/tools/agent/proof.ts +55 -0
  41. package/src/mcp/tools/agent/shared.ts +33 -23
  42. package/src/mcp/tools/agent/start-integration.ts +5 -4
  43. package/src/mcp/tools/verification/build.ts +10 -2
  44. package/src/mcp/tools/verification/callback-listener.ts +203 -0
  45. package/src/mcp/tools/verification/index.ts +2 -0
  46. package/src/mcp/tools/verification/proxy-callback-events.ts +374 -0
  47. package/src/mcp/tools/verification/read-callback-events.ts +160 -0
  48. package/src/mcp/tools/verification/result.ts +1 -1
  49. 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
+ }