11import { wrapFetchWithPaymentFromConfig } from "@x402/fetch" ;
22import { wrapMCPClientWithPaymentFromConfig } from "@x402/mcp" ;
33import { ClientFactory , JsonRpcTransportFactory , RestTransportFactory } from "@a2a-js/sdk/client" ;
4+ import boxen from "boxen" ;
45import type { Client } from "@modelcontextprotocol/sdk/client/index.js" ;
56import type { Wallet } from "./wallets/wallet.js" ;
67
@@ -16,10 +17,11 @@ export class DryRunPaymentRequired extends Error {
1617 readonly requirements : PaymentRequirementsInfo [ ] ;
1718 constructor ( requirements : PaymentRequirementsInfo [ ] ) {
1819 const req = requirements [ 0 ] ;
19- const amount = req ? formatPaymentAmount ( req ) : "an unknown amount" ;
20- super (
21- `This request requires payment of ${ amount } .\nRun the same command with --pay to authorize the transaction and proceed.` ,
22- ) ;
20+ const amount = req ? formatPaymentAmount ( req ) : null ;
21+ const payLine = amount
22+ ? `This request requires payment of ${ amount } .\nRun the same command with --pay to authorize the transaction and proceed.`
23+ : `This request requires payment, but the amount could not be determined.\nInspect the endpoint manually before running with --pay.` ;
24+ super ( payLine ) ;
2325 this . name = "DryRunPaymentRequired" ;
2426 this . requirements = requirements ;
2527 }
@@ -47,8 +49,8 @@ export function createDryRunFetch(): typeof fetch {
4749 try {
4850 const decoded = JSON . parse ( Buffer . from ( header , "base64" ) . toString ( "utf-8" ) ) ;
4951 requirements = ( decoded . accepts as PaymentRequirementsInfo [ ] ) ?? [ ] ;
50- } catch {
51- // ignore parse errors — we still throw DryRunPaymentRequired with empty requirements
52+ } catch ( e ) {
53+ if ( ! ( e instanceof SyntaxError ) ) throw e ;
5254 }
5355 } else {
5456 // Attempt to parse x402v1 body format
@@ -57,8 +59,8 @@ export function createDryRunFetch(): typeof fetch {
5759 if ( body ?. accepts ) {
5860 requirements = body . accepts as PaymentRequirementsInfo [ ] ;
5961 }
60- } catch {
61- // ignore
62+ } catch ( e ) {
63+ if ( ! ( e instanceof SyntaxError ) ) throw e ;
6264 }
6365 }
6466 throw new DryRunPaymentRequired ( requirements ) ;
@@ -73,6 +75,31 @@ export function createPaymentFetch(wallet: Wallet) {
7375 } ) ;
7476}
7577
78+ /** Resolve the fetch implementation based on the --pay flag. */
79+ export async function resolveFetch ( pay ?: boolean ) : Promise < typeof fetch > {
80+ if ( pay ) {
81+ const { getConfigOrThrow } = await import ( "./config.js" ) ;
82+ const { loadWallet } = await import ( "./wallets/wallet.js" ) ;
83+ const config = await getConfigOrThrow ( ) ;
84+ const wallet = loadWallet ( config . wallet ) ;
85+ return createPaymentFetch ( wallet ) as typeof fetch ;
86+ }
87+ return createDryRunFetch ( ) ;
88+ }
89+
90+ /** Display a DryRunPaymentRequired error in a boxed format and exit. */
91+ export function handleDryRunError ( err : DryRunPaymentRequired ) : never {
92+ console . error (
93+ boxen ( err . message , {
94+ title : "Payment Required" ,
95+ titleAlignment : "center" ,
96+ borderColor : "yellow" ,
97+ padding : 1 ,
98+ } ) ,
99+ ) ;
100+ process . exit ( 1 ) ;
101+ }
102+
76103export function createMcpPaymentClient ( mcpClient : Client , wallet : Wallet ) {
77104 return wrapMCPClientWithPaymentFromConfig ( mcpClient , {
78105 schemes : wallet . getX402Schemes ( ) ,
0 commit comments