@truealter/sdk 0.4.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@
2
2
  import { p256 } from '@noble/curves/p256';
3
3
  import { sha256 } from '@noble/hashes/sha256';
4
4
  import { hexToBytes, bytesToHex as bytesToHex$1, randomBytes } from '@noble/hashes/utils';
5
+ import { createHash, createPrivateKey } from 'crypto';
5
6
  import { existsSync, readFileSync, mkdirSync, writeFileSync, unlinkSync, renameSync, copyFileSync } from 'fs';
6
7
  import { homedir, platform } from 'os';
7
8
  import { join, dirname, resolve } from 'path';
@@ -10,7 +11,6 @@ import { createInterface } from 'readline';
10
11
  import * as ed25519 from '@noble/ed25519';
11
12
  import { sha512 } from '@noble/hashes/sha512';
12
13
  import { spawnSync } from 'child_process';
13
- import { createHash } from 'crypto';
14
14
 
15
15
  var __defProp = Object.defineProperty;
16
16
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -106,8 +106,7 @@ function loadPrivateKey(key) {
106
106
  return key;
107
107
  }
108
108
  if (typeof key === "string" && key.includes("-----BEGIN")) {
109
- const nodeCrypto = __require("crypto");
110
- const keyObj = nodeCrypto.createPrivateKey({ key, format: "pem" });
109
+ const keyObj = createPrivateKey({ key, format: "pem" });
111
110
  const jwk = keyObj.export({ format: "jwk" });
112
111
  if (jwk.crv !== "P-256" || !jwk.d) {
113
112
  throw new TypeError("PEM is not a P-256 private key.");
@@ -406,18 +405,24 @@ function ensureMcpPath(url) {
406
405
  return url;
407
406
  }
408
407
  }
409
-
410
- // src/x402.ts
411
408
  var X402Client = class {
412
409
  signer;
413
410
  maxPerQuery;
414
411
  networks;
415
412
  assets;
413
+ // undefined = allowlist check disabled (backward-compatible default).
414
+ // Non-null = active allowlist; reject any recipient not in the set.
415
+ recipientAllowlist;
416
416
  constructor(opts = {}) {
417
417
  this.signer = opts.signer;
418
418
  this.maxPerQuery = opts.maxPerQuery !== void 0 ? Number(opts.maxPerQuery) : void 0;
419
419
  this.networks = new Set(opts.networks ?? ["base", "base-sepolia"]);
420
420
  this.assets = new Set(opts.assets ?? ["USDC"]);
421
+ if (opts.recipientAllowlist !== void 0) {
422
+ this.recipientAllowlist = opts.recipientAllowlist.length === 0 ? void 0 : new Set(opts.recipientAllowlist.map((a) => a.toLowerCase()));
423
+ } else {
424
+ this.recipientAllowlist = void 0;
425
+ }
421
426
  }
422
427
  /**
423
428
  * Validate the envelope against this client's policy and, if a signer
@@ -443,6 +448,15 @@ var X402Client = class {
443
448
  );
444
449
  }
445
450
  }
451
+ if (this.recipientAllowlist !== void 0) {
452
+ const recipientNorm = (envelope.recipient ?? "").toLowerCase();
453
+ if (!recipientNorm || !this.recipientAllowlist.has(recipientNorm)) {
454
+ throw new AlterError(
455
+ "PAYMENT_REQUIRED",
456
+ `recipient "${envelope.recipient}" is not on the known-recipient allowlist`
457
+ );
458
+ }
459
+ }
446
460
  if (!this.signer) {
447
461
  throw new AlterPaymentRequired(envelope.resource ?? "unknown", envelope);
448
462
  }
@@ -500,6 +514,7 @@ var MCPClient = class {
500
514
  clientInfo;
501
515
  x402;
502
516
  signing;
517
+ extraHeaders;
503
518
  requestCounter = 0;
504
519
  initialised = false;
505
520
  constructor(opts = {}) {
@@ -511,6 +526,7 @@ var MCPClient = class {
511
526
  this.clientInfo = opts.clientInfo ?? { name: "@truealter/sdk", version: "0.2.0" };
512
527
  this.x402 = opts.x402;
513
528
  this.signing = opts.signing;
529
+ this.extraHeaders = opts.extraHeaders;
514
530
  }
515
531
  /**
516
532
  * Send the MCP `initialize` handshake and capture the resulting session
@@ -674,6 +690,7 @@ var MCPClient = class {
674
690
  }
675
691
  buildHeaders(extra) {
676
692
  const headers = {
693
+ ...this.extraHeaders ?? {},
677
694
  "Content-Type": "application/json",
678
695
  Accept: "application/json",
679
696
  "User-Agent": `${this.clientInfo.name}/${this.clientInfo.version}`
@@ -795,6 +812,7 @@ var DEFAULT_VERIFY_AT_ALLOWLIST = Object.freeze([
795
812
  "api.truealter.com",
796
813
  "mcp.truealter.com"
797
814
  ]);
815
+ var ALTER_PLATFORM_ISS = "did:alter:platform";
798
816
  async function verifyProvenance(envelope, opts = {}) {
799
817
  const token = typeof envelope === "string" ? envelope : envelope.token;
800
818
  if (!token) return { valid: false, reason: "empty token" };
@@ -877,9 +895,55 @@ async function verifyProvenance(envelope, opts = {}) {
877
895
  if (typeof payload.iat === "number" && payload.iat > now + 300) {
878
896
  return { valid: false, reason: "issued in the future", payload, kid: header.kid };
879
897
  }
898
+ const expectedIss = opts.expectedIss !== void 0 ? opts.expectedIss : ALTER_PLATFORM_ISS;
899
+ if (expectedIss !== "" && payload.iss !== expectedIss) {
900
+ return {
901
+ valid: false,
902
+ reason: `iss mismatch: expected "${expectedIss}", got "${payload.iss}"`,
903
+ payload,
904
+ kid: header.kid
905
+ };
906
+ }
907
+ if (opts.expectedAud !== void 0 && opts.expectedAud !== "") {
908
+ const tokenAud = payload.aud;
909
+ const audList = tokenAud === void 0 ? [] : Array.isArray(tokenAud) ? tokenAud : [tokenAud];
910
+ if (!audList.includes(opts.expectedAud)) {
911
+ return {
912
+ valid: false,
913
+ reason: `aud mismatch: expected "${opts.expectedAud}", got ${JSON.stringify(tokenAud ?? null)}`,
914
+ payload,
915
+ kid: header.kid
916
+ };
917
+ }
918
+ }
880
919
  return { valid: true, payload, kid: header.kid };
881
920
  }
882
- async function verifyToolSignatures(tools, signatures) {
921
+ async function verifyToolSignatures(tools, signatures, opts = {}) {
922
+ const jwksUrl = opts.jwksUrl ?? "https://api.truealter.com/.well-known/alter-keys.json";
923
+ const fetchImpl = opts.fetch ?? fetch;
924
+ if (!jwksUrl.startsWith("https://")) {
925
+ return tools.map((t) => ({
926
+ tool: t.name,
927
+ valid: false,
928
+ reason: `jwksUrl must be https: got ${jwksUrl}`
929
+ }));
930
+ }
931
+ const needsJwks = tools.some((t) => {
932
+ const sig = signatures[t.name];
933
+ return sig && sig.signature;
934
+ });
935
+ let jwks = null;
936
+ if (needsJwks) {
937
+ try {
938
+ jwks = await fetchJwks(jwksUrl, fetchImpl);
939
+ } catch (err) {
940
+ return tools.map((t) => ({
941
+ tool: t.name,
942
+ valid: false,
943
+ reason: `jwks fetch failed: ${err.message}`
944
+ }));
945
+ }
946
+ }
883
947
  const out = [];
884
948
  for (const tool of tools) {
885
949
  const sig = signatures[tool.name];
@@ -892,6 +956,63 @@ async function verifyToolSignatures(tools, signatures) {
892
956
  out.push({ tool: tool.name, valid: false, reason: "schema hash mismatch" });
893
957
  continue;
894
958
  }
959
+ const jwsToken = sig.signature;
960
+ if (!jwsToken) {
961
+ out.push({ tool: tool.name, valid: true, warn_no_signature: true });
962
+ continue;
963
+ }
964
+ const jwksDoc = jwks;
965
+ let jHeader;
966
+ let jPayloadRaw;
967
+ let jSigBytes;
968
+ try {
969
+ const parts2 = jwsToken.split(".");
970
+ if (parts2.length !== 3) throw new Error("JWS must have three segments");
971
+ jHeader = JSON.parse(new TextDecoder().decode(base64urlDecode(parts2[0])));
972
+ jPayloadRaw = new TextDecoder().decode(base64urlDecode(parts2[1]));
973
+ jSigBytes = base64urlDecode(parts2[2]);
974
+ } catch (err) {
975
+ out.push({ tool: tool.name, valid: false, reason: `malformed tool JWS: ${err.message}` });
976
+ continue;
977
+ }
978
+ if (jHeader.alg !== "ES256") {
979
+ out.push({ tool: tool.name, valid: false, reason: `unsupported tool sig alg: ${jHeader.alg}` });
980
+ continue;
981
+ }
982
+ if (jPayloadRaw !== sig.schema_hash) {
983
+ out.push({ tool: tool.name, valid: false, reason: "tool JWS payload does not match schema_hash" });
984
+ continue;
985
+ }
986
+ const jwk = jwksDoc.keys.find((k) => jHeader.kid ? k.kid === jHeader.kid : true);
987
+ if (!jwk) {
988
+ out.push({ tool: tool.name, valid: false, reason: `no JWK for kid=${jHeader.kid}` });
989
+ continue;
990
+ }
991
+ let publicKey;
992
+ try {
993
+ publicKey = await importEs256JwkAsPublicKey(jwk);
994
+ } catch (err) {
995
+ out.push({ tool: tool.name, valid: false, reason: `jwk import: ${err.message}` });
996
+ continue;
997
+ }
998
+ const parts = jwsToken.split(".");
999
+ const signedInput = new TextEncoder().encode(`${parts[0]}.${parts[1]}`);
1000
+ let sigValid = false;
1001
+ try {
1002
+ sigValid = await crypto.subtle.verify(
1003
+ { name: "ECDSA", hash: "SHA-256" },
1004
+ publicKey,
1005
+ toArrayBuffer(jSigBytes),
1006
+ toArrayBuffer(signedInput)
1007
+ );
1008
+ } catch (err) {
1009
+ out.push({ tool: tool.name, valid: false, reason: `sig verify error: ${err.message}` });
1010
+ continue;
1011
+ }
1012
+ if (!sigValid) {
1013
+ out.push({ tool: tool.name, valid: false, reason: "tool signature mismatch" });
1014
+ continue;
1015
+ }
895
1016
  out.push({ tool: tool.name, valid: true });
896
1017
  }
897
1018
  return out;
@@ -1073,10 +1194,10 @@ var AlterClient = class {
1073
1194
  }
1074
1195
  /** Verify a person is registered with ALTER (handle or id). */
1075
1196
  async verify(handleOrId, claims) {
1076
- const args = handleOrId.includes("@") ? { candidate_id: "", email: handleOrId } : handleOrId.startsWith("~") ? (
1077
- // ~handle — server resolves these via the candidate_id field
1078
- { candidate_id: handleOrId }
1079
- ) : { candidate_id: handleOrId };
1197
+ const args = handleOrId.includes("@") ? { member_id: "", email: handleOrId } : handleOrId.startsWith("~") ? (
1198
+ // ~handle — server resolves these via the member_id field
1199
+ { member_id: handleOrId }
1200
+ ) : { member_id: handleOrId };
1080
1201
  if (claims) args.claims = claims;
1081
1202
  return this.mcp.callTool("verify_identity", args);
1082
1203
  }
@@ -1523,6 +1644,26 @@ function restoreFromBackup(path, backupPath) {
1523
1644
  // src/wire/index.ts
1524
1645
  var TIMESTAMP = () => String(Math.floor(Date.now() / 1e3));
1525
1646
  var ISO_NOW = () => (/* @__PURE__ */ new Date()).toISOString();
1647
+ function readCfAccessEnv() {
1648
+ const envPath = join(homedir(), ".config", "alter", "cf-access.env");
1649
+ try {
1650
+ const content = readFileSync(envPath, "utf8");
1651
+ let clientId = "";
1652
+ let clientSecret = "";
1653
+ for (const line of content.split("\n")) {
1654
+ const trimmed = line.trim();
1655
+ if (trimmed.startsWith("#") || !trimmed.includes("=")) continue;
1656
+ const eqIdx = trimmed.indexOf("=");
1657
+ const key = trimmed.slice(0, eqIdx).replace(/^export\s+/, "").trim();
1658
+ const val = trimmed.slice(eqIdx + 1).trim().replace(/^["']|["']$/g, "");
1659
+ if (key === "CF_ACCESS_CLIENT_ID") clientId = val;
1660
+ if (key === "CF_ACCESS_CLIENT_SECRET") clientSecret = val;
1661
+ }
1662
+ if (clientId && clientSecret) return { clientId, clientSecret };
1663
+ } catch {
1664
+ }
1665
+ return void 0;
1666
+ }
1526
1667
  function clientById(id) {
1527
1668
  const hit = ALL_CLIENTS.find((c) => c.id === id);
1528
1669
  if (!hit) throw new Error(`unknown client id: ${id}`);
@@ -1531,6 +1672,7 @@ function clientById(id) {
1531
1672
  function wire(opts = {}) {
1532
1673
  const endpoint = opts.endpoint ?? DEFAULT_ENDPOINT;
1533
1674
  const apiKey = opts.apiKey;
1675
+ const cfAccess = opts.cfAccess ?? readCfAccessEnv();
1534
1676
  const probes = probeAll();
1535
1677
  const selection = opts.only ?? probes.filter((p) => p.installed).map((p) => p.client.id);
1536
1678
  const ts = TIMESTAMP();
@@ -1549,9 +1691,9 @@ function wire(opts = {}) {
1549
1691
  }
1550
1692
  try {
1551
1693
  if (id === "claude-code") {
1552
- targets.push(wireClaudeCode({ endpoint, apiKey }));
1694
+ targets.push(wireClaudeCode({ endpoint, apiKey, cfAccess }));
1553
1695
  } else {
1554
- targets.push(wireFileTarget({ id, endpoint, apiKey, timestamp: ts }));
1696
+ targets.push(wireFileTarget({ id, endpoint, apiKey, cfAccess, timestamp: ts }));
1555
1697
  }
1556
1698
  } catch (err) {
1557
1699
  const message = err.message;
@@ -1585,7 +1727,12 @@ function wireFileTarget(args) {
1585
1727
  `refusing to wire ${client.label}: config path ${sync.resolvedPath} lives under ${sync.matchedPrefix}. Synced volumes propagate credentials across devices \u2014 move the config off the sync root, or run wire on the device you want to target.`
1586
1728
  );
1587
1729
  }
1588
- const entry = args.id === "claude-desktop" ? generateClaudeDesktopConfig({ endpoint: args.endpoint, apiKey: args.apiKey }) : generateGenericMcpConfig({ endpoint: args.endpoint, apiKey: args.apiKey });
1730
+ const cfHeaders = {};
1731
+ if (args.cfAccess) {
1732
+ cfHeaders["CF-Access-Client-Id"] = args.cfAccess.clientId;
1733
+ cfHeaders["CF-Access-Client-Secret"] = args.cfAccess.clientSecret;
1734
+ }
1735
+ const entry = args.id === "claude-desktop" ? generateClaudeDesktopConfig({ endpoint: args.endpoint, apiKey: args.apiKey }) : generateGenericMcpConfig({ endpoint: args.endpoint, apiKey: args.apiKey, headers: cfHeaders });
1589
1736
  const rootKey = client.rootKey;
1590
1737
  const serverName = "alter";
1591
1738
  const result = atomicJsonMerge({
@@ -1617,7 +1764,8 @@ function wireFileTarget(args) {
1617
1764
  }
1618
1765
  function wireClaudeCode(args) {
1619
1766
  const cmd = "claude";
1620
- const argList = [
1767
+ const bridgePath = resolveBridgeScript();
1768
+ const argList = bridgePath ? ["mcp", "add", "--scope", "user", "alter", "--", "node", bridgePath] : [
1621
1769
  "mcp",
1622
1770
  "add",
1623
1771
  "--scope",
@@ -1625,16 +1773,15 @@ function wireClaudeCode(args) {
1625
1773
  "--transport",
1626
1774
  "http",
1627
1775
  "alter",
1628
- args.endpoint
1776
+ args.endpoint,
1777
+ ...args.apiKey ? ["--header", `X-ALTER-API-Key:${args.apiKey}`] : []
1629
1778
  ];
1630
- if (args.apiKey) {
1631
- argList.push("--header", `X-ALTER-API-Key:${args.apiKey}`);
1632
- }
1633
1779
  const full = `${cmd} ${argList.join(" ")}`;
1634
1780
  const run = spawnSync(cmd, argList, {
1635
1781
  encoding: "utf8",
1636
1782
  shell: process.platform === "win32",
1637
- timeout: 1e4
1783
+ timeout: 1e4,
1784
+ env: bridgePath ? { ...process.env, ALTER_PUBLIC_MCP_ENDPOINT: args.endpoint, ...args.apiKey ? { ALTER_API_KEY: args.apiKey } : {} } : void 0
1638
1785
  });
1639
1786
  if (run.error) {
1640
1787
  return {
@@ -1665,6 +1812,17 @@ function wireClaudeCode(args) {
1665
1812
  reason: `claude mcp add exited ${String(run.status)}`
1666
1813
  };
1667
1814
  }
1815
+ function resolveBridgeScript() {
1816
+ const { existsSync: existsSync5 } = __require("fs");
1817
+ const { join: join4, dirname: dirname4 } = __require("path");
1818
+ const siblingBridge = join4(dirname4(__filename), "..", "dist", "mcp-bridge.js");
1819
+ if (existsSync5(siblingBridge)) return siblingBridge;
1820
+ const srcBridge = join4(dirname4(__filename), "..", "mcp-bridge.js");
1821
+ if (existsSync5(srcBridge)) return srcBridge;
1822
+ const npmGlobalBridge = join4(dirname4(__filename), "mcp-bridge.js");
1823
+ if (existsSync5(npmGlobalBridge)) return npmGlobalBridge;
1824
+ return null;
1825
+ }
1668
1826
  function unwire() {
1669
1827
  const state = readWireState();
1670
1828
  const undone = [];
@@ -2,6 +2,7 @@
2
2
  import { p256 } from '@noble/curves/p256';
3
3
  import { sha256 } from '@noble/hashes/sha256';
4
4
  import { randomBytes } from '@noble/hashes/utils';
5
+ import { createPrivateKey } from 'crypto';
5
6
  import { createInterface } from 'readline';
6
7
  import { env, stderr, exit, stdin, stdout } from 'process';
7
8
 
@@ -9,12 +10,6 @@ var __defProp = Object.defineProperty;
9
10
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
10
11
  var __getOwnPropNames = Object.getOwnPropertyNames;
11
12
  var __hasOwnProp = Object.prototype.hasOwnProperty;
12
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
13
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
14
- }) : x)(function(x) {
15
- if (typeof require !== "undefined") return require.apply(this, arguments);
16
- throw Error('Dynamic require of "' + x + '" is not supported');
17
- });
18
13
  var __esm = (fn, res) => function __init() {
19
14
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
20
15
  };
@@ -99,8 +94,7 @@ function loadPrivateKey(key) {
99
94
  return key;
100
95
  }
101
96
  if (typeof key === "string" && key.includes("-----BEGIN")) {
102
- const nodeCrypto = __require("crypto");
103
- const keyObj = nodeCrypto.createPrivateKey({ key, format: "pem" });
97
+ const keyObj = createPrivateKey({ key, format: "pem" });
104
98
  const jwk = keyObj.export({ format: "jwk" });
105
99
  if (jwk.crv !== "P-256" || !jwk.d) {
106
100
  throw new TypeError("PEM is not a P-256 private key.");
@@ -220,18 +214,24 @@ var AlterInvalidResponse = class extends AlterError {
220
214
  Object.setPrototypeOf(this, new.target.prototype);
221
215
  }
222
216
  };
223
-
224
- // src/x402.ts
225
217
  var X402Client = class {
226
218
  signer;
227
219
  maxPerQuery;
228
220
  networks;
229
221
  assets;
222
+ // undefined = allowlist check disabled (backward-compatible default).
223
+ // Non-null = active allowlist; reject any recipient not in the set.
224
+ recipientAllowlist;
230
225
  constructor(opts = {}) {
231
226
  this.signer = opts.signer;
232
227
  this.maxPerQuery = opts.maxPerQuery !== void 0 ? Number(opts.maxPerQuery) : void 0;
233
228
  this.networks = new Set(opts.networks ?? ["base", "base-sepolia"]);
234
229
  this.assets = new Set(opts.assets ?? ["USDC"]);
230
+ if (opts.recipientAllowlist !== void 0) {
231
+ this.recipientAllowlist = opts.recipientAllowlist.length === 0 ? void 0 : new Set(opts.recipientAllowlist.map((a) => a.toLowerCase()));
232
+ } else {
233
+ this.recipientAllowlist = void 0;
234
+ }
235
235
  }
236
236
  /**
237
237
  * Validate the envelope against this client's policy and, if a signer
@@ -257,6 +257,15 @@ var X402Client = class {
257
257
  );
258
258
  }
259
259
  }
260
+ if (this.recipientAllowlist !== void 0) {
261
+ const recipientNorm = (envelope.recipient ?? "").toLowerCase();
262
+ if (!recipientNorm || !this.recipientAllowlist.has(recipientNorm)) {
263
+ throw new AlterError(
264
+ "PAYMENT_REQUIRED",
265
+ `recipient "${envelope.recipient}" is not on the known-recipient allowlist`
266
+ );
267
+ }
268
+ }
260
269
  if (!this.signer) {
261
270
  throw new AlterPaymentRequired(envelope.resource ?? "unknown", envelope);
262
271
  }
@@ -314,6 +323,7 @@ var MCPClient = class {
314
323
  clientInfo;
315
324
  x402;
316
325
  signing;
326
+ extraHeaders;
317
327
  requestCounter = 0;
318
328
  initialised = false;
319
329
  constructor(opts = {}) {
@@ -325,6 +335,7 @@ var MCPClient = class {
325
335
  this.clientInfo = opts.clientInfo ?? { name: "@truealter/sdk", version: "0.2.0" };
326
336
  this.x402 = opts.x402;
327
337
  this.signing = opts.signing;
338
+ this.extraHeaders = opts.extraHeaders;
328
339
  }
329
340
  /**
330
341
  * Send the MCP `initialize` handshake and capture the resulting session
@@ -488,6 +499,7 @@ var MCPClient = class {
488
499
  }
489
500
  buildHeaders(extra) {
490
501
  const headers = {
502
+ ...this.extraHeaders ?? {},
491
503
  "Content-Type": "application/json",
492
504
  Accept: "application/json",
493
505
  "User-Agent": `${this.clientInfo.name}/${this.clientInfo.version}`
@@ -556,10 +568,34 @@ async function safeText(resp) {
556
568
  // bin/mcp-bridge.ts
557
569
  var ENDPOINT = env.ALTER_MCP_ENDPOINT ?? "https://mcp.truealter.com/api/v1/mcp";
558
570
  var API_KEY = env.ALTER_API_KEY ?? void 0;
571
+ function buildExtraHeaders() {
572
+ const headers = {};
573
+ if (env.CF_ACCESS_CLIENT_ID && env.CF_ACCESS_CLIENT_SECRET) {
574
+ headers["CF-Access-Client-Id"] = env.CF_ACCESS_CLIENT_ID;
575
+ headers["CF-Access-Client-Secret"] = env.CF_ACCESS_CLIENT_SECRET;
576
+ }
577
+ if (env.ALTER_BRIDGE_HEADERS) {
578
+ try {
579
+ const parsed = JSON.parse(env.ALTER_BRIDGE_HEADERS);
580
+ Object.assign(headers, parsed);
581
+ } catch (err) {
582
+ stderr.write(
583
+ `[alter-bridge] warning: ALTER_BRIDGE_HEADERS is not valid JSON; ignored (${err.message})
584
+ `
585
+ );
586
+ }
587
+ }
588
+ return Object.keys(headers).length ? headers : void 0;
589
+ }
590
+ var EXTRA_HEADERS = buildExtraHeaders();
591
+ console.warn(
592
+ "This bridge is a dev/demo surface. Authenticated MCP tools require ES256 per-invocation signing; for production, import `@truealter/sdk` directly. Bridge signing lands in Wave-2."
593
+ );
559
594
  var client = new MCPClient({
560
595
  endpoint: ENDPOINT,
561
596
  apiKey: API_KEY,
562
- clientInfo: { name: "@truealter/sdk-mcp-bridge", version: "0.2.0" }
597
+ clientInfo: { name: "@truealter/sdk-mcp-bridge", version: "0.2.0" },
598
+ extraHeaders: EXTRA_HEADERS
563
599
  });
564
600
  function send(response) {
565
601
  stdout.write(JSON.stringify(response) + "\n");