@haven_ai/mcp 0.2.1-alpha.0 → 0.3.0-alpha.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/README.md CHANGED
@@ -44,9 +44,12 @@ Create a private JSON file from the values in the Haven agent handoff:
44
44
  `delegate_key` is required. Without it the MCP server cannot sign locally.
45
45
  `account_address` is the name the connector writes since #2908; a file that
46
46
  still says `safe_address` (or `safeAddress`) is read the same way, permanently.
47
- The same holds for the environment: `HAVEN_ACCOUNT_ADDRESS` is read first, and
48
- the older `HAVEN_WALLET_ADDRESS` / `HAVEN_SAFE_ADDRESS` are accepted for one
49
- release (#2914 removes them).
47
+ The environment is **not** the same: only `HAVEN_ACCOUNT_ADDRESS` is read.
48
+ `HAVEN_WALLET_ADDRESS` and `HAVEN_SAFE_ADDRESS` were accepted for one release
49
+ and #2914 removed them, so a machine still configured through either resolves
50
+ no account address at all. The credential-FILE fallback above is permanent —
51
+ a file on disk never rewrites itself — and the environment is not, which is
52
+ the whole difference between the two paragraphs.
50
53
 
51
54
  The Haven connector may also write split credentials:
52
55
 
package/dist/cli.cjs CHANGED
@@ -56,7 +56,6 @@ async function loadCredentialsFromFile(path) {
56
56
  delegateKey,
57
57
  agentId: stringField(raw.agent_id ?? raw.agentId),
58
58
  accountAddress,
59
- safeAddress: accountAddress,
60
59
  delegateAddress: stringField(raw.delegate_address ?? raw.delegateAddress),
61
60
  chainId: numberField(raw.chain_id ?? raw.chainId),
62
61
  network: stringField(raw.network),
@@ -86,13 +85,11 @@ async function loadCredentialsFromSplitFiles(identityPath, signerPath) {
86
85
  identity.agent_id ?? identity.agentId,
87
86
  signer.agent_id ?? signer.agentId
88
87
  ),
89
- ...accountAddressTwins(
90
- matchingStringField(
91
- "account_address",
92
- readAccountAddressField(identity),
93
- readAccountAddressField(signer),
94
- { caseInsensitive: true }
95
- )
88
+ accountAddress: matchingStringField(
89
+ "account_address",
90
+ readAccountAddressField(identity),
91
+ readAccountAddressField(signer),
92
+ { caseInsensitive: true }
96
93
  ),
97
94
  delegateAddress: matchingStringField(
98
95
  "delegate_address",
@@ -147,7 +144,7 @@ function loadCredentialsFromEnv() {
147
144
  apiKey,
148
145
  delegateKey,
149
146
  agentId: stringField(process.env.HAVEN_AGENT_ID),
150
- ...accountAddressTwins(readAccountAddressEnv(process.env)),
147
+ accountAddress: readAccountAddressEnv(process.env),
151
148
  chainId: numberField(process.env.HAVEN_CHAIN_ID),
152
149
  network: stringField(process.env.HAVEN_NETWORK),
153
150
  apiUrl: stringField(process.env.HAVEN_API_URL)
@@ -157,10 +154,22 @@ function readAccountAddressField(raw) {
157
154
  return stringField(raw.account_address ?? raw.safe_address ?? raw.safeAddress);
158
155
  }
159
156
  function readAccountAddressEnv(env) {
160
- return stringField(env.HAVEN_ACCOUNT_ADDRESS ?? env.HAVEN_WALLET_ADDRESS ?? env.HAVEN_SAFE_ADDRESS);
161
- }
162
- function accountAddressTwins(address) {
163
- return { accountAddress: address, safeAddress: address };
157
+ const current = stringField(env.HAVEN_ACCOUNT_ADDRESS);
158
+ for (const name of ["HAVEN_WALLET_ADDRESS", "HAVEN_SAFE_ADDRESS"]) {
159
+ const retired = stringField(env[name]);
160
+ if (!retired) continue;
161
+ if (!current) {
162
+ throw new Error(
163
+ `${name} is retired (#2906) \u2014 Haven accounts are addressed as accounts, not Safes. Set HAVEN_ACCOUNT_ADDRESS to the same value. Refusing rather than ignoring it, because an unset account address silently skips the sweep-destination check.`
164
+ );
165
+ }
166
+ if (retired.toLowerCase() !== current.toLowerCase()) {
167
+ throw new Error(
168
+ `${name} and HAVEN_ACCOUNT_ADDRESS were both set to different addresses. Remove the retired name, or make them match \u2014 picking one silently would hide the mismatch.`
169
+ );
170
+ }
171
+ }
172
+ return current;
164
173
  }
165
174
  function stringField(value) {
166
175
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -723,7 +732,7 @@ function computeConsentHash(input) {
723
732
  input.apiKeyPrefix,
724
733
  input.apiUrl ?? "",
725
734
  input.agentId ?? "",
726
- (input.safeAddress ?? "").toLowerCase(),
735
+ (input.accountAddress ?? "").toLowerCase(),
727
736
  (input.delegateAddress ?? "").toLowerCase(),
728
737
  input.chainId ?? ""
729
738
  ].join("|");
@@ -742,7 +751,7 @@ function renderConsentBlock(input, hash) {
742
751
  ];
743
752
  if (input.apiUrl) lines.push(`Haven API: ${input.apiUrl}`);
744
753
  if (input.agentId) lines.push(`Agent ID: ${input.agentId}`);
745
- if (input.safeAddress) lines.push(`Haven wallet (Safe): ${input.safeAddress}`);
754
+ if (input.accountAddress) lines.push(`Haven wallet (Safe): ${input.accountAddress}`);
746
755
  if (input.delegateAddress) lines.push(`Delegate (local signer): ${input.delegateAddress}`);
747
756
  if (typeof input.chainId === "number") lines.push(`Chain ID: ${input.chainId}`);
748
757
  lines.push("");
@@ -849,14 +858,14 @@ async function writeAckFile(path$1, hash) {
849
858
  }
850
859
  async function consentInputFromClient(haven, seed, toolNames) {
851
860
  let allowanceSummary = seed.allowanceSummary ?? [];
852
- let safeAddress = seed.safeAddress;
861
+ let accountAddress = seed.accountAddress;
853
862
  let delegateAddress = seed.delegateAddress;
854
863
  let chainId = seed.chainId;
855
864
  try {
856
865
  const summary = await haven.getAllowances();
857
866
  const list = isAllowanceSummary(summary) ? summary.allowances : Array.isArray(summary) ? summary : [];
858
867
  if (isAllowanceSummary(summary)) {
859
- safeAddress = summary.accountAddress ?? summary.safeAddress ?? safeAddress;
868
+ accountAddress = summary.accountAddress ?? accountAddress;
860
869
  delegateAddress = summary.delegateAddress;
861
870
  chainId = typeof summary.chainId === "number" ? summary.chainId : chainId;
862
871
  }
@@ -872,7 +881,7 @@ async function consentInputFromClient(haven, seed, toolNames) {
872
881
  apiKeyPrefix: derivePrefix(seed.apiKey),
873
882
  apiUrl: seed.apiUrl,
874
883
  agentId: seed.agentId,
875
- safeAddress,
884
+ accountAddress,
876
885
  delegateAddress,
877
886
  chainId,
878
887
  toolNames,
@@ -906,7 +915,7 @@ async function resolveHavenClient(options = {}) {
906
915
  return { client, credentials };
907
916
  }
908
917
  var MCP_NAME = "@haven_ai/mcp";
909
- var MCP_VERSION = "0.2.1-alpha.0";
918
+ var MCP_VERSION = "0.3.0-alpha.0";
910
919
  var MCP_INSTRUCTIONS = [
911
920
  "Haven local MCP server: signs in-process with the delegate key it holds on",
912
921
  "this machine \u2014 the key never leaves this process. Call haven_get_agent",
@@ -979,7 +988,7 @@ async function runConsentGate(haven, credentials, options) {
979
988
  apiKey: credentials.apiKey,
980
989
  apiUrl: credentials.apiUrl,
981
990
  agentId: credentials.agentId,
982
- safeAddress: credentials.accountAddress ?? credentials.safeAddress,
991
+ accountAddress: credentials.accountAddress,
983
992
  delegateAddress: credentials.delegateAddress,
984
993
  chainId: credentials.chainId,
985
994
  allowanceSummary: credentials.allowanceSummary