API Reference
Complete reference documentation for PayMCP classes, functions, and configuration options.
Core Classes
PayMCP
The main PayMCP class that integrates payment functionality into your MCP server.
- Python
- TypeScript
class PayMCP:
def __init__(
self,
mcp_instance,
providers: list = None,
mode: Mode = Mode.TWO_STEP,
state_store = None
)
class PayMCP {
constructor(
mcpInstance: FastMCP,
options: {
providers: Provider[],
mode?: Mode,
stateStore?: StateStore;
}
)
}
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mcp_instance | FastMCP | Required | Your MCP server instance |
providers | Union[dict, Iterable] | {} | Payment provider configurations (see Provider Configuration section) |
mode | Mode | TWO_STEP | Coordination mode strategy |
state_store | StateStore | InMemoryStateStore | State Store for TWO_STEP mode |
Provider Configuration
Use the canonical provider list format:
- Python
- TypeScript
providers = [StripeProvider(apiKey="sk_test_...")]
providers = [new StripeProvider({ apiKey: "sk_test_..." })];
Alternative formats are also supported (config mapping, mixed styles) - see the Alternative Configuration section below.
Examples
- Python
- TypeScript
from paymcp import PayMCP, Mode
from paymcp.providers import StripeProvider
PayMCP(
mcp,
providers=[StripeProvider(apiKey="sk_test_...")],
mode=Mode.TWO_STEP
)
import { installPayMCP, Mode } from 'paymcp';
import { StripeProvider } from 'paymcp/providers';
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.TWO_STEP
});
Mode
Enum defining available payment modes.
- Python
- TypeScript
class Mode(str, Enum):
TWO_STEP = "two_step"
RESUBMIT = "resubmit"
ELICITATION = "elicitation"
PROGRESS = "progress"
DYNAMIC_TOOLS = "dynamic_tools"
enum Mode {
TWO_STEP = "two_step",
RESUBMIT = "resubmit",
ELICITATION = "elicitation",
PROGRESS = "progress",
DYNAMIC_TOOLS = "dynamic_tools"
}
Coordination Modes
| Mode | Description | Best For |
|---|---|---|
TWO_STEP | Split into initiate/confirm steps | Maximum compatibility |
RESUBMIT | First call returns HTTP 402 with payment_url + payment_id; second call retries with the ID | Tool retries where the client handles user payment completion |
ELICITATION | Payment link during execution | Real-time interactions |
PROGRESS | Experimental auto-checking of payment status | Real-time interactions |
DYNAMIC_TOOLS | Dynamically expose the next valid tool action | Clients with listChanged support |
For more details about coordination mode concepts, see Coordination Modes.
RESUBMIT specifics
- First call: PayMCP invokes your tool without a
payment_id, responds with HTTP 402 Payment Required that includes apayment_urlandpayment_id, and instructs the caller to retry after payment. - Second call: The caller runs the same tool again with the provided
payment_id; PayMCP verifies payment server-side and executes your original tool logic if the payment succeeded.
StateStore
By default, when using the TWO_STEP mode, PayMCP stores 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.
Example: Using Redis for State Storage
- Python
- TypeScript
from redis.asyncio import from_url
from paymcp import PayMCP, RedisStateStore
redis = await from_url("redis://localhost:6379")
PayMCP(
mcp,
providers={"stripe": {"apiKey": "..."}},
state_store=RedisStateStore(redis)
)
import { createClient } from "redis";
import { installPayMCP, RedisStateStore, Mode } from "paymcp";
const redisClient = createClient({ url: "redis://localhost:6379" });
await redisClient.connect();
installPayMCP(server, {
providers: { /* ... */ },
mode: Mode.TWO_STEP,
stateStore: new RedisStateStore(redisClient),
});
Payment Providers
PayMCP provides an extensible provider system that abstracts payment providers behind a common interface. Providers can be supplied in multiple ways to give you maximum flexibility:
Configuration Methods
Recommended Provider Development
- Python
- TypeScript
from paymcp.providers import StripeProvider
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")])
import { installPayMCP } from 'paymcp';
import { StripeProvider } from 'paymcp/providers';
installPayMCP(mcp, { providers: [new StripeProvider({ apiKey: "sk_test_..." })] });
Alternative Configuration
- Python
- TypeScript
PayMCP(mcp, providers={
"stripe": {"apiKey": "..."}
})
import { installPayMCP } from 'paymcp';
installPayMCP(mcp, {
providers: {
"stripe": { apiKey: "...", }
}
});
- Python
- TypeScript
from paymcp.providers import StripeProvider
PayMCP(mcp, providers={
"stripe": StripeProvider(apiKey="sk_test_...")
})
import { installPayMCP } from 'paymcp';
import { StripeProvider } from 'paymcp/providers';
installPayMCP(mcp, {
providers: {
"stripe": new StripeProvider({ apiKey: "sk_test_..." })
}
});
This flexibility allows you to:
- Mix different configuration styles in the same setup
- Use custom providers alongside built-in ones
- Dynamically configure providers at runtime
- Share provider instances across multiple PayMCP setups
Custom Provider Development
BasePaymentProvider
All payment providers must inherit from BasePaymentProvider and implement the required methods.
- Python
- TypeScript
from paymcp.providers import BasePaymentProvider
class MyProvider(BasePaymentProvider):
def __init__(self, api_key: str, **kwargs):
self.api_key = api_key
super().__init__(**kwargs)
def create_payment(self, amount: float, currency: str, description: str) -> tuple[str, str]:
"""Create a payment and return (payment_id, payment_url)"""
return "payment_id", "https://myprovider.com/pay/payment_id"
def get_payment_status(self, payment_id: str) -> str:
"""Return payment status: 'paid', 'pending', 'failed', or 'cancelled'"""
return "paid"
import { BasePaymentProvider } from 'paymcp/providers';
class MyProvider extends BasePaymentProvider {
constructor(apiKey: string, options?: any) {
super(options);
this.apiKey = apiKey;
}
createPayment(amount: number, currency: string, description: string): [string, string] {
// Create a payment and return [payment_id, payment_url]
return ["payment_id", "https://myprovider.com/pay/payment_id"];
}
getPaymentStatus(paymentId: string): string {
// Return payment status: 'paid', 'pending', 'failed', or 'cancelled'
return "paid";
}
}
Decorators
@price
Decorator to add payment requirements to MCP tools.
- Python
- TypeScript
def price(amount: float, currency: str = "USD")
// In registerTool options:
price: { amount: number, currency?: string }
Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
amount | float | Required | Payment amount |
currency | str | "USD" | ISO 4217 currency code |
Example
- Python
- TypeScript
@mcp.tool()
@price(amount=0.50, currency="USD")
def generate_data_report(input: str, ctx: Context) -> str:
"""Generate a data report from input"""
return f"Report: {input}"
mcp.tool(
"generate_data_report",
{
description: "Generate a data report from input",
inputSchema: { input: z.string() },
price: { amount: 0.50, currency: "USD" },
},
async ({ input }, ctx) => {
return { content: [{ type: "text", text: `Report: ${input}` }] };
}
);
Provider Configuration
Stripe
- Python
- TypeScript
providers = [StripeProvider(apiKey="sk_test_...")]
providers = [new StripeProvider({ apiKey: "sk_test_..." })];
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | str | Yes | Stripe secret key (sk_test_... or sk_live_...) |
Walleot
- Python
- TypeScript
providers = {
"walleot": {
"apiKey": str, # Required: Walleot API key
}
}
providers = {
"walleot": {
apiKey: string // Required: Walleot API key
}
};
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
apiKey | str | Yes | Walleot API key (sk_test_... or sk_live_...) |
PayPal
- Python
- TypeScript
providers = [PayPalProvider(client_id="...", client_secret="...", sandbox=True)]
providers = [new PayPalProvider({ client_id: "...", client_secret: "...", sandbox: true })];
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
client_id | str | Yes | - | PayPal application client ID |
client_secret | str | Yes | - | PayPal application client secret |
sandbox | bool | No | True | Use PayPal sandbox environment |
Square
- Python
- TypeScript
providers = {
"square": {
"access_token": str, # Required: Square access token
"location_id": str, # Required: Square location ID
"sandbox": bool, # Optional: Use sandbox environment
"redirect_url": str, # Optional: Redirect URL
"api_version": str, # Optional: API version
}
}
providers = {
"square": {
access_token: string, // Required: Square access token
location_id: string, // Required: Square location ID
sandbox: boolean, // Optional: Use sandbox environment
redirect_url: string, // Optional: Redirect URL
api_version: string // Optional: API version
}
};
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
access_token | str | Yes | - | Square access token |
location_id | str | Yes | - | Square location identifier |
sandbox | bool | No | True | Use Square sandbox environment |
redirect_url | str | No | - | Post-payment redirect URL |
api_version | str | No | "2025-03-19" | Square API version |
Adyen
- Python
- TypeScript
providers = {
"adyen": {
"api_key": str, # Required: Adyen API key
"merchant_account": str, # Required: Merchant account name
"sandbox": bool, # Optional: Use test environment
}
}
providers = {
"adyen": {
api_key: string, // Required: Adyen API key
merchant_account: string, // Required: Merchant account name
sandbox: boolean // Optional: Use test environment
}
};
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
api_key | str | Yes | - | Adyen API key |
merchant_account | str | Yes | - | Adyen merchant account identifier |
sandbox | bool | No | True | Use Adyen test environment |
Coinbase Commerce
- Python
- TypeScript
providers = [CoinbaseProvider(api_key="...")]
providers = [new CoinbaseProvider({ api_key: "..." })];
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
api_key | str | Yes | - | Coinbase Commerce API key |
Context Requirements
All priced tools must include a ctx: Context parameter:
from mcp.server.fastmcp import Context
@mcp.tool()
@price(amount=1.00, currency="USD")
def my_tool(input: str, ctx: Context) -> str:
# ctx parameter is required for PayMCP integration
return process_input(input)
Why Context is Required
The Context parameter provides:
- User identification for payment tracking
- Progress reporting capabilities (PROGRESS mode)
- Elicitation support (ELICITATION mode)
- Tool execution metadata
Error Handling
PayMCP handles various error scenarios automatically:
Payment Errors
| Error Type | Description | User Action |
|---|---|---|
| Payment declined | Card/payment method rejected | Try different payment method |
| Insufficient funds | Not enough balance | Add funds or use different method |
| Payment timeout | User didn't complete payment | Retry the tool call |
| Invalid currency | Currency not supported | Use supported currency |
Configuration Errors
| Error Type | Description | Solution |
|---|---|---|
| Invalid API key | Wrong or expired key | Check provider dashboard |
| Missing provider | Provider not configured | Add provider to configuration |
| Invalid mode | Unsupported payment mode | Use supported mode |
Tool Errors
| Error Type | Description | Solution |
|---|---|---|
| Missing context | No ctx parameter | Add ctx: Context parameter |
| Invalid amount | Amount less than or equal to 0 or not numeric | Use valid positive amount |
Advanced Configuration
Multiple Providers
# PayMCP uses the first provider by default
# User will be able to choose how he wants to pay (coming soon)
PayMCP(
mcp,
providers={
"stripe": {"apiKey": "sk_..."},
"walleot": {"apiKey": "wk_..."},
"paypal": {
"client_id": "...",
"client_secret": "..."
}
}
)
Environment Variables
Use environment variables for secure credential storage:
import os
PayMCP(
mcp,
providers={
"stripe": {
"apiKey": os.getenv("STRIPE_SECRET_KEY"),
"success_url": os.getenv("STRIPE_SUCCESS_URL"),
"cancel_url": os.getenv("STRIPE_CANCEL_URL")
}
}
)
Version Information
Current PayMCP version: Check with paymcp.__version__
import paymcp
print(f"PayMCP version: {paymcp.__version__}")
Next Steps
- Quickstart Guide - Get started with PayMCP
- Provider Setup - Configure your payment provider
- Examples - See real-world implementations
- Troubleshooting - Common issues and solutions