@haven_ai/mcp 0.8.1-alpha.0 → 0.10.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 +3 -0
- package/dist/cli.cjs +66 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +67 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +66 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +6 -2
- package/dist/index.d.ts +6 -2
- package/dist/index.js +67 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -338,7 +338,21 @@ var toolSchemas = {
|
|
|
338
338
|
compact: v3.z.boolean().optional().describe("true drops challengePayload, selectedPayment and protocolReceiptPayload from each row; omit for the full row.")
|
|
339
339
|
},
|
|
340
340
|
haven_verify_receipt: {
|
|
341
|
-
receipt: v3.z.unknown()
|
|
341
|
+
receipt: v3.z.unknown(),
|
|
342
|
+
// #3723: the spread form — the endpoint's `{ receipt, verification }`
|
|
343
|
+
// spread as top-level arguments — verifies: `verification` is declared
|
|
344
|
+
// ACCEPTED-AND-IGNORED (Haven's own self-check, never read). The stdio
|
|
345
|
+
// z.object would strip it silently anyway; declaring it keeps the schema
|
|
346
|
+
// identical to the hosted runtime's, where the key must be declared to
|
|
347
|
+
// pass its strict refusal.
|
|
348
|
+
verification: v3.z.unknown().optional().describe("accepted and ignored \u2014 verification reads the receipt itself")
|
|
349
|
+
},
|
|
350
|
+
// #3723: the signed bundle's read — `{ receipt }` only, settled payments
|
|
351
|
+
// only. The endpoint's server-side `verification` is deliberately NOT
|
|
352
|
+
// returned: it is computed on Haven's server, not offline, and an agent
|
|
353
|
+
// that trusted it would skip haven_verify_receipt.
|
|
354
|
+
haven_get_receipt: {
|
|
355
|
+
payment_id: v3.z.string().min(1)
|
|
342
356
|
},
|
|
343
357
|
// #3329: a budget for one task that ends by itself — a short-lived child of
|
|
344
358
|
// the agent's own budget, capped and time-boxed independently of the period
|
|
@@ -423,6 +437,8 @@ var toolDescriptions = {
|
|
|
423
437
|
haven_submit_catalog_entry: sdk.composeDescription(sdk.toolDescriptions.submitCatalogEntry),
|
|
424
438
|
haven_list_receipts: sdk.composeDescription(sdk.toolDescriptions.listReceipts),
|
|
425
439
|
haven_verify_receipt: sdk.composeDescription(sdk.toolDescriptions.verifyReceipt),
|
|
440
|
+
// #3723: the signed bundle's read, described from the shared fragment.
|
|
441
|
+
haven_get_receipt: sdk.composeDescription(sdk.toolDescriptions.getReceipt),
|
|
426
442
|
haven_open_task_budget: OPEN_TASK_BUDGET_DESCRIPTION,
|
|
427
443
|
haven_close_task_budget: CLOSE_TASK_BUDGET_DESCRIPTION,
|
|
428
444
|
haven_get_task_budget: GET_TASK_BUDGET_DESCRIPTION,
|
|
@@ -711,6 +727,10 @@ function createToolHandlers(haven) {
|
|
|
711
727
|
price_atomic: entry.priceAtomic,
|
|
712
728
|
asset: entry.asset,
|
|
713
729
|
network: entry.network,
|
|
730
|
+
// #3839: same hint the hosted surface emits — a catalog hint, the
|
|
731
|
+
// live quote stays authoritative; "unknown" when nothing is recorded.
|
|
732
|
+
asset_transfer_methods: entry.assetTransferMethods ?? null,
|
|
733
|
+
funding_leg_expected: sdk.catalogFundingLegExpected(entry.assetTransferMethods),
|
|
714
734
|
status: entry.status,
|
|
715
735
|
verified_at: entry.verifiedAt,
|
|
716
736
|
source: entry.source,
|
|
@@ -769,6 +789,17 @@ function createToolHandlers(haven) {
|
|
|
769
789
|
const args = objectInput("haven_verify_receipt", input);
|
|
770
790
|
return runTool(async () => sdk.verifyPaymentReceipt(args.receipt));
|
|
771
791
|
},
|
|
792
|
+
// #3723: the signed bundle's home on the local surface. Parsed INSIDE
|
|
793
|
+
// runTool, so a missing payment_id is a structured INVALID_INPUT failure
|
|
794
|
+
// rather than a thrown ZodError (the hosted runtime's parseStrict already
|
|
795
|
+
// answers that way). Returns `{ receipt }` only — the endpoint's
|
|
796
|
+
// server-side `verification` is not offline evidence, and the agent
|
|
797
|
+
// verifies with haven_verify_receipt, which reads the bundle unchanged.
|
|
798
|
+
haven_get_receipt: async (input) => runTool(async () => {
|
|
799
|
+
const args = objectInput("haven_get_receipt", input);
|
|
800
|
+
const { receipt } = await haven.getReceipt(args.payment_id);
|
|
801
|
+
return { receipt };
|
|
802
|
+
}),
|
|
772
803
|
haven_open_task_budget: async (input) => {
|
|
773
804
|
const args = objectInput("haven_open_task_budget", input);
|
|
774
805
|
return runTool(async () => {
|
|
@@ -965,17 +996,26 @@ function parseMaybeJson(text) {
|
|
|
965
996
|
return text;
|
|
966
997
|
}
|
|
967
998
|
}
|
|
999
|
+
var MERCHANT_OUT_OF_GAS_REASON = "settlement_wallet_out_of_gas";
|
|
1000
|
+
function merchantOutOfGasMessage(settlementsRemaining, failFloor) {
|
|
1001
|
+
const remaining = typeof settlementsRemaining === "number" ? settlementsRemaining : null;
|
|
1002
|
+
const floor = typeof failFloor === "number" ? failFloor : null;
|
|
1003
|
+
const figures = remaining !== null && floor !== null ? ` It has gas for ${remaining} more settlement${remaining === 1 ? "" : "s"} and refuses new payments below ${floor} (settlements_remaining: ${remaining}, fail_floor: ${floor}).` : remaining !== null ? ` settlements_remaining: ${remaining}.` : "";
|
|
1004
|
+
return `The merchant refused this call: its settlement wallet is out of gas (reason_code: ${MERCHANT_OUT_OF_GAS_REASON}).` + figures + " No payment was created. The merchant's operator must top up its settlement wallet; until then every retry is refused again. Tell the user, and re-quote once the merchant has been topped up.";
|
|
1005
|
+
}
|
|
968
1006
|
var MerchantNotReadyError = class extends Error {
|
|
1007
|
+
constructor(message, nextToolOmittedReason = "the merchant needs to recover first; re-quote after the retry_after_s in the message") {
|
|
1008
|
+
super(message);
|
|
1009
|
+
this.nextToolOmittedReason = nextToolOmittedReason;
|
|
1010
|
+
this.name = "MerchantNotReadyError";
|
|
1011
|
+
}
|
|
1012
|
+
nextToolOmittedReason;
|
|
969
1013
|
code = sdk.AgentPaymentFailureCode.MerchantNotReady;
|
|
970
1014
|
statusCode = 503;
|
|
971
1015
|
nextAction = sdk.AgentPaymentNextAction.StopAndTellUser;
|
|
972
1016
|
// Genuinely retryable — unlike a rejection, nothing about THIS call was
|
|
973
1017
|
// wrong; the merchant's own wallet needs to recover first.
|
|
974
1018
|
retryWithNewQuote = true;
|
|
975
|
-
constructor(message) {
|
|
976
|
-
super(message);
|
|
977
|
-
this.name = "MerchantNotReadyError";
|
|
978
|
-
}
|
|
979
1019
|
};
|
|
980
1020
|
async function merchantNotReadyErrorFor(response) {
|
|
981
1021
|
if (response.status !== 503) return null;
|
|
@@ -988,7 +1028,14 @@ async function merchantNotReadyErrorFor(response) {
|
|
|
988
1028
|
if (!body || typeof body !== "object" || body.error !== "merchant_not_ready") {
|
|
989
1029
|
return null;
|
|
990
1030
|
}
|
|
991
|
-
const { reason_code, settlements_remaining, retry_after_s } = body;
|
|
1031
|
+
const { reason_code, settlements_remaining, fail_floor, retry_after_s } = body;
|
|
1032
|
+
if (reason_code === MERCHANT_OUT_OF_GAS_REASON) {
|
|
1033
|
+
return new MerchantNotReadyError(
|
|
1034
|
+
merchantOutOfGasMessage(settlements_remaining, fail_floor),
|
|
1035
|
+
// Same reason the hosted runtime returns (support/mcp-context.ts).
|
|
1036
|
+
"the merchant's operator must top up its settlement wallet first; re-quote after that"
|
|
1037
|
+
);
|
|
1038
|
+
}
|
|
992
1039
|
return new MerchantNotReadyError(
|
|
993
1040
|
"The merchant refused this call: it cannot settle a payment right now" + (typeof reason_code === "string" ? ` (reason_code: ${reason_code})` : "") + (typeof settlements_remaining === "number" ? `, settlements_remaining: ${settlements_remaining}` : "") + ". No payment was created." + (typeof retry_after_s === "number" ? ` Retry after approximately ${retry_after_s}s.` : " This is often transient; retry later.")
|
|
994
1041
|
);
|
|
@@ -1009,8 +1056,10 @@ function normalizeError(err) {
|
|
|
1009
1056
|
next_action: err.nextAction,
|
|
1010
1057
|
retry_with_new_quote: err.retryWithNewQuote,
|
|
1011
1058
|
// #3103: the local runtime's one decision site — no tool can act until
|
|
1012
|
-
// the merchant recovers
|
|
1013
|
-
|
|
1059
|
+
// the merchant recovers. The reason rides the error (#3834): the
|
|
1060
|
+
// generic one points at the message's retry_after_s, the out-of-gas
|
|
1061
|
+
// one at the operator top-up.
|
|
1062
|
+
next_tool_omitted_reason: err.nextToolOmittedReason
|
|
1014
1063
|
};
|
|
1015
1064
|
}
|
|
1016
1065
|
if (err instanceof sdk.HavenPaymentStateError) {
|
|
@@ -1052,6 +1101,14 @@ function normalizeError(err) {
|
|
|
1052
1101
|
body: err.body
|
|
1053
1102
|
};
|
|
1054
1103
|
}
|
|
1104
|
+
if (err instanceof v3.z.ZodError) {
|
|
1105
|
+
return {
|
|
1106
|
+
success: false,
|
|
1107
|
+
code: "INVALID_INPUT",
|
|
1108
|
+
message: err.errors.map((e) => `${e.path.join(".") || "(root)"}: ${e.message}`).join("; "),
|
|
1109
|
+
statusCode: 400
|
|
1110
|
+
};
|
|
1111
|
+
}
|
|
1055
1112
|
if (err instanceof sdk.HavenError) {
|
|
1056
1113
|
return {
|
|
1057
1114
|
success: false,
|
|
@@ -1288,7 +1345,7 @@ async function createHavenMcpServer(options = {}) {
|
|
|
1288
1345
|
return buildMcpServer(haven);
|
|
1289
1346
|
}
|
|
1290
1347
|
var MCP_NAME = "@haven_ai/mcp";
|
|
1291
|
-
var MCP_VERSION = "0.
|
|
1348
|
+
var MCP_VERSION = "0.10.0-alpha.0";
|
|
1292
1349
|
var MCP_INSTRUCTIONS = [
|
|
1293
1350
|
"Haven local MCP server: signs in-process with the delegate key it holds on",
|
|
1294
1351
|
"this machine \u2014 the key never leaves this process. Call haven_get_agent",
|