Build a Paid MCP Server: Charge Users Inside Claude
The Problem: Free AI Agents That Should Earn Money
You've built something useful. Your Claude-powered MCP server generates insights, writes code, or sells digital products. Users love it—but you're not capturing a cent.
Maybe it's a course recommendation bot that should charge $5 per consultation. Or a meal-planning assistant that monetizes premium meal plans. Or a code-generation tool that your agency uses internally and wants to bill customers per API call.
The friction point: payment processors don't integrate seamlessly into AI agent workflows. Stripe webhooks are clunky. PayPal's redirect breaks context. You end up building a separate dashboard, managing invoices outside your agent logic, and losing the magic of conversational commerce.
That's where AgentPay VN changes the game. It's an open-source Python SDK + MCP server that lets AI agents accept VietQR payments—QR codes that point straight to your merchant bank account. No middle-man holding funds. A bank feed confirms settlement within hours.
In this tutorial, you'll learn to embed payment flows directly into Claude conversations and build your first paid MCP server.
Why VietQR? Why AgentPay VN?
The Context: Vietnam's instant payment ecosystem has matured. VietQR is an interbank standard—users scan once, funds settle to your bank account instantly. It's ubiquitous in Vietnamese fintech, trusted, and zero-friction for customers.
Why AgentPay VN over traditional gateways?
| Feature | Stripe/PayPal | AgentPay VN |
|---|---|---|
| Holds funds? | Yes (1–7 days) | No (instant to your bank) |
| AI-agent native? | REST API (clunky) | MCP server (seamless) |
| Open-source? | Closed | MIT licensed (audit, fork, own) |
| For Vietnam market? | Poor UX | Native VietQR (instant adoption) |
| Settlement cost | 2–3% | Minimal |
If your users are in Vietnam (or you're building internationally but want a pilot), AgentPay VN is purpose-built.
Core Concept: The 3-Line Payment Flow
AgentPay VN abstracts payment complexity into three steps:
create_payment_request()— Generate a payment object with amount, description, and metadata.send_checkout_url()— Return a VietQR code URL to the user (they scan from their banking app).await_settlement()— Poll a bank feed or webhook until payment confirms.
No card details passed through your server. No PCI-DSS burden. Funds go straight to your bank account.
Installation & Setup
Step 1: Install the SDK
pip install agentpay-vn
Step 2: Start the MCP Server
agentpay-mcp
This launches a local MCP server (typically on port 3000 or configurable) that Claude can call.
Step 3: Configure Claude (SSE Transport)
Add this to your Claude client config (or .env):
{
"mcpServers": {
"agentpay": {
"command": "agentpay-mcp",
"args": [],
"env": {
"MERCHANT_BANK_ACCOUNT": "your_bank_account_number",
"MERCHANT_NAME": "Your Shop",
"BANK_FEED_URL": "https://your-bank-api.vn/feeds",
"BANK_FEED_API_KEY": "your_api_key"
}
}
}
}
Replace placeholders with your actual merchant bank details (obtained from your bank's developer portal).
Building Your First Paid Agent: A Premium Course Bot
Let's walk through a real scenario: a course recommendation service that charges $10 per personalized curriculum.
The User Experience
User in Claude: "I want to learn machine learning. Create a custom course path."
Agent (Claude + your MCP): "Great! I'll design your path. That's $10. Here's a QR code to pay…"
User scans QR with their banking app → approves → payment settles in seconds.
Agent: "Payment confirmed! Here's your personalized curriculum…"
The Code
Python backend (your MCP handler):
from agentpay_vn import create_payment_request, await_settlement
import json
from uuid import uuid4
async def handle_course_purchase(user_id: str, course_level: str) -> dict:
"""
MCP handler: Create a payment request for a course.
"""
# Step 1: Create the payment request
payment = create_payment_request(
amount=10.00, # USD or VND (set in config)
currency="USD",
description=f"Premium {course_level} ML course for user {user_id}",
merchant_reference=str(uuid4()), # Unique ID for this transaction
metadata={
"user_id": user_id,
"course_level": course_level,
"service": "course_bot"
}
)
# Step 2: Get the VietQR checkout URL (returned to Claude)
checkout_url = payment.get_checkout_url()
return {
"status": "payment_pending",
"message": f"Scan this QR to pay: {checkout_url}",
"checkout_url": checkout_url,
"payment_id": payment.id,
"amount": 10.00
}
async def confirm_course_purchase(payment_id: str, user_id: str) -> dict:
"""
MCP handler: Wait for settlement and return the course.
"""
# Step 3: Await settlement (blocks until payment confirmed or timeout)
settlement = await_settlement(
payment_id=payment_id,
timeout_seconds=300 # 5 minute wait
)
if settlement.status == "settled":
# Build the custom curriculum
curriculum = generate_curriculum(user_id, "advanced")
return {
"status": "success",
"message": "Payment confirmed! Here's your personalized course:",
"curriculum": curriculum,
"settled_at": settlement.timestamp,
"settlement_id": settlement.bank_reference
}
else:
return {
"status": "failed",
"message": "Payment not received. Please try again.",
"error": settlement.error_reason
}
def generate_curriculum(user_id: str, level: str) -> list:
"""Placeholder: your actual curriculum generation logic."""
return [
{"week": 1, "topic": "Linear Algebra Foundations"},
{"week": 2, "topic": "Calculus for ML"},
{"week": 3, "topic": "Probability & Statistics"},
]
Line-by-line breakdown:
- Lines 7–19:
create_payment_request()sets up a $10 transaction tied to the user's ID and course level. Themetadatadict is searchable later (e.g., "show me all ML course purchases"). - Line 23:
.get_checkout_url()returns a VietQR code link. You send this to Claude, Claude displays it to the user. - Lines 30–45:
await_settlement()is a blocking async call. It polls your bank's API (configured in the MCP server env) until the transaction lands in your account. No manual webhook plumbing. - Lines 47–61: If settled, unlock the curriculum. Otherwise, ask the user to retry.
MCP Manifest: Registering Your Handlers
Your MCP server exposes these functions as tools that Claude can invoke:
{
"tools": [
{
"name": "initiate_course_purchase",
"description": "Generate a VietQR payment link for a personalized ML course ($10 USD).",
"inputSchema": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "Unique identifier for the learner"
},
"course_level": {
"type": "string",
"enum": ["beginner", "intermediate", "advanced"],
"description": "Difficulty level"
}
},
"required": ["user_id", "course_level"]
}
},
{
"name": "confirm_course_purchase",
"description": "Check if payment settled and unlock the course.",
"inputSchema": {
"type": "object",
"properties": {
"payment_id": {
"type": "string",
"description": "ID from the payment request"
},
"user_id": {
"type": "string"
}
},
"required": ["payment_id", "user_id"]
}
}
]
}
Clause automatically discovers these tools and invokes them during conversation.
Advanced: Handling Multiple Currencies & Recurring Payments
Multi-Currency Support
AgentPay VN auto-converts USD/EUR to VND at real-time rates:
payment = create_payment_request(
amount=10.00,
currency="USD", # Automatically converts to VND
description="Premium service"
)
Recurring Subscriptions (Monthly Membership)
from agentpay_vn import create_subscription
subscription = create_subscription(
amount=5.00,
currency="USD",
frequency="monthly",
user_id="user_123",
metadata={"plan": "pro"}
)
checkout_link = subscription.get_checkout_url()
# User scans once; future payments auto-settle each month
Do's and Don'ts
| ✅ Do | ❌ Don't |
|---|---|
Store payment_id + user_id in your database for reconciliation |
Assume await_settlement() is instant (it's ~5–30 seconds) |
Use metadata to attach rich context (course, user tier, referral code) |
Log bank account numbers or sensitive data |
Call await_settlement() in a separate async task to avoid blocking Claude |
Retry indefinitely without exponential backoff |
| Display the VietQR URL immediately so users can scan while chatting | Redirect users away from Claude mid-conversation |
| Reconcile daily: compare your DB records to bank feed exports | Hardcode API keys (use environment variables) |
Real-World Example: An Eco-Friendly Café Upsells Merch
Scenario: A café bot recommends eco-friendly merchandise (bamboo straws, reusable cups) to customers based on their order history.
Flow:
- Customer asks: "What's the most sustainable coffee cup?"
- Bot recommends a $15 ceramic cup with personalized engraving.
- Claude calls
initiate_merch_purchase()→ generates VietQR. - Customer scans QR in their banking app (3 seconds).
- Money lands in café's account.
- Bot calls
confirm_merch_purchase()→ immediately sends engraving instructions.
Why this works: Humans already trust their banking app. No login, no card entry, no extra friction. Conversion rates for VietQR in Vietnam are 3–5× higher than traditional checkout forms.
Troubleshooting Common Issues
Q: Payment settled but await_settlement() didn't return?
- Check your bank feed API key. The MCP server needs live access to confirm deposits.
- Increase timeout_seconds to 600 (10 minutes) if your bank feed has latency.
Q: "Connection refused" when starting agentpay-mcp?
- Ensure port 3000 is free: lsof -i :3000 and kill the process if needed.
- Or specify a custom port: agentpay-mcp --port 3001.
Q: How do I test locally without real money?
- Use AgentPay VN's sandbox mode: SANDBOX_MODE=true agentpay-mcp.
- Payments are simulated; no real bank calls.
FAQ
Does AgentPay VN hold my money?
No. The VietQR code points directly to your merchant bank account. Funds settle there within minutes. AgentPay VN only orchestrates the payment flow and confirms settlement via your bank's API.
What if a user's bank doesn't support VietQR?
VietQR is now standard across 30+ major Vietnamese banks (Vietcombank, BIDV, ACB, Techcombank, etc.). Fallback: you can offer traditional bank transfer as a secondary option outside the MCP server.
Can I use AgentPay VN outside Vietnam?
Yes, if your users are in Vietnam or have Vietnamese bank accounts. International users would need a non-VietQR payment processor (integrate both side-by-side).
Is there a fee?
AgentPay VN itself is free (MIT licensed). Bank settlement fees are minimal—typically 0.5–1% depending on your bank's merchant tier. No payment holding fees, no escrow costs.
Key Takeaways
- AgentPay VN = AI agent payments without holding funds. Money goes straight to your bank account.
- VietQR is frictionless in Vietnam. Scan → pay → settled in seconds. Higher conversion than traditional gateways.
- Embed payments in Claude conversations. Users never leave the chat to enter card details.
- 3-line flow:
create_payment_request()→send_checkout_url()→await_settlement(). - Open-source & self-hosted. Audit the code, fork it, run it on your infrastructure.
- Real-world use cases: courses, merchandise, API credits, consulting time, meal plans, SaaS tiers.
What's Next?
You're ready to monetize your AI agents. Here's your action plan:
- Install AgentPay VN:
pip install agentpay-vn - Set up your merchant bank account with your bank's developer portal.
- Configure the MCP server with your bank feed API key.
- Build your first payment handler using the course bot example above.
- Test in Claude sandbox mode before going live.
- Deploy and watch payments roll in.
For detailed API docs, examples, and troubleshooting, visit https://agentpay.servicesai.vn/v1/docs.
GitHub repo (star it, fork it, contribute): https://github.com/phuocdu/agentpay-vn
Happy charging! 🎉