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 payments - 🔁 Choose between different modes (two_step, resubmit, elicit, progress, dynamic_tools, etc.)
- 🔌 Built-in support for major providers (see list) — plus a pluggable interface for custom providers.
- ⚙️ Easy integration with
FastMCPor 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.
🧭 Modes (formerly Payment Flows)
In version 0.4.2, the paymentFlow parameter was renamed to mode, which better reflects its purpose. The old name remains supported for backward compatibility.
The mode parameter controls how the user is guided through the payment process. Choose the strategy that fits your use case:
-
Mode.TWO_STEP(default)
Splits the tool into two separate MCP methods.
The first step returns apayment_urland anext_stepmethod for confirmation.
The second method (e.g.confirm_add_payment) verifies payment and runs the original logic.
Supported in most clients. -
Mode.RESUBMITAdds an optionalpayment_idto the original tool signature.- First call: the tool is invoked without
payment_id→ PayMCP returns apayment_url+payment_idand instructs a retry after payment. - Second call: the same tool is invoked again with the returned
payment_id→ PayMCP verifies payment server‑side and, if paid, executes the original tool logic.
- First call: the tool is invoked without
Similar compatibility to TWO_STEP, but with a simpler surface
-
Mode.ELICITATIONSends the user a payment link when the tool is invoked. If the client supports it, a payment UI is displayed immediately. Once the user completes payment, the tool proceeds. -
Mode.PROGRESS
Shows payment link and a progress indicator while the system waits for payment confirmation in the background. The result is returned automatically once payment is completed. -
Mode.DYNAMIC_TOOLSSteer the client and the LLM by changing the visible tool set at specific points in the flow (e.g., temporarily exposeconfirm_payment_*), thereby guiding the next valid action.
All modes require the MCP client to support the corresponding interaction pattern. When in doubt, start with TWO_STEP.
🗄️ State Storage
By default, when using the TWO_STEP payment flow, PayMCP stores pending tool arguments (for confirming payment) 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)
)
🧩 Supported Providers
Built-in support is available for the following providers. You can also write a custom provider.
🔌 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="...")])
📄 License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file paymcp-0.4.2.tar.gz.
File metadata
- Download URL: paymcp-0.4.2.tar.gz
- Upload date:
- Size: 62.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: pdm/2.26.0 CPython/3.10.14 Darwin/24.3.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd26e7d9cccd47b279f42f973a5a8ef02b608143ad91d316d7cf45560dcca88a
|
|
| MD5 |
480759c3c168d958efeed6d41331ba22
|
|
| BLAKE2b-256 |
04a44c974fffda32391f5b91300a2df35d4995d431e69aaf770e3b1eb449a378
|
File details
Details for the file paymcp-0.4.2-py3-none-any.whl.
File metadata
- Download URL: paymcp-0.4.2-py3-none-any.whl
- Upload date:
- Size: 34.7 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7b8717426f0e528fcf0370d588f9da9523fdf42e1cbc9134597d4e28b796fa09
|
|
| MD5 |
823d56d9c5bb15db03bc94aa96f8212d
|
|
| BLAKE2b-256 |
34dc1e0a282385ec168e402c14354e56ff48596eca5bb739a7fdcff2ae3538a6
|