Skip to main content

Provider-agnostic payment layer for MCP (Model Context Protocol) tools and agents.

Project description

PayMCP

Provider-agnostic payment layer for MCP (Model Context Protocol) tools and agents.

paymcp is a lightweight SDK that helps you add monetization to your MCP‑based tools, servers, or agents. It supports multiple payment providers and integrates seamlessly with MCP's tool/resource interface.

See the full documentation.


🔧 Features

  • ✅ Add @price(...) decorators to your MCP tools to enable pay‑per‑request billing.
  • ✅ Gate tools behind active subscriptions (where supported) with the @subscription(...) decorator; helper tools included.
  • 🔁 Pay‑per‑request flows support multiple modes (TWO_STEP / RESUBMIT / ELICITATION / PROGRESS / DYNAMIC_TOOLS).
  • 🔌 Built-in support for major providers (see list) — plus a pluggable interface for custom providers.
  • ⚙️ Easy integration with FastMCP or other MCP servers

🚀 Quickstart

Install the SDK from PyPI:

pip install mcp paymcp

Initialize PayMCP:

import os
from mcp.server.fastmcp import FastMCP, Context
from paymcp import Mode, price
from paymcp.providers import StripeProvider

mcp = FastMCP("AI agent name")

PayMCP(
    mcp,
    providers=[
        StripeProvider(api_key=os.getenv("STRIPE_API_KEY")),
    ],
    mode=Mode.TWO_STEP # optional, TWO_STEP (default) / RESUBMIT / ELICITATION / PROGRESS / DYNAMIC_TOOLS
)

Use the @price decorator on any tool:

@mcp.tool()
@price(amount=0.99, currency="USD")
def add(a: int, b: int, ctx: Context) -> int: # `ctx` is required by the PayMCP tool signature — include it even if unused
    """Adds two numbers and returns the result."""
    return a + b

Demo server: For a complete setup, see the example repo: python-paymcp-server-demo.

💰 Choose How to Charge (per tool)

Use either @price or @subscription on a tool (they are mutually exclusive).

Option A — Pay‑per‑request

@mcp.tool()
@price(amount=0.19, currency="USD")
def summarize(text: str, ctx: Context) -> str:
    return text[:200]

Option B — Subscription‑gated (providers with subscription support, e.g., Stripe)

User authentication is your responsibility. PayMCP will resolve identity from ctx.authInfo or a Bearer token (Authorization header). Make sure your token carries:

  • sub (treated as userId), and ideally
  • email (highly recommended for provider matching, e.g., Stripe).

PayMCP does not validate or verify the token; it only parses it to extract userId/email.

from paymcp import subscription

@mcp.tool()
@subscription(plan="price_pro_monthly")  # or a list of accepted plan IDs from your provider
async def generate_report(ctx: Context) -> str:
    return "Your report"

When you register the first subscription‑protected tool, PayMCP auto‑registers helper tools:

  • list_subscriptions — current subscriptions + available plans for the user.
  • start_subscription — accepts planId to create (or resume) a subscription.
  • cancel_subscription — accepts subscriptionId to cancel at period end.

🧩 Supported Providers

Built-in support is available for the following providers. You can also write a custom provider.

  • Stripe — pay‑per‑request + subscriptions

  • Adyen — pay‑per‑request

  • Coinbase Commerce — pay‑per‑request

  • PayPal — pay‑per‑request

  • Square — pay‑per‑request

  • Walleot — pay‑per‑request

  • 🔜 More providers welcome! Open an issue or PR.

🔌 Writing a Custom Provider

Any provider must subclass BasePaymentProvider and implement create_payment(...) and get_payment_status(...).

from paymcp.providers import BasePaymentProvider

class MyProvider(BasePaymentProvider):

    def create_payment(self, amount: float, currency: str, description: str):
        # Return (payment_id, payment_url)
        return "unique-payment-id", "https://example.com/pay"

    def get_payment_status(self, payment_id: str) -> str:
        return "paid"

PayMCP(mcp, providers=[MyProvider(api_key="...")])

🗄️ State Storage

By default, when using the TWO_STEP or RESUBMIT modes, PayMCP stores payment_id and pending tool arguments in memory using a process-local Map. This is not durable and will not work across server restarts or multiple server instances (no horizontal scaling).

To enable durable and scalable state storage, you can provide a custom StateStore implementation. PayMCP includes a built-in RedisStateStore, which works with any Redis-compatible client.

from redis.asyncio import from_url
from paymcp import PayMCP, RedisStateStore

redis = await from_url("redis://localhost:6379")
PayMCP(
    mcp,
    providers=[
        StripeProvider(api_key=os.getenv("STRIPE_API_KEY")),
    ],
    state_store=RedisStateStore(redis)
)

🧭 Modes (pay‑per‑request only)

In version 0.4.2, paymentFlow was renamed to mode (old name still works).

The mode parameter controls how the user is guided through the pay‑per‑request payment process. Pick what fits your client:

  • Mode.TWO_STEP (default) — Splits the tool into two MCP methods. First call returns payment_url + next_step; the confirm method verifies and runs the original logic. Works in most clients.
  • Mode.RESUBMIT — Adds optional payment_id to the tool signature. First call returns payment_url + payment_id; second call with payment_id verifies then runs the tool. Similar compatibility to TWO_STEP.
  • Mode.ELICITATION — Sends a payment link via MCP elicitation (if supported). After payment, the tool completes in the same call.
  • Mode.PROGRESS — Keeps the call open, streams progress while polling the provider, and returns automatically once paid.
  • Mode.DYNAMIC_TOOLS — Temporarily exposes additional tools (e.g., confirm_payment_*) to steer the client/LLM through the flow.

When in doubt, start with TWO_STEP.


🔒 Security Notice

PayMCP is NOT compatible with STDIO mode deployments where end users download and run MCP servers locally. This would expose your payment provider API keys to end users, creating serious security vulnerabilities.


📄 License

MIT License

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paymcp-0.5.1.tar.gz (85.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paymcp-0.5.1-py3-none-any.whl (47.1 kB view details)

Uploaded Python 3

File details

Details for the file paymcp-0.5.1.tar.gz.

File metadata

  • Download URL: paymcp-0.5.1.tar.gz
  • Upload date:
  • Size: 85.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.0 CPython/3.10.14 Darwin/24.3.0

File hashes

Hashes for paymcp-0.5.1.tar.gz
Algorithm Hash digest
SHA256 9d2465464ff2456adeb2668acb72a05cfed8f0aacd347c06ca363102acaf4a22
MD5 f96cdf67788efd1d5b7ab00d8d9d01ef
BLAKE2b-256 c6238d38400ba32ce9c0dd8de62b068f955de09c90f00b6e147f4d8610b1d546

See more details on using hashes here.

File details

Details for the file paymcp-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: paymcp-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 47.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: pdm/2.26.0 CPython/3.10.14 Darwin/24.3.0

File hashes

Hashes for paymcp-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 38309e97e71a914ebe0418e676552543d03e7f79c3eeea99b6e6636be511b988
MD5 1b05eecea25d23e029427eedb8cd1188
BLAKE2b-256 7c572881a4c9f26a1e24375c255892f6e3f150eabb938ff0b55f4b261b584971

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page