@truealter/sdk 0.0.1 → 0.2.0
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/LICENSE +17 -0
- package/README.md +441 -1
- package/dist/bin/alter-identity.js +1330 -0
- package/dist/bin/alter-identity.js.map +1 -0
- package/dist/bin/mcp-bridge.js +491 -0
- package/dist/bin/mcp-bridge.js.map +1 -0
- package/dist/index.cjs +1316 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1470 -0
- package/dist/index.d.ts +1470 -0
- package/dist/index.js +1253 -0
- package/dist/index.js.map +1 -0
- package/package.json +62 -8
- package/index.js +0 -1
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,1316 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var ed25519 = require('@noble/ed25519');
|
|
4
|
+
var sha512 = require('@noble/hashes/sha512');
|
|
5
|
+
var utils = require('@noble/hashes/utils');
|
|
6
|
+
|
|
7
|
+
function _interopNamespace(e) {
|
|
8
|
+
if (e && e.__esModule) return e;
|
|
9
|
+
var n = Object.create(null);
|
|
10
|
+
if (e) {
|
|
11
|
+
Object.keys(e).forEach(function (k) {
|
|
12
|
+
if (k !== 'default') {
|
|
13
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
14
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
get: function () { return e[k]; }
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
n.default = e;
|
|
22
|
+
return Object.freeze(n);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var ed25519__namespace = /*#__PURE__*/_interopNamespace(ed25519);
|
|
26
|
+
|
|
27
|
+
// src/errors.ts
|
|
28
|
+
var AlterError = class extends Error {
|
|
29
|
+
code;
|
|
30
|
+
cause;
|
|
31
|
+
constructor(code, message, cause) {
|
|
32
|
+
super(message);
|
|
33
|
+
this.name = "AlterError";
|
|
34
|
+
this.code = code;
|
|
35
|
+
this.cause = cause;
|
|
36
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var AlterNetworkError = class extends AlterError {
|
|
40
|
+
constructor(message, cause) {
|
|
41
|
+
super("NETWORK", message, cause);
|
|
42
|
+
this.name = "AlterNetworkError";
|
|
43
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
var AlterTimeoutError = class extends AlterError {
|
|
47
|
+
constructor(message, cause) {
|
|
48
|
+
super("TIMEOUT", message, cause);
|
|
49
|
+
this.name = "AlterTimeoutError";
|
|
50
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
var AlterAuthError = class extends AlterError {
|
|
54
|
+
status;
|
|
55
|
+
constructor(message, status = 401) {
|
|
56
|
+
super("AUTH", message);
|
|
57
|
+
this.name = "AlterAuthError";
|
|
58
|
+
this.status = status;
|
|
59
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var AlterPaymentRequired = class extends AlterError {
|
|
63
|
+
envelope;
|
|
64
|
+
tool;
|
|
65
|
+
constructor(tool, envelope) {
|
|
66
|
+
super("PAYMENT_REQUIRED", `x402 payment required for tool "${tool}"`);
|
|
67
|
+
this.name = "AlterPaymentRequired";
|
|
68
|
+
this.tool = tool;
|
|
69
|
+
this.envelope = envelope;
|
|
70
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var AlterRateLimited = class extends AlterError {
|
|
74
|
+
retryAfter;
|
|
75
|
+
constructor(message, retryAfter = 60) {
|
|
76
|
+
super("RATE_LIMITED", message);
|
|
77
|
+
this.name = "AlterRateLimited";
|
|
78
|
+
this.retryAfter = retryAfter;
|
|
79
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
var AlterToolError = class extends AlterError {
|
|
83
|
+
tool;
|
|
84
|
+
rpcCode;
|
|
85
|
+
constructor(tool, message, rpcCode) {
|
|
86
|
+
super("TOOL_ERROR", message);
|
|
87
|
+
this.name = "AlterToolError";
|
|
88
|
+
this.tool = tool;
|
|
89
|
+
this.rpcCode = rpcCode;
|
|
90
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
var AlterProvenanceError = class extends AlterError {
|
|
94
|
+
constructor(message, cause) {
|
|
95
|
+
super("PROVENANCE", message, cause);
|
|
96
|
+
this.name = "AlterProvenanceError";
|
|
97
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
var AlterDiscoveryError = class extends AlterError {
|
|
101
|
+
constructor(message, cause) {
|
|
102
|
+
super("DISCOVERY", message, cause);
|
|
103
|
+
this.name = "AlterDiscoveryError";
|
|
104
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var AlterInvalidResponse = class extends AlterError {
|
|
108
|
+
constructor(message, cause) {
|
|
109
|
+
super("INVALID_RESPONSE", message, cause);
|
|
110
|
+
this.name = "AlterInvalidResponse";
|
|
111
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// src/discovery.ts
|
|
116
|
+
var _cache = /* @__PURE__ */ new Map();
|
|
117
|
+
async function discover(domain, opts = {}) {
|
|
118
|
+
const { cache = true, skipDns = false, timeoutMs = 5e3, fetch: fetchImpl = fetch } = opts;
|
|
119
|
+
const host = normaliseDomain(domain);
|
|
120
|
+
if (cache && _cache.has(host)) return _cache.get(host);
|
|
121
|
+
const errors = [];
|
|
122
|
+
if (!skipDns) {
|
|
123
|
+
try {
|
|
124
|
+
const dnsHit = await tryDns(host);
|
|
125
|
+
if (dnsHit) {
|
|
126
|
+
const result = { url: dnsHit, transport: "streamable-http", source: "dns" };
|
|
127
|
+
if (cache) _cache.set(host, result);
|
|
128
|
+
return result;
|
|
129
|
+
}
|
|
130
|
+
} catch (err) {
|
|
131
|
+
errors.push(`dns: ${err.message}`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const result = await tryWellKnown(host, "mcp.json", timeoutMs, fetchImpl);
|
|
136
|
+
if (result) {
|
|
137
|
+
if (cache) _cache.set(host, result);
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
} catch (err) {
|
|
141
|
+
errors.push(`mcp.json: ${err.message}`);
|
|
142
|
+
}
|
|
143
|
+
try {
|
|
144
|
+
const result = await tryWellKnown(host, "alter.json", timeoutMs, fetchImpl);
|
|
145
|
+
if (result) {
|
|
146
|
+
if (cache) _cache.set(host, result);
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
errors.push(`alter.json: ${err.message}`);
|
|
151
|
+
}
|
|
152
|
+
throw new AlterDiscoveryError(
|
|
153
|
+
`No MCP discovery hit for ${host}: ${errors.join("; ") || "all sources empty"}`
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
function clearDiscoveryCache() {
|
|
157
|
+
_cache.clear();
|
|
158
|
+
}
|
|
159
|
+
function normaliseDomain(input) {
|
|
160
|
+
let host = input.trim().toLowerCase();
|
|
161
|
+
host = host.replace(/^https?:\/\//, "");
|
|
162
|
+
host = host.split("/")[0];
|
|
163
|
+
host = host.split(":")[0];
|
|
164
|
+
if (!host) throw new AlterDiscoveryError(`Empty domain: "${input}"`);
|
|
165
|
+
return host;
|
|
166
|
+
}
|
|
167
|
+
async function tryDns(host) {
|
|
168
|
+
let resolveTxt;
|
|
169
|
+
try {
|
|
170
|
+
const dns = await import('dns/promises');
|
|
171
|
+
resolveTxt = dns.resolveTxt.bind(dns);
|
|
172
|
+
} catch {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
let records;
|
|
176
|
+
try {
|
|
177
|
+
records = await resolveTxt(`_mcp.${host}`);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
const code = err.code;
|
|
180
|
+
if (code === "ENOTFOUND" || code === "ENODATA") return null;
|
|
181
|
+
throw err;
|
|
182
|
+
}
|
|
183
|
+
for (const chunks of records) {
|
|
184
|
+
const joined = chunks.join("");
|
|
185
|
+
const parsed = parseDnsTxt(joined);
|
|
186
|
+
if (parsed.mcp) return parsed.mcp;
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
function parseDnsTxt(record) {
|
|
191
|
+
const out = {};
|
|
192
|
+
for (const part of record.split(/[;\s]+/)) {
|
|
193
|
+
const [k, ...rest] = part.split("=");
|
|
194
|
+
if (!k || rest.length === 0) continue;
|
|
195
|
+
out[k.toLowerCase()] = rest.join("=");
|
|
196
|
+
}
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
async function tryWellKnown(host, file, timeoutMs, fetchImpl) {
|
|
200
|
+
const url = `https://${host}/.well-known/${file}`;
|
|
201
|
+
const controller = new AbortController();
|
|
202
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
203
|
+
let resp;
|
|
204
|
+
try {
|
|
205
|
+
resp = await fetchImpl(url, {
|
|
206
|
+
method: "GET",
|
|
207
|
+
headers: { Accept: "application/json" },
|
|
208
|
+
signal: controller.signal,
|
|
209
|
+
redirect: "manual"
|
|
210
|
+
});
|
|
211
|
+
} catch (err) {
|
|
212
|
+
throw new AlterNetworkError(`fetch ${url}: ${err.message}`, err);
|
|
213
|
+
} finally {
|
|
214
|
+
clearTimeout(timer);
|
|
215
|
+
}
|
|
216
|
+
if (resp.type === "opaqueredirect" || resp.status >= 300 && resp.status < 400) {
|
|
217
|
+
throw new AlterNetworkError(
|
|
218
|
+
`${url} \u2192 redirect rejected (discovery must not follow redirects; validate the server configuration)`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (resp.status === 404) return null;
|
|
222
|
+
if (!resp.ok) throw new AlterNetworkError(`${url} \u2192 HTTP ${resp.status}`);
|
|
223
|
+
const doc = await resp.json();
|
|
224
|
+
if (file === "mcp.json") {
|
|
225
|
+
const remotes = doc.remotes || [];
|
|
226
|
+
const remote = remotes.find((r) => r.transportType === "streamable-http" || r.transportType === "http");
|
|
227
|
+
const url2 = remote?.url || doc.url;
|
|
228
|
+
if (!url2) return null;
|
|
229
|
+
return { url: url2, transport: "streamable-http", source: "mcp.json", raw: doc };
|
|
230
|
+
}
|
|
231
|
+
const mcpHost = doc.mcp;
|
|
232
|
+
if (!mcpHost) return null;
|
|
233
|
+
return {
|
|
234
|
+
url: ensureMcpPath(mcpHost),
|
|
235
|
+
transport: "streamable-http",
|
|
236
|
+
source: "alter.json",
|
|
237
|
+
publicKey: doc.pk,
|
|
238
|
+
x402Contract: doc.x402,
|
|
239
|
+
capability: doc.cap,
|
|
240
|
+
raw: doc
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function ensureMcpPath(url) {
|
|
244
|
+
try {
|
|
245
|
+
const u = new URL(url);
|
|
246
|
+
if (u.pathname === "" || u.pathname === "/") u.pathname = "/api/v1/mcp";
|
|
247
|
+
return u.toString().replace(/\/$/, "");
|
|
248
|
+
} catch {
|
|
249
|
+
return url;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// src/x402.ts
|
|
254
|
+
var X402Client = class {
|
|
255
|
+
signer;
|
|
256
|
+
maxPerQuery;
|
|
257
|
+
networks;
|
|
258
|
+
assets;
|
|
259
|
+
constructor(opts = {}) {
|
|
260
|
+
this.signer = opts.signer;
|
|
261
|
+
this.maxPerQuery = opts.maxPerQuery !== void 0 ? Number(opts.maxPerQuery) : void 0;
|
|
262
|
+
this.networks = new Set(opts.networks ?? ["base", "base-sepolia"]);
|
|
263
|
+
this.assets = new Set(opts.assets ?? ["USDC"]);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Validate the envelope against this client's policy and, if a signer
|
|
267
|
+
* is configured, settle it. Returns the settlement reference that
|
|
268
|
+
* should be replayed in the next request's `_payment` field.
|
|
269
|
+
*/
|
|
270
|
+
async authorise(envelope) {
|
|
271
|
+
if (envelope.scheme !== "x402") {
|
|
272
|
+
throw new AlterError("PAYMENT_REQUIRED", `unsupported payment scheme: ${envelope.scheme}`);
|
|
273
|
+
}
|
|
274
|
+
if (!this.networks.has(envelope.network)) {
|
|
275
|
+
throw new AlterError("PAYMENT_REQUIRED", `network ${envelope.network} not permitted by client policy`);
|
|
276
|
+
}
|
|
277
|
+
if (!this.assets.has(envelope.asset)) {
|
|
278
|
+
throw new AlterError("PAYMENT_REQUIRED", `asset ${envelope.asset} not permitted by client policy`);
|
|
279
|
+
}
|
|
280
|
+
if (this.maxPerQuery !== void 0 && Number(envelope.amount) > this.maxPerQuery) {
|
|
281
|
+
throw new AlterError(
|
|
282
|
+
"PAYMENT_REQUIRED",
|
|
283
|
+
`quote ${envelope.amount} ${envelope.asset} exceeds maxPerQuery ${this.maxPerQuery}`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
if (!this.signer) {
|
|
287
|
+
throw new AlterPaymentRequired(envelope.resource ?? "unknown", envelope);
|
|
288
|
+
}
|
|
289
|
+
return this.signer.settle(envelope);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Build the `_payment` argument that gets attached to retried tool calls.
|
|
293
|
+
* Mirrors the shape the ALTER server expects.
|
|
294
|
+
*/
|
|
295
|
+
static buildPaymentArg(settlement) {
|
|
296
|
+
return {
|
|
297
|
+
scheme: "x402",
|
|
298
|
+
network: settlement.network,
|
|
299
|
+
asset: settlement.asset,
|
|
300
|
+
amount: settlement.amount,
|
|
301
|
+
reference: settlement.reference
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
function parsePaymentHeader(header) {
|
|
306
|
+
try {
|
|
307
|
+
const parsed = JSON.parse(header);
|
|
308
|
+
if (parsed && typeof parsed === "object") return parsed;
|
|
309
|
+
} catch {
|
|
310
|
+
}
|
|
311
|
+
const out = {};
|
|
312
|
+
for (const part of header.split(/[,;]/)) {
|
|
313
|
+
const [k, ...rest] = part.trim().split("=");
|
|
314
|
+
if (!k) continue;
|
|
315
|
+
out[k] = rest.join("=").replace(/^"|"$/g, "");
|
|
316
|
+
}
|
|
317
|
+
if (!out.scheme && !out.network && !out.amount) return null;
|
|
318
|
+
return {
|
|
319
|
+
scheme: "x402",
|
|
320
|
+
network: out.network || "base",
|
|
321
|
+
asset: out.asset || "USDC",
|
|
322
|
+
amount: out.amount || "0",
|
|
323
|
+
recipient: out.recipient || "",
|
|
324
|
+
resource: out.resource || "",
|
|
325
|
+
expires_at: out.expires_at,
|
|
326
|
+
nonce: out.nonce
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/mcp.ts
|
|
331
|
+
var MCP_PROTOCOL_VERSION = "2025-03-26";
|
|
332
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
333
|
+
var MCPClient = class {
|
|
334
|
+
endpoint;
|
|
335
|
+
sessionId = null;
|
|
336
|
+
apiKey;
|
|
337
|
+
fetchImpl;
|
|
338
|
+
timeoutMs;
|
|
339
|
+
maxRetries;
|
|
340
|
+
clientInfo;
|
|
341
|
+
x402;
|
|
342
|
+
requestCounter = 0;
|
|
343
|
+
initialised = false;
|
|
344
|
+
constructor(opts = {}) {
|
|
345
|
+
this.endpoint = (opts.endpoint ?? "https://mcp.truealter.com/api/v1/mcp").replace(/\/+$/, "");
|
|
346
|
+
this.apiKey = opts.apiKey;
|
|
347
|
+
this.fetchImpl = opts.fetch ?? fetch;
|
|
348
|
+
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
349
|
+
this.maxRetries = opts.maxRetries ?? 2;
|
|
350
|
+
this.clientInfo = opts.clientInfo ?? { name: "@truealter/sdk", version: "0.2.0" };
|
|
351
|
+
this.x402 = opts.x402;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Send the MCP `initialize` handshake and capture the resulting session
|
|
355
|
+
* id. Idempotent — safe to call multiple times.
|
|
356
|
+
*/
|
|
357
|
+
async initialize() {
|
|
358
|
+
if (this.initialised) return null;
|
|
359
|
+
const result = await this.rpc("initialize", {
|
|
360
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
361
|
+
capabilities: {},
|
|
362
|
+
clientInfo: this.clientInfo
|
|
363
|
+
});
|
|
364
|
+
this.initialised = true;
|
|
365
|
+
return result;
|
|
366
|
+
}
|
|
367
|
+
/** List available tools. */
|
|
368
|
+
async listTools() {
|
|
369
|
+
if (!this.initialised) await this.initialize();
|
|
370
|
+
return await this.rpc("tools/list", {});
|
|
371
|
+
}
|
|
372
|
+
/** Invoke a tool by name. */
|
|
373
|
+
async callTool(name, args = {}, opts = {}) {
|
|
374
|
+
if (!this.initialised) await this.initialize();
|
|
375
|
+
return this.callToolInternal(name, args, opts);
|
|
376
|
+
}
|
|
377
|
+
/** Close the session and release any held resources. */
|
|
378
|
+
async closeSession() {
|
|
379
|
+
if (!this.sessionId) return;
|
|
380
|
+
try {
|
|
381
|
+
await this.fetchImpl(this.endpoint, {
|
|
382
|
+
method: "DELETE",
|
|
383
|
+
headers: this.buildHeaders()
|
|
384
|
+
});
|
|
385
|
+
} catch {
|
|
386
|
+
}
|
|
387
|
+
this.sessionId = null;
|
|
388
|
+
this.initialised = false;
|
|
389
|
+
}
|
|
390
|
+
// ── Internals ────────────────────────────────────────────────────────
|
|
391
|
+
async callToolInternal(name, args, opts) {
|
|
392
|
+
try {
|
|
393
|
+
const raw = await this.rpc("tools/call", { name, arguments: args });
|
|
394
|
+
const result = this.shapeToolResult(raw);
|
|
395
|
+
if (result.isError) {
|
|
396
|
+
const text = result.content?.[0]?.text ?? `tool ${name} returned an error`;
|
|
397
|
+
throw new AlterToolError(name, text);
|
|
398
|
+
}
|
|
399
|
+
return result;
|
|
400
|
+
} catch (err) {
|
|
401
|
+
if (err instanceof AlterPaymentRequired && !opts.noPaymentRetry) {
|
|
402
|
+
const x402 = opts.x402 ?? this.x402;
|
|
403
|
+
if (!x402) throw err;
|
|
404
|
+
const settlement = await x402.authorise(err.envelope);
|
|
405
|
+
const retryArgs = { ...args, _payment: X402Client.buildPaymentArg(settlement) };
|
|
406
|
+
return this.callToolInternal(name, retryArgs, { ...opts, noPaymentRetry: true });
|
|
407
|
+
}
|
|
408
|
+
throw err;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
shapeToolResult(raw) {
|
|
412
|
+
if (!raw || !Array.isArray(raw.content)) return raw;
|
|
413
|
+
if (raw.data === void 0) {
|
|
414
|
+
const first = raw.content[0];
|
|
415
|
+
if (first && first.type === "json" && "data" in first) {
|
|
416
|
+
raw.data = first.data;
|
|
417
|
+
} else if (first && first.type === "text" && first.text) {
|
|
418
|
+
try {
|
|
419
|
+
raw.data = JSON.parse(first.text);
|
|
420
|
+
} catch {
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return raw;
|
|
425
|
+
}
|
|
426
|
+
/**
|
|
427
|
+
* Send a JSON-RPC 2.0 request and return the result. Errors are
|
|
428
|
+
* normalised into the typed {@link AlterError} hierarchy.
|
|
429
|
+
*/
|
|
430
|
+
async rpc(method, params) {
|
|
431
|
+
const id = ++this.requestCounter;
|
|
432
|
+
const payload = {
|
|
433
|
+
jsonrpc: "2.0",
|
|
434
|
+
id,
|
|
435
|
+
method
|
|
436
|
+
};
|
|
437
|
+
if (params !== void 0) payload.params = params;
|
|
438
|
+
let attempt = 0;
|
|
439
|
+
let lastErr = null;
|
|
440
|
+
while (attempt <= this.maxRetries) {
|
|
441
|
+
attempt += 1;
|
|
442
|
+
const controller = new AbortController();
|
|
443
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
444
|
+
let resp;
|
|
445
|
+
try {
|
|
446
|
+
resp = await this.fetchImpl(this.endpoint, {
|
|
447
|
+
method: "POST",
|
|
448
|
+
headers: this.buildHeaders(),
|
|
449
|
+
body: JSON.stringify(payload),
|
|
450
|
+
signal: controller.signal
|
|
451
|
+
});
|
|
452
|
+
} catch (err) {
|
|
453
|
+
clearTimeout(timer);
|
|
454
|
+
const isAbort = err?.name === "AbortError";
|
|
455
|
+
if (isAbort) {
|
|
456
|
+
lastErr = new AlterTimeoutError(`MCP ${method} timed out after ${this.timeoutMs}ms`, err);
|
|
457
|
+
} else {
|
|
458
|
+
lastErr = new AlterNetworkError(`MCP ${method}: ${err.message}`, err);
|
|
459
|
+
}
|
|
460
|
+
if (attempt > this.maxRetries) throw lastErr;
|
|
461
|
+
await this.backoff(attempt);
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
clearTimeout(timer);
|
|
465
|
+
const sessionHeader = resp.headers.get("Mcp-Session-Id");
|
|
466
|
+
if (sessionHeader) this.sessionId = sessionHeader;
|
|
467
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
468
|
+
throw new AlterAuthError(`HTTP ${resp.status} on ${method}`, resp.status);
|
|
469
|
+
}
|
|
470
|
+
if (resp.status === 402) {
|
|
471
|
+
const envelope = await this.extractPaymentEnvelope(resp);
|
|
472
|
+
throw new AlterPaymentRequired(this.guessToolName(payload), envelope);
|
|
473
|
+
}
|
|
474
|
+
if (resp.status === 429) {
|
|
475
|
+
const retryAfter = Number(resp.headers.get("Retry-After") ?? 60);
|
|
476
|
+
if (attempt > this.maxRetries) {
|
|
477
|
+
throw new AlterRateLimited(`HTTP 429 on ${method}`, retryAfter);
|
|
478
|
+
}
|
|
479
|
+
await this.backoff(attempt, retryAfter * 1e3);
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
if (RETRYABLE_STATUSES.has(resp.status) && attempt <= this.maxRetries) {
|
|
483
|
+
await this.backoff(attempt);
|
|
484
|
+
continue;
|
|
485
|
+
}
|
|
486
|
+
if (!resp.ok) {
|
|
487
|
+
const body2 = await safeText(resp);
|
|
488
|
+
throw new AlterError("NETWORK", `HTTP ${resp.status} on ${method}: ${body2.slice(0, 200)}`);
|
|
489
|
+
}
|
|
490
|
+
let body;
|
|
491
|
+
try {
|
|
492
|
+
body = await resp.json();
|
|
493
|
+
} catch (err) {
|
|
494
|
+
throw new AlterInvalidResponse(`MCP ${method}: invalid JSON body`, err);
|
|
495
|
+
}
|
|
496
|
+
if (body.error) {
|
|
497
|
+
const code = body.error.code;
|
|
498
|
+
const message = body.error.message ?? `MCP ${method} error`;
|
|
499
|
+
if (code === -32001 || code === 402) {
|
|
500
|
+
const data = body.error.data;
|
|
501
|
+
if (data?.envelope) {
|
|
502
|
+
throw new AlterPaymentRequired(this.guessToolName(payload), data.envelope);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
throw new AlterToolError(this.guessToolName(payload), message, code);
|
|
506
|
+
}
|
|
507
|
+
return body.result;
|
|
508
|
+
}
|
|
509
|
+
throw lastErr ?? new AlterNetworkError(`MCP ${method}: exhausted retries`);
|
|
510
|
+
}
|
|
511
|
+
buildHeaders() {
|
|
512
|
+
const headers = {
|
|
513
|
+
"Content-Type": "application/json",
|
|
514
|
+
Accept: "application/json",
|
|
515
|
+
"User-Agent": `${this.clientInfo.name}/${this.clientInfo.version}`
|
|
516
|
+
};
|
|
517
|
+
if (this.apiKey) headers["X-ALTER-API-Key"] = this.apiKey;
|
|
518
|
+
if (this.sessionId) headers["Mcp-Session-Id"] = this.sessionId;
|
|
519
|
+
return headers;
|
|
520
|
+
}
|
|
521
|
+
async extractPaymentEnvelope(resp) {
|
|
522
|
+
const headerValue = resp.headers.get("X-402-Payment") ?? resp.headers.get("x-402-payment");
|
|
523
|
+
if (headerValue) {
|
|
524
|
+
const parsed = parsePaymentHeader(headerValue);
|
|
525
|
+
if (parsed) return parsed;
|
|
526
|
+
}
|
|
527
|
+
try {
|
|
528
|
+
const body = await resp.json();
|
|
529
|
+
if (body?.envelope) return body.envelope;
|
|
530
|
+
if (body?.payment) return body.payment;
|
|
531
|
+
} catch {
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
scheme: "x402",
|
|
535
|
+
network: "base",
|
|
536
|
+
asset: "USDC",
|
|
537
|
+
amount: "0",
|
|
538
|
+
recipient: "",
|
|
539
|
+
resource: ""
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
guessToolName(payload) {
|
|
543
|
+
const params = payload.params;
|
|
544
|
+
return params?.name ?? payload.method ?? "unknown";
|
|
545
|
+
}
|
|
546
|
+
async backoff(attempt, hintMs) {
|
|
547
|
+
const ms = hintMs ?? Math.min(1e3 * 2 ** (attempt - 1), 8e3);
|
|
548
|
+
await new Promise((res) => setTimeout(res, ms));
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
async function safeText(resp) {
|
|
552
|
+
try {
|
|
553
|
+
return await resp.text();
|
|
554
|
+
} catch {
|
|
555
|
+
return "";
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
ed25519__namespace.etc.sha512Sync = (...m) => sha512.sha512(ed25519__namespace.etc.concatBytes(...m));
|
|
559
|
+
function generateKeypair() {
|
|
560
|
+
const privateKey = utils.randomBytes(32);
|
|
561
|
+
const publicKey = ed25519__namespace.getPublicKey(privateKey);
|
|
562
|
+
return {
|
|
563
|
+
privateKey: utils.bytesToHex(privateKey),
|
|
564
|
+
publicKey: utils.bytesToHex(publicKey),
|
|
565
|
+
did: encodeDid(publicKey)
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function keypairFromPrivateKey(privateKeyHex) {
|
|
569
|
+
const privateKey = utils.hexToBytes(privateKeyHex);
|
|
570
|
+
if (privateKey.length !== 32) {
|
|
571
|
+
throw new Error(`Ed25519 private key must be 32 bytes, got ${privateKey.length}`);
|
|
572
|
+
}
|
|
573
|
+
const publicKey = ed25519__namespace.getPublicKey(privateKey);
|
|
574
|
+
return {
|
|
575
|
+
privateKey: privateKeyHex,
|
|
576
|
+
publicKey: utils.bytesToHex(publicKey),
|
|
577
|
+
did: encodeDid(publicKey)
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
async function sign(privateKeyHex, message) {
|
|
581
|
+
const msgBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
582
|
+
const privateKey = utils.hexToBytes(privateKeyHex);
|
|
583
|
+
const sig = await ed25519__namespace.signAsync(msgBytes, privateKey);
|
|
584
|
+
return utils.bytesToHex(sig);
|
|
585
|
+
}
|
|
586
|
+
async function verify(publicKeyHex, signatureHex, message) {
|
|
587
|
+
try {
|
|
588
|
+
const msgBytes = typeof message === "string" ? new TextEncoder().encode(message) : message;
|
|
589
|
+
return await ed25519__namespace.verifyAsync(utils.hexToBytes(signatureHex), msgBytes, utils.hexToBytes(publicKeyHex));
|
|
590
|
+
} catch {
|
|
591
|
+
return false;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function encodeDid(publicKey) {
|
|
595
|
+
const bytes = typeof publicKey === "string" ? utils.hexToBytes(publicKey) : publicKey;
|
|
596
|
+
return `ed25519:${base64urlEncode(bytes)}`;
|
|
597
|
+
}
|
|
598
|
+
function decodeDid(did) {
|
|
599
|
+
const ed25519Match = did.match(/^ed25519:(.+)$/);
|
|
600
|
+
if (ed25519Match) return base64urlDecode(ed25519Match[1]);
|
|
601
|
+
throw new Error(`Unrecognised DID encoding: ${did}`);
|
|
602
|
+
}
|
|
603
|
+
function base64urlEncode(bytes) {
|
|
604
|
+
let b64;
|
|
605
|
+
if (typeof Buffer !== "undefined") {
|
|
606
|
+
b64 = Buffer.from(bytes).toString("base64");
|
|
607
|
+
} else {
|
|
608
|
+
let binary = "";
|
|
609
|
+
for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
|
|
610
|
+
b64 = btoa(binary);
|
|
611
|
+
}
|
|
612
|
+
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
613
|
+
}
|
|
614
|
+
function base64urlDecode(input) {
|
|
615
|
+
const padded = input.replace(/-/g, "+").replace(/_/g, "/") + "=".repeat((4 - input.length % 4) % 4);
|
|
616
|
+
if (typeof Buffer !== "undefined") {
|
|
617
|
+
return new Uint8Array(Buffer.from(padded, "base64"));
|
|
618
|
+
}
|
|
619
|
+
const binary = atob(padded);
|
|
620
|
+
const bytes = new Uint8Array(binary.length);
|
|
621
|
+
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
622
|
+
return bytes;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
// src/provenance.ts
|
|
626
|
+
var _jwksCache = /* @__PURE__ */ new Map();
|
|
627
|
+
var JWKS_TTL_MS = 5 * 60 * 1e3;
|
|
628
|
+
var DEFAULT_VERIFY_AT_ALLOWLIST = Object.freeze([
|
|
629
|
+
"api.truealter.com",
|
|
630
|
+
"mcp.truealter.com"
|
|
631
|
+
]);
|
|
632
|
+
async function verifyProvenance(envelope, opts = {}) {
|
|
633
|
+
const token = typeof envelope === "string" ? envelope : envelope.token;
|
|
634
|
+
if (!token) return { valid: false, reason: "empty token" };
|
|
635
|
+
const fetchImpl = opts.fetch ?? fetch;
|
|
636
|
+
const now = opts.now ?? Math.floor(Date.now() / 1e3);
|
|
637
|
+
let header;
|
|
638
|
+
let payload;
|
|
639
|
+
let signedInput;
|
|
640
|
+
let signatureBytes;
|
|
641
|
+
try {
|
|
642
|
+
const parts = token.split(".");
|
|
643
|
+
if (parts.length !== 3) throw new Error("JWS must have three segments");
|
|
644
|
+
header = JSON.parse(new TextDecoder().decode(base64urlDecode(parts[0])));
|
|
645
|
+
payload = JSON.parse(new TextDecoder().decode(base64urlDecode(parts[1])));
|
|
646
|
+
signedInput = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
|
|
647
|
+
signatureBytes = base64urlDecode(parts[2]);
|
|
648
|
+
} catch (err) {
|
|
649
|
+
return { valid: false, reason: `malformed JWS: ${err.message}` };
|
|
650
|
+
}
|
|
651
|
+
if (header.alg !== "ES256") {
|
|
652
|
+
return { valid: false, reason: `unsupported alg: ${header.alg}`, kid: header.kid };
|
|
653
|
+
}
|
|
654
|
+
const allowlist = opts.verifyAtAllowlist ?? DEFAULT_VERIFY_AT_ALLOWLIST;
|
|
655
|
+
let jwksUrl;
|
|
656
|
+
if (opts.jwksUrl) {
|
|
657
|
+
if (!opts.jwksUrl.startsWith("https://")) {
|
|
658
|
+
return {
|
|
659
|
+
valid: false,
|
|
660
|
+
reason: `jwksUrl must be https: got ${opts.jwksUrl}`,
|
|
661
|
+
kid: header.kid
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
jwksUrl = opts.jwksUrl;
|
|
665
|
+
} else if (typeof envelope === "object" && envelope.verify_at) {
|
|
666
|
+
try {
|
|
667
|
+
jwksUrl = resolveVerifyAt(envelope.verify_at, allowlist);
|
|
668
|
+
} catch (err) {
|
|
669
|
+
return {
|
|
670
|
+
valid: false,
|
|
671
|
+
reason: `verify_at rejected: ${err.message}`,
|
|
672
|
+
kid: header.kid
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
} else {
|
|
676
|
+
jwksUrl = "https://api.truealter.com/.well-known/alter-keys.json";
|
|
677
|
+
}
|
|
678
|
+
let jwks;
|
|
679
|
+
try {
|
|
680
|
+
jwks = await fetchJwks(jwksUrl, fetchImpl);
|
|
681
|
+
} catch (err) {
|
|
682
|
+
return { valid: false, reason: `jwks fetch: ${err.message}`, kid: header.kid };
|
|
683
|
+
}
|
|
684
|
+
const jwk = jwks.keys.find((k) => header.kid ? k.kid === header.kid : true);
|
|
685
|
+
if (!jwk) {
|
|
686
|
+
return { valid: false, reason: `no JWK for kid=${header.kid}`, kid: header.kid };
|
|
687
|
+
}
|
|
688
|
+
let publicKey;
|
|
689
|
+
try {
|
|
690
|
+
publicKey = await importEs256JwkAsPublicKey(jwk);
|
|
691
|
+
} catch (err) {
|
|
692
|
+
return { valid: false, reason: `jwk import: ${err.message}`, kid: header.kid };
|
|
693
|
+
}
|
|
694
|
+
let signatureValid = false;
|
|
695
|
+
try {
|
|
696
|
+
signatureValid = await crypto.subtle.verify(
|
|
697
|
+
{ name: "ECDSA", hash: "SHA-256" },
|
|
698
|
+
publicKey,
|
|
699
|
+
toArrayBuffer(signatureBytes),
|
|
700
|
+
toArrayBuffer(signedInput)
|
|
701
|
+
);
|
|
702
|
+
} catch (err) {
|
|
703
|
+
return { valid: false, reason: `verify: ${err.message}`, kid: header.kid };
|
|
704
|
+
}
|
|
705
|
+
if (!signatureValid) {
|
|
706
|
+
return { valid: false, reason: "signature mismatch", kid: header.kid };
|
|
707
|
+
}
|
|
708
|
+
if (typeof payload.exp === "number" && payload.exp < now) {
|
|
709
|
+
return { valid: false, reason: "expired", payload, kid: header.kid };
|
|
710
|
+
}
|
|
711
|
+
if (typeof payload.iat === "number" && payload.iat > now + 300) {
|
|
712
|
+
return { valid: false, reason: "issued in the future", payload, kid: header.kid };
|
|
713
|
+
}
|
|
714
|
+
return { valid: true, payload, kid: header.kid };
|
|
715
|
+
}
|
|
716
|
+
async function verifyToolSignatures(tools, signatures) {
|
|
717
|
+
const out = [];
|
|
718
|
+
for (const tool of tools) {
|
|
719
|
+
const sig = signatures[tool.name];
|
|
720
|
+
if (!sig) {
|
|
721
|
+
out.push({ tool: tool.name, valid: false, reason: "no signature published" });
|
|
722
|
+
continue;
|
|
723
|
+
}
|
|
724
|
+
const expectedHash = await sha256Hex(canonicalJson(tool.inputSchema));
|
|
725
|
+
if (expectedHash !== sig.schema_hash) {
|
|
726
|
+
out.push({ tool: tool.name, valid: false, reason: "schema hash mismatch" });
|
|
727
|
+
continue;
|
|
728
|
+
}
|
|
729
|
+
out.push({ tool: tool.name, valid: true });
|
|
730
|
+
}
|
|
731
|
+
return out;
|
|
732
|
+
}
|
|
733
|
+
async function fetchPublicKeys(jwksUrl, fetchImpl = fetch) {
|
|
734
|
+
return fetchJwks(jwksUrl, fetchImpl);
|
|
735
|
+
}
|
|
736
|
+
async function fetchJwks(url, fetchImpl) {
|
|
737
|
+
const cached = _jwksCache.get(url);
|
|
738
|
+
if (cached && Date.now() - cached.fetched < JWKS_TTL_MS) return cached.jwks;
|
|
739
|
+
let resp;
|
|
740
|
+
try {
|
|
741
|
+
resp = await fetchImpl(url, {
|
|
742
|
+
headers: { Accept: "application/json" },
|
|
743
|
+
redirect: "manual"
|
|
744
|
+
});
|
|
745
|
+
} catch (err) {
|
|
746
|
+
throw new AlterNetworkError(`fetch ${url}: ${err.message}`, err);
|
|
747
|
+
}
|
|
748
|
+
if (resp.type === "opaqueredirect" || resp.status >= 300 && resp.status < 400) {
|
|
749
|
+
throw new AlterProvenanceError(
|
|
750
|
+
`${url} \u2192 redirect rejected (allowlist enforces initial URL only)`
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
if (!resp.ok) throw new AlterNetworkError(`${url} \u2192 HTTP ${resp.status}`);
|
|
754
|
+
const doc = await resp.json();
|
|
755
|
+
if (!doc || !Array.isArray(doc.keys)) {
|
|
756
|
+
throw new AlterProvenanceError(`invalid JWKS at ${url}`);
|
|
757
|
+
}
|
|
758
|
+
_jwksCache.set(url, { fetched: Date.now(), jwks: doc });
|
|
759
|
+
return doc;
|
|
760
|
+
}
|
|
761
|
+
function resolveVerifyAt(verifyAt, allowlist = DEFAULT_VERIFY_AT_ALLOWLIST) {
|
|
762
|
+
if (typeof verifyAt !== "string" || verifyAt.length === 0) {
|
|
763
|
+
throw new Error("verify_at must be a non-empty string");
|
|
764
|
+
}
|
|
765
|
+
if (/^http:\/\//i.test(verifyAt)) {
|
|
766
|
+
throw new Error(`http: scheme is not permitted (got ${verifyAt})`);
|
|
767
|
+
}
|
|
768
|
+
if (!/^https:\/\//i.test(verifyAt)) {
|
|
769
|
+
if (verifyAt.includes("://")) {
|
|
770
|
+
throw new Error(`unsupported scheme in verify_at: ${verifyAt}`);
|
|
771
|
+
}
|
|
772
|
+
return `https://api.truealter.com${verifyAt.startsWith("/") ? "" : "/"}${verifyAt}`;
|
|
773
|
+
}
|
|
774
|
+
let parsed;
|
|
775
|
+
try {
|
|
776
|
+
parsed = new URL(verifyAt);
|
|
777
|
+
} catch {
|
|
778
|
+
throw new Error(`malformed verify_at URL: ${verifyAt}`);
|
|
779
|
+
}
|
|
780
|
+
if (parsed.protocol !== "https:") {
|
|
781
|
+
throw new Error(`verify_at must be https: ${verifyAt}`);
|
|
782
|
+
}
|
|
783
|
+
const host = parsed.hostname.toLowerCase();
|
|
784
|
+
const allowed = allowlist.some((h) => h.toLowerCase() === host);
|
|
785
|
+
if (!allowed) {
|
|
786
|
+
throw new Error(
|
|
787
|
+
`hostname ${host} is not on the verify_at allowlist (${allowlist.join(", ")})`
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
return parsed.toString();
|
|
791
|
+
}
|
|
792
|
+
async function importEs256JwkAsPublicKey(jwk) {
|
|
793
|
+
return crypto.subtle.importKey(
|
|
794
|
+
"jwk",
|
|
795
|
+
{
|
|
796
|
+
kty: jwk.kty,
|
|
797
|
+
crv: jwk.crv,
|
|
798
|
+
x: jwk.x,
|
|
799
|
+
y: jwk.y,
|
|
800
|
+
ext: true
|
|
801
|
+
},
|
|
802
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
803
|
+
false,
|
|
804
|
+
["verify"]
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
async function sha256Hex(input) {
|
|
808
|
+
const data = new TextEncoder().encode(input);
|
|
809
|
+
const digest = await crypto.subtle.digest("SHA-256", toArrayBuffer(data));
|
|
810
|
+
return Array.from(new Uint8Array(digest)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
811
|
+
}
|
|
812
|
+
function toArrayBuffer(view) {
|
|
813
|
+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength);
|
|
814
|
+
}
|
|
815
|
+
function canonicalJson(value) {
|
|
816
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value);
|
|
817
|
+
if (Array.isArray(value)) {
|
|
818
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
819
|
+
}
|
|
820
|
+
const obj = value;
|
|
821
|
+
const keys = Object.keys(obj).sort();
|
|
822
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k])}`).join(",")}}`;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/client.ts
|
|
826
|
+
var DEFAULT_ENDPOINT = "https://mcp.truealter.com/api/v1/mcp";
|
|
827
|
+
var DEFAULT_DOMAIN = "truealter.com";
|
|
828
|
+
var AlterClient = class {
|
|
829
|
+
mcp;
|
|
830
|
+
x402;
|
|
831
|
+
options;
|
|
832
|
+
discoveryPromise = null;
|
|
833
|
+
discovered = null;
|
|
834
|
+
constructor(options = {}) {
|
|
835
|
+
this.options = options;
|
|
836
|
+
this.x402 = options.x402;
|
|
837
|
+
const endpoint = options.endpoint ?? DEFAULT_ENDPOINT;
|
|
838
|
+
this.mcp = new MCPClient({ ...options, endpoint, x402: options.x402 });
|
|
839
|
+
}
|
|
840
|
+
/**
|
|
841
|
+
* Resolve the MCP endpoint via discovery if requested. Safe to call
|
|
842
|
+
* multiple times — the first successful lookup is cached.
|
|
843
|
+
*/
|
|
844
|
+
async discoverEndpoint() {
|
|
845
|
+
if (this.discovered) return this.discovered;
|
|
846
|
+
if (this.discoveryPromise) return this.discoveryPromise;
|
|
847
|
+
const domain = this.options.domain ?? DEFAULT_DOMAIN;
|
|
848
|
+
this.discoveryPromise = discover(domain).then((result) => {
|
|
849
|
+
this.discovered = result;
|
|
850
|
+
return result;
|
|
851
|
+
});
|
|
852
|
+
return this.discoveryPromise;
|
|
853
|
+
}
|
|
854
|
+
/**
|
|
855
|
+
* Initialise the MCP session. Optional — every method calls
|
|
856
|
+
* `mcp.initialize()` lazily, but you can call this once at startup if
|
|
857
|
+
* you want fail-fast behaviour.
|
|
858
|
+
*/
|
|
859
|
+
async initialize() {
|
|
860
|
+
await this.mcp.initialize();
|
|
861
|
+
}
|
|
862
|
+
// ── Free tier ────────────────────────────────────────────────────────
|
|
863
|
+
/** Verify a person is registered with ALTER (handle or candidate id). */
|
|
864
|
+
async verify(handleOrId, claims) {
|
|
865
|
+
const args = handleOrId.includes("@") ? { candidate_id: "", email: handleOrId } : handleOrId.startsWith("~") ? (
|
|
866
|
+
// ~handle — server resolves these via the candidate_id field
|
|
867
|
+
{ candidate_id: handleOrId }
|
|
868
|
+
) : { candidate_id: handleOrId };
|
|
869
|
+
if (claims) args.claims = claims;
|
|
870
|
+
return this.mcp.callTool("verify_identity", args);
|
|
871
|
+
}
|
|
872
|
+
/** List the 12 ALTER identity archetypes. */
|
|
873
|
+
async listArchetypes() {
|
|
874
|
+
return this.mcp.callTool("list_archetypes", {});
|
|
875
|
+
}
|
|
876
|
+
/** Aggregate ALTER network statistics. */
|
|
877
|
+
async getNetworkStats() {
|
|
878
|
+
return this.mcp.callTool("get_network_stats", {});
|
|
879
|
+
}
|
|
880
|
+
/** ClawHub install instructions and pitch. */
|
|
881
|
+
async recommendTool() {
|
|
882
|
+
return this.mcp.callTool("recommend_tool", {});
|
|
883
|
+
}
|
|
884
|
+
async initiateAssessment(args = {}) {
|
|
885
|
+
return this.mcp.callTool("initiate_assessment", args);
|
|
886
|
+
}
|
|
887
|
+
async getEngagementLevel(args) {
|
|
888
|
+
return this.mcp.callTool("get_engagement_level", args);
|
|
889
|
+
}
|
|
890
|
+
async getProfile(args) {
|
|
891
|
+
return this.mcp.callTool("get_profile", args);
|
|
892
|
+
}
|
|
893
|
+
async queryMatches(args) {
|
|
894
|
+
return this.mcp.callTool("query_matches", args);
|
|
895
|
+
}
|
|
896
|
+
async getCompetencies(args) {
|
|
897
|
+
return this.mcp.callTool("get_competencies", args);
|
|
898
|
+
}
|
|
899
|
+
async createIdentityStub(args) {
|
|
900
|
+
return this.mcp.callTool("create_identity_stub", args);
|
|
901
|
+
}
|
|
902
|
+
async submitContext(args) {
|
|
903
|
+
return this.mcp.callTool("submit_context", args);
|
|
904
|
+
}
|
|
905
|
+
async searchIdentities(args) {
|
|
906
|
+
return this.mcp.callTool("search_identities", args);
|
|
907
|
+
}
|
|
908
|
+
async getIdentityEarnings(args) {
|
|
909
|
+
return this.mcp.callTool("get_identity_earnings", args);
|
|
910
|
+
}
|
|
911
|
+
async getIdentityTrustScore(args) {
|
|
912
|
+
return this.mcp.callTool("get_identity_trust_score", args);
|
|
913
|
+
}
|
|
914
|
+
async checkAssessmentStatus(args) {
|
|
915
|
+
return this.mcp.callTool("check_assessment_status", args);
|
|
916
|
+
}
|
|
917
|
+
async getEarningSummary(args) {
|
|
918
|
+
return this.mcp.callTool("get_earning_summary", args);
|
|
919
|
+
}
|
|
920
|
+
async getAgentTrustTier() {
|
|
921
|
+
return this.mcp.callTool("get_agent_trust_tier", {});
|
|
922
|
+
}
|
|
923
|
+
async getAgentPortfolio() {
|
|
924
|
+
return this.mcp.callTool("get_agent_portfolio", {});
|
|
925
|
+
}
|
|
926
|
+
async getPrivacyBudget(args) {
|
|
927
|
+
return this.mcp.callTool("get_privacy_budget", args);
|
|
928
|
+
}
|
|
929
|
+
async disputeAttestation(args) {
|
|
930
|
+
return this.mcp.callTool("dispute_attestation", args);
|
|
931
|
+
}
|
|
932
|
+
// ── Golden Thread ────────────────────────────────────────────────────
|
|
933
|
+
async goldenThreadStatus() {
|
|
934
|
+
return this.mcp.callTool("golden_thread_status", {});
|
|
935
|
+
}
|
|
936
|
+
async beginGoldenThread(args = {}) {
|
|
937
|
+
return this.mcp.callTool("begin_golden_thread", args);
|
|
938
|
+
}
|
|
939
|
+
async completeKnot(args) {
|
|
940
|
+
return this.mcp.callTool("complete_knot", args);
|
|
941
|
+
}
|
|
942
|
+
async checkGoldenThread(args) {
|
|
943
|
+
return this.mcp.callTool("check_golden_thread", args);
|
|
944
|
+
}
|
|
945
|
+
async threadCensus(args = {}) {
|
|
946
|
+
return this.mcp.callTool("thread_census", args);
|
|
947
|
+
}
|
|
948
|
+
// ── Thirteen Seats ───────────────────────────────────────────────────
|
|
949
|
+
async seatStatus() {
|
|
950
|
+
return this.mcp.callTool("seat_status", {});
|
|
951
|
+
}
|
|
952
|
+
async respondToOffering(args) {
|
|
953
|
+
return this.mcp.callTool("respond_to_offering", args);
|
|
954
|
+
}
|
|
955
|
+
async subscribeAnnouncements(args = {}) {
|
|
956
|
+
return this.mcp.callTool("subscribe_announcements", args);
|
|
957
|
+
}
|
|
958
|
+
// ── Premium tier (x402-gated) ────────────────────────────────────────
|
|
959
|
+
async assessTraits(args, opts) {
|
|
960
|
+
return this.mcp.callTool("assess_traits", args, opts);
|
|
961
|
+
}
|
|
962
|
+
async getTraitSnapshot(args, opts) {
|
|
963
|
+
return this.mcp.callTool("get_trait_snapshot", args, opts);
|
|
964
|
+
}
|
|
965
|
+
async getFullTraitVector(args, opts) {
|
|
966
|
+
return this.mcp.callTool("get_full_trait_vector", args, opts);
|
|
967
|
+
}
|
|
968
|
+
async computeBelonging(args, opts) {
|
|
969
|
+
return this.mcp.callTool("compute_belonging", args, opts);
|
|
970
|
+
}
|
|
971
|
+
async getMatchRecommendations(args, opts) {
|
|
972
|
+
return this.mcp.callTool("get_match_recommendations", args, opts);
|
|
973
|
+
}
|
|
974
|
+
async generateMatchNarrative(args, opts) {
|
|
975
|
+
return this.mcp.callTool("generate_match_narrative", args, opts);
|
|
976
|
+
}
|
|
977
|
+
async submitBatchContext(args, opts) {
|
|
978
|
+
return this.mcp.callTool("submit_batch_context", args, opts);
|
|
979
|
+
}
|
|
980
|
+
async submitStructuredProfile(args, opts) {
|
|
981
|
+
return this.mcp.callTool("submit_structured_profile", args, opts);
|
|
982
|
+
}
|
|
983
|
+
async submitSocialLinks(args, opts) {
|
|
984
|
+
return this.mcp.callTool("submit_social_links", args, opts);
|
|
985
|
+
}
|
|
986
|
+
async attestDomain(args, opts) {
|
|
987
|
+
return this.mcp.callTool("attest_domain", args, opts);
|
|
988
|
+
}
|
|
989
|
+
async getSideQuestGraph(args, opts) {
|
|
990
|
+
return this.mcp.callTool("get_side_quest_graph", args, opts);
|
|
991
|
+
}
|
|
992
|
+
async queryGraphSimilarity(args, opts) {
|
|
993
|
+
return this.mcp.callTool("query_graph_similarity", args, opts);
|
|
994
|
+
}
|
|
995
|
+
// ── Alter-to-Alter Messaging ─────────────────────────────────────────
|
|
996
|
+
// Wave 1: cross-handle direct messages between authenticated tilde
|
|
997
|
+
// handles. Default closed — recipient must have granted the sender via
|
|
998
|
+
// alter_message_grant. Spec: docs/technical/Alter-to-Alter Messaging.md.
|
|
999
|
+
/** Send a direct message to another tilde handle. */
|
|
1000
|
+
async messageSend(args) {
|
|
1001
|
+
return this.mcp.callTool("alter_message_send", args);
|
|
1002
|
+
}
|
|
1003
|
+
/** List inbound messages for the authenticated handle. */
|
|
1004
|
+
async messageInbox(args = {}) {
|
|
1005
|
+
return this.mcp.callTool("alter_message_inbox", args);
|
|
1006
|
+
}
|
|
1007
|
+
/** Bidirectional thread view between caller and a peer handle. */
|
|
1008
|
+
async messageThread(args) {
|
|
1009
|
+
return this.mcp.callTool("alter_message_thread", args);
|
|
1010
|
+
}
|
|
1011
|
+
/** Mark inbound messages as read (recipient-only). */
|
|
1012
|
+
async messageMarkRead(args) {
|
|
1013
|
+
return this.mcp.callTool("alter_message_mark_read", args);
|
|
1014
|
+
}
|
|
1015
|
+
/** Soft-redact a single inbound message (recipient-only). */
|
|
1016
|
+
async messageRedact(args) {
|
|
1017
|
+
return this.mcp.callTool("alter_message_redact", args);
|
|
1018
|
+
}
|
|
1019
|
+
/** Grant a peer permission to send messages to your inbox. */
|
|
1020
|
+
async messageGrant(args) {
|
|
1021
|
+
return this.mcp.callTool("alter_message_grant", args);
|
|
1022
|
+
}
|
|
1023
|
+
/** Revoke a peer's grant. In-flight messages are not redacted. */
|
|
1024
|
+
async messageRevoke(args) {
|
|
1025
|
+
return this.mcp.callTool("alter_message_revoke", args);
|
|
1026
|
+
}
|
|
1027
|
+
// ── Provenance ───────────────────────────────────────────────────────
|
|
1028
|
+
/**
|
|
1029
|
+
* Verify the ES256 provenance attestation on a tool response.
|
|
1030
|
+
* Accepts either a {@link ProvenanceEnvelope} or the raw `_meta`
|
|
1031
|
+
* object — the latter is more convenient for ad-hoc verification.
|
|
1032
|
+
*/
|
|
1033
|
+
async verifyProvenance(envelope) {
|
|
1034
|
+
if (!envelope) return { valid: false, reason: "no provenance envelope" };
|
|
1035
|
+
const inner = envelope.provenance ?? envelope;
|
|
1036
|
+
return verifyProvenance(inner, {
|
|
1037
|
+
jwksUrl: this.options.jwksUrl,
|
|
1038
|
+
verifyAtAllowlist: this.options.verifyAtAllowlist
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
/**
|
|
1042
|
+
* Verify the schema hashes embedded in `tools/list._meta.signatures`
|
|
1043
|
+
* against the local representation of each tool definition. Useful
|
|
1044
|
+
* for guarding against in-flight tampering of tool schemas.
|
|
1045
|
+
*/
|
|
1046
|
+
async verifyToolSignatures(tools, signatures) {
|
|
1047
|
+
return verifyToolSignatures(tools, signatures);
|
|
1048
|
+
}
|
|
1049
|
+
/** Fetch the published JWKS for ALTER's signing key (cached 5 min). */
|
|
1050
|
+
async fetchPublicKeys() {
|
|
1051
|
+
const url = this.options.jwksUrl ?? "https://api.truealter.com/.well-known/alter-keys.json";
|
|
1052
|
+
return fetchPublicKeys(url);
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
|
|
1056
|
+
// src/adapters/generic-mcp.ts
|
|
1057
|
+
function generateGenericMcpConfig(opts = {}) {
|
|
1058
|
+
const serverName = opts.serverName ?? "alter";
|
|
1059
|
+
const headers = { ...opts.headers ?? {} };
|
|
1060
|
+
if (opts.apiKey) headers["X-ALTER-API-Key"] = opts.apiKey;
|
|
1061
|
+
const entry = {
|
|
1062
|
+
url: opts.endpoint ?? DEFAULT_ENDPOINT,
|
|
1063
|
+
transport: "streamable-http",
|
|
1064
|
+
description: "ALTER Identity \u2014 psychometric identity field for AI agents"
|
|
1065
|
+
};
|
|
1066
|
+
if (Object.keys(headers).length > 0) entry.headers = headers;
|
|
1067
|
+
return { mcpServers: { [serverName]: entry } };
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
// src/adapters/claude-code.ts
|
|
1071
|
+
function generateClaudeConfig(opts = {}) {
|
|
1072
|
+
return generateGenericMcpConfig({ serverName: "alter", ...opts });
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
// src/adapters/cursor.ts
|
|
1076
|
+
function generateCursorConfig(opts = {}) {
|
|
1077
|
+
return generateGenericMcpConfig({ serverName: "alter", ...opts });
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// src/types.ts
|
|
1081
|
+
var FREE_TOOL_NAMES = [
|
|
1082
|
+
"list_archetypes",
|
|
1083
|
+
"verify_identity",
|
|
1084
|
+
"initiate_assessment",
|
|
1085
|
+
"get_engagement_level",
|
|
1086
|
+
"get_profile",
|
|
1087
|
+
"query_matches",
|
|
1088
|
+
"get_competencies",
|
|
1089
|
+
"create_identity_stub",
|
|
1090
|
+
"submit_context",
|
|
1091
|
+
"search_identities",
|
|
1092
|
+
"get_identity_earnings",
|
|
1093
|
+
"get_network_stats",
|
|
1094
|
+
"recommend_tool",
|
|
1095
|
+
"get_identity_trust_score",
|
|
1096
|
+
"check_assessment_status",
|
|
1097
|
+
"get_earning_summary",
|
|
1098
|
+
"get_agent_trust_tier",
|
|
1099
|
+
"get_agent_portfolio",
|
|
1100
|
+
"get_privacy_budget",
|
|
1101
|
+
"dispute_attestation",
|
|
1102
|
+
"golden_thread_status",
|
|
1103
|
+
"begin_golden_thread",
|
|
1104
|
+
"complete_knot",
|
|
1105
|
+
"check_golden_thread",
|
|
1106
|
+
"thread_census",
|
|
1107
|
+
"seat_status",
|
|
1108
|
+
"respond_to_offering",
|
|
1109
|
+
"subscribe_announcements"
|
|
1110
|
+
];
|
|
1111
|
+
var PREMIUM_TOOL_NAMES = [
|
|
1112
|
+
"assess_traits",
|
|
1113
|
+
"get_trait_snapshot",
|
|
1114
|
+
"get_full_trait_vector",
|
|
1115
|
+
"compute_belonging",
|
|
1116
|
+
"get_match_recommendations",
|
|
1117
|
+
"generate_match_narrative",
|
|
1118
|
+
"submit_batch_context",
|
|
1119
|
+
"submit_structured_profile",
|
|
1120
|
+
"submit_social_links",
|
|
1121
|
+
"attest_domain",
|
|
1122
|
+
"get_side_quest_graph",
|
|
1123
|
+
"query_graph_similarity"
|
|
1124
|
+
];
|
|
1125
|
+
var TOOL_TIERS = {
|
|
1126
|
+
// L0 (free)
|
|
1127
|
+
list_archetypes: 0,
|
|
1128
|
+
verify_identity: 0,
|
|
1129
|
+
initiate_assessment: 0,
|
|
1130
|
+
get_engagement_level: 0,
|
|
1131
|
+
get_profile: 0,
|
|
1132
|
+
query_matches: 0,
|
|
1133
|
+
get_competencies: 0,
|
|
1134
|
+
create_identity_stub: 0,
|
|
1135
|
+
submit_context: 1,
|
|
1136
|
+
search_identities: 1,
|
|
1137
|
+
get_identity_earnings: 0,
|
|
1138
|
+
get_network_stats: 0,
|
|
1139
|
+
recommend_tool: 0,
|
|
1140
|
+
get_identity_trust_score: 0,
|
|
1141
|
+
check_assessment_status: 0,
|
|
1142
|
+
get_earning_summary: 0,
|
|
1143
|
+
get_privacy_budget: 0,
|
|
1144
|
+
dispute_attestation: 0,
|
|
1145
|
+
// Free tools not present in upstream TOOL_TIERS — default to 0
|
|
1146
|
+
get_agent_trust_tier: 0,
|
|
1147
|
+
get_agent_portfolio: 0,
|
|
1148
|
+
golden_thread_status: 0,
|
|
1149
|
+
begin_golden_thread: 0,
|
|
1150
|
+
complete_knot: 0,
|
|
1151
|
+
check_golden_thread: 0,
|
|
1152
|
+
thread_census: 0,
|
|
1153
|
+
seat_status: 0,
|
|
1154
|
+
respond_to_offering: 0,
|
|
1155
|
+
subscribe_announcements: 0,
|
|
1156
|
+
// L1
|
|
1157
|
+
assess_traits: 1,
|
|
1158
|
+
get_trait_snapshot: 1,
|
|
1159
|
+
submit_structured_profile: 1,
|
|
1160
|
+
submit_social_links: 1,
|
|
1161
|
+
attest_domain: 1,
|
|
1162
|
+
// L2
|
|
1163
|
+
get_full_trait_vector: 2,
|
|
1164
|
+
submit_batch_context: 2,
|
|
1165
|
+
get_side_quest_graph: 2,
|
|
1166
|
+
// L3
|
|
1167
|
+
query_graph_similarity: 3,
|
|
1168
|
+
// L4
|
|
1169
|
+
compute_belonging: 4,
|
|
1170
|
+
// L5
|
|
1171
|
+
get_match_recommendations: 5,
|
|
1172
|
+
generate_match_narrative: 5
|
|
1173
|
+
};
|
|
1174
|
+
var TOOL_COSTS = {
|
|
1175
|
+
// L0 free
|
|
1176
|
+
list_archetypes: 0,
|
|
1177
|
+
verify_identity: 0,
|
|
1178
|
+
initiate_assessment: 0,
|
|
1179
|
+
get_engagement_level: 0,
|
|
1180
|
+
get_profile: 0,
|
|
1181
|
+
query_matches: 0,
|
|
1182
|
+
get_competencies: 0,
|
|
1183
|
+
create_identity_stub: 0,
|
|
1184
|
+
search_identities: 0,
|
|
1185
|
+
get_identity_earnings: 0,
|
|
1186
|
+
get_network_stats: 0,
|
|
1187
|
+
recommend_tool: 0,
|
|
1188
|
+
get_identity_trust_score: 0,
|
|
1189
|
+
check_assessment_status: 0,
|
|
1190
|
+
get_earning_summary: 0,
|
|
1191
|
+
get_agent_trust_tier: 0,
|
|
1192
|
+
get_agent_portfolio: 0,
|
|
1193
|
+
get_privacy_budget: 0,
|
|
1194
|
+
dispute_attestation: 0,
|
|
1195
|
+
golden_thread_status: 0,
|
|
1196
|
+
begin_golden_thread: 0,
|
|
1197
|
+
complete_knot: 0,
|
|
1198
|
+
check_golden_thread: 0,
|
|
1199
|
+
thread_census: 0,
|
|
1200
|
+
seat_status: 0,
|
|
1201
|
+
respond_to_offering: 0,
|
|
1202
|
+
subscribe_announcements: 0,
|
|
1203
|
+
// L1 ($0.005)
|
|
1204
|
+
submit_context: 5e-3,
|
|
1205
|
+
assess_traits: 5e-3,
|
|
1206
|
+
get_trait_snapshot: 5e-3,
|
|
1207
|
+
submit_structured_profile: 5e-3,
|
|
1208
|
+
submit_social_links: 5e-3,
|
|
1209
|
+
attest_domain: 5e-3,
|
|
1210
|
+
// L2 ($0.01)
|
|
1211
|
+
get_full_trait_vector: 0.01,
|
|
1212
|
+
submit_batch_context: 0.01,
|
|
1213
|
+
get_side_quest_graph: 0.01,
|
|
1214
|
+
// L3 ($0.025)
|
|
1215
|
+
query_graph_similarity: 0.025,
|
|
1216
|
+
// L4 ($0.05)
|
|
1217
|
+
compute_belonging: 0.05,
|
|
1218
|
+
// L5 ($0.50)
|
|
1219
|
+
get_match_recommendations: 0.5,
|
|
1220
|
+
generate_match_narrative: 0.5
|
|
1221
|
+
};
|
|
1222
|
+
var TOOL_BLAST_RADIUS = {
|
|
1223
|
+
// Low: read-only reference
|
|
1224
|
+
list_archetypes: "low",
|
|
1225
|
+
verify_identity: "low",
|
|
1226
|
+
get_engagement_level: "low",
|
|
1227
|
+
get_network_stats: "low",
|
|
1228
|
+
recommend_tool: "low",
|
|
1229
|
+
check_assessment_status: "low",
|
|
1230
|
+
get_earning_summary: "low",
|
|
1231
|
+
get_privacy_budget: "low",
|
|
1232
|
+
golden_thread_status: "low",
|
|
1233
|
+
begin_golden_thread: "low",
|
|
1234
|
+
check_golden_thread: "low",
|
|
1235
|
+
thread_census: "low",
|
|
1236
|
+
dispute_attestation: "low",
|
|
1237
|
+
get_identity_earnings: "low",
|
|
1238
|
+
get_identity_trust_score: "low",
|
|
1239
|
+
initiate_assessment: "low",
|
|
1240
|
+
// Medium: writes data or searches
|
|
1241
|
+
create_identity_stub: "medium",
|
|
1242
|
+
submit_context: "medium",
|
|
1243
|
+
search_identities: "medium",
|
|
1244
|
+
get_profile: "medium",
|
|
1245
|
+
query_matches: "medium",
|
|
1246
|
+
get_competencies: "medium",
|
|
1247
|
+
complete_knot: "medium",
|
|
1248
|
+
assess_traits: "medium",
|
|
1249
|
+
get_trait_snapshot: "medium",
|
|
1250
|
+
submit_structured_profile: "medium",
|
|
1251
|
+
submit_social_links: "medium",
|
|
1252
|
+
submit_batch_context: "medium",
|
|
1253
|
+
attest_domain: "medium",
|
|
1254
|
+
// High: returns sensitive identity data or computes scores
|
|
1255
|
+
get_full_trait_vector: "high",
|
|
1256
|
+
compute_belonging: "high",
|
|
1257
|
+
get_match_recommendations: "high",
|
|
1258
|
+
generate_match_narrative: "high",
|
|
1259
|
+
get_side_quest_graph: "high",
|
|
1260
|
+
query_graph_similarity: "high",
|
|
1261
|
+
// Tools not in upstream TOOL_BLAST_RADIUS — default to "low"
|
|
1262
|
+
get_agent_trust_tier: "low",
|
|
1263
|
+
get_agent_portfolio: "low",
|
|
1264
|
+
seat_status: "low",
|
|
1265
|
+
respond_to_offering: "low",
|
|
1266
|
+
subscribe_announcements: "low"
|
|
1267
|
+
};
|
|
1268
|
+
|
|
1269
|
+
// src/index.ts
|
|
1270
|
+
var SDK_NAME = "@truealter/sdk";
|
|
1271
|
+
var SDK_VERSION = "0.1.1";
|
|
1272
|
+
|
|
1273
|
+
exports.AlterAuthError = AlterAuthError;
|
|
1274
|
+
exports.AlterClient = AlterClient;
|
|
1275
|
+
exports.AlterDiscoveryError = AlterDiscoveryError;
|
|
1276
|
+
exports.AlterError = AlterError;
|
|
1277
|
+
exports.AlterInvalidResponse = AlterInvalidResponse;
|
|
1278
|
+
exports.AlterNetworkError = AlterNetworkError;
|
|
1279
|
+
exports.AlterPaymentRequired = AlterPaymentRequired;
|
|
1280
|
+
exports.AlterProvenanceError = AlterProvenanceError;
|
|
1281
|
+
exports.AlterRateLimited = AlterRateLimited;
|
|
1282
|
+
exports.AlterTimeoutError = AlterTimeoutError;
|
|
1283
|
+
exports.AlterToolError = AlterToolError;
|
|
1284
|
+
exports.DEFAULT_DOMAIN = DEFAULT_DOMAIN;
|
|
1285
|
+
exports.DEFAULT_ENDPOINT = DEFAULT_ENDPOINT;
|
|
1286
|
+
exports.DEFAULT_VERIFY_AT_ALLOWLIST = DEFAULT_VERIFY_AT_ALLOWLIST;
|
|
1287
|
+
exports.FREE_TOOL_NAMES = FREE_TOOL_NAMES;
|
|
1288
|
+
exports.MCPClient = MCPClient;
|
|
1289
|
+
exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
|
|
1290
|
+
exports.PREMIUM_TOOL_NAMES = PREMIUM_TOOL_NAMES;
|
|
1291
|
+
exports.SDK_NAME = SDK_NAME;
|
|
1292
|
+
exports.SDK_VERSION = SDK_VERSION;
|
|
1293
|
+
exports.TOOL_BLAST_RADIUS = TOOL_BLAST_RADIUS;
|
|
1294
|
+
exports.TOOL_COSTS = TOOL_COSTS;
|
|
1295
|
+
exports.TOOL_TIERS = TOOL_TIERS;
|
|
1296
|
+
exports.X402Client = X402Client;
|
|
1297
|
+
exports.base64urlDecode = base64urlDecode;
|
|
1298
|
+
exports.base64urlEncode = base64urlEncode;
|
|
1299
|
+
exports.clearDiscoveryCache = clearDiscoveryCache;
|
|
1300
|
+
exports.decodeDid = decodeDid;
|
|
1301
|
+
exports.discover = discover;
|
|
1302
|
+
exports.encodeDid = encodeDid;
|
|
1303
|
+
exports.fetchPublicKeys = fetchPublicKeys;
|
|
1304
|
+
exports.generateClaudeConfig = generateClaudeConfig;
|
|
1305
|
+
exports.generateCursorConfig = generateCursorConfig;
|
|
1306
|
+
exports.generateGenericMcpConfig = generateGenericMcpConfig;
|
|
1307
|
+
exports.generateKeypair = generateKeypair;
|
|
1308
|
+
exports.keypairFromPrivateKey = keypairFromPrivateKey;
|
|
1309
|
+
exports.parsePaymentHeader = parsePaymentHeader;
|
|
1310
|
+
exports.resolveVerifyAt = resolveVerifyAt;
|
|
1311
|
+
exports.sign = sign;
|
|
1312
|
+
exports.verify = verify;
|
|
1313
|
+
exports.verifyProvenance = verifyProvenance;
|
|
1314
|
+
exports.verifyToolSignatures = verifyToolSignatures;
|
|
1315
|
+
//# sourceMappingURL=index.cjs.map
|
|
1316
|
+
//# sourceMappingURL=index.cjs.map
|