x402

package module
v0.8.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 26, 2025 License: MIT Imports: 32 Imported by: 0

README

mcp-go-x402

x402 payment protocol support for MCP-Go clients and servers.

This library provides:

  • Client Transport: Automatic x402 payment handling for MCP clients
  • Server Wrapper: Payment collection support for MCP servers

Features

Client Features
  • 🔌 Drop-in replacement: Fully compatible with mcp-go transport interface
  • 💰 Automatic payments: Handles 402 responses transparently
  • 🔐 Multiple signers: Support for private keys, mnemonics, keystores
  • 🎯 Payment control: Optional callback for payment approval
  • 🧪 Testing support: Mock signers and payment recorders for easy testing
Server Features
  • 💳 Payment collection: Require payments for specific MCP tools
  • 🔒 Payment verification: Automatic verification via x402 facilitator
  • ⛓️ On-chain settlement: Automatic settlement of verified payments
  • 🎛️ Flexible pricing: Set different prices for different tools
  • 🔄 Mixed mode: Support both free and paid tools on same server

Installation

go get github.com/mark3labs/mcp-go-x402

Quick Start

Client Usage
package main

import (
    "context"
    "log"
    
    "github.com/mark3labs/mcp-go/client"
    "github.com/mark3labs/mcp-go/mcp"
    x402 "github.com/mark3labs/mcp-go-x402"
)

func main() {
    signer, err := x402.NewPrivateKeySigner(
        "YOUR_PRIVATE_KEY_HEX",
        x402.AcceptUSDCBase(),
    )
    if err != nil {
        log.Fatal(err)
    }
    
    transport, err := x402.New(x402.Config{
        ServerURL: "https://paid-mcp-server.example.com",
        Signers:   []x402.PaymentSigner{signer},
    })
    if err != nil {
        log.Fatal(err)
    }
    
    mcpClient := client.NewClient(transport)
    
    ctx := context.Background()
    if err := mcpClient.Start(ctx); err != nil {
        log.Fatal(err)
    }
    defer mcpClient.Close()
    
    _, err = mcpClient.Initialize(ctx, mcp.InitializeRequest{
        Params: mcp.InitializeParams{
            ProtocolVersion: "1.0.0",
            ClientInfo: mcp.Implementation{
                Name:    "x402-client",
                Version: "1.0.0",
            },
        },
    })
    if err != nil {
        log.Fatal(err)
    }
    
    tools, _ := mcpClient.ListTools(ctx, mcp.ListToolsRequest{})
    log.Printf("Found %d tools", len(tools.Tools))
}
Server Usage
package main

import (
    "context"
    "log"
    
    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
    x402server "github.com/mark3labs/mcp-go-x402/server"
)

func main() {
    // Configure x402 server
    config := &x402server.Config{
        FacilitatorURL:  "https://facilitator.x402.rs",
        VerifyOnly:      false, // Set to true for testing without settlement
    }
    
    // Create x402 server
    srv := x402server.NewX402Server("my-server", "1.0.0", config)
    
    // Add a free tool
    srv.AddTool(
        mcp.NewTool("free-tool", 
            mcp.WithDescription("This tool is free")),
        freeToolHandler,
    )
    
    // Add a paid tool with multiple payment options
    srv.AddPayableTool(
        mcp.NewTool("premium-tool",
            mcp.WithDescription("Premium feature"),
            mcp.WithString("input", mcp.Required())),
        premiumToolHandler,
        x402server.RequireUSDCBase("0xYourWallet", "10000", "Premium feature"),
        x402server.RequireUSDCBaseSepolia("0xYourWallet", "5000", "Premium feature (testnet)"),
    )
    
    // Start server
    log.Println("Starting x402 MCP server on :8080")
    if err := srv.Start(":8080"); err != nil {
        log.Fatal(err)
    }
}

func freeToolHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    return &mcp.CallToolResult{
        Content: []mcp.Content{mcp.NewTextContent("Free response")},
    }, nil
}

func premiumToolHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    input := req.GetString("input", "")
    // Process premium request
    return &mcp.CallToolResult{
        Content: []mcp.Content{mcp.NewTextContent("Premium response for: " + input)},
    }, nil
}

Solana (SVM) Support

The library supports Solana payments using SPL tokens in addition to EVM-based payments.

Client Usage with Solana
// Create Solana signer with base58 private key
signer, err := x402.NewSolanaPrivateKeySigner(
    privateKeyBase58,
    x402.AcceptUSDCSolanaDevnet(),
)

// Or load from Solana CLI keypair file
signer, err := x402.NewSolanaPrivateKeySignerFromFile(
    "~/.config/solana/id.json",
    x402.AcceptUSDCSolana().WithPriority(2),
)

// Use with transport
transport, err := x402.New(x402.Config{
    ServerURL: "http://localhost:8080",
    Signers:   []x402.PaymentSigner{signer},
})
Server Usage with Solana
srv.AddPayableTool(
    mcp.NewTool("premium-search",
        mcp.WithDescription("Premium search on Solana")),
    searchHandler,
    x402server.RequireUSDCSolanaDevnet(
        recipientAddress,
        "1000000",
        "Premium search access",
    ),
)
Multi-Chain Support
evmSigner, _ := x402.NewPrivateKeySigner(
    evmPrivateKey, 
    x402.AcceptUSDCBaseSepolia().WithPriority(1),
)

solSigner, _ := x402.NewSolanaPrivateKeySigner(
    solPrivateKey,
    x402.AcceptUSDCSolanaDevnet().WithPriority(2),
)

transport, _ := x402.New(x402.Config{
    ServerURL: serverURL,
    Signers:   []x402.PaymentSigner{evmSigner, solSigner},
})

See examples/svm-client and examples/svm-server for complete working examples.

Client Configuration Options

Basic Configuration
signer, err := x402.NewPrivateKeySigner(
    privateKey,
    x402.AcceptUSDCBase(),
    x402.AcceptUSDCBaseSepolia(),
)

config := x402.Config{
    ServerURL: "https://server.example.com",
    Signers:   []x402.PaymentSigner{signer},
}
With Payment Approval Callback
config := x402.Config{
    ServerURL: "https://server.example.com",
    Signers:   []x402.PaymentSigner{signer},
    PaymentCallback: func(amount *big.Int, resource string) bool {
        if amount.Cmp(big.NewInt(100000)) > 0 {
            fmt.Printf("Approve payment of %s for %s? ", amount, resource)
            return getUserApproval()
        }
        return true
    },
}
With Event Callbacks
config := x402.Config{
    ServerURL: "https://server.example.com",
    Signers:   []x402.PaymentSigner{signer},
    OnPaymentAttempt: func(event x402.PaymentEvent) {
        log.Printf("Attempting payment: %s to %s", event.Amount, event.Recipient)
    },
    OnPaymentSuccess: func(event x402.PaymentEvent) {
        log.Printf("Payment successful: tx %s", event.Transaction)
    },
    OnPaymentFailure: func(event x402.PaymentEvent, err error) {
        log.Printf("Payment failed: %v", err)
    },
}
Multiple Signers with Fallback

Configure multiple signers with different payment options and priorities. The client will try signers in priority order until one succeeds:

// Create personal wallet for small payments
personalSigner, _ := x402.NewPrivateKeySigner(
    personalKey,
    x402.AcceptUSDCBase().WithMaxAmount("50000"), // Max 0.05 USDC
)
personalSigner.WithPriority(1) // Try first

// Create business wallet for larger payments
businessSigner, _ := x402.NewPrivateKeySigner(
    businessKey,
    x402.AcceptUSDCBase(), // No limit
)
businessSigner.WithPriority(2) // Fallback

config := x402.Config{
    ServerURL: "https://server.example.com",
    Signers:   []x402.PaymentSigner{personalSigner, businessSigner},
}
Multiple Signers with Different Networks
// Mainnet signer
mainnetSigner, _ := x402.NewPrivateKeySigner(
    mainnetKey,
    x402.AcceptUSDCBase(),
)

// Testnet signer for development
testnetSigner, _ := x402.NewPrivateKeySigner(
    testnetKey,
    x402.AcceptUSDCBaseSepolia(),
)

config := x402.Config{
    ServerURL: "https://server.example.com",
    Signers:   []x402.PaymentSigner{mainnetSigner, testnetSigner},
}

Server Configuration Options

Basic Server Configuration
config := &x402server.Config{
    FacilitatorURL:  "https://facilitator.x402.rs",
    VerifyOnly:      false, // Set to true for testing without settlement
}
Multiple Payment Options

Servers can now offer multiple payment options per tool, allowing clients to choose their preferred network or take advantage of discounts:

srv.AddPayableTool(
    mcp.NewTool("analytics",
        mcp.WithDescription("Advanced analytics"),
        mcp.WithString("query", mcp.Required())),
    analyticsHandler,
    // Base mainnet - cheapest option
    x402server.RequireUSDCBase("0xYourWallet", "50000", "Analytics via Base - 0.05 USDC"),
    // Polygon mainnet - moderate fees
    x402server.RequireUSDCPolygon("0xYourWallet", "75000", "Analytics via Polygon - 0.075 USDC"),
    // Avalanche mainnet
    x402server.RequireUSDCAvalanche("0xYourWallet", "100000", "Analytics via Avalanche - 0.1 USDC"),
    // Testnet options for development
    x402server.RequireUSDCBaseSepolia("0xYourWallet", "10000", "Analytics via Base Sepolia (testnet) - 0.01 USDC"),
    x402server.RequireUSDCPolygonAmoy("0xYourWallet", "10000", "Analytics via Polygon Amoy (testnet) - 0.01 USDC"),
    x402server.RequireUSDCAvalancheFuji("0xYourWallet", "10000", "Analytics via Avalanche Fuji (testnet) - 0.01 USDC"),
)
Available Server Helper Functions

Mainnet:

  • RequireUSDCBase(payTo, amount, description) - Base mainnet
  • RequireUSDCPolygon(payTo, amount, description) - Polygon mainnet
  • RequireUSDCAvalanche(payTo, amount, description) - Avalanche C-Chain mainnet
  • RequireUSDCSolana(payTo, amount, description) - Solana mainnet

Testnet:

  • RequireUSDCBaseSepolia(payTo, amount, description) - Base Sepolia testnet
  • RequireUSDCPolygonAmoy(payTo, amount, description) - Polygon Amoy testnet
  • RequireUSDCAvalancheFuji(payTo, amount, description) - Avalanche Fuji testnet
  • RequireUSDCSolanaDevnet(payTo, amount, description) - Solana devnet

When a client requests a paid tool without payment, they receive all available payment options and can choose the one that works best for them based on:

  • Network preference (gas fees, speed)
  • Available balance on different chains
  • Price differences (discounts for certain networks)
Using with Existing MCP Server
// If you already have an MCP server, wrap it with x402
mcpServer := server.NewMCPServer("existing", "1.0")
httpServer := server.NewStreamableHTTPServer(mcpServer)

// Wrap with x402 handler
x402Handler := x402server.NewX402Handler(httpServer, config)

// Use as http.Handler
http.Handle("/", x402Handler)
http.ListenAndServe(":8080", nil)

Signer Options (Client)

EVM Signers
Private Key
signer, err := x402.NewPrivateKeySigner(
    "0xYourPrivateKeyHex",
    x402.AcceptUSDCBase(),       // Must specify at least one payment option
)
Mnemonic (BIP-39)
signer, err := x402.NewMnemonicSigner(
    "your twelve word mnemonic phrase here ...",
    "m/44'/60'/0'/0/0", // Optional: derivation path
    x402.AcceptUSDCBase(),
)
Keystore File
keystoreJSON, _ := os.ReadFile("keystore.json")
signer, err := x402.NewKeystoreSigner(
    keystoreJSON,
    "password",
    x402.AcceptUSDCBase(),
)
Solana Signers
Solana Private Key (Base58)
signer, err := x402.NewSolanaPrivateKeySigner(
    "YourBase58PrivateKey",
    x402.AcceptUSDCSolana(),     // Mainnet
    // x402.AcceptUSDCSolanaDevnet(), // Or devnet for testing
)
Solana Keypair File
// Load from Solana CLI keypair file
signer, err := x402.NewSolanaPrivateKeySignerFromFile(
    "~/.config/solana/id.json",
    x402.AcceptUSDCSolanaDevnet(),
)
Multiple Payment Options with Priorities
signer, err := x402.NewPrivateKeySigner(
    privateKey,
    // Priority 1: Prefer Base (cheap & fast)
    x402.AcceptUSDCBase().WithPriority(1),
    
    // Priority 2: Polygon (moderate fees)
    x402.AcceptUSDCPolygon().WithPriority(2),
    
    // Priority 3: Avalanche
    x402.AcceptUSDCAvalanche().WithPriority(3),
    
    // Priority 4: Fallback to testnets
    x402.AcceptUSDCBaseSepolia().WithPriority(4),
    x402.AcceptUSDCPolygonAmoy().WithPriority(5),
    x402.AcceptUSDCAvalancheFuji().WithPriority(6),
)
Supported Chains
EVM Chains (Mainnet)
  • Base: x402.AcceptUSDCBase() - Chain ID: 8453
  • Polygon: x402.AcceptUSDCPolygon() - Chain ID: 137
  • Avalanche C-Chain: x402.AcceptUSDCAvalanche() - Chain ID: 43114
EVM Chains (Testnet)
  • Base Sepolia: x402.AcceptUSDCBaseSepolia() - Chain ID: 84532
  • Polygon Amoy: x402.AcceptUSDCPolygonAmoy() - Chain ID: 80002
  • Avalanche Fuji: x402.AcceptUSDCAvalancheFuji() - Chain ID: 43113
Solana Chains
  • Solana Mainnet: x402.AcceptUSDCSolana()
  • Solana Devnet: x402.AcceptUSDCSolanaDevnet()
With Custom Limits
signer, err := x402.NewPrivateKeySigner(
    privateKey,
    x402.AcceptUSDCBase()
        .WithMaxAmount("100000")    // Max 0.1 USDC per payment
        .WithMinBalance("1000000"), // Keep 1 USDC reserve
)
Custom Signer
type MyCustomSigner struct {
    paymentOptions []x402.ClientPaymentOption
}

func NewMyCustomSigner() *MyCustomSigner {
    return &MyCustomSigner{
        paymentOptions: []x402.ClientPaymentOption{
            x402.AcceptUSDCBase(),
            x402.AcceptUSDCBaseSepolia(),
        },
    }
}

func (s *MyCustomSigner) SignPayment(ctx context.Context, req x402.PaymentRequirement) (*x402.PaymentPayload, error) {
    // Your custom signing logic
    // Could use hardware wallet, remote signer, etc.
}

func (s *MyCustomSigner) GetAddress() string {
    return "0xYourAddress"
}

func (s *MyCustomSigner) SupportsNetwork(network string) bool {
    for _, opt := range s.paymentOptions {
        if opt.Network == network {
            return true
        }
    }
    return false
}

func (s *MyCustomSigner) HasAsset(asset, network string) bool {
    for _, opt := range s.paymentOptions {
        if opt.Network == network && opt.Asset == asset {
            return true
        }
    }
    return false
}

func (s *MyCustomSigner) GetPaymentOption(network, asset string) *x402.ClientPaymentOption {
    for _, opt := range s.paymentOptions {
        if opt.Network == network && opt.Asset == asset {
            optCopy := opt
            return &optCopy
        }
    }
    return nil
}

Testing

Using Mock Signers
Mock EVM Signer
func TestMyMCPClient(t *testing.T) {
    // No real wallet needed for tests
    signer := x402.NewMockSigner(
        "0xTestWallet",
        x402.AcceptUSDCBaseSepolia(), // Mock signer for testing
    )
    
    transport, _ := x402.New(x402.Config{
        ServerURL: "https://test-server.example.com",
        Signers:   []x402.PaymentSigner{signer},
    })
    
    // Test your MCP client
    client := client.NewClient(transport)
    // ...
}
Mock Solana Signer
func TestSolanaClient(t *testing.T) {
    signer := x402.NewMockSolanaSigner(
        "DYw8jCTfwHNRJhhmFcbXvVDTqWMEVFBX6ZKUmG5CNSKK",
        x402.AcceptUSDCSolanaDevnet(),
    )
    
    transport, _ := x402.New(x402.Config{
        ServerURL: "https://test-server.example.com",
        Signers:   []x402.PaymentSigner{signer},
    })
    // ...
}
Recording Payments
func TestPaymentFlow(t *testing.T) {
    // Create mock signer and recorder
    signer := x402.NewMockSigner(
        "0xTestWallet",
        x402.AcceptUSDCBaseSepolia(),
    )
    recorder := x402.NewPaymentRecorder()
    
    transport, _ := x402.New(x402.Config{
        ServerURL: testServer.URL,
        Signers:   []x402.PaymentSigner{signer},
    })
    
    // Attach the recorder using the helper function
    x402.WithPaymentRecorder(recorder)(transport)
    
    // Make requests...
    
    // Verify payments
    assert.Equal(t, 2, recorder.PaymentCount()) // Attempt + Success events
    lastPayment := recorder.LastPayment()
    assert.Equal(t, x402.PaymentEventSuccess, lastPayment.Type)
    assert.Equal(t, "20000", recorder.TotalAmount())
}

Supported Networks

EVM Networks
  • base - Base Mainnet (via AcceptUSDCBase(), RequireUSDCBase())
  • base-sepolia - Base Sepolia Testnet (via AcceptUSDCBaseSepolia(), RequireUSDCBaseSepolia())
Solana (SVM) Networks
  • solana - Solana Mainnet (via AcceptUSDCSolana(), RequireUSDCSolana())
  • solana-devnet - Solana Devnet (via AcceptUSDCSolanaDevnet(), RequireUSDCSolanaDevnet())

Additional networks can be supported by manually configuring ClientPaymentOption or PaymentRequirement objects with the appropriate network, asset, and scheme parameters.

Security Considerations

General
  • Private keys: Never hardcode private keys. Use environment variables or secure key management.
  • Payment approval: Use PaymentCallback to control payment approval based on amount or resource.
  • Network verification: The library verifies network and asset compatibility before signing.
  • Per-option limits: Use .WithMaxAmount() on payment options to set per-network spending limits.
EVM-Specific
  • Chain ID verification: Signers verify the chain ID matches the payment option configuration.
  • EIP-712 signing: All EVM signatures use typed structured data per EIP-712.
Solana-Specific
  • Blockhash expiration: Solana transactions expire after ~60-90 seconds. The facilitator must submit quickly.
  • Fee payer trust: The facilitator acts as the fee payer and adds their signature before submission.
  • Transaction inspection: Clients should validate the transaction matches the payment requirement before signing.

Examples

See the examples directory for more detailed examples:

EVM Examples
  • Client - Simple client that can pay for tool use with EVM chains
  • Server - Server that collects payments on EVM chains
SVM (Solana) Examples
  • SVM Client - Client that uses Solana for payments
  • SVM Server - Server that collects payments on Solana

Architecture

Client Flow
  1. Client makes MCP request through x402 transport
  2. If server returns 402 Payment Required, transport extracts payment requirements
  3. Transport uses configured signer to create payment authorization
  4. Transport retries request with X-PAYMENT header
  5. Server verifies and settles payment, then returns response
Server Flow
  1. Server receives MCP request
  2. Checks if requested tool requires payment
  3. If no payment provided, returns 402 with payment requirements
  4. If payment provided, verifies with facilitator service
  5. Settles payment on-chain (unless in verify-only mode)
  6. Executes tool and returns response with payment confirmation

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE file for details.

Acknowledgments

Documentation

Index

Constants

View Source
const (
	// EVM Mainnet USDC addresses
	USDCAddressBase      = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913" // Base mainnet
	USDCAddressPolygon   = "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359" // Polygon mainnet
	USDCAddressAvalanche = "0xb97ef9ef8734c71904d8002f8b6bc66dd9c48a6e" // Avalanche C-Chain

	// EVM Testnet USDC addresses
	USDCAddressBaseSepolia   = "0x036cbd53842c5426634e7929541ec2318f3dcf7e" // Base Sepolia
	USDCAddressPolygonAmoy   = "0x41e94eb019c0762f9bfcf9fb1e58725bfb0e7582" // Polygon Amoy
	USDCAddressAvalancheFuji = "0x5425890298aed601595a70ab815c96711a31bc65" // Avalanche Fuji

	// Solana USDC mint addresses
	USDCMintSolana       = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // Solana mainnet
	USDCMintSolanaDevnet = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU" // Solana devnet
)

USDC contract addresses (lowercase for consistency)

Variables

View Source
var (
	// Payment errors
	ErrPaymentRequired     = errors.New("payment required")
	ErrNoAcceptablePayment = errors.New("no acceptable payment method found")
	ErrSigningFailed       = errors.New("failed to sign payment")
	ErrInvalidPaymentReqs  = errors.New("invalid payment requirements")

	// Network errors
	ErrUnsupportedNetwork = errors.New("unsupported network")
	ErrUnsupportedAsset   = errors.New("unsupported asset")

	// Signer errors
	ErrInvalidPrivateKey     = errors.New("invalid private key")
	ErrInvalidMnemonic       = errors.New("invalid mnemonic phrase")
	ErrInvalidKeystore       = errors.New("invalid keystore file")
	ErrWrongPassword         = errors.New("wrong keystore password")
	ErrNoSignerConfigured    = errors.New("no payment signer configured")
	ErrNoViablePaymentOption = errors.New("no viable payment option found across all signers")
)
View Source
var ErrSessionTerminated = errors.New("session terminated (404). need to re-initialize")

ErrSessionTerminated is returned when a session is terminated (404)

Functions

func NewSVMPayload added in v0.8.0

func NewSVMPayload(transactionBase64 string) map[string]any

NewSVMPayload creates a Solana (SVM) payment payload with a base64-encoded transaction

func WithPaymentRecorder

func WithPaymentRecorder(recorder *PaymentRecorder) func(*X402Transport)

WithPaymentRecorder adds a payment recorder for testing

Types

type ClientPaymentOption added in v0.4.0

type ClientPaymentOption struct {
	PaymentRequirement

	// Client-specific fields
	Priority   int      `json:"-"` // Lower number = higher priority
	MaxAmount  string   `json:"-"` // Client's max willing to pay with this option
	MinBalance string   `json:"-"` // Don't use if balance falls below this
	ChainID    *big.Int `json:"-"` // Chain ID for signing (EVM networks)
	NetworkID  string   `json:"-"` // Network ID for non-EVM networks (e.g., "mainnet-beta", "devnet")
}

ClientPaymentOption represents a payment method the client accepts

func AcceptUSDCAvalanche added in v0.8.2

func AcceptUSDCAvalanche() ClientPaymentOption

AcceptUSDCAvalanche creates a client payment option for USDC on Avalanche C-Chain mainnet

func AcceptUSDCAvalancheFuji added in v0.8.2

func AcceptUSDCAvalancheFuji() ClientPaymentOption

AcceptUSDCAvalancheFuji creates a client payment option for USDC on Avalanche Fuji testnet

func AcceptUSDCBase added in v0.4.0

func AcceptUSDCBase() ClientPaymentOption

AcceptUSDCBase creates a client payment option for USDC on Base mainnet

func AcceptUSDCBaseSepolia added in v0.4.0

func AcceptUSDCBaseSepolia() ClientPaymentOption

AcceptUSDCBaseSepolia creates a client payment option for USDC on Base Sepolia testnet

func AcceptUSDCPolygon added in v0.8.2

func AcceptUSDCPolygon() ClientPaymentOption

AcceptUSDCPolygon creates a client payment option for USDC on Polygon mainnet

func AcceptUSDCPolygonAmoy added in v0.8.2

func AcceptUSDCPolygonAmoy() ClientPaymentOption

AcceptUSDCPolygonAmoy creates a client payment option for USDC on Polygon Amoy testnet

func AcceptUSDCSolana added in v0.8.0

func AcceptUSDCSolana() ClientPaymentOption

AcceptUSDCSolana creates a client payment option for USDC on Solana mainnet

func AcceptUSDCSolanaDevnet added in v0.8.0

func AcceptUSDCSolanaDevnet() ClientPaymentOption

AcceptUSDCSolanaDevnet creates a client payment option for USDC on Solana devnet

func (ClientPaymentOption) WithMaxAmount added in v0.4.0

func (opt ClientPaymentOption) WithMaxAmount(amount string) ClientPaymentOption

WithMaxAmount sets the maximum amount the client is willing to pay with this option

func (ClientPaymentOption) WithMinBalance added in v0.4.0

func (opt ClientPaymentOption) WithMinBalance(amount string) ClientPaymentOption

WithMinBalance sets the minimum balance to maintain (won't use if balance would fall below)

func (ClientPaymentOption) WithPriority added in v0.4.0

func (opt ClientPaymentOption) WithPriority(p int) ClientPaymentOption

WithPriority sets the priority for this payment option

type Config

type Config struct {
	ServerURL        string
	Signer           PaymentSigner   // DEPRECATED: Use Signers instead
	Signers          []PaymentSigner // Multiple signers with priority
	PaymentCallback  func(amount *big.Int, resource string) bool
	HTTPClient       *http.Client
	OnPaymentAttempt func(PaymentEvent)
	OnPaymentSuccess func(PaymentEvent)
	OnPaymentFailure func(PaymentEvent, error)
	OnSignerAttempt  func(PaymentEvent) // Per-signer attempt callback
}

Config configures the X402Transport

type HandlerConfig

type HandlerConfig struct {
	PaymentCallback func(amount *big.Int, resource string) bool
	OnSignerAttempt func(PaymentEvent)
}

HandlerConfig configures the payment handler

type KeystoreSigner

type KeystoreSigner struct {
	*PrivateKeySigner
}

KeystoreSigner signs with a key from an encrypted keystore file

func NewKeystoreSigner

func NewKeystoreSigner(keystoreJSON []byte, password string, options ...ClientPaymentOption) (*KeystoreSigner, error)

NewKeystoreSigner creates a signer from an encrypted keystore JSON with explicit payment options

func (*KeystoreSigner) GetPriority added in v0.7.0

func (s *KeystoreSigner) GetPriority() int

GetPriority returns the signer's priority

func (*KeystoreSigner) WithPriority added in v0.7.0

func (s *KeystoreSigner) WithPriority(priority int) *KeystoreSigner

WithPriority sets the signer's priority

type MnemonicSigner

type MnemonicSigner struct {
	*PrivateKeySigner
}

MnemonicSigner signs with a key derived from a mnemonic phrase

func NewMnemonicSigner

func NewMnemonicSigner(mnemonic string, derivationPath string, options ...ClientPaymentOption) (*MnemonicSigner, error)

NewMnemonicSigner creates a signer from a BIP-39 mnemonic phrase with explicit payment options

func (*MnemonicSigner) GetPriority added in v0.7.0

func (s *MnemonicSigner) GetPriority() int

GetPriority returns the signer's priority

func (*MnemonicSigner) WithPriority added in v0.7.0

func (s *MnemonicSigner) WithPriority(priority int) *MnemonicSigner

WithPriority sets the signer's priority

type MockSigner

type MockSigner struct {
	// contains filtered or unexported fields
}

MockSigner is a test signer that generates fake signatures

func NewMockSigner

func NewMockSigner(address string, options ...ClientPaymentOption) *MockSigner

NewMockSigner creates a mock signer for testing with explicit payment options

func (*MockSigner) GetAddress

func (m *MockSigner) GetAddress() string

GetAddress returns the mock signer's address

func (*MockSigner) GetPaymentOption added in v0.4.0

func (m *MockSigner) GetPaymentOption(network, asset string) *ClientPaymentOption

GetPaymentOption returns the client payment option that matches the network and asset

func (*MockSigner) GetPriority added in v0.7.0

func (m *MockSigner) GetPriority() int

GetPriority returns the signer's priority

func (*MockSigner) HasAsset

func (m *MockSigner) HasAsset(asset, network string) bool

HasAsset returns true if the mock signer has the given asset on the network

func (*MockSigner) SignPayment

func (m *MockSigner) SignPayment(ctx context.Context, req PaymentRequirement) (*PaymentPayload, error)

SignPayment creates a mock payment signature for testing

func (*MockSigner) SupportsNetwork

func (m *MockSigner) SupportsNetwork(network string) bool

SupportsNetwork returns true if the mock signer supports the given network

func (*MockSigner) WithPriority added in v0.7.0

func (m *MockSigner) WithPriority(priority int) *MockSigner

WithPriority sets the signer's priority

type MockSolanaSigner added in v0.8.0

type MockSolanaSigner struct {
	// contains filtered or unexported fields
}

func NewMockSolanaSigner added in v0.8.0

func NewMockSolanaSigner(address string, options ...ClientPaymentOption) *MockSolanaSigner

NewMockSolanaSigner creates a mock Solana signer for testing with explicit payment options

func (*MockSolanaSigner) GetAddress added in v0.8.0

func (m *MockSolanaSigner) GetAddress() string

GetAddress returns the mock signer's address

func (*MockSolanaSigner) GetPaymentOption added in v0.8.0

func (m *MockSolanaSigner) GetPaymentOption(network, asset string) *ClientPaymentOption

GetPaymentOption returns the client payment option that matches the network and asset

func (*MockSolanaSigner) GetPriority added in v0.8.0

func (m *MockSolanaSigner) GetPriority() int

GetPriority returns the mock signer's priority (lower = higher precedence)

func (*MockSolanaSigner) HasAsset added in v0.8.0

func (m *MockSolanaSigner) HasAsset(asset, network string) bool

HasAsset returns true if the mock signer has the given asset on the network

func (*MockSolanaSigner) SignPayment added in v0.8.0

SignPayment creates a mock payment signature for testing

func (*MockSolanaSigner) SupportsNetwork added in v0.8.0

func (m *MockSolanaSigner) SupportsNetwork(network string) bool

SupportsNetwork returns true if the mock signer supports the given network

func (*MockSolanaSigner) WithPriority added in v0.8.0

func (m *MockSolanaSigner) WithPriority(priority int) *MockSolanaSigner

WithPriority sets the mock signer's priority for multi-signer configurations

type MultiSignerError added in v0.7.0

type MultiSignerError struct {
	Message        string
	SignerFailures []SignerFailure
}

MultiSignerError aggregates failures from multiple signers

func (*MultiSignerError) Error added in v0.7.0

func (e *MultiSignerError) Error() string

Error returns the formatted error message with details from all signer failures

func (*MultiSignerError) Unwrap added in v0.7.0

func (e *MultiSignerError) Unwrap() error

Unwrap returns the first signer's wrapped error if available

type PaymentAuthorization

type PaymentAuthorization struct {
	From        string `json:"from"`
	To          string `json:"to"`
	Value       string `json:"value"`
	ValidAfter  string `json:"validAfter"`
	ValidBefore string `json:"validBefore"`
	Nonce       string `json:"nonce"`
}

PaymentAuthorization contains EIP-3009 authorization data

type PaymentError

type PaymentError struct {
	Code     string
	Message  string
	Resource string
	Amount   string
	Network  string
	Wrapped  error
}

PaymentError provides detailed payment error information

func NewPaymentError

func NewPaymentError(code, message, resource, amount, network string, wrapped error) *PaymentError

NewPaymentError creates a new PaymentError

func (*PaymentError) Error

func (e *PaymentError) Error() string

Error returns the formatted error message

func (*PaymentError) Unwrap

func (e *PaymentError) Unwrap() error

Unwrap returns the underlying wrapped error

type PaymentEvent

type PaymentEvent struct {
	Type           PaymentEventType
	Resource       string
	Method         string
	Amount         *big.Int
	Network        string
	Asset          string
	Recipient      string
	Transaction    string
	Error          error
	Timestamp      int64
	SignerIndex    int    // Position in signers array
	SignerPriority int    // Signer's priority value
	SignerAddress  string // Signer's address
	AttemptNumber  int    // Sequential attempt count
}

PaymentEvent represents a payment lifecycle event

type PaymentEventType

type PaymentEventType string

PaymentEventType represents types of payment events

const (
	PaymentEventAttempt       PaymentEventType = "attempt"
	PaymentEventSuccess       PaymentEventType = "success"
	PaymentEventFailure       PaymentEventType = "failure"
	PaymentEventSignerAttempt PaymentEventType = "signer_attempt"
	PaymentEventSignerSuccess PaymentEventType = "signer_success"
	PaymentEventSignerFailure PaymentEventType = "signer_failure"
)

type PaymentHandler

type PaymentHandler struct {
	// contains filtered or unexported fields
}

PaymentHandler handles x402 payment operations

func NewPaymentHandler

func NewPaymentHandler(signer PaymentSigner, config *HandlerConfig) (*PaymentHandler, error)

NewPaymentHandler creates a new payment handler (backward compatibility)

func NewPaymentHandlerMulti added in v0.7.0

func NewPaymentHandlerMulti(signers []PaymentSigner, config *HandlerConfig) (*PaymentHandler, error)

NewPaymentHandlerMulti creates a new payment handler with multiple signers

func (*PaymentHandler) CreatePayment

CreatePayment creates a signed payment for the given requirements

func (*PaymentHandler) ShouldPay

func (h *PaymentHandler) ShouldPay(req PaymentRequirement) (bool, error)

ShouldPay determines if a payment should be made

type PaymentPayload

type PaymentPayload struct {
	X402Version int    `json:"x402Version"`
	Scheme      string `json:"scheme"`
	Network     string `json:"network"`
	Payload     any    `json:"payload"`
}

PaymentPayload is the signed payment sent in X-PAYMENT header

func (*PaymentPayload) Encode

func (p *PaymentPayload) Encode() string

Encode encodes the payment payload as base64 for the X-PAYMENT header

type PaymentPayloadData

type PaymentPayloadData struct {
	Signature     string               `json:"signature"`
	Authorization PaymentAuthorization `json:"authorization"`
}

PaymentPayloadData contains the signature and authorization

type PaymentRecorder

type PaymentRecorder struct {
	// contains filtered or unexported fields
}

PaymentRecorder records payment events for testing

func NewPaymentRecorder

func NewPaymentRecorder() *PaymentRecorder

NewPaymentRecorder creates a new payment recorder

func (*PaymentRecorder) Clear

func (r *PaymentRecorder) Clear()

Clear clears all recorded events

func (*PaymentRecorder) FailedPayments

func (r *PaymentRecorder) FailedPayments() []PaymentEvent

FailedPayments returns only failed payment events (returns deep copies)

func (*PaymentRecorder) GetEvents

func (r *PaymentRecorder) GetEvents() []PaymentEvent

GetEvents returns all recorded events (returns deep copies to prevent mutations)

func (*PaymentRecorder) LastPayment

func (r *PaymentRecorder) LastPayment() *PaymentEvent

LastPayment returns the most recent payment event (returns a copy to prevent mutations)

func (*PaymentRecorder) PaymentCount

func (r *PaymentRecorder) PaymentCount() int

PaymentCount returns the number of recorded payments

func (*PaymentRecorder) Record

func (r *PaymentRecorder) Record(event PaymentEvent)

Record records a payment event

func (*PaymentRecorder) SuccessfulPayments

func (r *PaymentRecorder) SuccessfulPayments() []PaymentEvent

SuccessfulPayments returns only successful payment events (returns deep copies)

func (*PaymentRecorder) TotalAmount

func (r *PaymentRecorder) TotalAmount() string

TotalAmount returns the total amount of all successful payments

type PaymentRequirement

type PaymentRequirement struct {
	Scheme            string            `json:"scheme"`
	Network           string            `json:"network"`
	MaxAmountRequired string            `json:"maxAmountRequired"`
	Asset             string            `json:"asset"`
	PayTo             string            `json:"payTo"`
	Resource          string            `json:"resource"`
	Description       string            `json:"description"`
	MimeType          string            `json:"mimeType,omitempty"`
	OutputSchema      interface{}       `json:"outputSchema,omitempty"`
	MaxTimeoutSeconds int               `json:"maxTimeoutSeconds"`
	Extra             map[string]string `json:"extra,omitempty"`
}

PaymentRequirement represents a payment method from the server

type PaymentRequirementsResponse

type PaymentRequirementsResponse struct {
	X402Version int                  `json:"x402Version"`
	Error       string               `json:"error"`
	Accepts     []PaymentRequirement `json:"accepts"`
}

PaymentRequirementsResponse is the 402 response body

type PaymentSigner

type PaymentSigner interface {
	// SignPayment signs a payment authorization for the given requirement
	SignPayment(ctx context.Context, req PaymentRequirement) (*PaymentPayload, error)

	// GetAddress returns the signer's address
	GetAddress() string

	// SupportsNetwork returns true if the signer supports the given network
	SupportsNetwork(network string) bool

	// HasAsset returns true if the signer has the given asset on the network
	HasAsset(asset, network string) bool

	// GetPaymentOption returns the client payment option that matches the network and asset
	GetPaymentOption(network, asset string) *ClientPaymentOption

	// GetPriority returns the signer's priority (lower = higher precedence)
	GetPriority() int
}

PaymentSigner signs x402 payment authorizations

type PrivateKeySigner

type PrivateKeySigner struct {
	// contains filtered or unexported fields
}

PrivateKeySigner signs with a raw private key

func NewPrivateKeySigner

func NewPrivateKeySigner(privateKeyHex string, options ...ClientPaymentOption) (*PrivateKeySigner, error)

NewPrivateKeySigner creates a signer from a hex-encoded private key with explicit payment options

func (*PrivateKeySigner) GetAddress

func (s *PrivateKeySigner) GetAddress() string

GetAddress returns the signer's Ethereum address

func (*PrivateKeySigner) GetPaymentOption added in v0.4.0

func (s *PrivateKeySigner) GetPaymentOption(network, asset string) *ClientPaymentOption

GetPaymentOption returns the client payment option that matches the network and asset

func (*PrivateKeySigner) GetPriority added in v0.7.0

func (s *PrivateKeySigner) GetPriority() int

GetPriority returns the signer's priority (lower value = higher priority)

func (*PrivateKeySigner) HasAsset

func (s *PrivateKeySigner) HasAsset(asset, network string) bool

HasAsset returns true if the signer has the given asset on the network

func (*PrivateKeySigner) SignPayment

SignPayment signs a payment authorization for the given requirement

func (*PrivateKeySigner) SupportsNetwork

func (s *PrivateKeySigner) SupportsNetwork(network string) bool

SupportsNetwork returns true if the signer supports the given network

func (*PrivateKeySigner) WithPriority added in v0.7.0

func (s *PrivateKeySigner) WithPriority(priority int) *PrivateKeySigner

WithPriority sets the signer's priority for multi-signer configurations

type SettlementResponse

type SettlementResponse struct {
	Success     bool   `json:"success"`
	Transaction string `json:"transaction"`
	Network     string `json:"network"`
	Payer       string `json:"payer"`
	ErrorReason string `json:"errorReason,omitempty"`
}

SettlementResponse represents the X-PAYMENT-RESPONSE header content

type SignerFailure added in v0.7.0

type SignerFailure struct {
	SignerIndex    int
	SignerPriority int
	SignerAddress  string
	Reason         string
	WrappedError   error
}

SignerFailure represents a single signer's failure details

type SolanaPrivateKeySigner added in v0.8.0

type SolanaPrivateKeySigner struct {
	// contains filtered or unexported fields
}

func NewSolanaPrivateKeySigner added in v0.8.0

func NewSolanaPrivateKeySigner(privateKeyBase58 string, options ...ClientPaymentOption) (*SolanaPrivateKeySigner, error)

NewSolanaPrivateKeySigner creates a signer from a base58-encoded Solana private key with explicit payment options

func NewSolanaPrivateKeySignerFromFile added in v0.8.0

func NewSolanaPrivateKeySignerFromFile(filepath string, options ...ClientPaymentOption) (*SolanaPrivateKeySigner, error)

NewSolanaPrivateKeySignerFromFile creates a signer from a Solana keypair file with explicit payment options

func (*SolanaPrivateKeySigner) GetAddress added in v0.8.0

func (s *SolanaPrivateKeySigner) GetAddress() string

GetAddress returns the signer's Solana address

func (*SolanaPrivateKeySigner) GetPaymentOption added in v0.8.0

func (s *SolanaPrivateKeySigner) GetPaymentOption(network, asset string) *ClientPaymentOption

GetPaymentOption returns the client payment option that matches the network and asset

func (*SolanaPrivateKeySigner) GetPriority added in v0.8.0

func (s *SolanaPrivateKeySigner) GetPriority() int

GetPriority returns the signer's priority (lower = higher precedence)

func (*SolanaPrivateKeySigner) HasAsset added in v0.8.0

func (s *SolanaPrivateKeySigner) HasAsset(asset, network string) bool

HasAsset returns true if the signer has the given asset on the network

func (*SolanaPrivateKeySigner) SignPayment added in v0.8.0

SignPayment signs a payment authorization for the given requirement

func (*SolanaPrivateKeySigner) SupportsNetwork added in v0.8.0

func (s *SolanaPrivateKeySigner) SupportsNetwork(network string) bool

SupportsNetwork returns true if the signer supports the given network

func (*SolanaPrivateKeySigner) WithPriority added in v0.8.0

func (s *SolanaPrivateKeySigner) WithPriority(priority int) *SolanaPrivateKeySigner

WithPriority sets the signer's priority for multi-signer configurations

type X402Transport

type X402Transport struct {
	// contains filtered or unexported fields
}

X402Transport implements transport.Interface with x402 payment support It is based on StreamableHTTP with added x402 payment handling

func New

func New(config Config) (*X402Transport, error)

New creates a new X402Transport

func (*X402Transport) Close

func (t *X402Transport) Close() error

Close implements transport.Interface

func (*X402Transport) GetSessionId

func (t *X402Transport) GetSessionId() string

GetSessionId implements transport.Interface

func (*X402Transport) SendNotification

func (t *X402Transport) SendNotification(ctx context.Context, notification mcp.JSONRPCNotification) error

SendNotification implements transport.Interface

func (*X402Transport) SendRequest

SendRequest implements transport.Interface with x402 payment handling

func (*X402Transport) SetNotificationHandler

func (t *X402Transport) SetNotificationHandler(handler func(mcp.JSONRPCNotification))

SetNotificationHandler implements transport.Interface

func (*X402Transport) SetProtocolVersion

func (t *X402Transport) SetProtocolVersion(version string)

SetProtocolVersion implements transport.Interface

func (*X402Transport) SetRequestHandler

func (t *X402Transport) SetRequestHandler(handler transport.RequestHandler)

SetRequestHandler implements transport.Interface

func (*X402Transport) Start

func (t *X402Transport) Start(ctx context.Context) error

Start implements transport.Interface

Directories

Path Synopsis
examples
server command
svm-client command
svm-server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL