Mppx.compose
Present multiple payment options
Combines multiple method handlers into one HTTP or MCP handler that presents every payment offer to the client.
Usage
Present both stablecoin and Stripe card payment options for a single endpoint. The client picks whichever method it supports.
import { , , } from 'mppx/server'
const = '0x20c0000000000000000000000000000000000000'
const = '0x20C000000000000000000000b9537d11c60E8b50'
const = '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
const = .({ })
const = .({
: 2,
: 'acct_1234',
: ['card'],
: 'sk_live_...',
})
const = .({ : [, ] })
export async function (: Request) {
const = await .(
[, { : '1', : }],
[, { : '1', : }],
[, { : '1', : 'usd' }],
)()
if (. === 402) return .
return .(.({ : '...' }))
}With MCP
Use instance composition with Transport.mcpSdk() to offer multiple payment options from one MCP tool. The transport returns every Challenge in the payment-required error and dispatches the selected Credential to one matching handler.
import { } from '@modelcontextprotocol/sdk/server/mcp'
import { , , } from 'mppx/server'
const = '0x20c0000000000000000000000000000000000000'
const = '0x20C000000000000000000000b9537d11c60E8b50'
const = .({
: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
})
const = .({
: [],
: .(),
})
const = new ({ : 'example', : '1.0.0' })
.('premium', { : 'Read premium data' }, async () => {
const = await .(
[.., { : '1', : }],
[.., { : '1', : }],
)()
if (. === 402) throw .
return .({ : [{ : 'Premium data', : 'text' }] })
})Nested compositions
Use the static Mppx.compose() function to combine configured handlers or another composed handler. Credential dispatch and discovery metadata include every nested offer.
const stablecoins = Mppx.compose(
mppx.tempo.charge({ amount: '1', currency: pathUSD }),
mppx.tempo.charge({ amount: '1', currency: USDCe }),
)
const paid = Mppx.compose(
stablecoins,
mppx.stripe.charge({ amount: '1', currency: 'usd' }),
)Behavior
- No Credential over HTTP: Calls all handlers and merges their
402Challenges into a single response with multipleWWW-Authenticateheaders. - No Credential over MCP: Calls all handlers and combines their Challenges in configured order. MCP SDK transport returns an
McpError; raw MCP transport preserves the JSON-RPC request ID. - Intent shorthand: When multiple registered methods share an intent,
mppx.charge(options)and other intent functions implicitly compose every matching method over HTTP or MCP. Use explicit composition when offers need different options. - Offer policies: HTTP composition calls each method's
canOfferhook, then the instance-levelselectOffershook, before generating Payment auth, x402, or HTML offers. MCP composition requires methods that use the configured MCP transport and rejects HTTPcanOfferhooks. Static compositions applycanOffer; direct method handlers don't. Accept-Paymentpresent: Ranks and filters the merged Challenges by the client's supportedmethod/intententries. Entries withq=0are excluded. If the header is invalid or filters out every Challenge, all Challenges are returned.- Credential present: Dispatches to exactly one handler matching the Credential's method, intent, request terms, and scope without re-running offer policies. MCP verification failures don't fall through to another offer.
- Discovery enabled: Exposes every configured offer to
discovery()and proxy metadata, including offers from nested compositions.
Signatures
Instance
type InstanceCompose = (
...entries: readonly [Method.Server | MethodHandler | string, Options][]
) => ComposedHandler<Transport>Instance composition supports HTTP, MCP SDK, and raw MCP transports.
Static
type StaticCompose = (
...handlers: readonly (ComposedHandler | ConfiguredHandler)[]
) => ComposedHandlerStatic composition combines configured HTTP handlers and supports nested compositions.
Return type
type ReturnType<Transport> = (input: InputOf<Transport>) => Promise<
| { status: 402; challenge: ChallengeOutputOf<Transport> }
| { status: 200; withReceipt: WithReceipt<Transport> }
>Parameters
...entries
- Type:
readonly [Method.Server | MethodHandler | string, Options][]
Each entry is a tuple of a method reference (or string key like "tempo/charge") and the request options for that method. Requires at least one entry.
...handlers
- Type:
readonly (ComposedHandler | ConfiguredHandler)[]
Configured route handlers returned by an mppx method or another static composition. Requires at least one handler.