Build a Paid MCP Server: Charge Users Inside Claude

2026-08-25 · AgentPay VN

mcp-serverai-agentspaymentspythonvietqr

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:

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:

  1. create_payment_request(): Agent asks for payment. You create a request with amount, description, and merchant bank details.
  2. send_checkout_url(): Agent gets back a VietQR URL. It's shared with the user (in chat, via email, or QR code).
  3. 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


Get Started Now

Ready to monetize your AI agents? Here's your next step:

  1. Install: pip install agentpay-vn
  2. Read the docs: https://agentpay.servicesai.vn/v1/docs
  3. Explore the code: https://github.com/phuocdu/agentpay-vn
  4. Set your bank credentials in environment variables.
  5. 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!

Get started →

← All posts