Build a Paid MCP Server: Charge Users Inside Claude
The Problem: AI Agents That Can't Earn
Imagine you've built a Claude-powered tutoring bot that genuinely helps students prepare for exams. It's brilliant—personalized explanations, adaptive difficulty, real-time feedback. But there's a problem: you can't charge anyone.
Your agent runs inside Claude's MCP (Model Context Protocol) framework. Users love it. Yet every response it gives is free labor. No Stripe webhook magic, no PayPal integration—those were built for websites and apps, not for AI agents operating inside a conversation.
This is the gap AgentPay VN fills. In the next 15 minutes, you'll learn to turn your Claude agent into a revenue-generating service that charges users directly from their Vietnamese bank accounts—no middleman, no money held by your platform, just instant settlement straight to your merchant account.
Why AgentPay VN Is Different: No Middle Layer
Traditional payment processors were designed for businesses, not agents. They hold your money, take days to settle, require hosting. AgentPay VN inverts this:
- Zero balance risk: The QR code points directly at your bank account. No funds ever touch AgentPay's systems.
- Instant confirmation: A bank feed ping confirms settlement within seconds, so your agent knows payment arrived before serving premium content.
- MIT-licensed, open: You own the code. No surprise API changes, no vendor lock-in.
- Made for agents: The SDK speaks agent—simple request/response, no webhooks required.
For a Vietnamese business, this is decisive. You get VietQR compliance out of the box, and payments clear to your Viet bank account immediately.
The Three-Line Flow
Before we code, understand the heartbeat:
create_payment_request → send checkout_url → await_settlement
That's it. Your agent creates a request, gives the user a VietQR URL, then pauses until the bank confirms the user paid. Once confirmed, unlock the feature.
Setting Up AgentPay VN
Installation
pip install agentpay-vn
That's all. No account signup, no API keys (yet). The SDK works with your own bank details.
Your First Payment Request
Here's a complete, annotated example:
from agentpay_vn import PaymentProcessor
import asyncio
# Initialize with your merchant bank account
processor = PaymentProcessor(
merchant_account_number="0123456789",
merchant_bank_code="970403", # Example: MB Bank
merchant_name="My Tutoring Bot"
)
async def charge_for_exam_prep():
# Step 1: Create a payment request for 50,000 VND (exam prep package)
payment_request = await processor.create_payment_request(
amount_vnd=50000,
description="Premium Exam Prep: Full Math & Physics Package",
user_id="student_123",
order_id="order_2024_001"
)
# payment_request now contains:
# - checkout_url: The VietQR link the student scans
# - request_id: Unique ID to track this payment
# - qr_code: Raw QR image data (optional)
print(f"Share this URL: {payment_request.checkout_url}")
print(f"Waiting for payment confirmation...")
# Step 2: Wait for the bank to confirm settlement
settlement = await processor.await_settlement(
request_id=payment_request.request_id,
timeout_seconds=600 # 10-minute window; user must pay within this time
)
if settlement.confirmed:
print(f"✓ Received {settlement.amount_vnd} VND in {settlement.settlement_time}")
# Unlock premium content
return {"status": "paid", "features": ["advanced_problems", "live_explanations"]}
else:
print("✗ Payment timed out or failed.")
return {"status": "unpaid", "features": []}
# Run it
result = asyncio.run(charge_for_exam_prep())
Line-by-line breakdown:
- Lines 4–8: Initialize the processor with your bank details.
merchant_bank_codeis the NAPAS code for your bank (MB = 970403, VCB = 970436, etc.). - Line 12: Create a payment request for 50,000 VND. The
user_idandorder_idlet you track who paid for what. - Line 23: The
checkout_urlis your money maker—this is the VietQR link the user scans with their phone to pay. - Line 27:
await_settlementis the magic. The agent pauses here, polling your bank account via the bank feed, until payment lands. - Lines 35–36: Once confirmed, you know the user paid. Unlock features, serve premium responses, etc.
Integrating with Claude via MCP
Now the real power: embed this payment flow directly into a Claude MCP server. Claude calls your tools, your tools can request payment, and the conversation pauses until the user pays.
MCP Server Configuration
Create mcp_server.py:
from mcp.server import Server
from mcp.types import Tool, TextContent
from agentpay_vn import PaymentProcessor
import json
import asyncio
server = Server("paid-tutoring-bot")
processor = PaymentProcessor(
merchant_account_number="0123456789",
merchant_bank_code="970403",
merchant_name="My Tutoring Bot"
)
@server.call_tool()
async def request_premium_explanation(user_id: str, topic: str, amount_vnd: int = 25000):
"""
User asks for a deep dive on a topic.
If they haven't paid, request payment.
If they have, unlock the explanation.
"""
# Check if user has an active subscription/credit
is_paid = await processor.check_user_balance(user_id)
if not is_paid:
# Initiate payment
payment = await processor.create_payment_request(
amount_vnd=amount_vnd,
description=f"Premium explanation: {topic}",
user_id=user_id,
order_id=f"exp_{user_id}_{topic}"
)
return TextContent(
text=f"This premium explanation costs {amount_vnd:,} VND. "
f"Scan this QR to pay: {payment.checkout_url}\n"
f"Once you pay, I'll give you the full breakdown."
)
else:
# User is paid; serve the premium content
explanation = generate_deep_explanation(topic)
return TextContent(text=explanation)
if __name__ == "__main__":
server.run()
Claude's Claude Settings (claude_config.json)
Tell Claude about your paid service:
{
"name": "paid-tutoring-bot",
"description": "Premium tutoring with AI-powered explanations and payment via VietQR",
"mcp_servers": [
{
"name": "tutoring-server",
"url": "sse://localhost:3000",
"tools": [
{
"name": "request_premium_explanation",
"description": "Unlock deep-dive explanations on any topic for 25,000 VND",
"input_schema": {
"type": "object",
"properties": {
"user_id": {"type": "string"},
"topic": {"type": "string"},
"amount_vnd": {"type": "integer", "default": 25000}
},
"required": ["user_id", "topic"]
}
}
]
}
]
}
Now when a user chats with Claude and asks for premium content, Claude automatically calls request_premium_explanation, which presents the VietQR link. Once the user pays, the agent unlocks the goods.
Real-World Walkthrough: An Online Café Shop
Let's ground this in reality. Imagine Cà Phê Thông Minh (Smart Café), a Vietnamese coffee shop offering a Claude-powered ordering bot.
Scenario: A customer asks: "I want your special pour-over latte and a croissant, but suggest the best pairing."
-
Claude responds: "I'd recommend our Ethiopia Yirgacheffe single-origin with our almond croissant—the brightness complements the nuttiness. Your order is 185,000 VND." Claude calls
create_payment_request. -
Bot sends VietQR: The customer sees a QR code in the chat. They scan it with their banking app and pay 185,000 VND from their Vietcombank account.
-
Instant confirmation: AgentPay's bank feed detects the payment within 3 seconds. Your MCP server's
await_settlementresolves. -
Bot confirms: "Payment received! Your order is confirmed. Pick up at counter 3 in 12 minutes." The café's POS system is already printing the receipt.
-
Zero friction: No separate checkout page, no third-party app, no fees beyond the standard NAPAS fee (0.5–1%). The money lands in Cà Phê Thông Minh's bank account instantly.
This works because: - The café owns the bank account—no middleman. - VietQR is ubiquitous in Vietnam; every customer recognizes it. - The agent pauses mid-conversation while awaiting payment, creating natural UX. - Settlement is instant, so the kitchen starts working immediately.
Advanced: Subscriptions and Refunds
Once you've mastered basic payments, consider:
Recurring Payments (Monthly Subscription)
async def enable_monthly_subscription(user_id: str, plan: str = "pro"):
"""
Charge a user monthly (e.g., 199,000 VND for Premium access).
In production, store the recurring_id in your DB and check monthly.
"""
pricing = {"basic": 99000, "pro": 199000, "elite": 399000}
amount = pricing.get(plan, 199000)
payment = await processor.create_payment_request(
amount_vnd=amount,
description=f"Monthly subscription: {plan.upper()}",
user_id=user_id,
order_id=f"sub_{user_id}_{int(time.time())}",
recurring=True # Mark as recurring
)
# In a production system, store payment.recurring_id
# and schedule a monthly charge via a cron job
return payment
Handling Refunds
If a user requests a refund (e.g., they're unsatisfied), use:
async def refund_payment(request_id: str, reason: str):
"""
Refund a payment. AgentPay handles the bank transfer reversal.
"""
refund = await processor.refund_payment(
original_request_id=request_id,
reason=reason
)
return refund.status # "refunded" or "pending"
Do's and Don'ts
| Do | Don't |
|---|---|
| Await settlement before unlocking premium features | Trust user-submitted confirmation; always verify via bank feed |
| Set a reasonable timeout (e.g., 10 minutes) so users aren't stuck | Leave requests open indefinitely; timeouts prevent zombie processes |
| Log all payment requests and settlements for accounting | Lose track of who paid; use order_id and user_id consistently |
| Test with small amounts (1,000–10,000 VND) before going live | Jump to 10,000,000 VND charges without testing |
| Display the checkout URL clearly; VietQR works on all banking apps | Embed the QR in an image only; provide the clickable link too |
Troubleshooting & FAQ
Q: What if the user's bank doesn't support VietQR?
A: VietQR is standard across 77 Vietnamese banks (Vietcombank, MB Bank, Techcombank, ACB, etc.). If a user's bank isn't supported, they can still transfer manually using the account number—but VietQR is the frictionless path.
Q: How long does settlement take?
A: Once the user confirms the payment in their banking app, the bank feed notifies AgentPay within 3–10 seconds. Your agent's await_settlement resolves immediately, so the user gets feedback in near-real-time. The money itself clears to your account within 24 hours (standard Vietnam banking).
Q: What's the fee?
A: AgentPay VN doesn't charge a fee. You pay the standard NAPAS interchange fee (0.5–1%), which is the same whether you use Stripe, PayPal, or any processor. Your bank handles this automatically.
Q: Can I offer a free tier alongside paid features?
A: Absolutely. In your MCP server, check if the user has already paid for a feature. If not, offer a limited free response, then prompt for payment if they want the premium version. You control the paywall logic entirely.
Q: What if payment fails halfway through?
A: await_settlement will timeout if no payment is detected. Your agent catches the timeout and can retry, inform the user, or offer an alternative payment method. The request stays open; there's no zombie transaction.
Key Takeaways
- Three-line flow:
create_payment_request→ send URL →await_settlement. That's your entire payment cycle. - No middleman: The VietQR points to your bank account. AgentPay only coordinates the settlement confirmation; money never passes through it.
- Agent-native: Built for AI agents. MCP integration is seamless; Claude calls your payment tool just like any other.
- Instant feedback: Bank settlement is confirmed within seconds, so your agent unlocks premium features immediately.
- Scalable: Start with a single feature (e.g., premium explanations) and expand to subscriptions, refunds, and multi-tier pricing.
- Production-ready: MIT-licensed, open-source, battle-tested in Vietnamese e-commerce. You own the code.
Getting Started Now
You have everything you need:
- Install the SDK:
pip install agentpay-vn - Read the full docs: https://agentpay.servicesai.vn/v1/docs
- Explore the source: https://github.com/phuocdu/agentpay-vn
- Build your MCP server: Use the examples above to integrate into your Claude bot.
- Test locally: Start with 1,000 VND transactions to verify the flow.
Your Claude agent can now earn money. Not through ads, not through upselling—through genuine value delivered at the moment of use, paid directly by users who want what you're offering. That's the future of agent economics. Go build it.