Build a Paid MCP Server: Charge Users Inside Claude

2026-08-11 · AgentPay VN

mcp-serverai-agentspayment-integrationpython-sdkvietqr

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:

AgentPay VN is the open-source glue (MIT license) that makes this work inside Claude.


Architecture: How It Works

Before code, understand the flow:

  1. User requests a paid service from your Claude MCP server (e.g., "Generate a logo").
  2. Your server calls create_payment_request() with amount, description, and merchant bank details.
  3. AgentPay VN generates a VietQR code and returns a checkout URL.
  4. Your MCP server returns the checkout URL to Claude; Claude presents it to the user.
  5. User scans the QR or clicks the link, confirms payment in their banking app.
  6. Your server calls await_settlement() to detect when the payment cleared.
  7. 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:


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:

  1. 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"}

  2. wait_for_payment: Block until settlement. Tool call: wait_for_payment(request_id="req_xyz", timeout=300) Response: {"settled": true, "transaction_id": "txn_123"}

  3. 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

  1. User prompt: "I need a Vietnamese café menu in 15 minutes."
  2. Claude checks the request: Needs design work → premium feature.
  3. Claude calls MCP: create_payment(amount_vnd=200_000, description="Custom Café Menu Design")
  4. User sees: A VietQR code in the chat. They scan it with their banking app.
  5. User confirms the 200k VND charge (≈$8).
  6. Claude polls via wait_for_payment(). After 30 seconds, settlement confirms.
  7. Claude generates a beautiful menu PDF using Canva API or custom design tool.
  8. 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


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:

The barrier to monetizing AI agents just dropped. Your Claude instance can accept payments in minutes. Build that paid MCP server today.

Get started →

← All posts