mpp

package module
v0.0.0-...-d1a8725 Latest Latest
Warning

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

Go to latest
Published: Mar 29, 2026 License: MIT Imports: 2 Imported by: 0

README

mpp-go

Go Reference CI

Go SDK for the Machine Payments Protocol (MPP) — inline HTTP 402 payments for APIs and AI agents.

What is MPP?

MPP lets API servers charge per-request or per-session using standard HTTP headers — no payment dashboard, no API keys, no billing setup on the client. The protocol extends HTTP 402 with a WWW-Authenticate: Payment challenge/response flow:

Client                              Server
  │                                   │
  │──── GET /api/data ───────────────>│
  │                                   │  (no Authorization header)
  │<─── 402 Payment Required ─────────│
  │     WWW-Authenticate: Payment     │
  │       realm="my-api"              │
  │       method="tempo"              │
  │       intent="charge"             │
  │       request="<base64url-json>"  │
  │                                   │
  │  [client pays / signs credential] │
  │                                   │
  │──── GET /api/data ───────────────>│
  │     Authorization: Payment        │
  │       challenge=<challenge>       │
  │       payload=<credential>        │
  │                                   │
  │<─── 200 OK ───────────────────────│
  │     Payment-Receipt: Payment ...  │

mpp-go provides:

  • Server middleware for net/http, Gin, Echo, and Fiber
  • Client that auto-handles 402 challenges and retries
  • Payment methods: Tempo (on-chain EVM), Stripe, Mock (testing)
  • Session payments (payment channels / pay-as-you-go)
  • SSE streaming with metered voucher flow
  • MCP integration for AI agent payments (Model Context Protocol)

Installation

go get github.com/deszhou/mpp-go

For Ethereum/Tempo on-chain verification, build with the geth tag:

go build -tags geth ./...

Quick Start

Server — Mock (no real payment, good for development)
package main

import (
    "net/http"

    netmpp "github.com/deszhou/mpp-go/http/nethttp"
    "github.com/deszhou/mpp-go/methods/mock"
    "github.com/deszhou/mpp-go/server"
)

func main() {
    mppServer := server.New(
        server.WithMethod(&mock.ServerMethod{}),
        server.WithRealm("my-api"),
    )

    charge := server.StaticCharge(mock.MethodName, "1000000", "pathUSD", nil) // 1.00 USD
    http.Handle("/api/data", netmpp.Middleware(mppServer, charge)(myHandler))
    http.ListenAndServe(":8080", nil)
}
Server — Tempo (on-chain EVM, requires -tags geth)
package main

import (
    "net/http"

    netmpp "github.com/deszhou/mpp-go/http/nethttp"
    "github.com/deszhou/mpp-go/methods/tempo"
    "github.com/deszhou/mpp-go/server"
    "github.com/deszhou/mpp-go/store"
)

func main() {
    verifier := tempo.NewEthVerifier() // requires -tags geth
    mppServer := server.New(
        server.WithMethod(tempo.NewServerMethod(verifier,
            tempo.WithRecipient("0xYourAddress"),
            tempo.WithNetworkID(42431),
        )),
        server.WithStore(store.NewMemoryStore()),
        server.WithRealm("my-api"),
        server.WithSecretKey("your-secret-key"),
    )

    charge := server.StaticCharge("tempo", "1000000", "pathUSD", nil) // 1.00 USD
    http.Handle("/api/data", netmpp.Middleware(mppServer, charge)(myHandler))
    http.ListenAndServe(":8080", nil)
}
Client

The client automatically handles 402 challenges and retries with payment:

package main

import (
    "context"
    "fmt"

    mppClient "github.com/deszhou/mpp-go/client"
    "github.com/deszhou/mpp-go/methods/mock"
)

func main() {
    c := mppClient.NewHTTPClient(
        []mppClient.PaymentProvider{
            &mock.ClientProvider{WalletAddress: "0xYourAddress"},
        },
    )

    resp, err := c.Get(context.Background(), "https://api.example.com/data")
    fmt.Println(resp.Status, err)
}

For Tempo on-chain payments (requires -tags geth):

signer := tempo.NewEthSigner(privateKey)
c := mppClient.NewHTTPClient(
    []mppClient.PaymentProvider{tempo.NewClientProvider(signer)},
)
Reading the Receipt

After payment verification, the receipt is available from the request context:

func myHandler(w http.ResponseWriter, r *http.Request) {
    receipt := netmpp.ReceiptFromContext(r.Context())
    fmt.Fprintf(w, "paid via %s, ref: %s", receipt.Method, receipt.Reference)
}

Framework Middleware

All middleware adapters share the same behavior: no Authorization header → issue 402; invalid credential → reissue 402; valid payment → call next handler with receipt in context.

Gin
import ginmpp "github.com/deszhou/mpp-go/http/gin"

r := gin.New()
r.Use(ginmpp.Middleware(mppServer, charge))
r.GET("/api/data", func(c *gin.Context) {
    receipt := ginmpp.ReceiptFromContext(c)
    c.JSON(200, gin.H{"receipt": receipt})
})
Echo
import echompp "github.com/deszhou/mpp-go/http/echo"

e := echo.New()
e.Use(echompp.Middleware(mppServer, charge))
e.GET("/api/data", func(c echo.Context) error {
    receipt := echompp.ReceiptFromContext(c)
    return c.JSON(200, receipt)
})
Fiber
import fibermpp "github.com/deszhou/mpp-go/http/fiber"

app := fiber.New()
app.Use(fibermpp.Middleware(mppServer, charge))
app.Get("/api/data", func(c *fiber.Ctx) error {
    receipt := fibermpp.ReceiptFromContext(c)
    return c.JSON(receipt)
})

Dynamic Pricing

Use a ChargeFunc closure for per-request pricing:

charge := func(r *http.Request) (protocol.MethodName, string, string, *server.ChargeOptions, error) {
    amount := computePrice(r) // your pricing logic
    return "tempo", amount, "pathUSD", nil, nil
}

Session Payments (Pay-as-you-go)

Session payments use payment channels for streaming or multi-request billing. The client opens a channel with an initial deposit, then sends signed vouchers for each unit consumed.

// Server: register a session method
mppServer := server.New(
    server.WithSessionMethod(tempoSession.NewServerMethod(channelStore)),
)

// Server: verify each request
result, _, err := mppServer.VerifySession(ctx, r.Header.Get("Authorization"))
if result.ManagementResponse != nil {
    // lifecycle event (Open / TopUp / Close) — return to client
    json.NewEncoder(w).Encode(result.ManagementResponse)
    return
}
// proceed: payment channel has sufficient balance

SSE Metered Streaming

For streaming APIs billed by token or chunk:

import "github.com/deszhou/mpp-go/sse"

// Server sends SSE events; client pays per voucher
srv := sse.NewServer(mppServer, channelStore)
srv.ServeHTTP(w, r) // handles voucher negotiation automatically

MCP Integration (AI Agents)

For Model Context Protocol tool servers, mpp-go provides JSON-RPC helpers:

import "github.com/deszhou/mpp-go/mcp"

// Extract payment challenge from a -32042 JSON-RPC error
challenge, err := mcp.ParsePaymentRequiredError(jsonRPCErr)

// Attach credential to tool call params
params = mcp.AttachCredential(params, credential)

Packages

Package Description
github.com/deszhou/mpp-go/server Core server: Mpp, challenge/verify, charge & session
github.com/deszhou/mpp-go/client HTTP client with auto-retry on 402
github.com/deszhou/mpp-go/protocol Wire types: challenge, credential, receipt, headers
github.com/deszhou/mpp-go/methods/tempo Tempo on-chain payment method (charge + session)
github.com/deszhou/mpp-go/methods/stripe Stripe Payment Intent method
github.com/deszhou/mpp-go/methods/mock In-memory mock for testing
github.com/deszhou/mpp-go/http/nethttp net/http middleware
github.com/deszhou/mpp-go/http/gin Gin middleware
github.com/deszhou/mpp-go/http/echo Echo middleware
github.com/deszhou/mpp-go/http/fiber Fiber middleware
github.com/deszhou/mpp-go/sse SSE event types and metered streaming
github.com/deszhou/mpp-go/mcp MCP (Model Context Protocol) payment helpers
github.com/deszhou/mpp-go/digest HTTP body digest (sha-256=<base64>)
github.com/deszhou/mpp-go/mperr RFC 9457 Problem Details error types
github.com/deszhou/mpp-go/store Challenge store (memory + channel state)
github.com/deszhou/mpp-go/expires RFC 3339 expiry timestamp helpers

Build Tags

Tag Effect
geth Enables tempo.NewEthVerifier() and tempo.NewEthSigner() via go-ethereum

Without geth, on-chain Ethereum operations are unavailable but all other packages compile normally. This keeps the default dependency footprint small.

Protocol

mpp-go implements the Machine Payments Protocol specification:

  • HTTP 402 + WWW-Authenticate: Payment realm="…" method="…" intent="…" request="…"
  • HMAC-SHA256 challenge IDs (32-byte, base64url) — wire-compatible with mpp-rs
  • JCS (RFC 8785) canonical JSON encoding for payment requests
  • RFC 9457 Problem Details error responses
  • RFC 3339 timestamps for challenge expiry

Examples

See the examples/ directory:

Example Description
examples/server net/http server with mock payment
examples/client Client that auto-pays 402 challenges
examples/tempo Tempo flow with mock EVM signer/verifier — run with go run ./examples/tempo (no build tags). Real RPC via NewEthSigner / NewEthVerifier needs -tags geth.

Run the mock examples locally:

go run ./examples/server &
go run ./examples/client
go run ./examples/tempo

Contributing

Pull requests are welcome. For significant changes, open an issue first to discuss the approach.

go test ./...
go test -tags geth ./...
go vet ./...

License

MIT

Documentation

Overview

Package mpp provides a Go SDK for the Machine Payments Protocol (MPP).

MPP is an open standard for inline HTTP payments built on top of the HTTP 402 "Payment Required" status code and the WWW-Authenticate / Authorization header pair (Web Payment Auth, IETF draft-ryan-httpauth-payment).

Quick start — server side

mppServer := server.New(server.WithMethod("tempo", myTempoVerifier))
http.Handle("/api/data", nethttp.Middleware(mppServer)(myHandler))

Quick start — client side

provider := &client.StaticProvider{Method: "tempo", Credential: myCredFn}
httpClient := client.NewHTTPClient(provider)
resp, err := httpClient.Get("https://api.example.com/data")

RFC 9457 error types live in package github.com/deszhou/mpp-go/mperr. They are re-exported here for convenience.

Index

Constants

View Source
const (
	WWWAuthenticateHeader = protocol.WWWAuthenticateHeader
	AuthorizationHeader   = protocol.AuthorizationHeader
	PaymentReceiptHeader  = protocol.PaymentReceiptHeader
	PaymentScheme         = protocol.PaymentScheme
)

Header name constants re-exported for convenience.

View Source
const (
	CoreProblemTypeBase    = mperr.CoreProblemTypeBase
	SessionProblemTypeBase = mperr.SessionProblemTypeBase
)

RFC 9457 base URIs.

View Source
const Version = "0.1.0"

Variables

This section is empty.

Functions

This section is empty.

Types

type MppError

type MppError = mperr.MppError

Payment error types (re-exported from mperr).

func NewMppError

func NewMppError(kind MppErrorKind, message string) *MppError

NewMppError creates an MppError (delegates to mperr).

type MppErrorKind

type MppErrorKind = mperr.MppErrorKind

Payment error types (re-exported from mperr).

const (
	KindMalformedCredential  MppErrorKind = mperr.KindMalformedCredential
	KindInvalidChallenge     MppErrorKind = mperr.KindInvalidChallenge
	KindVerificationFailed   MppErrorKind = mperr.KindVerificationFailed
	KindPaymentExpired       MppErrorKind = mperr.KindPaymentExpired
	KindPaymentRequired      MppErrorKind = mperr.KindPaymentRequired
	KindInvalidPayload       MppErrorKind = mperr.KindInvalidPayload
	KindBadRequest           MppErrorKind = mperr.KindBadRequest
	KindInsufficientBalance  MppErrorKind = mperr.KindInsufficientBalance
	KindInvalidSignature     MppErrorKind = mperr.KindInvalidSignature
	KindSignerMismatch       MppErrorKind = mperr.KindSignerMismatch
	KindAmountExceedsDeposit MppErrorKind = mperr.KindAmountExceedsDeposit
	KindDeltaTooSmall        MppErrorKind = mperr.KindDeltaTooSmall
	KindChannelNotFound      MppErrorKind = mperr.KindChannelNotFound
	KindChannelClosed        MppErrorKind = mperr.KindChannelClosed
	KindInternal             MppErrorKind = mperr.KindInternal
)

Problem kind constants (re-exported from mperr).

type PaymentErrorDetails

type PaymentErrorDetails = mperr.PaymentErrorDetails

Payment error types (re-exported from mperr).

Directories

Path Synopsis
Package client implements the MPP client-side payment provider and HTTP client.
Package client implements the MPP client-side payment provider and HTTP client.
Package digest provides SHA-256 body digest computation and verification.
Package digest provides SHA-256 body digest computation and verification.
examples
client command
Example MPP client that automatically handles HTTP 402 payment challenges.
Example MPP client that automatically handles HTTP 402 payment challenges.
server command
Example MPP server using the standard net/http package and the mock payment method.
Example MPP server using the standard net/http package and the mock payment method.
tempo command
Example: full Tempo payment flow using the mock EVM signer.
Example: full Tempo payment flow using the mock EVM signer.
Package expires provides helpers for generating RFC 3339 expiration timestamps.
Package expires provides helpers for generating RFC 3339 expiration timestamps.
http
echo
Package echo provides MPP middleware for the Echo web framework.
Package echo provides MPP middleware for the Echo web framework.
fiber
Package fiber provides MPP middleware for the Fiber web framework.
Package fiber provides MPP middleware for the Fiber web framework.
gin
Package gin provides MPP middleware for the Gin web framework.
Package gin provides MPP middleware for the Gin web framework.
nethttp
Package nethttp provides MPP middleware for the standard library net/http package.
Package nethttp provides MPP middleware for the standard library net/http package.
Package mcp provides MCP (Model Context Protocol) integration for MPP session payments.
Package mcp provides MCP (Model Context Protocol) integration for MPP session payments.
methods
mock
Package mock provides a mock payment method for development and testing.
Package mock provides a mock payment method for development and testing.
stripe
Package stripe implements the MPP "stripe" payment method using Stripe Short-Lived Payment Tokens (SPT) and the Stripe Payment Intents API.
Package stripe implements the MPP "stripe" payment method using Stripe Short-Lived Payment Tokens (SPT) and the Stripe Payment Intents API.
tempo
Package tempo implements the MPP "tempo" payment method using EVM-compatible on-chain transactions via the Tempo network.
Package tempo implements the MPP "tempo" payment method using EVM-compatible on-chain transactions via the Tempo network.
Package mperr defines RFC 9457 problem-details types and kinds for MPP failures.
Package mperr defines RFC 9457 problem-details types and kinds for MPP failures.
Package protocol contains the core MPP wire types, header parsing/formatting, and intent definitions.
Package protocol contains the core MPP wire types, header parsing/formatting, and intent definitions.
intents
Package intents provides MPP payment intent request types.
Package intents provides MPP payment intent request types.
Package server implements the MPP server-side payment challenge and credential verification logic.
Package server implements the MPP server-side payment challenge and credential verification logic.
Package sse provides Server-Sent Events utilities for MPP session payments.
Package sse provides Server-Sent Events utilities for MPP session payments.
Package store provides challenge-tracking storage for replay protection.
Package store provides challenge-tracking storage for replay protection.

Jump to

Keyboard shortcuts

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