Build a Paid MCP Server: Charge Users Inside Claude
The Problem: Your AI Agent Works, But Where's the Money?
You've built an incredible Claude-powered MCP server. It writes resumes. It designs logos. It analyzes financial documents. Users love it—but you're not getting paid.
Every day, thousands of developers face this exact wall: their AI agents create real value, but monetizing that value through traditional payment gateways feels like friction. Stripe integrations are overkill for a side project. International payments are a headache. And worst of all, you're forced to choose between a clunky checkout flow that breaks your user's experience or no revenue at all.
That's where AgentPay VN changes the game. Imagine this: a user asks Claude to generate a custom business plan. Before delivering it, your MCP server generates a VietQR payment request—a single QR code. The user scans with their phone banking app. The payment settles directly into your account. The user gets their file. No merchant accounts. No hold periods. No complexity.
This tutorial walks you through building exactly that: a production-ready, paid MCP server that charges users from inside Claude itself.
Why VietQR? Why Now?
VietQR is Vietnam's national instant payment infrastructure. Every major bank supports it. Your customer already has it in their banking app. Unlike traditional card payments:
- Direct settlement: Money hits your bank account in minutes, not days.
- Zero fees: AgentPay never touches the funds. The QR points straight at your merchant account.
- Instant confirmation: Your MCP server knows payment status via bank feeds—no polling, no webhooks to manage.
- Frictionless UX: QR codes feel native to mobile users in Southeast Asia and beyond.
AgentPay VN is the open-source glue (MIT license) that makes this work inside Claude.
Architecture: How It Works
Before code, understand the flow:
- User requests a paid service from your Claude MCP server (e.g., "Generate a logo").
- Your server calls
create_payment_request()with amount, description, and merchant bank details. - AgentPay VN generates a VietQR code and returns a checkout URL.
- Your MCP server returns the checkout URL to Claude; Claude presents it to the user.
- User scans the QR or clicks the link, confirms payment in their banking app.
- Your server calls
await_settlement()to detect when the payment cleared. - Once confirmed, your MCP delivers the paid content (file download, API access, etc.).
The entire transaction is atomic: either the user pays and gets the good, or they don't.
Step 1: Install and Configure AgentPay VN
Installation
Start with the SDK:
pip install agentpay-vn
For MCP server support (Claude Desktop / LM Studio compatibility):
pip install agentpay-mcp
Environment Setup
Create a .env file with your VietQR merchant details:
# .env
MERCHANT_BANK_ACCOUNT=0123456789 # Your bank account number
MERCHANT_BANK_CODE=MB # Your bank code (MB, VCB, TCB, etc.)
MERCHANT_NAME=My AI Service # Display name on payment
AGENTPAY_API_KEY=your_key_here # Optional: for advanced features
Step 2: Build Your First Paid MCP Server
Here's a real example: a resume-writing service that charges per document.
Python Implementation
import os
from dotenv import load_dotenv
from agentpay_vn import PaymentClient, PaymentRequest, SettlementWatcher
import asyncio
load_dotenv()
# Initialize AgentPay client
payment_client = PaymentClient(
merchant_bank_account=os.getenv('MERCHANT_BANK_ACCOUNT'),
merchant_bank_code=os.getenv('MERCHANT_BANK_CODE'),
merchant_name=os.getenv('MERCHANT_NAME')
)
async def charge_for_resume(user_id: str, resume_data: dict) -> dict:
"""
Step 1: Create a payment request for a premium resume (500,000 VND)
"""
payment_req = PaymentRequest(
amount_vnd=500_000, # 500k VND (≈$20 USD)
description=f"Premium Resume for {user_id}",
metadata={ # Attach context
"user_id": user_id,
"service": "resume_generator",
"template": resume_data.get("template")
}
)
# Step 2: Generate VietQR checkout link
payment_response = await payment_client.create_payment_request(payment_req)
print(f"Checkout URL: {payment_response.checkout_url}")
print(f"QR Code: {payment_response.qr_code_url}")
print(f"Request ID: {payment_response.request_id}")
# Step 3: Wait for settlement (polls bank feed every 5 seconds, timeout 5 min)
settlement = await payment_client.await_settlement(
request_id=payment_response.request_id,
timeout_seconds=300,
poll_interval_seconds=5
)
if settlement.is_settled:
# Payment confirmed! Now generate the premium resume
resume_pdf = generate_premium_resume(resume_data)
return {
"status": "success",
"download_url": upload_to_storage(resume_pdf),
"transaction_id": settlement.transaction_id,
"settled_at": settlement.settled_at.isoformat()
}
else:
return {
"status": "payment_timeout",
"request_id": payment_response.request_id,
"message": "Payment not received within 5 minutes"
}
def generate_premium_resume(data: dict) -> bytes:
"""Generate a fancy PDF resume (your logic here)"""
# Use reportlab, fpdf, or a templating service
pass
def upload_to_storage(pdf_bytes: bytes) -> str:
"""Upload to S3 / GCS and return signed download link"""
pass
# Test it
if __name__ == "__main__":
result = asyncio.run(charge_for_resume(
user_id="user_42",
resume_data={"name": "John Doe", "template": "modern"}
))
print(result)
Line-by-line breakdown:
- Lines 13-17: Initialize the client with your bank details.
- Lines 22-35: Define payment request with amount (500k VND = ~$20), description, and metadata (useful for logging which user paid for what).
- Line 38: Call
create_payment_request()to generate the VietQR checkout link. - Lines 42-45: Log the URLs for debugging or returning to the user.
- Lines 48-54:
await_settlement()blocks until the bank confirms the payment or 5 minutes pass. This is your gate: only after this returnsis_settled=Truedo you deliver the paid content. - Lines 56-61: Conditional logic: if settled, generate & deliver; otherwise, return error.
Step 3: Wire It Into Claude via MCP
AgentPay includes an MCP server. Configure it in Claude Desktop:
MCP Server Configuration (Claude settings)
{
"mcpServers": {
"agentpay": {
"command": "python",
"args": [
"-m",
"agentpay_mcp",
"--merchant-account",
"0123456789",
"--merchant-bank",
"MB",
"--merchant-name",
"My AI Resume Service"
],
"env": {
"AGENTPAY_API_KEY": "your_api_key_here"
}
}
}
}
Once configured, Claude can call three tools directly:
-
create_payment: Generate a checkout link.Claude: "User wants a premium resume. Let me charge them." Tool call: create_payment(amount_vnd=500000, description="Premium Resume") Response: {"checkout_url": "https://...", "request_id": "req_xyz"} -
wait_for_payment: Block until settlement.Tool call: wait_for_payment(request_id="req_xyz", timeout=300) Response: {"settled": true, "transaction_id": "txn_123"} -
get_payment_status: Check status without blocking.Tool call: get_payment_status(request_id="req_xyz") Response: {"status": "pending", "amount": 500000}
Real-World Walkthrough: AI Café Menu Customizer
Imagine you run a café and want to sell custom menu designs to other small businesses.
The Flow
- User prompt: "I need a Vietnamese café menu in 15 minutes."
- Claude checks the request: Needs design work → premium feature.
- Claude calls MCP:
create_payment(amount_vnd=200_000, description="Custom Café Menu Design") - User sees: A VietQR code in the chat. They scan it with their banking app.
- User confirms the 200k VND charge (≈$8).
- Claude polls via
wait_for_payment(). After 30 seconds, settlement confirms. - Claude generates a beautiful menu PDF using Canva API or custom design tool.
- User downloads the menu in chat.
Total time: 2 minutes. Friction: Near zero. Revenue per transaction: 200k VND.
Scale this to 10 requests per day = 2M VND/day = 60M VND/month (≈$2,500 USD). That's real money for AI automation.
Best Practices vs. Common Pitfalls
| ✅ Do | ❌ Don't |
|---|---|
| Set realistic timeouts (300s = 5 min) | Don't wait forever; users get impatient |
Log request_id and metadata for audits |
Don't lose payment records; you need them for refunds/taxes |
| Handle settlement timeouts gracefully | Don't crash if payment doesn't confirm; retry or refund |
| Show the checkout URL immediately | Don't delay showing the QR code; users see it as lag |
| Validate amounts server-side (prevent manipulation) | Don't trust client-supplied amounts |
| Use settlement confirmation, not just "pending" | Don't deliver content before is_settled=True |
Advanced: Async Patterns & Scaling
For high-volume services (100+ concurrent requests):
import asyncio
from concurrent.futures import ThreadPoolExecutor
async def handle_bulk_payments(requests: list):
"""
Process multiple payment requests in parallel.
"""
tasks = [
charge_for_resume(req["user_id"], req["data"])
for req in requests
]
results = await asyncio.gather(*tasks) # Concurrent execution
return results
# Usage
requests = [
{"user_id": "u1", "data": {...}},
{"user_id": "u2", "data": {...}},
# ...
]
results = asyncio.run(handle_bulk_payments(requests))
Why this matters: If you're serving 100 Claude users simultaneously, you don't want payment confirmations to block each other. Async allows your MCP server to handle multiple payments in parallel.
FAQ
Q1: What if the user scans the QR but never completes payment?
A: await_settlement() times out after 5 minutes (configurable). You then return a message like "Payment not received. The payment request has expired. Please try again." The user can request a fresh checkout link.
Q2: Does AgentPay take a cut? A: No. AgentPay is MIT open-source and doesn't touch money. The QR points directly at your merchant bank account. You keep 100% of the payment (minus your bank's flat fee if any).
Q3: How do I handle refunds?
A: Store the bank transaction ID (settlement.transaction_id) for each payment. If a user requests a refund, you initiate a reverse transfer from your bank dashboard using that transaction ID. AgentPay doesn't manage refunds—that's between you and your bank.
Q4: Can I use this outside Vietnam? A: VietQR is a Vietnam-only infrastructure right now, but AgentPay's architecture is designed to support other regional payment schemes (India's UPI, Thailand's PromptPay, etc.) in future versions. For now, target Vietnamese users or SE Asia expat communities.
Key Takeaways
- VietQR payments settle in minutes, not days. Your MCP server can confirm payment and deliver content immediately.
- AgentPay VN eliminates friction: one QR code, one scan, money in your account. No merchant accounts. No delays.
- The 3-line pattern is powerful:
create_payment_request()→send checkout_url()→await_settlement(). Memorize it. - Metadata is crucial: Store
user_id, service type, andrequest_idin every payment. You'll need it for taxes, audits, and customer support. - Async/concurrent patterns scale. If you're monetizing AI agents for dozens of users, parallel payment handling is non-negotiable.
- Test locally first: Use sandbox mode (check docs) before going live with real bank credentials.
Get Started Now
Your first paid MCP server is three commands away:
pip install agentpay-vn
pip install agentpay-mcp
# Copy the code above, set your .env, run it
Resources:
- Installation & docs: https://agentpay.servicesai.vn/v1/docs
- GitHub (MIT source code): https://github.com/phuocdu/agentpay-vn
- Python SDK:
pip install agentpay-vn - MCP server:
pip install agentpay-mcp
The barrier to monetizing AI agents just dropped. Your Claude instance can accept payments in minutes. Build that paid MCP server today.