Build a Paid MCP Server: Charge Users Inside Claude
The Problem: Free AI Agents Don't Pay Your Bills
You've built a brilliant Claude-powered MCP server—maybe it drafts legal contracts, analyzes market data, or automates customer support. Users love it. But then the question hits: How do you charge them?
Traditional payment gateways require redirects away from Claude. Stripe webhooks need careful orchestration. Transaction fees eat 2–3% of every dollar. And if you're in Vietnam or Southeast Asia, you're navigating currency conversions and cross-border friction that compounds the pain.
Worst of all: you're building tools for an AI agent ecosystem where the agent never leaves the conversation. Asking Claude to open a payment page breaks the flow entirely.
That's where AgentPay VN changes the game. It's a purpose-built Python SDK + MCP server that lets AI agents collect payments directly through VietQR—Vietnam's unified QR payment standard—without ever holding funds. Money flows straight to your merchant bank account. Settlement is instant and transparent.
In this tutorial, you'll learn to build a paid MCP server that charges users from inside Claude—in about 30 minutes.
Why AgentPay VN for Paid MCP Servers?
Let's be clear: AgentPay VN isn't a general payment processor. It's architected for a specific, powerful use case:
AI agents collecting payments in conversation.
Here's what makes it different:
- Zero friction: Agents generate a VietQR checkout URL. Users scan or click it. Payment settles. Agent proceeds.
- No escrow: Unlike traditional gateways, AgentPay never holds money. The QR code points directly at your bank account. A bank feed confirms settlement in seconds.
- Open source (MIT): Full transparency. No vendor lock-in. Run it anywhere.
- MCP-native: Works seamlessly with Claude and other MCP clients. It's not bolted on—it's designed for agents.
- Instant settlement: For VietQR, settlement happens within minutes, not days.
The catch? It's built for Vietnamese markets and VietQR infrastructure. If your users are in Vietnam or Southeast Asia, this is a no-brainer. If not, you'll need local bank integration.
How AgentPay VN Works: The 3-Line Flow
Before diving into code, understand the flow:
create_payment_request(): Agent asks for payment. You create a request with amount, description, and merchant bank details.send_checkout_url(): Agent gets back a VietQR URL. It's shared with the user (in chat, via email, or QR code).await_settlement(): Agent waits for bank confirmation. Once settled, it unlocks the service (download file, generate report, etc.).
No webhooks. No polling loops. Just clean, agent-native payment flow.
Step 1: Install and Configure AgentPay VN
Installation
pip install agentpay-vn
That's it. No API keys. No OAuth flows. Just the SDK.
If you're running an MCP server, also install the official server:
pip install agentpay-mcp
Configure Your Bank Details
You'll need:
- Bank account number (your merchant account)
- Bank code (e.g., 970407 for Techcombank, 970418 for Agribank)
- Account holder name (registered with your bank)
Store these securely in environment variables:
export AGENTPAY_BANK_ACCOUNT="0123456789"
export AGENTPAY_BANK_CODE="970407"
export AGENTPAY_ACCOUNT_NAME="Your Business Name"
Step 2: Create Your First Payment Request
Here's a real Python example—a course-selling bot:
from agentpay_vn import PaymentManager, PaymentRequest
import os
from datetime import datetime
# Initialize the payment manager
payment_mgr = PaymentManager(
bank_account=os.getenv("AGENTPAY_BANK_ACCOUNT"),
bank_code=os.getenv("AGENTPAY_BANK_CODE"),
account_name=os.getenv("AGENTPAY_ACCOUNT_NAME")
)
# User wants to buy a "Python for AI Agents" course
request = PaymentRequest(
amount=450_000, # VND (roughly $18 USD)
description="Python for AI Agents - Advanced Module",
reference_id="course_001_user_john", # Track which user/product
metadata={
"course_id": "python-ai-agents",
"user_email": "john@example.com",
"duration_days": 30
}
)
# Create the payment request
response = payment_mgr.create_payment_request(request)
print(f"Checkout URL: {response.checkout_url}")
print(f"Request ID: {response.request_id}")
print(f"QR Code: {response.qr_code_url}")
Line-by-line breakdown:
- Lines 1–2: Import AgentPay VN modules and standard libraries.
- Lines 5–10: Initialize PaymentManager with your bank credentials from environment variables. This happens once, typically on server startup.
- Lines 12–21: Create a PaymentRequest. amount is in VND. reference_id ties payment back to your app (course ID + user). metadata stores extra context (course details, email, etc.).
- Lines 23–24: Call create_payment_request(). It generates a unique VietQR payload and returns a response with checkout_url, request_id, and QR code image.
Step 3: Send the Checkout URL to the User
Now the agent presents the payment to Claude:
# In your MCP tool handler (e.g., Flask, FastAPI, or raw MCP)
def buy_course(course_id: str, user_email: str):
"""
MCP tool: User requests to buy a course.
Agent calls this, gets back a payment URL, and shares it with the user.
"""
# Validate and fetch course
course = get_course_from_db(course_id)
if not course:
return {"error": "Course not found"}
# Create payment request
request = PaymentRequest(
amount=course.price_vnd,
description=f"Purchase: {course.title}",
reference_id=f"{course_id}_{user_email}",
metadata={"course_id": course_id, "user_email": user_email}
)
payment_response = payment_mgr.create_payment_request(request)
# Return checkout details to the agent
return {
"status": "payment_required",
"checkout_url": payment_response.checkout_url,
"message": f"Please scan the QR code or click the link to pay {course.price_vnd:,} VND",
"request_id": payment_response.request_id
}
The agent now has a URL. It can: - Display it in the chat for the user to click. - Embed the QR code image. - Send it via email or SMS. - Wait for payment confirmation (next step).
Step 4: Wait for Settlement and Unlock the Service
Once the user pays, AgentPay VN polls your bank feed and confirms settlement:
async def deliver_course_after_payment(request_id: str, course_id: str, user_email: str):
"""
Wait for payment settlement, then unlock the course.
"""
# Poll for settlement (timeout after 5 minutes)
settlement = await payment_mgr.await_settlement(
request_id=request_id,
timeout_seconds=300
)
if not settlement:
return {
"error": "Payment not received within 5 minutes. Please try again.",
"status": "timeout"
}
# Payment confirmed! Unlock the course
print(f"✓ Payment settled: {settlement.transaction_id}")
print(f" Amount: {settlement.amount_received} VND")
print(f" Timestamp: {settlement.settled_at}")
# Grant access
grant_course_access(user_email, course_id, expires_days=30)
# Generate download link
download_link = generate_course_download_link(course_id, user_email)
return {
"status": "delivered",
"message": "Course unlocked! Here's your download link.",
"download_url": download_link,
"transaction_id": settlement.transaction_id
}
What's happening:
- await_settlement(): Polls your bank feed (or AgentPay's settlement API) until the payment arrives. Waits up to 5 minutes.
- Settlement object: Contains transaction ID, amount received, and timestamp. Use this for record-keeping.
- Unlock: Once confirmed, you grant access, generate download links, or activate accounts.
Integrate with Claude via MCP
Here's how to wire AgentPay VN into Claude as an MCP server:
MCP Configuration (Claude Desktop)
Add this to your claude_desktop_config.json:
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": ["-m", "agentpay_mcp"],
"env": {
"AGENTPAY_BANK_ACCOUNT": "0123456789",
"AGENTPAY_BANK_CODE": "970407",
"AGENTPAY_ACCOUNT_NAME": "Your Business Name",
"AGENTPAY_TIMEOUT_SECONDS": "300"
}
}
}
}
Now Claude can call AgentPay tools natively:
User: "I want to buy the advanced Python course."
Claude (with AgentPay MCP):
1. Calls: create_payment_request(amount=450000, description="...")
2. Gets: checkout_url = "https://qr.agentpay.vn/..."
3. Shows: "Please scan this QR code to pay 450,000 VND"
4. Calls: await_settlement(request_id="...")
5. Once settled: "Payment confirmed! Your course is unlocked. Download here: [link]"
All in the Claude conversation. No redirects. No friction.
Real-World Example: Café Loyalty Program Bot
Imagine a café that sells memberships via AI agent:
Scenario: Customer chats with a bot. Bot offers a "Premium Member" tier: 20% discount, free coffee monthly, priority ordering. Price: 199,000 VND/month.
async def offer_membership(user_id: str, tier: str = "premium"):
"""Agent offers café membership to user."""
pricing = {
"basic": {"vnd": 99_000, "duration_days": 30, "features": ["5% discount"]},
"premium": {"vnd": 199_000, "duration_days": 30, "features": ["20% discount", "free coffee"]},
}
tier_info = pricing[tier]
# Create payment
payment = PaymentRequest(
amount=tier_info["vnd"],
description=f"Café Membership: {tier.title()}",
reference_id=f"membership_{user_id}_{tier}",
metadata={"user_id": user_id, "tier": tier, "duration_days": tier_info["duration_days"]}
)
response = payment_mgr.create_payment_request(payment)
# Wait for payment
settlement = await payment_mgr.await_settlement(response.request_id, timeout_seconds=600)
if settlement:
# Activate membership in café database
activate_membership(user_id, tier, duration_days=tier_info["duration_days"])
return f"✓ Welcome to {tier.title()} membership! Enjoy {', '.join(tier_info['features'])}"
else:
return "Payment not received. Try again later."
The agent handles the entire funnel—no human intervention needed.
Do's and Don'ts
| Do | Don't |
|---|---|
Store reference_id in your database for reconciliation. |
Hardcode bank credentials in code. Use environment variables. |
Use metadata to track context (course_id, user_email, etc.). |
Reuse the same request_id for multiple payments. |
Set reasonable timeout_seconds (300–600). Users need time to scan and pay. |
Assume payment is instant. Always await_settlement(). |
| Log transaction IDs and settlement timestamps for auditing. | Process requests without verifying the settlement object. |
| Test with small amounts first (e.g., 1,000 VND). | Ignore bank errors or network failures. Implement retry logic. |
Advanced: Handling Edge Cases
Timeout and Retry Logic
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10))
async def settle_with_retry(request_id: str):
"""Retry settlement check up to 3 times with exponential backoff."""
settlement = await payment_mgr.await_settlement(request_id, timeout_seconds=120)
if not settlement:
raise Exception(f"Settlement failed for {request_id}")
return settlement
Batch Processing
For high-volume scenarios (e.g., course platform with 100+ daily sales):
from concurrent.futures import ThreadPoolExecutor
async def process_pending_payments(limit: int = 50):
"""Check settlements for all pending payments."""
pending = get_pending_payments_from_db(limit=limit)
with ThreadPoolExecutor(max_workers=5) as executor:
for payment in pending:
executor.submit(settle_with_retry, payment.request_id)
FAQ
Q: What if the user's bank account doesn't support VietQR? A: VietQR is the unified standard in Vietnam; nearly all accounts support it. But if a user's bank is outside Vietnam, they won't be able to pay. Integrate a fallback (e.g., Stripe, PayPal) for international users.
Q: Does AgentPay VN charge transaction fees? A: No. It's open-source (MIT). You pay only what your bank charges for VietQR transfers (typically 0–0.5% or flat 1,000–2,000 VND per transaction).
Q: Can I test locally before going live?
A: Yes. Use a test bank account and set AGENTPAY_ENV=staging in your environment. Amounts up to 1,000 VND won't settle (sandbox mode).
Q: What if settlement fails?
A: Implement retry logic (see Advanced section). If the user's payment truly fails, await_settlement() returns None after the timeout. You can then ask the user to try again or provide a refund code.
Key Takeaways
- AgentPay VN is built for AI agents: No redirects, no friction. Payment happens inside the conversation.
- Zero escrow: Money flows straight to your bank. No middleman holding funds.
- 3-line flow: Create request → Send URL → Await settlement. Simple, predictable.
- MCP-native: Works seamlessly with Claude and other MCP clients.
- Open source: Full transparency, run anywhere, no vendor lock-in.
- Instant settlement: VietQR payments settle in minutes, not days.
- Best for Vietnam/Southeast Asia: Optimized for local infrastructure and markets.
Get Started Now
Ready to monetize your AI agents? Here's your next step:
- Install:
pip install agentpay-vn - Read the docs: https://agentpay.servicesai.vn/v1/docs
- Explore the code: https://github.com/phuocdu/agentpay-vn
- Set your bank credentials in environment variables.
- Build your first payment tool using the examples above.
Your AI agent can be collecting payments by tomorrow. No complex integrations. No friction. Just clean, agent-native monetization.
Questions? Jump into the GitHub discussions or check the docs. Happy building!