@haven_ai/mcp 0.1.7-alpha → 0.1.10-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/dist/cli.cjs CHANGED
@@ -218,6 +218,18 @@ async function warnIfCredentialFilePermissive(path, log = (message) => process.s
218
218
  }
219
219
  var headersSchema = v3.z.record(v3.z.string(), v3.z.string()).optional();
220
220
  var toolSchemas = {
221
+ haven_send: {
222
+ asset: v3.z.enum(["ETH", "USDC"]),
223
+ recipient: v3.z.string().min(1),
224
+ amount: v3.z.string().min(1),
225
+ idempotencyKey: v3.z.string().optional()
226
+ },
227
+ haven_pay_mcp_tool: {
228
+ merchant_url: v3.z.string().url(),
229
+ tool_name: v3.z.string().min(1),
230
+ arguments: v3.z.record(v3.z.string(), v3.z.unknown()).optional(),
231
+ idempotencyKey: v3.z.string().optional()
232
+ },
221
233
  haven_quote_x402: {
222
234
  url: v3.z.string().url(),
223
235
  method: v3.z.string().optional(),
@@ -264,11 +276,18 @@ var toolSchemas = {
264
276
  },
265
277
  haven_get_agent: {},
266
278
  haven_get_allowances: {},
279
+ haven_sweep_delegate: {},
280
+ haven_discover_tools: {
281
+ category: v3.z.string().optional(),
282
+ rail: v3.z.enum(["x402", "mpp"]).optional()
283
+ },
267
284
  haven_list_receipts: {
268
285
  limit: v3.z.number().int().min(1).max(100).optional()
269
286
  }
270
287
  };
271
288
  var toolDescriptions = {
289
+ haven_send: sdk.composeDescription(sdk.toolDescriptions.send),
290
+ haven_pay_mcp_tool: sdk.composeDescription(sdk.toolDescriptions.payMcpTool),
272
291
  haven_quote_x402: sdk.composeDescription(sdk.toolDescriptions.quoteX402),
273
292
  haven_pay_x402_quote: sdk.composeDescription(sdk.toolDescriptions.payX402),
274
293
  haven_pay_x402: sdk.composeDescription(sdk.toolDescriptions.payX402OneShot),
@@ -280,16 +299,98 @@ var toolDescriptions = {
280
299
  haven_get_resume_state: sdk.composeDescription(sdk.toolDescriptions.getResumeState),
281
300
  haven_get_agent: sdk.composeDescription(sdk.toolDescriptions.getAgent),
282
301
  haven_get_allowances: sdk.composeDescription(sdk.toolDescriptions.getAllowances),
302
+ haven_sweep_delegate: sdk.composeDescription(sdk.toolDescriptions.sweep_delegate),
303
+ haven_discover_tools: sdk.composeDescription(sdk.toolDescriptions.discoverTools),
283
304
  haven_list_receipts: sdk.composeDescription(sdk.toolDescriptions.listReceipts)
284
305
  };
285
306
  function createToolHandlers(haven) {
286
307
  return {
308
+ haven_send: async (input) => {
309
+ return runTool(async () => {
310
+ const args = objectInput("haven_send", input);
311
+ try {
312
+ const result = await haven.pay({
313
+ token: args.asset,
314
+ amount: args.amount,
315
+ to: args.recipient
316
+ });
317
+ return {
318
+ payment_id: result.paymentId,
319
+ status: result.status,
320
+ tx_hash: result.txHash ?? null,
321
+ asset: args.asset,
322
+ amount: args.amount,
323
+ recipient: args.recipient
324
+ };
325
+ } catch (err) {
326
+ if (err instanceof sdk.HavenPaymentStateError && isPendingApproval(err.status)) {
327
+ return {
328
+ payment_id: err.paymentId,
329
+ status: "pending_approval",
330
+ asset: args.asset,
331
+ amount: args.amount,
332
+ recipient: args.recipient
333
+ };
334
+ }
335
+ throw err;
336
+ }
337
+ });
338
+ },
339
+ haven_pay_mcp_tool: async (input) => {
340
+ return runTool(async () => {
341
+ const args = objectInput("haven_pay_mcp_tool", input);
342
+ const envelope = buildMcpToolsCallEnvelope(args.tool_name, args.arguments);
343
+ const response = await haven.fetch(
344
+ args.merchant_url,
345
+ {
346
+ method: "POST",
347
+ headers: { "Content-Type": "application/json" },
348
+ body: JSON.stringify(envelope)
349
+ },
350
+ { idempotencyKey: args.idempotencyKey }
351
+ );
352
+ return responsePayload(response);
353
+ });
354
+ },
287
355
  haven_quote_x402: async (input) => {
288
356
  const args = objectInput("haven_quote_x402", input);
289
- return runTool(async () => haven.quoteX402(args.url, requestInit(args), { idempotencyKey: args.idempotencyKey }));
357
+ try {
358
+ return { success: true, data: await haven.quoteX402(args.url, requestInit(args), { idempotencyKey: args.idempotencyKey }) };
359
+ } catch (err) {
360
+ if (err instanceof sdk.HavenApiError && err.message.includes("quoteX402 only supports standard x402")) {
361
+ return wrongTool(
362
+ "WRONG_RAIL",
363
+ "The URL responds with an MPP machine-payment challenge, not an x402 payment. Use haven_quote_mpp to inspect this merchant.",
364
+ "haven_quote_mpp"
365
+ );
366
+ }
367
+ return normalizeError(err);
368
+ }
290
369
  },
291
370
  haven_pay_x402_quote: async (input) => {
292
371
  const args = objectInput("haven_pay_x402_quote", input);
372
+ const quote = args.quote;
373
+ if (!quote || typeof quote !== "object") {
374
+ return wrongTool(
375
+ "WRONG_TOOL",
376
+ "The quote argument is missing or is not a valid x402 quote object. Call haven_quote_x402 first to obtain a quote, or use haven_pay_x402 to handle the full probe \u2192 pay \u2192 retry round trip automatically.",
377
+ "haven_quote_x402"
378
+ );
379
+ }
380
+ if (!quote.paymentRequired && quote.rail === "mpp") {
381
+ return wrongTool(
382
+ "WRONG_TOOL",
383
+ "The quote is for the MPP rail. Use haven_pay_mpp_challenge to pay an MPP quote.",
384
+ "haven_pay_mpp_challenge"
385
+ );
386
+ }
387
+ if (!quote.paymentRequired) {
388
+ return wrongTool(
389
+ "WRONG_TOOL",
390
+ "The quote is missing the required paymentRequired field. Call haven_quote_x402 first to obtain a valid x402 quote.",
391
+ "haven_quote_x402"
392
+ );
393
+ }
293
394
  return runTool(async () => {
294
395
  const response = await haven.payX402Quote(args.quote, { idempotencyKey: args.idempotencyKey });
295
396
  return responsePayload(response);
@@ -304,6 +405,16 @@ function createToolHandlers(haven) {
304
405
  },
305
406
  haven_resume_x402_payment: async (input) => {
306
407
  const args = objectInput("haven_resume_x402_payment", input);
408
+ if (args.resume_state && typeof args.resume_state === "object") {
409
+ const stateRail = args.resume_state.rail;
410
+ if (stateRail && stateRail !== "x402") {
411
+ return wrongTool(
412
+ "WRONG_TOOL",
413
+ `The resume state is for the '${stateRail}' rail, not x402. Use haven_resume_mpp_payment instead.`,
414
+ "haven_resume_mpp_payment"
415
+ );
416
+ }
417
+ }
307
418
  return runTool(async () => {
308
419
  const state = await resumeState(args, "x402");
309
420
  const response = await haven.resumeX402Payment(state);
@@ -312,20 +423,54 @@ function createToolHandlers(haven) {
312
423
  },
313
424
  haven_quote_mpp: async (input) => {
314
425
  const args = objectInput("haven_quote_mpp", input);
315
- return runTool(async () => {
426
+ try {
316
427
  if (args.challenge) {
317
- return haven.quoteMpp(args.challenge, requestInit(args), {
318
- idempotencyKey: args.idempotencyKey
319
- });
428
+ return {
429
+ success: true,
430
+ data: await haven.quoteMpp(args.challenge, requestInit(args), {
431
+ idempotencyKey: args.idempotencyKey
432
+ })
433
+ };
320
434
  }
321
435
  if (!args.url) {
322
- throw new sdk.HavenApiError("haven_quote_mpp requires either url or challenge.", 400);
436
+ return normalizeError(new sdk.HavenApiError("haven_quote_mpp requires either url or challenge.", 400));
323
437
  }
324
- return haven.quoteMpp(args.url, requestInit(args), { idempotencyKey: args.idempotencyKey });
325
- });
438
+ return { success: true, data: await haven.quoteMpp(args.url, requestInit(args), { idempotencyKey: args.idempotencyKey }) };
439
+ } catch (err) {
440
+ if (err instanceof Error && err.message.includes("No MACHINE-PAYMENT-CHALLENGE header found")) {
441
+ return wrongTool(
442
+ "WRONG_RAIL",
443
+ "The URL responds with an x402 payment requirement, not an MPP machine-payment challenge. Use haven_quote_x402 to inspect this merchant.",
444
+ "haven_quote_x402"
445
+ );
446
+ }
447
+ return normalizeError(err);
448
+ }
326
449
  },
327
450
  haven_pay_mpp_challenge: async (input) => {
328
451
  const args = objectInput("haven_pay_mpp_challenge", input);
452
+ const quote = args.quote;
453
+ if (!quote || typeof quote !== "object") {
454
+ return wrongTool(
455
+ "WRONG_TOOL",
456
+ "The quote argument is missing or is not a valid MPP quote object. Call haven_quote_mpp first to obtain a quote.",
457
+ "haven_quote_mpp"
458
+ );
459
+ }
460
+ if (quote.paymentRequired || quote.rail === "x402") {
461
+ return wrongTool(
462
+ "WRONG_TOOL",
463
+ "The quote is for the x402 rail. Use haven_pay_x402_quote to pay an x402 quote.",
464
+ "haven_pay_x402_quote"
465
+ );
466
+ }
467
+ if (!quote.challenge) {
468
+ return wrongTool(
469
+ "WRONG_TOOL",
470
+ "The quote is missing the required challenge field. Call haven_quote_mpp first to obtain a valid MPP quote.",
471
+ "haven_quote_mpp"
472
+ );
473
+ }
329
474
  return runTool(async () => {
330
475
  const response = await haven.payMppChallenge(args.quote, { idempotencyKey: args.idempotencyKey });
331
476
  return responsePayload(response);
@@ -333,6 +478,16 @@ function createToolHandlers(haven) {
333
478
  },
334
479
  haven_resume_mpp_payment: async (input) => {
335
480
  const args = objectInput("haven_resume_mpp_payment", input);
481
+ if (args.resume_state && typeof args.resume_state === "object") {
482
+ const stateRail = args.resume_state.rail;
483
+ if (stateRail && stateRail !== "mpp") {
484
+ return wrongTool(
485
+ "WRONG_TOOL",
486
+ `The resume state is for the '${stateRail}' rail, not mpp. Use haven_resume_x402_payment instead.`,
487
+ "haven_resume_x402_payment"
488
+ );
489
+ }
490
+ }
336
491
  return runTool(async () => {
337
492
  const state = await resumeState(args, "mpp");
338
493
  const response = await haven.resumeMppPayment(state);
@@ -349,6 +504,34 @@ function createToolHandlers(haven) {
349
504
  },
350
505
  haven_get_agent: async () => runTool(async () => haven.getAgent()),
351
506
  haven_get_allowances: async () => runTool(async () => haven.getAllowances()),
507
+ haven_sweep_delegate: async () => runTool(async () => haven.sweepDelegate()),
508
+ haven_discover_tools: async (input) => {
509
+ const args = objectInput("haven_discover_tools", input);
510
+ return runTool(async () => {
511
+ const entries = await haven.discoverTools({
512
+ category: typeof args.category === "string" ? args.category : void 0,
513
+ rail: args.rail === "x402" || args.rail === "mpp" ? args.rail : void 0
514
+ });
515
+ return entries.map((entry) => ({
516
+ id: entry.id,
517
+ name: entry.name,
518
+ description: entry.description,
519
+ category: entry.category,
520
+ resource_url: entry.resourceUrl,
521
+ rail: entry.rail,
522
+ protocol: entry.protocol,
523
+ tool_name: entry.toolName,
524
+ price_display: entry.priceDisplay,
525
+ price_atomic: entry.priceAtomic,
526
+ asset: entry.asset,
527
+ network: entry.network,
528
+ status: entry.status,
529
+ verified_at: entry.verifiedAt,
530
+ // Which Haven pay tool reaches this entry from the local MCP surface.
531
+ suggested_tool: entry.protocol === "mcp" ? "haven_pay_mcp_tool" : entry.rail === "x402" ? "haven_pay_x402" : "haven_quote_mpp"
532
+ }));
533
+ });
534
+ },
352
535
  haven_list_receipts: async (input) => {
353
536
  const args = objectInput("haven_list_receipts", input);
354
537
  return runTool(async () => haven.listReceipts({ limit: args.limit }));
@@ -365,6 +548,23 @@ function createToolHandlers(haven) {
365
548
  return state;
366
549
  }
367
550
  }
551
+ function isPendingApproval(status) {
552
+ return status === "pending" || status === "pending_approval";
553
+ }
554
+ function wrongTool(code, message, suggested_tool) {
555
+ return { success: false, code, message, suggested_tool };
556
+ }
557
+ function buildMcpToolsCallEnvelope(toolName, args) {
558
+ return {
559
+ jsonrpc: "2.0",
560
+ id: `haven-mcp-${Date.now()}`,
561
+ method: "tools/call",
562
+ params: {
563
+ name: toolName,
564
+ arguments: args ?? {}
565
+ }
566
+ };
567
+ }
368
568
  function objectInput(name, input) {
369
569
  return v3.z.object(toolSchemas[name]).parse(input ?? {});
370
570
  }
@@ -640,7 +840,7 @@ async function resolveHavenClient(options = {}) {
640
840
  return { client, credentials };
641
841
  }
642
842
  var MCP_NAME = "@haven_ai/mcp";
643
- var MCP_VERSION = "0.1.7-alpha";
843
+ var MCP_VERSION = "0.1.10-alpha.0";
644
844
  function buildMcpServer(haven) {
645
845
  const server = new mcp_js.McpServer({
646
846
  name: MCP_NAME,