MPP.Client.Transport behaviour (mpp v0.14.0)

Copy Markdown View Source

Behaviour for client-side transports that bridge a protocol response/request pair and the MPP payment flow.

A Transport implementation knows how to:

  1. Detect whether a response signals "payment required" (HTTP 402, JSON-RPC error code -32042, etc.)
  2. Extract the challenges carried on that response
  3. Attach a decoded credential to a new request for retry

This is the transport-shaped glue that sits between the provider-side MPP.Client.PaymentProvider abstraction and whatever concrete client (Req, an MCP JSON-RPC client, etc.) is actually issuing requests. HTTP is MPP.Client.Transport.HTTP; MCP is MPP.Client.Transport.MCP; generic JSON-RPC (root-level _meta) is MPP.Client.Transport.JsonRpc. WebSocket (typed MPP frames) is MPP.Client.Transport.WebSocket.

Callbacks

Selection

select_challenge/2 delegates to MPP.Client.SelectionPolicy — the transport-neutral policy surface shared with HTTP (MPP.Client.Req) and MCP client orchestration. The default preserves server-advertised order; pass :selection or :accept_payment to select_challenge/3 to configure it.

API Functions

FunctionArityDescriptionParam Kinds
select_challenge3Pick a MultiProvider-supported challenge via MPP.Client.SelectionPolicy.challenges: value, multi: value, opts: value

Summary

Callbacks

Extract the MPP.Challenge list carried on a payment-required response.

Return true if the response signals that a payment is required.

Return a new request with the given credential attached in transport-specific form.

Callbacks

get_challenges(response)

@callback get_challenges(response :: term()) ::
  {:ok, [MPP.Challenge.t()]} | {:error, term()}

Extract the MPP.Challenge list carried on a payment-required response.

Returning {:ok, []} is not a valid outcome — an empty or unparseable challenge set should surface as {:error, reason} so callers can distinguish "402 with no Payment challenges" from "402 with N challenges".

payment_required?(response)

@callback payment_required?(response :: term()) :: boolean()

Return true if the response signals that a payment is required.

For HTTP, this is status == 402. For MCP/JSON-RPC, this is error.code == -32042.

set_credential(request, credential)

@callback set_credential(request :: term(), credential :: MPP.Credential.t()) :: term()

Return a new request with the given credential attached in transport-specific form.

For HTTP, this sets Authorization: Payment <base64url>. For MCP, this injects the credential into params._meta["org.paymentauth/credential"]. Each transport owns its wire format — the credential struct is passed in decoded form so the transport is free to serialise it however it needs to.

Functions

select_challenge(challenges, multi, opts \\ [])

@spec select_challenge([MPP.Challenge.t()], MPP.Client.MultiProvider.t(), keyword()) ::
  {:ok, MPP.Challenge.t()} | {:error, :no_supported_challenge}

Pick a supported challenge via MPP.Client.SelectionPolicy.

Options:

  • :selection — a SelectionPolicy.t() (default :server_order)
  • :accept_payment — preference entries; used when :selection is omitted

Returns {:error, :no_supported_challenge} if no challenge matches any provider, including the empty-list case.