Quickstart
Get PayMCP up and running in your MCP server in just a few minutes.
Installation
Install PayMCP:
- Python
- TypeScript
pip install paymcp
npm install paymcp
Requirements
- Python 3.8+ or Node.js 16+
- An MCP server framework (Official MCP SDK recommended)
- Hosted server environment (not STDIO mode)
- API keys from your chosen payment provider
AI Coding Agents (Skills)
If you use an AI coding agent with Skills support, we recommend installing the monetization skill. Skills are folders of instructions and resources that your agent loads when relevant. They teach the agent how to perform specialized tasks like adding pricing, subscriptions, and provider configuration to MCP servers.
Install the monetization skill
If you are using Claude Code, you can install the skill directly with:
/plugin marketplace add PayMCP/skills
/plugin install paymcp@paymcp-skills
You can also use the Vercel Skills CLI to install skills across different AI coding agents:
npx skills add https://github.com/PayMCP/skills --skill monetization
Or copy the skill folder into your agent's skills directory (varies by agent):
| Agent | Skills directory (macOS/Linux) | Skills directory (Windows) |
|---|---|---|
| Claude Code | ~/.claude/skills/ | %USERPROFILE%\\.claude\\skills\\ |
| VS Code and GitHub Copilot | ~/.copilot/skills/ | %USERPROFILE%\\.copilot\\skills\\ |
| Gemini CLI | ~/.gemini/skills/ | %USERPROFILE%\\.gemini\\skills\\ |
| Cline | ~/.cline/skills/ | %USERPROFILE%\\.cline\\skills\\ |
| Goose | ~/.config/goose/skills/ | %USERPROFILE%\\.config\\goose\\skills\\ |
| Codex | ~/.codex/skills/ | %USERPROFILE%\\.codex\\skills\\ |
After installation, you can simply ask your agent to add PayMCP monetization and follow its guided instructions.
Basic Setup
1. Initialize Your MCP Server
- Python
- TypeScript
from mcp.server.fastmcp import FastMCP, Context
from paymcp import PayMCP, price
from paymcp.providers import StripeProvider
mcp = FastMCP("My AI Assistant")
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { installPayMCP } from 'paymcp';
import { StripeProvider } from 'paymcp/providers';
const mcp = new McpServer({name: "My AI Assistant"});
2. Configure PayMCP
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")])
installPayMCP(mcp, { providers: [new StripeProvider({ apiKey: "sk_test_..." })] });
Adding Pricing
- Python
- TypeScript
@mcp.tool()
@price(amount=0.50, currency="USD")
def generate_ai_image(prompt: str, ctx: Context) -> str:
"""Generate an AI image from a text prompt"""
return f"Generated image for: {prompt}"
import { z } from 'zod';
mcp.registerTool(
"generate_ai_image",
{
description: "Generate an AI image from a text prompt",
inputSchema: { prompt: z.string() },
_meta: { price: { amount: 0.50, currency: "USD" } },
},
async ({ prompt }, extra) => {
return { content: [{ type: "text", text: `Generated image for: ${prompt}` }] };
}
);
Different Price Points
- Python
- TypeScript
@mcp.tool()
@price(amount=0.05, currency="USD")
def check_text_grammar(text: str, ctx: Context) -> str:
"""Check and correct grammar in text"""
return corrected_text
@mcp.tool()
@price(amount=2.99, currency="USD")
def analyze_document(document: str, ctx: Context) -> dict:
"""Perform detailed document analysis"""
return analysis_results
import { z } from 'zod';
mcp.registerTool(
"check_text_grammar",
{
description: "Check and correct grammar in text",
inputSchema: { text: z.string() },
_meta: { price: { amount: 0.05, currency: "USD" } },
},
async ({ text }, extra) => {
return { content: [{ type: "text", text: correctedText }] };
}
);
mcp.registerTool(
"analyze_document",
{
description: "Perform detailed document analysis",
inputSchema: { document: z.string() },
_meta: { price: { amount: 2.99, currency: "USD" } },
},
async ({ document }, extra) => {
return { content: [{ type: "text", text: JSON.stringify(analysisResults) }] };
}
);
Subscriptions
Gate tools behind an active subscription instead of pay-by-request.
- Python
- TypeScript
from paymcp import subscription
@mcp.tool()
@subscription(plan="price_pro_monthly") # or a list of accepted plan IDs
async def generate_report(ctx: Context) -> str:
return "Your report"
mcp.registerTool(
"generate_report",
{
title: "Generate report",
description: "Requires an active Pro subscription.",
_meta: { subscription: { plan: "price_pro_monthly" } }, // or an array of accepted plan ids
},
async (extra) => {
return { content: [{ type: "text", text: "Your report" }] };
}
);
Coordination Modes
Choose the mode (AUTO, RESUBMIT, ELICITATION, TWO_STEP, X402, PROGRESS, or DYNAMIC_TOOLS) that works best for your use case:
AUTO (Default)
Automatically detects client capabilities. If X402 is configured and supported by the client, it uses X402; otherwise it uses ELICITATION when supported and falls back to RESUBMIT.
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")], mode=Mode.AUTO)
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.AUTO
});
RESUBMIT (Retry-after-error)
Adds an optional payment_id to the original tool signature.
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")], mode=Mode.RESUBMIT)
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.RESUBMIT
});
Call sequence
- First call: PayMCP invokes the tool without a
payment_id, responds with Payment Required Error containing apayment_urlpluspayment_id, and instructs the client to retry. - Second call: The client calls the same tool again with the returned
payment_id; PayMCP validates payment server-side and runs your original tool logic if paid.
ELICITATION (Interactive)
For real-time interactions.
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")], mode=Mode.ELICITATION)
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.ELICITATION
});
Shows payment link immediately when tool is called (if supported by client) Waits for payment confirmation before proceeding
TWO_STEP
Splits tool execution into two steps.
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")], mode=Mode.TWO_STEP)
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.TWO_STEP
});
Confirmation tool will be added automatically.
X402 (On-chain)
Use this mode only with an x402-capable client and the X402 provider. See the X402 Provider guide for setup details.
- Python
- TypeScript
PayMCP(mcp, providers=[X402Provider(pay_to=[{"address": "0xAddress"}])], mode=Mode.X402)
installPayMCP(mcp, {
providers: [new X402Provider({"payTo":[{"address": "0xAddress"}]})],
mode: Mode.X402
});
By default PayMCP uses the public facilitator at https://facilitator.paymcp.info and no API keys are required. To change facilitators, set facilitator.url. The Coinbase CDP facilitator (https://api.cdp.coinbase.com/platform/v2/x402) requires apiKeyId and apiKeySecret.
PROGRESS (Experimental)
For experimental auto-checking of payment status.
- Python
- TypeScript
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")], mode=Mode.PROGRESS)
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.PROGRESS
});
Shows payment link and progress indicator (if supported by client) Automatically proceeds when payment is received
DYNAMIC_TOOLS (Guided Tool Lists)
For clients that support dynamic tool lists and listChanged notifications:
- Python
- TypeScript
PayMCP(
mcp,
providers=[StripeProvider(apiKey="sk_test_...")],
mode=Mode.DYNAMIC_TOOLS
)
# Temporarily hides/shows tools to steer the next valid action
installPayMCP(mcp, {
providers: [new StripeProvider({ apiKey: "sk_test_..." })],
mode: Mode.DYNAMIC_TOOLS
});
// Temporarily hides/shows tools to steer the next valid action
See the list of MCP clients and their capabilities here: https://modelcontextprotocol.io/clients
Configuring StateStore
By default, PayMCP uses an in-memory StateStore, which does not persist across server restarts. It's highly recommended to use RedisStateStore in production environments.
- Python
- TypeScript
from redis.asyncio import from_url
from paymcp import PayMCP, RedisStateStore
redis = await from_url("redis://localhost:6379")
PayMCP(
mcp,
providers=[''' ... ''' ],
state_store=RedisStateStore(redis)
)
import { createClient } from "redis";
import { installPayMCP, RedisStateStore } from "paymcp";
const redisClient = createClient({ url: "redis://localhost:6379" });
await redisClient.connect();
installPayMCP(mcp, {
providers: [ /* ... */ ],
stateStore: new RedisStateStore(redisClient),
});
Testing Your Integration
1. Start Your Server
- Python
- TypeScript
# server.py
from mcp.server.fastmcp import FastMCP, Context
from paymcp import PayMCP, price
from paymcp.providers import StripeProvider
mcp = FastMCP("Test Server")
PayMCP(mcp, providers=[StripeProvider(apiKey="sk_test_...")])
@mcp.tool()
@price(amount=1.00, currency="USD")
def test_payment_integration(name: str, ctx: Context) -> str:
"""Test payment integration with greeting"""
return f"Hello, {name}! Payment successful."
if __name__ == "__main__":
mcp.run(transport="streamable-http")
// server.ts
import { McpServer, StdioServerTransport } from '@modelcontextprotocol/server';
import { installPayMCP } from 'paymcp';
import { StripeProvider } from 'paymcp/providers';
import { z } from 'zod';
const mcp = new McpServer({name:"Test Server"});
installPayMCP(mcp, { providers: [new StripeProvider({ apiKey: "sk_test_..." })] });
mcp.registerTool(
"test_payment_integration",
{
description: "Test payment integration with greeting",
inputSchema: { name: z.string() },
_meta: { price: { amount: 1.00, currency: "USD" } },
},
async ({ name }, extra) => {
return { content: [{ type: "text", text: `Hello, ${name}! Payment successful.` }] };
}
);
async function main() {
const transport = new StdioServerTransport();
await mcp.connect(transport);
console.log('MCP server is running...');
}
main().catch(error => {
console.error('Server error:', error);
process.exit(1);
});
2. Connect Your MCP Client
For testing, we recommend using the MCP Inspector.
- Run your MCP server code.
- Check the console for the
/mcpURL (e.g.http://127.0.0.1:8000/mcp). - Start the inspector with:
npx @modelcontextprotocol/inspector@latest - In MCP Inspector, select streamable HTTP as the transport type and enter your
/mcpURL.
3. Use Test Credentials
Always use test/sandbox credentials during development:
- Stripe: Use
sk_test_...keys and test card4242424242424242 - PayPal: Set
sandbox=True - Square: Use sandbox environment
- Walleot: Use test API keys
- Coinbase Commerce: No sandbox is available, so test with very small amounts.
- USDC (Base): Use Base-sepolia network (eip155:84532)
- USDC (Solana): Use devnet network (solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1)
Next Steps
✅ Basic setup complete! Your MCP tools will now ask for payment before running.
Explore More:
- Coordination Modes - Learn about different coordination modes
- Provider Guides - Provider-specific configuration
- Examples - Real-world implementation examples
Need help? Check our troubleshooting guide or open an issue.