mcpField
M
mpp

mpp

github.com/tenequm開発4070 回インストール5 日前に更新
リポジトリ

mpp について

Machine Payments Protocolを実装するためのスキルです。マシン間リクエストのHTTP 402決済を標準化するプロトコルで、決済クライアントとサーバー、複数の決済方式、セッション、MCPトランスポートを扱います。

主な機能

  1. 01HTTP 402のチャレンジ、クレデンシャル、レシート処理
  2. 02複数の決済方式とインテント
  3. 03TypeScript、Python、RustのSDKガイド
  4. 04従量課金型の決済セッション
  5. 05決済対応のMCPクライアントとサーバー
  6. 06リクエスト、アカウント、サービス検出用CLI

活用シーン

  1. 01APIリクエストやコンテンツへの課金
  2. 02LLMストリーミングや高頻度API呼び出しの課金
  3. 03MCPツール呼び出しへの決済要件の適用
  4. 04既存APIへの決済ゲートの追加

MCP 対応

MCPクライアントとサーバーのラッパーを通じて、決済が必要なMCPツール呼び出しをサポートします。MCP-over-HTTPの決済チャレンジは、決済対応リクエスト内で処理できます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/tenequm/skills --skill mpp

インストール後、Claude Code で/mppを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

CHANGELOG.md
LICENSE.txt
references/
cli.md
custom-methods.md
discovery-and-proxy.md
lightning-method.md
production-gotchas.md
protocol-spec.md
python-sdk.md
rust-sdk.md
sessions.md
stripe-method.md
subscriptions.md
tempo-method.md
transports.md
typescript-sdk.md

詳細

MPP - Machine Payments Protocol

MPP は、機械間決済向けに HTTP 402 Payment Required を標準化するオープンプロトコルです(Tempo と Stripe が共同作成)。クライアントは同じ HTTP リクエスト内で支払いを行うため、アカウント、API キー、チェックアウトフローは必要ありません。

コアプロトコル仕様は、Payment HTTP Authentication Scheme として IETF に提出されています。

このスキルのコードでは、プレースホルダーのトークン名(<USDC_TEMPO_MAINNET>、<PATHUSD_TESTNET>)を使用しています。実際のアドレスは、Tempo のドキュメントと references/tempo-method.md に記載されています。

コアアーキテクチャ

すべての MPP 決済は、次の 3 つのプリミティブを基盤としています。

  1. チャレンジ - サーバーが発行する支払い要件(WWW-Authenticate: Payment ヘッダー内)
  2. クレデンシャル - クライアントが送信する支払い証明(Authorization: Payment ヘッダー内)
  3. レシート - 支払いが成功したことをサーバーが確認する情報(Payment-Receipt ヘッダー内)

決済方式とインテント

MPP は決済方式に依存しません。各方式が独自の決済レールを定義します。

方式レールSDK パッケージステータス
TempoTempo チェーン上の TIP-20 ステーブルコインmppx(組み込み)本番環境対応
Stripeカード/ウォレット(SPT)+オンチェーンの暗号資産入金mppx(組み込み)本番環境対応
EVMEIP-3009 ステーブルコイン認証(x402-exact 互換)mppx(組み込み)本番環境対応
LightningLightning Network 経由の Bitcoin@buildonspark/lightning-mpp-sdk本番環境対応
StellarStellar 上の SEP-41 トークン、charge + channel@stellar/mpp本番環境対応(channel の wire 仕様はまだ策定中のため、変更される可能性があります)
SolanaSolana ネイティブの charge + session(SOL、SPL、Token-2022)@solana/mpp本番環境対応
MonadMonad の charge(ERC-3009、決済モード)@monad-crypto/mpp本番環境対応
NEAR Intents1Click 入金アドレス経由のクロスチェーン charge@defuse-protocol/nearintents-mpp-sdk本番環境対応(トラストレスではありません。決済バックエンド経由でルーティングされ、方式ごとのリスクポリシー向けに methodDetails.settlementBackend: "near-intents" として通知されます)
RedotPayRedotPay 残高(rdt)またはステーブルコインの証明。charge のみ@redotpay/mpp本番環境対応
Card暗号化されたネットワークトークン(Visa)mpp-card本番環境対応
Custom任意のレールMethod.from() + Method.toClient/toServer拡張可能

方式ごとの詳細については、references/tempo-method.md、references/stripe-method.md、references/lightning-method.md、references/custom-methods.md を参照してください。

インテントパターン最適な用途
chargeリクエストごとの単発決済API 呼び出し、コンテンツへのアクセス、固定料金のエンドポイント
session決済チャネルを介した従量課金LLM ストリーミング、従量課金、頻繁に利用される API
subscription認可済みキーを介した継続アクセス(Tempo) - references/subscriptions.md を参照アクセス権とリクエストごとの課金を分けるプラン/ティア

クイックスタート:サーバー(TypeScript)

import { Mppx, tempo } from 'mppx/server'

const mppx = Mppx.create({
  methods: [tempo({
    currency: '<PATHUSD_TESTNET>', // pathUSD testnet
    recipient: '0xYourAddress',
  })],
})

export async function handler(request: Request) {
  const result = await mppx.charge({ amount: '0.01' })(request)
  if (result.status === 402) return result.challenge
  return result.withReceipt(Response.json({ data: '...' }))
}

インストール:npm install mppx viem(mppx 0.8.15 では viem >= 2.54.0 が必要です)。

完成したサーバーを npx mppx validate http://localhost:3000 で検証し、エンドツーエンドの動作を確認してください。

クイックスタート:クライアント(TypeScript)

import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'

// Polyfills globalThis.fetch to handle 402 automatically
Mppx.create({
  methods: [tempo({ account: privateKeyToAccount('0x...') })],
})

const res = await fetch('https://api.example.com/paid')
// Payment happens transparently when server returns 402

ブラウザーでは、mppx 0.6.0 でデフォルトの動作が変更されました。ポリフィルされた fetch は、Accept-Payment を同一オリジンのエンドポイントにのみ送信するため、クロスオリジンの有料 API には acceptPaymentPolicy('always' / { origins: [...] })が必要です。クライアントの fetch は、段階的なチャレンジを maxPaymentRetries(デフォルトは 3)まで再試行します。グローバルでない代替手段(Fetch.from/polyfill/restore、Mppx.restore())については、references/typescript-sdk.md を参照してください。

クイックスタート:サーバー(Python)

from fastapi import FastAPI
from mpp import Credential, Receipt
from mpp.server import Mpp
from mpp.methods.tempo import tempo, ChargeIntent

app = FastAPI()
server = Mpp.create(method=tempo(
    currency="<PATHUSD_TESTNET>",
    recipient="0xYourAddress", intents={"charge": ChargeIntent()},
))

@app.get("/resource")
@server.pay(amount="0.50")
async def get_resource(request, credential: Credential, receipt: Receipt):
    return {"data": "paid content", "payer": credential.source}

インストール:pip install "pympp[tempo]"。全パターンについては、references/python-sdk.md を参照してください。

クイックスタート:サーバー(Rust)

インストール:cargo add mpp --features tempo,server。全パターンについては、references/rust-sdk.md を参照してください。

フレームワークミドルウェア(TypeScript)

各フレームワークには独自のインポートがあります(mppx/nextjs、mppx/hono、mppx/express、mppx/elysia)。

// Next.js
import { Mppx, tempo } from 'mppx/nextjs'
const mppx = Mppx.create({ methods: [tempo({ currency: '<PATHUSD_TESTNET>', recipient: '0x...' })] })
export const GET = mppx.charge({ amount: '0.1' })(() => Response.json({ data: '...' }))

// Hono
import { Mppx, tempo } from 'mppx/hono'
app.get('/resource', mppx.charge({ amount: '0.1' }), (c) => c.json({ data: '...' }))

Express と Elysia の例については、references/typescript-sdk.md を参照してください。

セッション:従量課金ストリーミング

セッションでは、最初に一度だけ決済チャネルを開き、その後の各リクエストにはオフチェーンのバウチャーを使用します。リクエストごとのブロックチェーン取引は不要です。レイテンシは 100 ミリ秒未満で、リクエストごとの手数料はほぼゼロです。

セッション v2(mppx 0.7.0 以降のデフォルト): tempo.session() は TIP-1034 のプリコンパイル済みチャネルフローです。それ以前のエスクローコントラクト実装はセッション v1で、非推奨の tempo.sessionLegacy として引き続き利用できます。v2 を想定するクライアントは v1 セッションを拒否してチャージフローにフォールバックするため、クライアントとサーバーでは同じフローを使用してください。クライアント API は 2 種類あります。tempo.session({ account, maxDeposit }) は Mppx.create() にメソッドを登録し(fetch による透過的な 402 処理)、tempo.session.manager({ account, maxDeposit }) はライフサイクルを直接制御するための管理クライアント(.sse()、.close())を返します。

// Server - session endpoint with automatic settlement
const mppx = Mppx.create({
  methods: [tempo.session({
    currency: '<PATHUSD_TESTNET>', recipient: '0x...',
    store: Store.redis(redis),
    settlementSchedule: { amount: '1.00', intervalMs: 300_000 },
    bootstrap: true, // let returning clients recover their channel on this route
  })],
})
const result = await mppx.session({ amount: '0.001', unitType: 'token' })(request)
if (result.status === 402) return result.challenge
return result.withReceipt(Response.json({ data: '...' }))
// Server - SSE streaming with per-word billing
export const GET = mppx.session({ amount: '0.001', unitType: 'word' })(
  async () => async function* (stream) {
    for (const word of ['hello', 'world']) {
      await stream.charge()
      yield word
    }
  }
)

// Client - session with auto-managed channel
Mppx.create({ methods: [tempo({ account, maxDeposit: '1' })] })
const res = await fetch('http://localhost:3000/api/resource')
// 1st request: opens channel on-chain; 2nd+: off-chain vouchers

セッションは Ws.serve() を介して WebSocket でもストリーミングできます。ライフサイクル、決済、ストア、SSE と WebSocket のパターン、チャネルの復旧については、references/sessions.md を参照してください。

マルチメソッド対応

単一のエンドポイントで Tempo のステーブルコイン、Stripe のカード、Lightning のビットコインを受け付けます。

const mppx = Mppx.create({
  methods: [
    tempo({ currency: '<PATHUSD_TESTNET>', recipient: '0x...' }),
    stripe.charge({ client: new Stripe(key), networkId: 'profile_...', paymentMethodTypes: ['card'] }),
    spark.charge({ mnemonic: process.env.MNEMONIC! }),
  ],
})

Mppx.compose() を使用すると、ルートごとの価格設定を適用しながら、複数のメソッドを単一の 402 レスポンスで提示できます。チャレンジを生成する場所と検証する場所の両方で同じ分岐を適用してください。そうしないと、402 で提示される選択肢がサーバーで受け付けられる選択肢より少なくなります。詳しくは references/typescript-sdk.md を参照してください。

決済リンク(HTML)

決済メソッドの設定で html: true を指定すると、ブラウザーで 402 エンドポイントにアクセスした際に、テーマ設定、マルチメソッドの合成タブ、Solana ウォレットに対応した、ブラウザー向けの決済ページが表示されます。サービスワーカーが認証情報の送信を処理し、その後、決済済みのレスポンスを表示するためにページが再読み込みされます。

mppx/html のエクスポート(Config、Text、Theme)でカスタマイズできます。また、Html.init(methodName) を使用して、カスタムメソッドの決済リンクを作成できます。

ゼロドル認証(Proof 資格情報)

支払いを行わずにエージェントの ID を認証します。クライアントは取引を作成する代わりに、チャレンジ ID に対する EIP-712 の Proof に署名します。ガスの消費も、資金の移動もありません。

// Server - zero-dollar charge, with a store for replay protection
const mppx = Mppx.create({
  methods: [tempo.charge({ currency: '<PATHUSD_TESTNET>', recipient: '0x...', store })],
})
const result = await mppx.charge({ amount: '0' })(request)

mppx 0.8.0 以降、これらの Proof は支払い元のウォレットに紐づけられます。EIP-712 の Proof 型付きデータ(tempo.Proof として公開)には、ドメインバージョン 3 で account フィールドが含まれるため、あるアカウント向けに署名された Proof は、別のアカウントでは検証されなくなりました。

ユースケース:ID 検証、長時間実行されるジョブのポーリング、無料の継続アクセスを伴う有料アンロック、複数ステップのエージェントパイプライン。mpp.dev/advanced/identity を参照してください。

決済プロキシ

既存の API を MPP 決済で保護します。

// import { openai, Proxy } from 'mppx/proxy' - a service inside Proxy.create({ services: [...] })
openai({
  apiKey: process.env.OPENAI_API_KEY,
  routes: {
    'POST /v1/chat/completions': mppx.charge({ amount: '0.05' }),
    'GET /v1/models': true, // literal `true` marks a free route
  },
})

組み込みプリセットの openai()、anthropic()、stripe() に加え、任意のアップストリームに対応する custom() を利用できます。Proxy.create()、提供するディスカバリーエンドポイント、プロキシを使わないサーバー向けの discovery() ヘルパーについては、references/discovery-and-proxy.md を参照してください。

MCP トランスポート

MCP のツール呼び出しでは、JSON-RPC エラーコード -32042(サーバーは -32043 を発行することもあります)を使った支払いが必要になる場合があります。

// Server - import tempo from mppx/server, NOT mppx/tempo
import { McpServer } from 'mppx/mcp/server'
import { tempo } from 'mppx/server'
const server = McpServer.wrap(baseServer, { methods: [tempo.charge({ /* ... */ })], secretKey })

// Client - payment-aware MCP client (import tempo from mppx/client)
import { McpClient } from 'mppx/mcp/client'
import { tempo } from 'mppx/client'
const mcp = McpClient.wrap(client, { methods: [tempo({ account })] })
const result = await mcp.callTool({ name: 'premium_tool', arguments: {} })

MCP-over-HTTP のチャレンジは、支払いに対応した同一のフェッチ内で決済されます。また、両側で Transport.from/http/mcp/mcpSdk を使ってトランスポートをプラグインできます。詳しくは references/transports.md をご覧ください。

Privy サーバーウォレット

@privy-io/node/viem の createViemAccount(@privy-io/node >= 0.20.0 が必要)は、Privy のサーバーウォレットを基盤とする viem の Account を返すため、ローカルアカウントを指定する箇所にそのまま tempo({ account }) を渡せます。

サーバー側での署名はアプリ所有のサーバーウォレットで機能します。ユーザー所有の埋め込みウォレットには、認証キーまたはキーのクォーラムが必要です。セットアップの詳細と、手動での toAccount() の構築方法については references/typescript-sdk.md をご覧ください。

テストと CLI

# Create an account (stored in keychain), then fund it on testnet
npx mppx account create
npx mppx account fund --network testnet

# Make a paid request
npx mppx http://localhost:3000/resource

# Parse a challenge without signing it
npx mppx sign --dry-run --challenge '<www-authenticate value>'

# Validate a server implementation end-to-end
npx mppx validate http://localhost:3000

CLI では、init、sessions(一覧表示/表示/終了)、discover、services、mcp add、skills add も利用できます。設定は MPPX_CONFIG または明示的に指定した --config から読み込まれます。作業ディレクトリからの自動検出は行われません。完全なリファレンスは references/cli.md をご覧ください。

SDK パッケージ

言語パッケージインストール
TypeScriptmppxnpm install mppx
Pythonpympppip install "pympp[tempo]"
Rustmppcargo add mpp --features tempo,client,server
Rubympp-rb(Stripe による公式 SDK)gem 名はリポジトリをご覧ください
Gompp-go(Tempo による公式 SDK)go get github.com/tempoxyz/mpp-go
Elixirmpp(コミュニティ製)hex.pm/packages/mpp
Swiftmpp-swift(コミュニティ製)リポジトリをご覧ください

SDK の機能に関する注記です。ドキュメントの対応表は内容が食い違うものが 2 つ公開されているため、SDK のソースを確認しています。

  • Session インテント:TypeScript と Rust のみです。
  • Proof Credentials(ゼロドル認証):TypeScript、Rust、Ruby で対応しています。pympp は対応していません。Python の Tempo メソッドが実装しているペイロード型は hash と transaction のみです。
  • Stripe、MCP、イベント処理:TypeScript、Python、Rust、Ruby で対応しています。公式の mpp-go は対応していません。公式の mpp-go には、net/http、Gin、Echo、Chi のミドルウェアを使う client/server/charge/fee-sponsorship/proof が含まれています。別途、コミュニティ製の Go mppx(cp0x)もあります。

Go と Ruby には、mpp.dev/sdk/go と mpp.dev/sdk/ruby に公式 SDK ドキュメントのページがあります。

コンテキストに合ったサブパス(mppx/server、mppx/client、またはフレームワークのサブパス)から、必ず Mppx と tempo をインポートしてください。注:Mppx と tempo は mppx/tempo からエクスポートされません。このサブパスからエクスポートされるのは Session と Ws のみです。サブパスの正式な一覧は references/typescript-sdk.md にあります。

主な概念

  • Challenge/Credential/Receipt:3つのプロトコルプリミティブです。Challenge ID は改ざんを防ぐため、HMAC-SHA256 に結び付けられています。references/protocol-spec.md を参照してください。
  • 分割決済:1回のトランザクションで複数の受取人に対して1つの請求を行います(分割数は1〜10、分割ごとのメモ、expectedRecipients)。references/tempo-method.md を参照してください。
  • 手数料のスポンサー:サーバーがクライアントに代わってガス代を支払います。上限は maxInFlightReservations/maxInFlightTotalFee で設定します。
  • リレー:tempo.charge({ relay }) を通じて、Credential の検証とブロードキャストを Tempo API または互換性のあるリレーに委任します。
  • プッシュ/プルモード:クライアントがトランザクションをブロードキャストする(プッシュ)か、サーバーが行う(プル)かを選べます。
  • クライアントのチェーン固定:tempo.charge({ expectedChainId }) は、誤った Tempo ネットワーク向けの Challenge を拒否します。
  • 再利用可能なクライアントチャネル:channelStore を渡すと、支払い側のセッションチャネルをプロセス間で保存して再利用できます。
  • x402 相互運用:evm.charge({ x402: { facilitator } }) を使うと、1つのルートからネイティブの MPP と x402「exact」Challenge を提供できます。クライアントは Payment 認証付きの Challenge を優先します。
  • カスタムメソッド:Method.from() を使って、任意の決済レールを実装できます。references/custom-methods.md を参照してください。

決済フック

ハンドラーに手を加えずに、ログ記録、メトリクス、トレースを追加できます。Mppx.create() が返すオブジェクトに登録してください。登録ごとに登録解除関数が返されます。

  • サーバー(mppx/server):onChallengeCreated、onPaymentSuccess、onPaymentFailed、onSessionSettlement、on('*')
  • クライアント(mppx/client):onChallengeReceived、onCredentialCreated、onPaymentResponse、onPaymentFailed

サーバーハンドラーはリクエスト処理中にインラインで待機されるため、処理を高速に保ってください。不透明な 402 の背後にある実際のエラーを確認するには、onPaymentFailed が実用的な方法です。references/typescript-sdk.md と mpp.dev/advanced/payment-hooks を参照してください。

エージェントの支出管理

Tempo アクセスキーを使って、エージェントの決済権限を制限できます。アクセスキーは委任用署名キーで、支出制御機能、有効期限、取り消し手段が組み込まれています。

import { Expiry } from 'accounts'
import { numberToHex, parseUnits } from 'viem'
import { Scopes } from 'viem/tempo'

const accessKey = {
  expiry: Expiry.days(7),
  limits: [{ token: usdc, limit: numberToHex(parseUnits('10', 6)), period: 86_400 }], // 10 USDC/day
  scopes: [Scopes.tip20(usdc).transfer({ recipients: [recipientAddress] })],
}
// Authorize: provider.request({ method: 'wallet_connect', params: [{ capabilities: { authorizeAccessKey: accessKey } }] })

Mppx.create({
  methods: [tempo({
    account: provider.getAccount(),
    ...provider.getMppxParameters({ accessKey: accessKeyAddress }),
  })],
})

支出上限は16進数でエンコードされます。生の bigint ではなく、numberToHex(parseUnits(...)) を渡してください。アプリ/ツール/デプロイごとに別々のキーを使うことで、委任されたランタイムを分離できます。mpp.dev/guides/managing-agent-spend と Tempo access keys を参照してください。

本番環境での注意点

特に時間を取られる障害パターンです。詳しくは references/production-gotchas.md を参照してください。

  • Tempo にはネイティブのガストークンがありません。 feeToken を設定するか、setUserToken を呼び出してください。そうしないと、gas_limit: 0 でトランザクションが失敗します。「Fund with ETH」エラーは、「ステーブルコインの手数料トークンで資金を補充する」という意味です。
  • セッションは自動で決済されません。 settlementSchedule を設定するか、独自に tempo.settle()/tempo.settleBatch() の一括処理を実行し、アイドル状態のチャネルにはクローズポリシーを組み合わせてください。そうしないと、収益は未換金のバウチャーとして蓄積され、チャネルは支払い側のデポジットを保持したまま開いた状態になります。
  • 請求はハンドラーの実行前に決済されます。 処理の成功を決済の条件にする場合は、validateCredential の後に broadcastCredential を使ってください。Challenge はデフォルトで5分後に期限切れになります。
  • 本番環境では Store.memory() を絶対に使わないでください。 チャネル状態が失われると、デポジットが無期限に予約されたままになります。
  • realm を明示的に設定してください。 環境変数はリクエストごとのホスト名より優先され、Kubernetes の HOSTNAME はデプロイのたびに変わるため、mppscan のアトリビューションが壊れます。
  • セッションのバウチャー、close、topUp の Credential は、本文のない POST リクエストです。 本文バリデーターが mppx.session() より前に実行されると、誤って 400 を返します。本文を読み取る前にリクエストを複製してください。そうしないと、mppx が空の本文を受け取り、402 を返します。
  • サイズの大きな 402 ヘッダーは nginx のデフォルトバッファー(4k)を超え、502 として現れます。

参考資料

ファイル内容
references/protocol-spec.mdChallenge/Credential/Receipt、ステータスコード、セキュリティ
references/typescript-sdk.mdmppx:サーバー、クライアント、ミドルウェア、トランスポート、ストア
references/cli.mdmppx CLI:リクエスト、検証、署名、アカウント、設定
references/production-gotchas.md実環境で確認された障害モードとその修正方法
references/sessions.mdチャネル、バウチャー、決済、SSE/WS、復旧
references/subscriptions.mdサブスクリプションのインテント:有効化、更新、キャンセル
references/tempo-method.mdTempo:手数料、リレー、プッシュ/プル、分配、セッション
references/stripe-method.mdStripe:SPT の法定通貨フロー、暗号資産の入金、Elements
references/discovery-and-proxy.mdプロキシサービス、ディスカバリードキュメント、レジストリ
references/transports.mdHTTP、MCP、WebSocket のトランスポートバインディング
references/python-sdk.mdpympp:@server.pay、非同期クライアント、チャージインテント
references/rust-sdk.mdmpp Rust:サーバー/クライアント、機能、セッション
references/lightning-method.mdLightning:BOLT11 チャージ、ベアラーセッション、Spark
references/custom-methods.mdMethod.from、toClient、toServer のパターン

公式リソース

コメント