@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
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from 'readline';
|
|
3
|
+
import { env, stderr, exit, stdin, stdout } from 'process';
|
|
4
|
+
|
|
5
|
+
// src/errors.ts
|
|
6
|
+
var AlterError = class extends Error {
|
|
7
|
+
code;
|
|
8
|
+
cause;
|
|
9
|
+
constructor(code, message, cause) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = "AlterError";
|
|
12
|
+
this.code = code;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
var AlterNetworkError = class extends AlterError {
|
|
18
|
+
constructor(message, cause) {
|
|
19
|
+
super("NETWORK", message, cause);
|
|
20
|
+
this.name = "AlterNetworkError";
|
|
21
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var AlterTimeoutError = class extends AlterError {
|
|
25
|
+
constructor(message, cause) {
|
|
26
|
+
super("TIMEOUT", message, cause);
|
|
27
|
+
this.name = "AlterTimeoutError";
|
|
28
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var AlterAuthError = class extends AlterError {
|
|
32
|
+
status;
|
|
33
|
+
constructor(message, status = 401) {
|
|
34
|
+
super("AUTH", message);
|
|
35
|
+
this.name = "AlterAuthError";
|
|
36
|
+
this.status = status;
|
|
37
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var AlterPaymentRequired = class extends AlterError {
|
|
41
|
+
envelope;
|
|
42
|
+
tool;
|
|
43
|
+
constructor(tool, envelope) {
|
|
44
|
+
super("PAYMENT_REQUIRED", `x402 payment required for tool "${tool}"`);
|
|
45
|
+
this.name = "AlterPaymentRequired";
|
|
46
|
+
this.tool = tool;
|
|
47
|
+
this.envelope = envelope;
|
|
48
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var AlterRateLimited = class extends AlterError {
|
|
52
|
+
retryAfter;
|
|
53
|
+
constructor(message, retryAfter = 60) {
|
|
54
|
+
super("RATE_LIMITED", message);
|
|
55
|
+
this.name = "AlterRateLimited";
|
|
56
|
+
this.retryAfter = retryAfter;
|
|
57
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var AlterToolError = class extends AlterError {
|
|
61
|
+
tool;
|
|
62
|
+
rpcCode;
|
|
63
|
+
constructor(tool, message, rpcCode) {
|
|
64
|
+
super("TOOL_ERROR", message);
|
|
65
|
+
this.name = "AlterToolError";
|
|
66
|
+
this.tool = tool;
|
|
67
|
+
this.rpcCode = rpcCode;
|
|
68
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var AlterInvalidResponse = class extends AlterError {
|
|
72
|
+
constructor(message, cause) {
|
|
73
|
+
super("INVALID_RESPONSE", message, cause);
|
|
74
|
+
this.name = "AlterInvalidResponse";
|
|
75
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// src/x402.ts
|
|
80
|
+
var X402Client = class {
|
|
81
|
+
signer;
|
|
82
|
+
maxPerQuery;
|
|
83
|
+
networks;
|
|
84
|
+
assets;
|
|
85
|
+
constructor(opts = {}) {
|
|
86
|
+
this.signer = opts.signer;
|
|
87
|
+
this.maxPerQuery = opts.maxPerQuery !== void 0 ? Number(opts.maxPerQuery) : void 0;
|
|
88
|
+
this.networks = new Set(opts.networks ?? ["base", "base-sepolia"]);
|
|
89
|
+
this.assets = new Set(opts.assets ?? ["USDC"]);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate the envelope against this client's policy and, if a signer
|
|
93
|
+
* is configured, settle it. Returns the settlement reference that
|
|
94
|
+
* should be replayed in the next request's `_payment` field.
|
|
95
|
+
*/
|
|
96
|
+
async authorise(envelope) {
|
|
97
|
+
if (envelope.scheme !== "x402") {
|
|
98
|
+
throw new AlterError("PAYMENT_REQUIRED", `unsupported payment scheme: ${envelope.scheme}`);
|
|
99
|
+
}
|
|
100
|
+
if (!this.networks.has(envelope.network)) {
|
|
101
|
+
throw new AlterError("PAYMENT_REQUIRED", `network ${envelope.network} not permitted by client policy`);
|
|
102
|
+
}
|
|
103
|
+
if (!this.assets.has(envelope.asset)) {
|
|
104
|
+
throw new AlterError("PAYMENT_REQUIRED", `asset ${envelope.asset} not permitted by client policy`);
|
|
105
|
+
}
|
|
106
|
+
if (this.maxPerQuery !== void 0 && Number(envelope.amount) > this.maxPerQuery) {
|
|
107
|
+
throw new AlterError(
|
|
108
|
+
"PAYMENT_REQUIRED",
|
|
109
|
+
`quote ${envelope.amount} ${envelope.asset} exceeds maxPerQuery ${this.maxPerQuery}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
if (!this.signer) {
|
|
113
|
+
throw new AlterPaymentRequired(envelope.resource ?? "unknown", envelope);
|
|
114
|
+
}
|
|
115
|
+
return this.signer.settle(envelope);
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build the `_payment` argument that gets attached to retried tool calls.
|
|
119
|
+
* Mirrors the shape the ALTER server expects.
|
|
120
|
+
*/
|
|
121
|
+
static buildPaymentArg(settlement) {
|
|
122
|
+
return {
|
|
123
|
+
scheme: "x402",
|
|
124
|
+
network: settlement.network,
|
|
125
|
+
asset: settlement.asset,
|
|
126
|
+
amount: settlement.amount,
|
|
127
|
+
reference: settlement.reference
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
function parsePaymentHeader(header) {
|
|
132
|
+
try {
|
|
133
|
+
const parsed = JSON.parse(header);
|
|
134
|
+
if (parsed && typeof parsed === "object") return parsed;
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
const out = {};
|
|
138
|
+
for (const part of header.split(/[,;]/)) {
|
|
139
|
+
const [k, ...rest] = part.trim().split("=");
|
|
140
|
+
if (!k) continue;
|
|
141
|
+
out[k] = rest.join("=").replace(/^"|"$/g, "");
|
|
142
|
+
}
|
|
143
|
+
if (!out.scheme && !out.network && !out.amount) return null;
|
|
144
|
+
return {
|
|
145
|
+
scheme: "x402",
|
|
146
|
+
network: out.network || "base",
|
|
147
|
+
asset: out.asset || "USDC",
|
|
148
|
+
amount: out.amount || "0",
|
|
149
|
+
recipient: out.recipient || "",
|
|
150
|
+
resource: out.resource || "",
|
|
151
|
+
expires_at: out.expires_at,
|
|
152
|
+
nonce: out.nonce
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// src/mcp.ts
|
|
157
|
+
var MCP_PROTOCOL_VERSION = "2025-03-26";
|
|
158
|
+
var RETRYABLE_STATUSES = /* @__PURE__ */ new Set([429, 502, 503, 504]);
|
|
159
|
+
var MCPClient = class {
|
|
160
|
+
endpoint;
|
|
161
|
+
sessionId = null;
|
|
162
|
+
apiKey;
|
|
163
|
+
fetchImpl;
|
|
164
|
+
timeoutMs;
|
|
165
|
+
maxRetries;
|
|
166
|
+
clientInfo;
|
|
167
|
+
x402;
|
|
168
|
+
requestCounter = 0;
|
|
169
|
+
initialised = false;
|
|
170
|
+
constructor(opts = {}) {
|
|
171
|
+
this.endpoint = (opts.endpoint ?? "https://mcp.truealter.com/api/v1/mcp").replace(/\/+$/, "");
|
|
172
|
+
this.apiKey = opts.apiKey;
|
|
173
|
+
this.fetchImpl = opts.fetch ?? fetch;
|
|
174
|
+
this.timeoutMs = opts.timeoutMs ?? 3e4;
|
|
175
|
+
this.maxRetries = opts.maxRetries ?? 2;
|
|
176
|
+
this.clientInfo = opts.clientInfo ?? { name: "@truealter/sdk", version: "0.2.0" };
|
|
177
|
+
this.x402 = opts.x402;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Send the MCP `initialize` handshake and capture the resulting session
|
|
181
|
+
* id. Idempotent — safe to call multiple times.
|
|
182
|
+
*/
|
|
183
|
+
async initialize() {
|
|
184
|
+
if (this.initialised) return null;
|
|
185
|
+
const result = await this.rpc("initialize", {
|
|
186
|
+
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
187
|
+
capabilities: {},
|
|
188
|
+
clientInfo: this.clientInfo
|
|
189
|
+
});
|
|
190
|
+
this.initialised = true;
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
/** List available tools. */
|
|
194
|
+
async listTools() {
|
|
195
|
+
if (!this.initialised) await this.initialize();
|
|
196
|
+
return await this.rpc("tools/list", {});
|
|
197
|
+
}
|
|
198
|
+
/** Invoke a tool by name. */
|
|
199
|
+
async callTool(name, args = {}, opts = {}) {
|
|
200
|
+
if (!this.initialised) await this.initialize();
|
|
201
|
+
return this.callToolInternal(name, args, opts);
|
|
202
|
+
}
|
|
203
|
+
/** Close the session and release any held resources. */
|
|
204
|
+
async closeSession() {
|
|
205
|
+
if (!this.sessionId) return;
|
|
206
|
+
try {
|
|
207
|
+
await this.fetchImpl(this.endpoint, {
|
|
208
|
+
method: "DELETE",
|
|
209
|
+
headers: this.buildHeaders()
|
|
210
|
+
});
|
|
211
|
+
} catch {
|
|
212
|
+
}
|
|
213
|
+
this.sessionId = null;
|
|
214
|
+
this.initialised = false;
|
|
215
|
+
}
|
|
216
|
+
// ── Internals ────────────────────────────────────────────────────────
|
|
217
|
+
async callToolInternal(name, args, opts) {
|
|
218
|
+
try {
|
|
219
|
+
const raw = await this.rpc("tools/call", { name, arguments: args });
|
|
220
|
+
const result = this.shapeToolResult(raw);
|
|
221
|
+
if (result.isError) {
|
|
222
|
+
const text = result.content?.[0]?.text ?? `tool ${name} returned an error`;
|
|
223
|
+
throw new AlterToolError(name, text);
|
|
224
|
+
}
|
|
225
|
+
return result;
|
|
226
|
+
} catch (err) {
|
|
227
|
+
if (err instanceof AlterPaymentRequired && !opts.noPaymentRetry) {
|
|
228
|
+
const x402 = opts.x402 ?? this.x402;
|
|
229
|
+
if (!x402) throw err;
|
|
230
|
+
const settlement = await x402.authorise(err.envelope);
|
|
231
|
+
const retryArgs = { ...args, _payment: X402Client.buildPaymentArg(settlement) };
|
|
232
|
+
return this.callToolInternal(name, retryArgs, { ...opts, noPaymentRetry: true });
|
|
233
|
+
}
|
|
234
|
+
throw err;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
shapeToolResult(raw) {
|
|
238
|
+
if (!raw || !Array.isArray(raw.content)) return raw;
|
|
239
|
+
if (raw.data === void 0) {
|
|
240
|
+
const first = raw.content[0];
|
|
241
|
+
if (first && first.type === "json" && "data" in first) {
|
|
242
|
+
raw.data = first.data;
|
|
243
|
+
} else if (first && first.type === "text" && first.text) {
|
|
244
|
+
try {
|
|
245
|
+
raw.data = JSON.parse(first.text);
|
|
246
|
+
} catch {
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return raw;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Send a JSON-RPC 2.0 request and return the result. Errors are
|
|
254
|
+
* normalised into the typed {@link AlterError} hierarchy.
|
|
255
|
+
*/
|
|
256
|
+
async rpc(method, params) {
|
|
257
|
+
const id = ++this.requestCounter;
|
|
258
|
+
const payload = {
|
|
259
|
+
jsonrpc: "2.0",
|
|
260
|
+
id,
|
|
261
|
+
method
|
|
262
|
+
};
|
|
263
|
+
if (params !== void 0) payload.params = params;
|
|
264
|
+
let attempt = 0;
|
|
265
|
+
let lastErr = null;
|
|
266
|
+
while (attempt <= this.maxRetries) {
|
|
267
|
+
attempt += 1;
|
|
268
|
+
const controller = new AbortController();
|
|
269
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
270
|
+
let resp;
|
|
271
|
+
try {
|
|
272
|
+
resp = await this.fetchImpl(this.endpoint, {
|
|
273
|
+
method: "POST",
|
|
274
|
+
headers: this.buildHeaders(),
|
|
275
|
+
body: JSON.stringify(payload),
|
|
276
|
+
signal: controller.signal
|
|
277
|
+
});
|
|
278
|
+
} catch (err) {
|
|
279
|
+
clearTimeout(timer);
|
|
280
|
+
const isAbort = err?.name === "AbortError";
|
|
281
|
+
if (isAbort) {
|
|
282
|
+
lastErr = new AlterTimeoutError(`MCP ${method} timed out after ${this.timeoutMs}ms`, err);
|
|
283
|
+
} else {
|
|
284
|
+
lastErr = new AlterNetworkError(`MCP ${method}: ${err.message}`, err);
|
|
285
|
+
}
|
|
286
|
+
if (attempt > this.maxRetries) throw lastErr;
|
|
287
|
+
await this.backoff(attempt);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
clearTimeout(timer);
|
|
291
|
+
const sessionHeader = resp.headers.get("Mcp-Session-Id");
|
|
292
|
+
if (sessionHeader) this.sessionId = sessionHeader;
|
|
293
|
+
if (resp.status === 401 || resp.status === 403) {
|
|
294
|
+
throw new AlterAuthError(`HTTP ${resp.status} on ${method}`, resp.status);
|
|
295
|
+
}
|
|
296
|
+
if (resp.status === 402) {
|
|
297
|
+
const envelope = await this.extractPaymentEnvelope(resp);
|
|
298
|
+
throw new AlterPaymentRequired(this.guessToolName(payload), envelope);
|
|
299
|
+
}
|
|
300
|
+
if (resp.status === 429) {
|
|
301
|
+
const retryAfter = Number(resp.headers.get("Retry-After") ?? 60);
|
|
302
|
+
if (attempt > this.maxRetries) {
|
|
303
|
+
throw new AlterRateLimited(`HTTP 429 on ${method}`, retryAfter);
|
|
304
|
+
}
|
|
305
|
+
await this.backoff(attempt, retryAfter * 1e3);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (RETRYABLE_STATUSES.has(resp.status) && attempt <= this.maxRetries) {
|
|
309
|
+
await this.backoff(attempt);
|
|
310
|
+
continue;
|
|
311
|
+
}
|
|
312
|
+
if (!resp.ok) {
|
|
313
|
+
const body2 = await safeText(resp);
|
|
314
|
+
throw new AlterError("NETWORK", `HTTP ${resp.status} on ${method}: ${body2.slice(0, 200)}`);
|
|
315
|
+
}
|
|
316
|
+
let body;
|
|
317
|
+
try {
|
|
318
|
+
body = await resp.json();
|
|
319
|
+
} catch (err) {
|
|
320
|
+
throw new AlterInvalidResponse(`MCP ${method}: invalid JSON body`, err);
|
|
321
|
+
}
|
|
322
|
+
if (body.error) {
|
|
323
|
+
const code = body.error.code;
|
|
324
|
+
const message = body.error.message ?? `MCP ${method} error`;
|
|
325
|
+
if (code === -32001 || code === 402) {
|
|
326
|
+
const data = body.error.data;
|
|
327
|
+
if (data?.envelope) {
|
|
328
|
+
throw new AlterPaymentRequired(this.guessToolName(payload), data.envelope);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
throw new AlterToolError(this.guessToolName(payload), message, code);
|
|
332
|
+
}
|
|
333
|
+
return body.result;
|
|
334
|
+
}
|
|
335
|
+
throw lastErr ?? new AlterNetworkError(`MCP ${method}: exhausted retries`);
|
|
336
|
+
}
|
|
337
|
+
buildHeaders() {
|
|
338
|
+
const headers = {
|
|
339
|
+
"Content-Type": "application/json",
|
|
340
|
+
Accept: "application/json",
|
|
341
|
+
"User-Agent": `${this.clientInfo.name}/${this.clientInfo.version}`
|
|
342
|
+
};
|
|
343
|
+
if (this.apiKey) headers["X-ALTER-API-Key"] = this.apiKey;
|
|
344
|
+
if (this.sessionId) headers["Mcp-Session-Id"] = this.sessionId;
|
|
345
|
+
return headers;
|
|
346
|
+
}
|
|
347
|
+
async extractPaymentEnvelope(resp) {
|
|
348
|
+
const headerValue = resp.headers.get("X-402-Payment") ?? resp.headers.get("x-402-payment");
|
|
349
|
+
if (headerValue) {
|
|
350
|
+
const parsed = parsePaymentHeader(headerValue);
|
|
351
|
+
if (parsed) return parsed;
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
const body = await resp.json();
|
|
355
|
+
if (body?.envelope) return body.envelope;
|
|
356
|
+
if (body?.payment) return body.payment;
|
|
357
|
+
} catch {
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
scheme: "x402",
|
|
361
|
+
network: "base",
|
|
362
|
+
asset: "USDC",
|
|
363
|
+
amount: "0",
|
|
364
|
+
recipient: "",
|
|
365
|
+
resource: ""
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
guessToolName(payload) {
|
|
369
|
+
const params = payload.params;
|
|
370
|
+
return params?.name ?? payload.method ?? "unknown";
|
|
371
|
+
}
|
|
372
|
+
async backoff(attempt, hintMs) {
|
|
373
|
+
const ms = hintMs ?? Math.min(1e3 * 2 ** (attempt - 1), 8e3);
|
|
374
|
+
await new Promise((res) => setTimeout(res, ms));
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
async function safeText(resp) {
|
|
378
|
+
try {
|
|
379
|
+
return await resp.text();
|
|
380
|
+
} catch {
|
|
381
|
+
return "";
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// bin/mcp-bridge.ts
|
|
386
|
+
var ENDPOINT = env.ALTER_MCP_ENDPOINT ?? "https://mcp.truealter.com/api/v1/mcp";
|
|
387
|
+
var API_KEY = env.ALTER_API_KEY ?? void 0;
|
|
388
|
+
var client = new MCPClient({
|
|
389
|
+
endpoint: ENDPOINT,
|
|
390
|
+
apiKey: API_KEY,
|
|
391
|
+
clientInfo: { name: "@truealter/sdk-mcp-bridge", version: "0.2.0" }
|
|
392
|
+
});
|
|
393
|
+
function send(response) {
|
|
394
|
+
stdout.write(JSON.stringify(response) + "\n");
|
|
395
|
+
}
|
|
396
|
+
function logDebug(...args) {
|
|
397
|
+
if (env.ALTER_BRIDGE_DEBUG) {
|
|
398
|
+
stderr.write(`[alter-bridge] ${args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ")}
|
|
399
|
+
`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
async function handle(req) {
|
|
403
|
+
const id = req.id ?? null;
|
|
404
|
+
try {
|
|
405
|
+
let result;
|
|
406
|
+
switch (req.method) {
|
|
407
|
+
case "initialize":
|
|
408
|
+
result = await client.rpc("initialize", req.params ?? {});
|
|
409
|
+
break;
|
|
410
|
+
case "initialized":
|
|
411
|
+
case "notifications/initialized":
|
|
412
|
+
return { jsonrpc: "2.0", id, result: null };
|
|
413
|
+
case "tools/list":
|
|
414
|
+
result = await client.rpc("tools/list", req.params ?? {});
|
|
415
|
+
break;
|
|
416
|
+
case "tools/call": {
|
|
417
|
+
const params = req.params ?? {};
|
|
418
|
+
if (!params.name) throw new AlterError("TOOL_ERROR", 'tools/call missing "name"');
|
|
419
|
+
result = await client.callTool(params.name, params.arguments ?? {});
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
case "resources/list":
|
|
423
|
+
case "resources/read":
|
|
424
|
+
case "prompts/list":
|
|
425
|
+
case "prompts/get":
|
|
426
|
+
case "ping":
|
|
427
|
+
result = await client.rpc(req.method, req.params ?? {});
|
|
428
|
+
break;
|
|
429
|
+
default:
|
|
430
|
+
result = await client.rpc(req.method, req.params ?? {});
|
|
431
|
+
}
|
|
432
|
+
return { jsonrpc: "2.0", id, result };
|
|
433
|
+
} catch (err) {
|
|
434
|
+
if (err instanceof AlterPaymentRequired) {
|
|
435
|
+
return {
|
|
436
|
+
jsonrpc: "2.0",
|
|
437
|
+
id,
|
|
438
|
+
error: {
|
|
439
|
+
code: 402,
|
|
440
|
+
message: `x402 payment required for ${err.tool}`,
|
|
441
|
+
data: { envelope: err.envelope }
|
|
442
|
+
}
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
if (err instanceof AlterError) {
|
|
446
|
+
return {
|
|
447
|
+
jsonrpc: "2.0",
|
|
448
|
+
id,
|
|
449
|
+
error: { code: -32e3, message: err.message, data: { code: err.code } }
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
jsonrpc: "2.0",
|
|
454
|
+
id,
|
|
455
|
+
error: { code: -32603, message: err.message ?? "internal error" }
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async function main() {
|
|
460
|
+
logDebug("starting; endpoint=", ENDPOINT, "apiKey=", API_KEY ? "(set)" : "(none)");
|
|
461
|
+
const rl = createInterface({ input: stdin, crlfDelay: Infinity });
|
|
462
|
+
for await (const line of rl) {
|
|
463
|
+
const trimmed = line.trim();
|
|
464
|
+
if (!trimmed) continue;
|
|
465
|
+
let req;
|
|
466
|
+
try {
|
|
467
|
+
req = JSON.parse(trimmed);
|
|
468
|
+
} catch {
|
|
469
|
+
logDebug("skipping non-JSON line:", trimmed.slice(0, 80));
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
if (req.jsonrpc !== "2.0" || typeof req.method !== "string") {
|
|
473
|
+
logDebug("skipping malformed request:", trimmed.slice(0, 80));
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
const response = await handle(req);
|
|
477
|
+
if (req.id !== void 0 && req.id !== null) {
|
|
478
|
+
send(response);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
logDebug("stdin closed; exiting");
|
|
482
|
+
await client.closeSession().catch(() => {
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
main().catch((err) => {
|
|
486
|
+
stderr.write(`[alter-bridge] fatal: ${err.message}
|
|
487
|
+
`);
|
|
488
|
+
exit(1);
|
|
489
|
+
});
|
|
490
|
+
//# sourceMappingURL=mcp-bridge.js.map
|
|
491
|
+
//# sourceMappingURL=mcp-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/errors.ts","../../src/x402.ts","../../src/mcp.ts","../../bin/mcp-bridge.ts"],"names":["body"],"mappings":"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","file":"mcp-bridge.js","sourcesContent":["/**\n * Typed error hierarchy for the ALTER Identity SDK.\n *\n * Every error thrown by the SDK is an instance of {@link AlterError}, with\n * a discriminated `code` field for programmatic handling. Network failures,\n * authentication problems, payment-required responses, rate limits, tool\n * execution failures, and provenance verification mismatches each get\n * their own subclass so consumers can `instanceof`-narrow.\n */\n\nexport type AlterErrorCode =\n | 'NETWORK'\n | 'TIMEOUT'\n | 'AUTH'\n | 'PAYMENT_REQUIRED'\n | 'RATE_LIMITED'\n | 'TOOL_ERROR'\n | 'PROVENANCE'\n | 'DISCOVERY'\n | 'INVALID_RESPONSE'\n | 'UNSUPPORTED';\n\nexport class AlterError extends Error {\n public readonly code: AlterErrorCode;\n public readonly cause?: unknown;\n\n constructor(code: AlterErrorCode, message: string, cause?: unknown) {\n super(message);\n this.name = 'AlterError';\n this.code = code;\n this.cause = cause;\n // Preserve the prototype chain across transpilation targets.\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterNetworkError extends AlterError {\n constructor(message: string, cause?: unknown) {\n super('NETWORK', message, cause);\n this.name = 'AlterNetworkError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterTimeoutError extends AlterError {\n constructor(message: string, cause?: unknown) {\n super('TIMEOUT', message, cause);\n this.name = 'AlterTimeoutError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterAuthError extends AlterError {\n public readonly status: number;\n\n constructor(message: string, status: number = 401) {\n super('AUTH', message);\n this.name = 'AlterAuthError';\n this.status = status;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * Thrown on HTTP 402. Carries the payment envelope returned by the server\n * so an x402 client can settle the transaction and retry.\n */\nexport class AlterPaymentRequired extends AlterError {\n public readonly envelope: PaymentEnvelope;\n public readonly tool: string;\n\n constructor(tool: string, envelope: PaymentEnvelope) {\n super('PAYMENT_REQUIRED', `x402 payment required for tool \"${tool}\"`);\n this.name = 'AlterPaymentRequired';\n this.tool = tool;\n this.envelope = envelope;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterRateLimited extends AlterError {\n public readonly retryAfter: number;\n\n constructor(message: string, retryAfter: number = 60) {\n super('RATE_LIMITED', message);\n this.name = 'AlterRateLimited';\n this.retryAfter = retryAfter;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterToolError extends AlterError {\n public readonly tool: string;\n public readonly rpcCode?: number;\n\n constructor(tool: string, message: string, rpcCode?: number) {\n super('TOOL_ERROR', message);\n this.name = 'AlterToolError';\n this.tool = tool;\n this.rpcCode = rpcCode;\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterProvenanceError extends AlterError {\n constructor(message: string, cause?: unknown) {\n super('PROVENANCE', message, cause);\n this.name = 'AlterProvenanceError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterDiscoveryError extends AlterError {\n constructor(message: string, cause?: unknown) {\n super('DISCOVERY', message, cause);\n this.name = 'AlterDiscoveryError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\nexport class AlterInvalidResponse extends AlterError {\n constructor(message: string, cause?: unknown) {\n super('INVALID_RESPONSE', message, cause);\n this.name = 'AlterInvalidResponse';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/**\n * x402 payment envelope returned in HTTP 402 responses or in the\n * `X-402-Payment` response header. The shape mirrors the x402 spec.\n */\nexport interface PaymentEnvelope {\n scheme: 'x402';\n network: 'base' | 'base-sepolia' | 'solana' | string;\n asset: 'USDC' | string;\n amount: string;\n recipient: string;\n resource: string;\n expires_at?: string;\n nonce?: string;\n /** Anything else the server included verbatim. */\n [extra: string]: unknown;\n}\n","/**\n * x402 micropayment client.\n *\n * Premium MCP tools return HTTP 402 with a payment envelope. The\n * {@link X402Client} settles the envelope on Base L2 (USDC) and replays\n * the original request with the resulting transaction reference.\n *\n * The actual on-chain settlement is delegated to a pluggable\n * {@link X402Signer} so that the SDK ships *without* a hard dependency\n * on viem, ethers, or any specific wallet library. Apps that want a\n * default signer should pass `viemX402Signer` (separate, opt-in package).\n */\n\nimport { AlterError, AlterPaymentRequired, type PaymentEnvelope } from './errors.js';\n\nexport interface X402Signer {\n /**\n * Settle a payment envelope and return a settlement reference (a tx hash\n * for EVM chains, a signature for off-chain payments). The reference is\n * what gets sent back to the MCP server to authorise the retry.\n */\n settle(envelope: PaymentEnvelope): Promise<X402Settlement>;\n}\n\nexport interface X402Settlement {\n /** EVM tx hash, Solana signature, or facilitator-issued reference. */\n reference: string;\n /** Network the settlement was broadcast on. */\n network: string;\n /** Amount paid (matches envelope.amount). */\n amount: string;\n /** Asset paid (matches envelope.asset). */\n asset: string;\n}\n\nexport interface X402ClientOptions {\n /** Pluggable signer. Required if you want automatic settlement. */\n signer?: X402Signer;\n /**\n * Maximum amount the client will spend per query, in the asset's display\n * unit (e.g. `\"0.50\"` for fifty cents USDC). Hard cap — quotes above this\n * are rejected even if a signer is configured.\n */\n maxPerQuery?: string;\n /** Permitted networks. Defaults to `['base', 'base-sepolia']`. */\n networks?: string[];\n /** Permitted assets. Defaults to `['USDC']`. */\n assets?: string[];\n}\n\nexport class X402Client {\n private readonly signer?: X402Signer;\n private readonly maxPerQuery?: number;\n private readonly networks: Set<string>;\n private readonly assets: Set<string>;\n\n constructor(opts: X402ClientOptions = {}) {\n this.signer = opts.signer;\n this.maxPerQuery = opts.maxPerQuery !== undefined ? Number(opts.maxPerQuery) : undefined;\n this.networks = new Set(opts.networks ?? ['base', 'base-sepolia']);\n this.assets = new Set(opts.assets ?? ['USDC']);\n }\n\n /**\n * Validate the envelope against this client's policy and, if a signer\n * is configured, settle it. Returns the settlement reference that\n * should be replayed in the next request's `_payment` field.\n */\n async authorise(envelope: PaymentEnvelope): Promise<X402Settlement> {\n if (envelope.scheme !== 'x402') {\n throw new AlterError('PAYMENT_REQUIRED', `unsupported payment scheme: ${envelope.scheme}`);\n }\n if (!this.networks.has(envelope.network)) {\n throw new AlterError('PAYMENT_REQUIRED', `network ${envelope.network} not permitted by client policy`);\n }\n if (!this.assets.has(envelope.asset)) {\n throw new AlterError('PAYMENT_REQUIRED', `asset ${envelope.asset} not permitted by client policy`);\n }\n if (this.maxPerQuery !== undefined && Number(envelope.amount) > this.maxPerQuery) {\n throw new AlterError(\n 'PAYMENT_REQUIRED',\n `quote ${envelope.amount} ${envelope.asset} exceeds maxPerQuery ${this.maxPerQuery}`,\n );\n }\n if (!this.signer) {\n // No signer — re-raise so the caller can handle settlement themselves.\n throw new AlterPaymentRequired(envelope.resource ?? 'unknown', envelope);\n }\n return this.signer.settle(envelope);\n }\n\n /**\n * Build the `_payment` argument that gets attached to retried tool calls.\n * Mirrors the shape the ALTER server expects.\n */\n static buildPaymentArg(settlement: X402Settlement): Record<string, string> {\n return {\n scheme: 'x402',\n network: settlement.network,\n asset: settlement.asset,\n amount: settlement.amount,\n reference: settlement.reference,\n };\n }\n}\n\n/**\n * Parse an `X-402-Payment` response header into a {@link PaymentEnvelope}.\n * The header value is JSON or a key=value list — we handle both.\n */\nexport function parsePaymentHeader(header: string): PaymentEnvelope | null {\n try {\n const parsed = JSON.parse(header);\n if (parsed && typeof parsed === 'object') return parsed as PaymentEnvelope;\n } catch {\n // fall through to kv parsing\n }\n const out: Record<string, string> = {};\n for (const part of header.split(/[,;]/)) {\n const [k, ...rest] = part.trim().split('=');\n if (!k) continue;\n out[k] = rest.join('=').replace(/^\"|\"$/g, '');\n }\n if (!out.scheme && !out.network && !out.amount) return null;\n return {\n scheme: 'x402',\n network: out.network || 'base',\n asset: out.asset || 'USDC',\n amount: out.amount || '0',\n recipient: out.recipient || '',\n resource: out.resource || '',\n expires_at: out.expires_at,\n nonce: out.nonce,\n };\n}\n","/**\n * Low-level MCP JSON-RPC 2.0 client over Streamable HTTP.\n *\n * The MCP spec (revision 2025-03-26) defines a request/response protocol\n * over HTTP POST with optional `Mcp-Session-Id` correlation. This module\n * is the thin transport — see {@link AlterClient} for the typed wrapper\n * around ALTER's tool surface.\n *\n * Pure native `fetch()` — no axios, no node-fetch, no ws.\n */\n\nimport {\n AlterAuthError,\n AlterError,\n AlterInvalidResponse,\n AlterNetworkError,\n AlterPaymentRequired,\n AlterRateLimited,\n AlterTimeoutError,\n AlterToolError,\n type PaymentEnvelope,\n} from './errors.js';\nimport { parsePaymentHeader, X402Client } from './x402.js';\n\nexport const MCP_PROTOCOL_VERSION = '2025-03-26';\n\nexport interface MCPClientInfo {\n name: string;\n version: string;\n}\n\nexport interface MCPClientOptions {\n /** Streamable HTTP endpoint. Default: https://mcp.truealter.com */\n endpoint?: string;\n /** Optional API key for the `X-ALTER-API-Key` header. */\n apiKey?: string;\n /** Override fetch (testing). */\n fetch?: typeof fetch;\n /** Per-request timeout in milliseconds. Default 30_000. */\n timeoutMs?: number;\n /** Number of retry attempts on transient (429/502/503/504) failures. Default 2. */\n maxRetries?: number;\n /** Client info advertised in `initialize`. */\n clientInfo?: MCPClientInfo;\n /** Optional x402 client for automatic premium tool payment. */\n x402?: X402Client;\n}\n\nexport interface MCPCallOptions {\n /** Override the configured x402 client for this single call. */\n x402?: X402Client;\n /** Skip retries on 402 (useful for \"is this premium?\" probes). */\n noPaymentRetry?: boolean;\n}\n\nexport interface MCPToolDefinition {\n name: string;\n description?: string;\n inputSchema?: unknown;\n _meta?: Record<string, unknown>;\n}\n\nexport interface MCPListToolsResult {\n tools: MCPToolDefinition[];\n _meta?: {\n signatures?: Record<string, { schema_hash: string; signature?: string | null; kid?: string | null }>;\n [extra: string]: unknown;\n };\n}\n\nexport interface MCPContentBlock {\n type: 'text' | 'json' | string;\n text?: string;\n data?: unknown;\n}\n\nexport interface MCPCallToolResult<T = unknown> {\n content: MCPContentBlock[];\n isError?: boolean;\n /** Parsed structured payload — set when content[0].type === 'json' or text parses as JSON. */\n data?: T;\n _meta?: {\n provenance?: import('./provenance.js').ProvenanceEnvelope;\n [extra: string]: unknown;\n };\n}\n\nconst RETRYABLE_STATUSES = new Set([429, 502, 503, 504]);\n\nexport class MCPClient {\n public readonly endpoint: string;\n public sessionId: string | null = null;\n\n private readonly apiKey: string | undefined;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly maxRetries: number;\n private readonly clientInfo: MCPClientInfo;\n private readonly x402?: X402Client;\n private requestCounter = 0;\n private initialised = false;\n\n constructor(opts: MCPClientOptions = {}) {\n this.endpoint = (opts.endpoint ?? 'https://mcp.truealter.com/api/v1/mcp').replace(/\\/+$/, '');\n this.apiKey = opts.apiKey;\n this.fetchImpl = opts.fetch ?? fetch;\n this.timeoutMs = opts.timeoutMs ?? 30_000;\n this.maxRetries = opts.maxRetries ?? 2;\n this.clientInfo = opts.clientInfo ?? { name: '@truealter/sdk', version: '0.2.0' };\n this.x402 = opts.x402;\n }\n\n /**\n * Send the MCP `initialize` handshake and capture the resulting session\n * id. Idempotent — safe to call multiple times.\n */\n async initialize(): Promise<unknown> {\n if (this.initialised) return null;\n const result = await this.rpc('initialize', {\n protocolVersion: MCP_PROTOCOL_VERSION,\n capabilities: {},\n clientInfo: this.clientInfo,\n });\n this.initialised = true;\n return result;\n }\n\n /** List available tools. */\n async listTools(): Promise<MCPListToolsResult> {\n if (!this.initialised) await this.initialize();\n return (await this.rpc('tools/list', {})) as MCPListToolsResult;\n }\n\n /** Invoke a tool by name. */\n async callTool<T = unknown>(\n name: string,\n args: Record<string, unknown> = {},\n opts: MCPCallOptions = {},\n ): Promise<MCPCallToolResult<T>> {\n if (!this.initialised) await this.initialize();\n return this.callToolInternal<T>(name, args, opts);\n }\n\n /** Close the session and release any held resources. */\n async closeSession(): Promise<void> {\n if (!this.sessionId) return;\n try {\n await this.fetchImpl(this.endpoint, {\n method: 'DELETE',\n headers: this.buildHeaders(),\n });\n } catch {\n // best-effort\n }\n this.sessionId = null;\n this.initialised = false;\n }\n\n // ── Internals ────────────────────────────────────────────────────────\n\n private async callToolInternal<T>(\n name: string,\n args: Record<string, unknown>,\n opts: MCPCallOptions,\n ): Promise<MCPCallToolResult<T>> {\n try {\n const raw = (await this.rpc('tools/call', { name, arguments: args })) as MCPCallToolResult<T>;\n const result = this.shapeToolResult<T>(raw);\n if (result.isError) {\n const text = result.content?.[0]?.text ?? `tool ${name} returned an error`;\n throw new AlterToolError(name, text);\n }\n return result;\n } catch (err) {\n if (err instanceof AlterPaymentRequired && !opts.noPaymentRetry) {\n const x402 = opts.x402 ?? this.x402;\n if (!x402) throw err;\n const settlement = await x402.authorise(err.envelope);\n const retryArgs = { ...args, _payment: X402Client.buildPaymentArg(settlement) };\n return this.callToolInternal<T>(name, retryArgs, { ...opts, noPaymentRetry: true });\n }\n throw err;\n }\n }\n\n private shapeToolResult<T>(raw: MCPCallToolResult<T>): MCPCallToolResult<T> {\n if (!raw || !Array.isArray(raw.content)) return raw;\n if (raw.data === undefined) {\n const first = raw.content[0];\n if (first && first.type === 'json' && 'data' in first) {\n raw.data = first.data as T;\n } else if (first && first.type === 'text' && first.text) {\n try {\n raw.data = JSON.parse(first.text) as T;\n } catch {\n // leave undefined; caller can read raw.content[0].text\n }\n }\n }\n return raw;\n }\n\n /**\n * Send a JSON-RPC 2.0 request and return the result. Errors are\n * normalised into the typed {@link AlterError} hierarchy.\n */\n async rpc(method: string, params: Record<string, unknown> | unknown[] | undefined): Promise<unknown> {\n const id = ++this.requestCounter;\n const payload: Record<string, unknown> = {\n jsonrpc: '2.0',\n id,\n method,\n };\n if (params !== undefined) payload.params = params;\n\n let attempt = 0;\n let lastErr: unknown = null;\n while (attempt <= this.maxRetries) {\n attempt += 1;\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.timeoutMs);\n let resp: Response;\n try {\n resp = await this.fetchImpl(this.endpoint, {\n method: 'POST',\n headers: this.buildHeaders(),\n body: JSON.stringify(payload),\n signal: controller.signal,\n });\n } catch (err) {\n clearTimeout(timer);\n const isAbort = (err as Error)?.name === 'AbortError';\n if (isAbort) {\n lastErr = new AlterTimeoutError(`MCP ${method} timed out after ${this.timeoutMs}ms`, err);\n } else {\n lastErr = new AlterNetworkError(`MCP ${method}: ${(err as Error).message}`, err);\n }\n if (attempt > this.maxRetries) throw lastErr;\n await this.backoff(attempt);\n continue;\n }\n clearTimeout(timer);\n\n // Capture session id when present.\n const sessionHeader = resp.headers.get('Mcp-Session-Id');\n if (sessionHeader) this.sessionId = sessionHeader;\n\n if (resp.status === 401 || resp.status === 403) {\n throw new AlterAuthError(`HTTP ${resp.status} on ${method}`, resp.status);\n }\n if (resp.status === 402) {\n const envelope = await this.extractPaymentEnvelope(resp);\n throw new AlterPaymentRequired(this.guessToolName(payload), envelope);\n }\n if (resp.status === 429) {\n const retryAfter = Number(resp.headers.get('Retry-After') ?? 60);\n if (attempt > this.maxRetries) {\n throw new AlterRateLimited(`HTTP 429 on ${method}`, retryAfter);\n }\n await this.backoff(attempt, retryAfter * 1000);\n continue;\n }\n if (RETRYABLE_STATUSES.has(resp.status) && attempt <= this.maxRetries) {\n await this.backoff(attempt);\n continue;\n }\n if (!resp.ok) {\n const body = await safeText(resp);\n throw new AlterError('NETWORK', `HTTP ${resp.status} on ${method}: ${body.slice(0, 200)}`);\n }\n\n let body: { result?: unknown; error?: { code: number; message: string; data?: unknown } };\n try {\n body = (await resp.json()) as typeof body;\n } catch (err) {\n throw new AlterInvalidResponse(`MCP ${method}: invalid JSON body`, err);\n }\n\n if (body.error) {\n // Map JSON-RPC errors to typed errors when possible.\n const code = body.error.code;\n const message = body.error.message ?? `MCP ${method} error`;\n if (code === -32001 || code === 402) {\n // Payment-required encoded as an RPC error rather than HTTP 402.\n const data = body.error.data as { envelope?: PaymentEnvelope } | undefined;\n if (data?.envelope) {\n throw new AlterPaymentRequired(this.guessToolName(payload), data.envelope);\n }\n }\n throw new AlterToolError(this.guessToolName(payload), message, code);\n }\n return body.result;\n }\n throw lastErr ?? new AlterNetworkError(`MCP ${method}: exhausted retries`);\n }\n\n private buildHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n 'User-Agent': `${this.clientInfo.name}/${this.clientInfo.version}`,\n };\n if (this.apiKey) headers['X-ALTER-API-Key'] = this.apiKey;\n if (this.sessionId) headers['Mcp-Session-Id'] = this.sessionId;\n return headers;\n }\n\n private async extractPaymentEnvelope(resp: Response): Promise<PaymentEnvelope> {\n const headerValue = resp.headers.get('X-402-Payment') ?? resp.headers.get('x-402-payment');\n if (headerValue) {\n const parsed = parsePaymentHeader(headerValue);\n if (parsed) return parsed;\n }\n try {\n const body = (await resp.json()) as { envelope?: PaymentEnvelope; payment?: PaymentEnvelope };\n if (body?.envelope) return body.envelope;\n if (body?.payment) return body.payment;\n } catch {\n // fall through\n }\n return {\n scheme: 'x402',\n network: 'base',\n asset: 'USDC',\n amount: '0',\n recipient: '',\n resource: '',\n };\n }\n\n private guessToolName(payload: Record<string, unknown>): string {\n const params = payload.params as { name?: string } | undefined;\n return params?.name ?? (payload.method as string) ?? 'unknown';\n }\n\n private async backoff(attempt: number, hintMs?: number): Promise<void> {\n const ms = hintMs ?? Math.min(1000 * 2 ** (attempt - 1), 8000);\n await new Promise((res) => setTimeout(res, ms));\n }\n}\n\nasync function safeText(resp: Response): Promise<string> {\n try {\n return await resp.text();\n } catch {\n return '';\n }\n}\n","#!/usr/bin/env node\n/**\n * alter-mcp-bridge — stdio ↔ Streamable-HTTP MCP bridge powered by @truealter/sdk.\n *\n * Claude Code, Cursor, and most desktop MCP hosts speak the stdio\n * transport. The live ALTER MCP server speaks Streamable HTTP. This\n * bridge connects them: read JSON-RPC frames from stdin, forward them\n * through the SDK's MCPClient, and write the results back to stdout.\n *\n * Why use the SDK as the transport (instead of forwarding raw HTTP)?\n *\n * 1. We get session id capture, retry, 402 detection, and provenance\n * verification for free.\n * 2. Every call exercises @truealter/sdk end-to-end — if the bridge\n * works, the SDK works.\n * 3. We can attach an X402 signer here later and the bridge will\n * transparently settle premium tool calls.\n *\n * Frame format: line-delimited JSON-RPC (one object per line over\n * stdin/stdout). MCP does not require a specific stdio framing in the\n * spec, but every host I have seen uses LDJSON, including Claude Code.\n */\n\nimport { createInterface } from 'node:readline';\nimport { stdin, stdout, stderr, exit, env } from 'node:process';\n\nimport { MCPClient } from '../src/mcp.js';\nimport { AlterError, AlterPaymentRequired } from '../src/errors.js';\n\nconst ENDPOINT =\n env.ALTER_MCP_ENDPOINT ?? 'https://mcp.truealter.com/api/v1/mcp';\nconst API_KEY = env.ALTER_API_KEY ?? undefined;\n\nconst client = new MCPClient({\n endpoint: ENDPOINT,\n apiKey: API_KEY,\n clientInfo: { name: '@truealter/sdk-mcp-bridge', version: '0.2.0' },\n});\n\ninterface JsonRpcRequest {\n jsonrpc: '2.0';\n id?: number | string | null;\n method: string;\n params?: Record<string, unknown> | unknown[];\n}\n\ninterface JsonRpcResponse {\n jsonrpc: '2.0';\n id: number | string | null;\n result?: unknown;\n error?: { code: number; message: string; data?: unknown };\n}\n\nfunction send(response: JsonRpcResponse): void {\n stdout.write(JSON.stringify(response) + '\\n');\n}\n\nfunction logDebug(...args: unknown[]): void {\n if (env.ALTER_BRIDGE_DEBUG) {\n stderr.write(`[alter-bridge] ${args.map((a) => (typeof a === 'string' ? a : JSON.stringify(a))).join(' ')}\\n`);\n }\n}\n\nasync function handle(req: JsonRpcRequest): Promise<JsonRpcResponse> {\n const id = req.id ?? null;\n try {\n let result: unknown;\n switch (req.method) {\n case 'initialize':\n // The SDK does its own initialize; we re-handshake here so the\n // host's protocolVersion / clientInfo flow upstream untouched.\n result = await client.rpc('initialize', (req.params as Record<string, unknown>) ?? {});\n break;\n case 'initialized':\n case 'notifications/initialized':\n // Notifications have no response.\n return { jsonrpc: '2.0', id, result: null };\n case 'tools/list':\n result = await client.rpc('tools/list', (req.params as Record<string, unknown>) ?? {});\n break;\n case 'tools/call': {\n const params = (req.params ?? {}) as { name?: string; arguments?: Record<string, unknown> };\n if (!params.name) throw new AlterError('TOOL_ERROR', 'tools/call missing \"name\"');\n result = await client.callTool(params.name, params.arguments ?? {});\n break;\n }\n case 'resources/list':\n case 'resources/read':\n case 'prompts/list':\n case 'prompts/get':\n case 'ping':\n result = await client.rpc(req.method, (req.params as Record<string, unknown>) ?? {});\n break;\n default:\n // Forward anything we don't recognise — the upstream server can\n // accept or reject it. This keeps the bridge protocol-version\n // independent.\n result = await client.rpc(req.method, (req.params as Record<string, unknown>) ?? {});\n }\n return { jsonrpc: '2.0', id, result };\n } catch (err) {\n if (err instanceof AlterPaymentRequired) {\n return {\n jsonrpc: '2.0',\n id,\n error: {\n code: 402,\n message: `x402 payment required for ${err.tool}`,\n data: { envelope: err.envelope },\n },\n };\n }\n if (err instanceof AlterError) {\n return {\n jsonrpc: '2.0',\n id,\n error: { code: -32000, message: err.message, data: { code: err.code } },\n };\n }\n return {\n jsonrpc: '2.0',\n id,\n error: { code: -32603, message: (err as Error).message ?? 'internal error' },\n };\n }\n}\n\nasync function main(): Promise<void> {\n logDebug('starting; endpoint=', ENDPOINT, 'apiKey=', API_KEY ? '(set)' : '(none)');\n\n const rl = createInterface({ input: stdin, crlfDelay: Infinity });\n\n for await (const line of rl) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let req: JsonRpcRequest;\n try {\n req = JSON.parse(trimmed) as JsonRpcRequest;\n } catch {\n logDebug('skipping non-JSON line:', trimmed.slice(0, 80));\n continue;\n }\n if (req.jsonrpc !== '2.0' || typeof req.method !== 'string') {\n logDebug('skipping malformed request:', trimmed.slice(0, 80));\n continue;\n }\n const response = await handle(req);\n // MCP notifications (id absent) get no response.\n if (req.id !== undefined && req.id !== null) {\n send(response);\n }\n }\n\n logDebug('stdin closed; exiting');\n await client.closeSession().catch(() => {\n /* ignore */\n });\n}\n\nmain().catch((err: unknown) => {\n stderr.write(`[alter-bridge] fatal: ${(err as Error).message}\\n`);\n exit(1);\n});\n"]}
|