@haven_ai/mcp 0.7.0-alpha.0 → 0.8.1-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 +11 -7
- package/dist/cli.cjs +145 -12
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +146 -13
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +145 -12
- 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 +145 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -119,7 +119,7 @@ Environment variable form:
|
|
|
119
119
|
- `haven_list_receipts`
|
|
120
120
|
- `haven_open_task_budget` (#3329)
|
|
121
121
|
- `haven_close_task_budget` (#3329)
|
|
122
|
-
- `haven_submit` (#3329 — relays a local signer signature by `task_budget_id
|
|
122
|
+
- `haven_submit` (#3329 — relays a local signer signature by `task_budget_id`, or (#3506) by `sub_budget_id` for a sub-budget this agent delegates (listed in `haven_get_agent`'s `pendingSubBudgetSignatures[]`); a `payment_id` is refused on this runtime, which signs and submits payments inline)
|
|
123
123
|
|
|
124
124
|
### `idempotencyKey` is removed — send `idempotency_key`
|
|
125
125
|
|
|
@@ -190,13 +190,17 @@ live.
|
|
|
190
190
|
## Audit log
|
|
191
191
|
|
|
192
192
|
Every MCP tool invocation tags the underlying Haven API call with
|
|
193
|
-
`X-Haven-MCP-Tool: <tool_name>`. The backend records
|
|
194
|
-
`agent_tool_invocations` row
|
|
195
|
-
|
|
193
|
+
`X-Haven-MCP-Tool: <tool_name>`. The backend records an
|
|
194
|
+
`agent_tool_invocations` row (tool name, payment id when present, result
|
|
195
|
+
status, nextAction, error code, HTTP status, timestamp) for the tools on its
|
|
196
|
+
allowlist (`MCP_TOOL_NAMES` in the backend's `agentToolAudit.ts`):
|
|
197
|
+
`haven_quote_x402`, `haven_pay_x402_quote`, `haven_resume_x402_payment`,
|
|
198
|
+
`haven_get_payment_status`, `haven_get_resume_state`, `haven_get_agent`,
|
|
199
|
+
`haven_get_allowances` and `haven_list_receipts`. Every other tool, including
|
|
200
|
+
`haven_send`, `haven_pay_x402` and `haven_submit`, leaves no row. The agent's
|
|
196
201
|
activity feed in the Haven dashboard surfaces these rows alongside payments,
|
|
197
|
-
so the wallet owner can see
|
|
198
|
-
|
|
199
|
-
money.
|
|
202
|
+
so the wallet owner can see which of those tools the agent called and what
|
|
203
|
+
happened — including the read-only calls that don't move money.
|
|
200
204
|
|
|
201
205
|
The audit log is informational. The agent's signed budget delegation — its
|
|
202
206
|
on-chain caveat enforcers — remains the only thing that can stop a spend;
|
package/dist/cli.cjs
CHANGED
|
@@ -353,12 +353,19 @@ var toolSchemas = {
|
|
|
353
353
|
haven_close_task_budget: {
|
|
354
354
|
task_budget_id: v3.z.string().min(1)
|
|
355
355
|
},
|
|
356
|
-
// #
|
|
357
|
-
//
|
|
358
|
-
//
|
|
359
|
-
|
|
356
|
+
// #3518: read ONE task budget by id, any status — the status check a close
|
|
357
|
+
// refusal's "re-check the budget's status" points at, on the local surface
|
|
358
|
+
// too (schema and wording parity with the hosted read).
|
|
359
|
+
haven_get_task_budget: {
|
|
360
|
+
task_budget_id: v3.z.string().min(1)
|
|
361
|
+
},
|
|
362
|
+
// #3329 / #3506: relays a signature from the local signer — the open/close
|
|
363
|
+
// signature for a task budget or a sub-budget row, or (schema parity with
|
|
364
|
+
// the hosted surface) a direct-payment signature by payment_id. Exactly one
|
|
365
|
+
// of task_budget_id / sub_budget_id / payment_id, never two or none.
|
|
360
366
|
haven_submit: {
|
|
361
367
|
task_budget_id: v3.z.string().min(1).optional(),
|
|
368
|
+
sub_budget_id: v3.z.string().min(1).optional(),
|
|
362
369
|
payment_id: v3.z.string().min(1).optional(),
|
|
363
370
|
signature: v3.z.string().regex(/^0x[0-9a-fA-F]+$/, "signature must be a 0x-prefixed hex string")
|
|
364
371
|
}
|
|
@@ -386,11 +393,19 @@ var CLOSE_TASK_BUDGET_DESCRIPTION = [
|
|
|
386
393
|
"the signature with haven_submit. A task budget past its own deadline closes immediately, the",
|
|
387
394
|
"same as the pending case."
|
|
388
395
|
].join(" ");
|
|
396
|
+
var GET_TASK_BUDGET_DESCRIPTION = [
|
|
397
|
+
"Read one task budget by id, any status.",
|
|
398
|
+
"Returns { task_budget } with status (pending | open | closing | closed), isExpired, maxDisplay, recipientAddress, label and expiresAt \u2014",
|
|
399
|
+
"the check to run after a close or submit refusal says to re-check the budget's status.",
|
|
400
|
+
"haven_get_agent lists live task budgets only; this reads any one, closed or expired included."
|
|
401
|
+
].join(" ");
|
|
389
402
|
var SUBMIT_DESCRIPTION = [
|
|
390
403
|
"Relay a signature from the local signer. Pass exactly one of task_budget_id (from",
|
|
391
|
-
"haven_open_task_budget or haven_close_task_budget)
|
|
392
|
-
"
|
|
393
|
-
|
|
404
|
+
"haven_open_task_budget or haven_close_task_budget), sub_budget_id (from haven_get_agent",
|
|
405
|
+
"pendingSubBudgetSignatures[]) or payment_id \u2014 never two, never none \u2014 plus signature.",
|
|
406
|
+
"For a task budget this opens or closes it on-chain and returns { task_budget,",
|
|
407
|
+
'status }; a close in progress may return { task_budget, status: "closed", close_tx_hash }.',
|
|
408
|
+
"A sub_budget_id returns { sub_budget, status } with the next signer step, if one is owed."
|
|
394
409
|
].join(" ");
|
|
395
410
|
var toolDescriptions = {
|
|
396
411
|
haven_send: sdk.composeDescription(sdk.toolDescriptions.send),
|
|
@@ -410,8 +425,101 @@ var toolDescriptions = {
|
|
|
410
425
|
haven_verify_receipt: sdk.composeDescription(sdk.toolDescriptions.verifyReceipt),
|
|
411
426
|
haven_open_task_budget: OPEN_TASK_BUDGET_DESCRIPTION,
|
|
412
427
|
haven_close_task_budget: CLOSE_TASK_BUDGET_DESCRIPTION,
|
|
428
|
+
haven_get_task_budget: GET_TASK_BUDGET_DESCRIPTION,
|
|
413
429
|
haven_submit: SUBMIT_DESCRIPTION
|
|
414
430
|
};
|
|
431
|
+
function subBudgetSignStep(subBudgetId) {
|
|
432
|
+
return {
|
|
433
|
+
next_action: "sign",
|
|
434
|
+
next_tool: "mcp__haven-signer__haven_sign",
|
|
435
|
+
next_arguments: { sub_budget_id: subBudgetId }
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
async function submitSubBudgetTool(haven, subBudgetId, signature) {
|
|
439
|
+
let result;
|
|
440
|
+
try {
|
|
441
|
+
result = await haven.submitSubBudget(subBudgetId, signature);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
const code = err instanceof sdk.HavenApiError ? err.body?.error_code : void 0;
|
|
444
|
+
if (code === "close_needs_reprepare") {
|
|
445
|
+
let fresh;
|
|
446
|
+
try {
|
|
447
|
+
fresh = await haven.closeSubBudget(subBudgetId);
|
|
448
|
+
} catch (closeErr) {
|
|
449
|
+
return normalizeError(closeErr);
|
|
450
|
+
}
|
|
451
|
+
if (fresh.status === "closed") {
|
|
452
|
+
return {
|
|
453
|
+
success: true,
|
|
454
|
+
data: {
|
|
455
|
+
sub_budget: fresh.subBudget,
|
|
456
|
+
status: "closed",
|
|
457
|
+
next_action: "none",
|
|
458
|
+
next_tool_omitted_reason: "the sub-budget is closed on-chain; nothing further to sign or submit for it"
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
return {
|
|
463
|
+
success: false,
|
|
464
|
+
code: "CLOSE_NEEDS_REPREPARE",
|
|
465
|
+
message: "The stored close operation for this sub-budget was stale, so nothing was relayed. Haven prepared a fresh one: sign it with haven_sign, then call haven_submit again with the new signature.",
|
|
466
|
+
statusCode: 409,
|
|
467
|
+
...subBudgetSignStep(subBudgetId)
|
|
468
|
+
};
|
|
469
|
+
}
|
|
470
|
+
if (code === "close_outcome_unconfirmed") {
|
|
471
|
+
return {
|
|
472
|
+
success: false,
|
|
473
|
+
code: "CLOSE_OUTCOME_UNCONFIRMED",
|
|
474
|
+
message: "The close operation was sent but its outcome is not confirmed yet (on Base that can take tens of minutes). Wait, then call haven_submit again with the same arguments: it reports closed once the chain has finalised the disable, or prepares a fresh operation to sign if the earlier one did not land.",
|
|
475
|
+
statusCode: 502,
|
|
476
|
+
next_action: "check_status_later",
|
|
477
|
+
next_tool: "haven_submit",
|
|
478
|
+
next_arguments: { sub_budget_id: subBudgetId, signature }
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
return normalizeError(err);
|
|
482
|
+
}
|
|
483
|
+
return runTool(async () => {
|
|
484
|
+
const submitted = {
|
|
485
|
+
sub_budget: result.subBudget,
|
|
486
|
+
status: result.status,
|
|
487
|
+
...result.closeTxHash !== void 0 ? { close_tx_hash: result.closeTxHash } : {}
|
|
488
|
+
};
|
|
489
|
+
if (result.status === "closed") {
|
|
490
|
+
return {
|
|
491
|
+
...submitted,
|
|
492
|
+
next_action: "none",
|
|
493
|
+
next_tool_omitted_reason: "the sub-budget is closed on-chain; nothing further to sign or submit for it"
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
let pending;
|
|
497
|
+
try {
|
|
498
|
+
pending = await haven.listPendingSubBudgetSignatures();
|
|
499
|
+
} catch {
|
|
500
|
+
pending = null;
|
|
501
|
+
}
|
|
502
|
+
if (pending === null) {
|
|
503
|
+
return {
|
|
504
|
+
...submitted,
|
|
505
|
+
next_action: "check_status_later",
|
|
506
|
+
next_tool: "haven_get_agent",
|
|
507
|
+
next_arguments: {},
|
|
508
|
+
reason: "This sub-budget row is open, but Haven could not say whether its tree has another row awaiting your signature. Call haven_get_agent and sign any pendingSubBudgetSignatures row."
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
const tree = result.subBudget.parentSubBudgetId ?? result.subBudget.id;
|
|
512
|
+
const sibling = pending.find(
|
|
513
|
+
(row) => row.purpose === "open" && row.subBudgetId !== result.subBudget.id && (row.parentSubBudgetId ?? row.subBudgetId) === tree
|
|
514
|
+
);
|
|
515
|
+
if (sibling) return { ...submitted, ...subBudgetSignStep(sibling.subBudgetId) };
|
|
516
|
+
return {
|
|
517
|
+
...submitted,
|
|
518
|
+
next_action: "none",
|
|
519
|
+
next_tool_omitted_reason: "no other row of this sub-budget awaits your signature, so the sub-budget is fully open and the sub-agent can spend through its grant"
|
|
520
|
+
};
|
|
521
|
+
});
|
|
522
|
+
}
|
|
415
523
|
function createToolHandlers(haven) {
|
|
416
524
|
return {
|
|
417
525
|
haven_send: async (input) => {
|
|
@@ -567,7 +675,17 @@ function createToolHandlers(haven) {
|
|
|
567
675
|
const args = objectInput("haven_get_resume_state", input);
|
|
568
676
|
return runTool(async () => haven.getResumeState(args.payment_id));
|
|
569
677
|
},
|
|
570
|
-
haven_get_agent: async () => runTool(async () =>
|
|
678
|
+
haven_get_agent: async () => runTool(async () => {
|
|
679
|
+
const summary = await haven.getAgentSummary();
|
|
680
|
+
if (!Array.isArray(summary.pendingSubBudgetSignatures)) return summary;
|
|
681
|
+
return {
|
|
682
|
+
...summary,
|
|
683
|
+
pendingSubBudgetSignatures: summary.pendingSubBudgetSignatures.map((row) => ({
|
|
684
|
+
...row,
|
|
685
|
+
...subBudgetSignStep(row.subBudgetId)
|
|
686
|
+
}))
|
|
687
|
+
};
|
|
688
|
+
}),
|
|
571
689
|
haven_get_allowances: async () => runTool(async () => haven.getAllowances()),
|
|
572
690
|
haven_sweep_delegate: async () => runTool(async () => haven.sweepDelegate()),
|
|
573
691
|
haven_discover_tools: async (input) => {
|
|
@@ -694,17 +812,32 @@ function createToolHandlers(haven) {
|
|
|
694
812
|
};
|
|
695
813
|
});
|
|
696
814
|
},
|
|
815
|
+
// #3518: read ONE task budget by id, any status — the status check a
|
|
816
|
+
// close/submit refusal's "re-check the budget's status" points at. The
|
|
817
|
+
// SDK relays `GET /task-budgets/:id` (the backend route answers any
|
|
818
|
+
// status) and a 404 carries the backend's own message through runTool.
|
|
819
|
+
haven_get_task_budget: async (input) => {
|
|
820
|
+
const args = objectInput("haven_get_task_budget", input);
|
|
821
|
+
return runTool(async () => {
|
|
822
|
+
const taskBudget = await haven.getTaskBudget(args.task_budget_id);
|
|
823
|
+
return { task_budget: taskBudget };
|
|
824
|
+
});
|
|
825
|
+
},
|
|
697
826
|
haven_submit: async (input) => {
|
|
698
827
|
const args = objectInput("haven_submit", input);
|
|
699
828
|
const hasTaskBudget = typeof args.task_budget_id === "string" && args.task_budget_id.length > 0;
|
|
829
|
+
const hasSubBudget = typeof args.sub_budget_id === "string" && args.sub_budget_id.length > 0;
|
|
700
830
|
const hasPayment = typeof args.payment_id === "string" && args.payment_id.length > 0;
|
|
701
|
-
if (hasTaskBudget
|
|
831
|
+
if ([hasTaskBudget, hasSubBudget, hasPayment].filter(Boolean).length !== 1) {
|
|
702
832
|
return {
|
|
703
833
|
success: false,
|
|
704
834
|
code: "INVALID_INPUT",
|
|
705
|
-
message: "haven_submit takes exactly one of task_budget_id or
|
|
835
|
+
message: "haven_submit takes exactly one of payment_id, task_budget_id or sub_budget_id, never two or none. Nothing was relayed."
|
|
706
836
|
};
|
|
707
837
|
}
|
|
838
|
+
if (hasSubBudget) {
|
|
839
|
+
return submitSubBudgetTool(haven, args.sub_budget_id, args.signature);
|
|
840
|
+
}
|
|
708
841
|
return runTool(async () => {
|
|
709
842
|
if (hasTaskBudget) {
|
|
710
843
|
const result = await haven.submitTaskBudget(args.task_budget_id, args.signature);
|
|
@@ -715,7 +848,7 @@ function createToolHandlers(haven) {
|
|
|
715
848
|
};
|
|
716
849
|
}
|
|
717
850
|
throw new sdk.HavenApiError(
|
|
718
|
-
"haven_submit with payment_id is not supported on the local MCP surface: haven_send signs and submits a direct payment in one call, so there is no separate relay step. Use haven_submit with task_budget_id to relay a
|
|
851
|
+
"haven_submit with payment_id is not supported on the local MCP surface: haven_send signs and submits a direct payment in one call, so there is no separate relay step. Use haven_submit with task_budget_id or sub_budget_id to relay a budget open/close signature.",
|
|
719
852
|
400
|
|
720
853
|
);
|
|
721
854
|
});
|
|
@@ -1147,7 +1280,7 @@ async function resolveHavenClient(options = {}) {
|
|
|
1147
1280
|
return { client, credentials };
|
|
1148
1281
|
}
|
|
1149
1282
|
var MCP_NAME = "@haven_ai/mcp";
|
|
1150
|
-
var MCP_VERSION = "0.
|
|
1283
|
+
var MCP_VERSION = "0.8.1-alpha.0";
|
|
1151
1284
|
var MCP_INSTRUCTIONS = [
|
|
1152
1285
|
"Haven local MCP server: signs in-process with the delegate key it holds on",
|
|
1153
1286
|
"this machine \u2014 the key never leaves this process. Call haven_get_agent",
|