@haven_ai/mcp 0.2.1-alpha.0 → 0.4.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 +6 -3
- package/dist/cli.cjs +70 -27
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +70 -27
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +70 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +99 -21
- package/dist/index.d.ts +99 -21
- package/dist/index.js +70 -27
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -54,7 +54,6 @@ async function loadCredentialsFromFile(path) {
|
|
|
54
54
|
delegateKey,
|
|
55
55
|
agentId: stringField(raw.agent_id ?? raw.agentId),
|
|
56
56
|
accountAddress,
|
|
57
|
-
safeAddress: accountAddress,
|
|
58
57
|
delegateAddress: stringField(raw.delegate_address ?? raw.delegateAddress),
|
|
59
58
|
chainId: numberField(raw.chain_id ?? raw.chainId),
|
|
60
59
|
network: stringField(raw.network),
|
|
@@ -84,13 +83,11 @@ async function loadCredentialsFromSplitFiles(identityPath, signerPath) {
|
|
|
84
83
|
identity.agent_id ?? identity.agentId,
|
|
85
84
|
signer.agent_id ?? signer.agentId
|
|
86
85
|
),
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
{ caseInsensitive: true }
|
|
93
|
-
)
|
|
86
|
+
accountAddress: matchingStringField(
|
|
87
|
+
"account_address",
|
|
88
|
+
readAccountAddressField(identity),
|
|
89
|
+
readAccountAddressField(signer),
|
|
90
|
+
{ caseInsensitive: true }
|
|
94
91
|
),
|
|
95
92
|
delegateAddress: matchingStringField(
|
|
96
93
|
"delegate_address",
|
|
@@ -145,7 +142,7 @@ function loadCredentialsFromEnv() {
|
|
|
145
142
|
apiKey,
|
|
146
143
|
delegateKey,
|
|
147
144
|
agentId: stringField(process.env.HAVEN_AGENT_ID),
|
|
148
|
-
|
|
145
|
+
accountAddress: readAccountAddressEnv(process.env),
|
|
149
146
|
chainId: numberField(process.env.HAVEN_CHAIN_ID),
|
|
150
147
|
network: stringField(process.env.HAVEN_NETWORK),
|
|
151
148
|
apiUrl: stringField(process.env.HAVEN_API_URL)
|
|
@@ -155,10 +152,22 @@ function readAccountAddressField(raw) {
|
|
|
155
152
|
return stringField(raw.account_address ?? raw.safe_address ?? raw.safeAddress);
|
|
156
153
|
}
|
|
157
154
|
function readAccountAddressEnv(env) {
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
155
|
+
const current = stringField(env.HAVEN_ACCOUNT_ADDRESS);
|
|
156
|
+
for (const name of ["HAVEN_WALLET_ADDRESS", "HAVEN_SAFE_ADDRESS"]) {
|
|
157
|
+
const retired = stringField(env[name]);
|
|
158
|
+
if (!retired) continue;
|
|
159
|
+
if (!current) {
|
|
160
|
+
throw new Error(
|
|
161
|
+
`${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.`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
if (retired.toLowerCase() !== current.toLowerCase()) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`${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.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return current;
|
|
162
171
|
}
|
|
163
172
|
function stringField(value) {
|
|
164
173
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
@@ -293,11 +302,14 @@ var toolSchemas = {
|
|
|
293
302
|
website: z.string().optional()
|
|
294
303
|
},
|
|
295
304
|
haven_list_receipts: {
|
|
296
|
-
limit: z.number().int().min(1).max(100).optional()
|
|
305
|
+
limit: z.number().int().min(1).max(100).optional(),
|
|
306
|
+
/** #3128: the previous page's next_cursor (a receipt id). */
|
|
307
|
+
cursor: z.string().min(1).optional()
|
|
297
308
|
},
|
|
298
309
|
haven_verify_receipt: {
|
|
299
310
|
receipt: z.unknown()
|
|
300
311
|
}
|
|
312
|
+
// #3101: keys survive on the type (see the hosted server's contracts.ts).
|
|
301
313
|
};
|
|
302
314
|
var toolDescriptions = {
|
|
303
315
|
haven_send: composeDescription(toolDescriptions$1.send),
|
|
@@ -488,12 +500,32 @@ function createToolHandlers(haven) {
|
|
|
488
500
|
source: entry.source,
|
|
489
501
|
domain_verified: entry.domainVerified,
|
|
490
502
|
verified_payable: entry.verifiedPayable,
|
|
491
|
-
// Which Haven pay tool reaches this entry from the local MCP surface
|
|
503
|
+
// Which Haven pay tool reaches this entry from the local MCP surface,
|
|
504
|
+
// and — #3100 (epic #3105, decision 4) — the arguments that tool
|
|
505
|
+
// accepts VERBATIM, spelled in ITS vocabulary (`merchant_url`, not
|
|
506
|
+
// the entry's `resource_url`). The local surface keeps pointing at
|
|
507
|
+
// its pay tools: they need no cap, so a verbatim hint exists.
|
|
492
508
|
// #1328: the 'mpp' rail's only-ever catalog row (the Haven MPP demo
|
|
493
509
|
// resource) is delisted with the mpp_demo retirement, so this
|
|
494
510
|
// fallback is unreachable today; it stays x402 rather than naming a
|
|
495
511
|
// deleted tool in case a future non-demo 'mpp' rail entry appears.
|
|
496
|
-
|
|
512
|
+
// A row without a tool_name cannot get a verbatim hint —
|
|
513
|
+
// haven_pay_mcp_tool requires tool_name — so it gets the REASON
|
|
514
|
+
// instead of a hint its own tool refuses (haven-reviewer on #3113;
|
|
515
|
+
// the epic's "omitted + reason, never null" shape, decision 3).
|
|
516
|
+
...entry.protocol === "mcp" ? entry.toolName ? {
|
|
517
|
+
suggested_tool: "haven_pay_mcp_tool",
|
|
518
|
+
suggested_arguments: {
|
|
519
|
+
merchant_url: entry.resourceUrl,
|
|
520
|
+
tool_name: entry.toolName,
|
|
521
|
+
...entry.toolArguments ? { arguments: entry.toolArguments } : {}
|
|
522
|
+
}
|
|
523
|
+
} : {
|
|
524
|
+
suggested_tool_omitted_reason: "this catalog row carries no tool_name, which haven_pay_mcp_tool requires; read the merchant's tool list yourself, then call haven_pay_mcp_tool with merchant_url, tool_name and arguments"
|
|
525
|
+
} : {
|
|
526
|
+
suggested_tool: "haven_pay_x402",
|
|
527
|
+
suggested_arguments: { url: entry.resourceUrl }
|
|
528
|
+
}
|
|
497
529
|
}));
|
|
498
530
|
});
|
|
499
531
|
},
|
|
@@ -513,7 +545,7 @@ function createToolHandlers(haven) {
|
|
|
513
545
|
},
|
|
514
546
|
haven_list_receipts: async (input) => {
|
|
515
547
|
const args = objectInput("haven_list_receipts", input);
|
|
516
|
-
return runTool(async () => haven.
|
|
548
|
+
return runTool(async () => haven.listReceiptsPage({ limit: args.limit, cursor: args.cursor }));
|
|
517
549
|
},
|
|
518
550
|
haven_verify_receipt: async (input) => {
|
|
519
551
|
const args = objectInput("haven_verify_receipt", input);
|
|
@@ -658,7 +690,11 @@ function normalizeError(err) {
|
|
|
658
690
|
message: err.message,
|
|
659
691
|
statusCode: err.statusCode,
|
|
660
692
|
nextAction: err.nextAction,
|
|
661
|
-
|
|
693
|
+
next_action: err.nextAction,
|
|
694
|
+
retry_with_new_quote: err.retryWithNewQuote,
|
|
695
|
+
// #3103: the local runtime's one decision site — no tool can act until
|
|
696
|
+
// the merchant recovers; the message carries retry_after_s.
|
|
697
|
+
next_tool_omitted_reason: "the merchant needs to recover first; re-quote after the retry_after_s in the message"
|
|
662
698
|
};
|
|
663
699
|
}
|
|
664
700
|
if (err instanceof HavenPaymentStateError) {
|
|
@@ -671,6 +707,7 @@ function normalizeError(err) {
|
|
|
671
707
|
status: err.status,
|
|
672
708
|
phase: err.phase,
|
|
673
709
|
nextAction: err.nextAction,
|
|
710
|
+
next_action: err.nextAction,
|
|
674
711
|
resume_state: err.resumeState,
|
|
675
712
|
body: err.body
|
|
676
713
|
};
|
|
@@ -692,6 +729,7 @@ function normalizeError(err) {
|
|
|
692
729
|
paymentId: err.paymentId,
|
|
693
730
|
phase: stringOrUndefined(body?.phase),
|
|
694
731
|
nextAction: stringOrUndefined(body?.nextAction) ?? stringOrUndefined(body?.next_action) ?? AgentPaymentNextAction.StopAndTellUser,
|
|
732
|
+
next_action: stringOrUndefined(body?.nextAction) ?? stringOrUndefined(body?.next_action) ?? AgentPaymentNextAction.StopAndTellUser,
|
|
695
733
|
body: err.body
|
|
696
734
|
};
|
|
697
735
|
}
|
|
@@ -708,7 +746,11 @@ function normalizeError(err) {
|
|
|
708
746
|
success: false,
|
|
709
747
|
code: "UNKNOWN_ERROR",
|
|
710
748
|
message: err instanceof Error ? err.message : String(err),
|
|
711
|
-
nextAction: AgentPaymentNextAction.StopAndTellUser
|
|
749
|
+
nextAction: AgentPaymentNextAction.StopAndTellUser,
|
|
750
|
+
next_action: AgentPaymentNextAction.StopAndTellUser,
|
|
751
|
+
// #3103: the second local decision site — nothing structured can follow an
|
|
752
|
+
// error this runtime did not recognise.
|
|
753
|
+
next_tool_omitted_reason: "an error this runtime does not recognise; tell the user what the message says"
|
|
712
754
|
};
|
|
713
755
|
}
|
|
714
756
|
function stringOrUndefined(value) {
|
|
@@ -721,7 +763,7 @@ function computeConsentHash(input) {
|
|
|
721
763
|
input.apiKeyPrefix,
|
|
722
764
|
input.apiUrl ?? "",
|
|
723
765
|
input.agentId ?? "",
|
|
724
|
-
(input.
|
|
766
|
+
(input.accountAddress ?? "").toLowerCase(),
|
|
725
767
|
(input.delegateAddress ?? "").toLowerCase(),
|
|
726
768
|
input.chainId ?? ""
|
|
727
769
|
].join("|");
|
|
@@ -740,7 +782,7 @@ function renderConsentBlock(input, hash) {
|
|
|
740
782
|
];
|
|
741
783
|
if (input.apiUrl) lines.push(`Haven API: ${input.apiUrl}`);
|
|
742
784
|
if (input.agentId) lines.push(`Agent ID: ${input.agentId}`);
|
|
743
|
-
if (input.
|
|
785
|
+
if (input.accountAddress) lines.push(`Haven wallet (Safe): ${input.accountAddress}`);
|
|
744
786
|
if (input.delegateAddress) lines.push(`Delegate (local signer): ${input.delegateAddress}`);
|
|
745
787
|
if (typeof input.chainId === "number") lines.push(`Chain ID: ${input.chainId}`);
|
|
746
788
|
lines.push("");
|
|
@@ -847,14 +889,14 @@ async function writeAckFile(path, hash) {
|
|
|
847
889
|
}
|
|
848
890
|
async function consentInputFromClient(haven, seed, toolNames) {
|
|
849
891
|
let allowanceSummary = seed.allowanceSummary ?? [];
|
|
850
|
-
let
|
|
892
|
+
let accountAddress = seed.accountAddress;
|
|
851
893
|
let delegateAddress = seed.delegateAddress;
|
|
852
894
|
let chainId = seed.chainId;
|
|
853
895
|
try {
|
|
854
896
|
const summary = await haven.getAllowances();
|
|
855
897
|
const list = isAllowanceSummary(summary) ? summary.allowances : Array.isArray(summary) ? summary : [];
|
|
856
898
|
if (isAllowanceSummary(summary)) {
|
|
857
|
-
|
|
899
|
+
accountAddress = summary.accountAddress ?? accountAddress;
|
|
858
900
|
delegateAddress = summary.delegateAddress;
|
|
859
901
|
chainId = typeof summary.chainId === "number" ? summary.chainId : chainId;
|
|
860
902
|
}
|
|
@@ -870,7 +912,7 @@ async function consentInputFromClient(haven, seed, toolNames) {
|
|
|
870
912
|
apiKeyPrefix: derivePrefix(seed.apiKey),
|
|
871
913
|
apiUrl: seed.apiUrl,
|
|
872
914
|
agentId: seed.agentId,
|
|
873
|
-
|
|
915
|
+
accountAddress,
|
|
874
916
|
delegateAddress,
|
|
875
917
|
chainId,
|
|
876
918
|
toolNames,
|
|
@@ -904,7 +946,7 @@ async function resolveHavenClient(options = {}) {
|
|
|
904
946
|
return { client, credentials };
|
|
905
947
|
}
|
|
906
948
|
var MCP_NAME = "@haven_ai/mcp";
|
|
907
|
-
var MCP_VERSION = "0.
|
|
949
|
+
var MCP_VERSION = "0.4.0-alpha.0";
|
|
908
950
|
var MCP_INSTRUCTIONS = [
|
|
909
951
|
"Haven local MCP server: signs in-process with the delegate key it holds on",
|
|
910
952
|
"this machine \u2014 the key never leaves this process. Call haven_get_agent",
|
|
@@ -913,7 +955,8 @@ var MCP_INSTRUCTIONS = [
|
|
|
913
955
|
"",
|
|
914
956
|
"To pay: haven_discover_tools to find a payable service, then",
|
|
915
957
|
"haven_pay_mcp_tool for MCP merchants or haven_pay_x402 for any x402",
|
|
916
|
-
"paywall. Tool responses carry nextAction
|
|
958
|
+
"paywall. Tool responses carry next_action (nextAction is the same value, kept one more",
|
|
959
|
+
"release) and, when no tool follows, next_tool_omitted_reason \u2014 follow them; description prose",
|
|
917
960
|
"is fallback, not the source of truth.",
|
|
918
961
|
"",
|
|
919
962
|
"A payment outside the agent budget is declined before any money moves. Haven",
|
|
@@ -977,7 +1020,7 @@ async function runConsentGate(haven, credentials, options) {
|
|
|
977
1020
|
apiKey: credentials.apiKey,
|
|
978
1021
|
apiUrl: credentials.apiUrl,
|
|
979
1022
|
agentId: credentials.agentId,
|
|
980
|
-
|
|
1023
|
+
accountAddress: credentials.accountAddress,
|
|
981
1024
|
delegateAddress: credentials.delegateAddress,
|
|
982
1025
|
chainId: credentials.chainId,
|
|
983
1026
|
allowanceSummary: credentials.allowanceSummary
|