@haven_ai/mcp 0.1.6-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 +209 -9
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +210 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +209 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +210 -10
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
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
|
-
|
|
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
|
-
|
|
426
|
+
try {
|
|
316
427
|
if (args.challenge) {
|
|
317
|
-
return
|
|
318
|
-
|
|
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
|
-
|
|
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.
|
|
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,
|