Build a Paid MCP Server: Charge Users Inside Claude

2026-09-09 · AgentPay VN

mcp-serverai-agentspayment-integrationvietqrpython

The Problem: Your MCP Server Works, But Who Pays?

You've built an MCP server that provides real value—maybe it generates images, runs analyses, or accesses premium data. Your Claude users love it. But here's the friction point: how do you monetize it?

Traditional payment gateways require redirects, browser windows, and manual confirmation flows. That breaks the magic of Claude's seamless context. You end up with:

Today, there's a cleaner way: AgentPay VN lets your MCP server generate a VietQR payment link, embed it in Claude's context, and settle straight to your bank account—no middleman holding your money, no complex integrations.

Why VietQR + MCP Is a Winning Combo

VietQR is Vietnam's instant payment standard. It's ubiquitous, frictionless, and secure. When combined with an MCP server, you unlock a flow that feels native to Claude:

  1. User requests a premium feature inside Claude conversation
  2. Your MCP server generates a QR code (3-line Python call)
  3. User scans and pays via their banking app
  4. Settlement confirmed via bank feed → feature unlocked
  5. No redirect, no tab-switching, minimal friction

AgentPay VN handles the complexity—it's open-source (MIT license), Python-native, and specifically designed for this agent-first workflow.

What You're NOT Getting

What You ARE Getting

Installation & Setup: 5 Minutes to Your First Payment

Step 1: Install AgentPay VN

pip install agentpay-vn

Verify installation:

python -c "import agentpay_vn; print(agentpay_vn.__version__)"

Step 2: Configure Your Merchant Account

You'll need: - VietQR merchant ID (register at your bank or via VietQR portal) - Bank account details (verified account where payments settle) - Optional: Merchant name, logo, transaction reference pattern

Store these in environment variables:

export VIETQR_MERCHANT_ID="your_merchant_id"
export MERCHANT_BANK_ACCOUNT="your_account_number"
export MERCHANT_BANK_CODE="970012"  # Example: VIETCOMBANK

Step 3: Deploy the MCP Server

AgentPay VN ships with a pre-built MCP server:

agentpay-mcp --port 3000

This starts a local MCP server on http://localhost:3000 that Claude can call.

Building Your First Paid Feature: The Code

Let's build a real scenario: an image enhancement bot that charges $2 USD (~50,000 VND) per premium enhancement.

Example 1: Payment Request Flow

from agentpay_vn import PaymentGateway, PaymentRequest
import json
import time

# Initialize gateway with your credentials
gateway = PaymentGateway(
    merchant_id="MERCHANT_ID",
    bank_account="1234567890",
    bank_code="970012"
)

# User requests premium image enhancement
def create_premium_enhancement_payment():
    """Create a payment request for premium image processing."""

    # Step 1: Define the payment
    payment = PaymentRequest(
        amount=50000,  # 50,000 VND (~$2 USD)
        currency="VND",
        description="Premium Image Enhancement - 4K Upscaling",
        reference_id="enhance_img_001",  # Unique ID for this request
        merchant_name="ImagePro Bot",
        expiry_seconds=300  # QR valid for 5 minutes
    )

    # Step 2: Generate VietQR payload
    qr_data = gateway.create_payment_request(payment)

    # qr_data contains:
    # - qr_code_url: Direct link to PNG QR image
    # - qr_string: Raw QR content (for embedding)
    # - checkout_url: Human-readable payment link
    # - payment_id: Internal tracking ID

    return {
        "status": "awaiting_payment",
        "amount": 50000,
        "currency": "VND",
        "qr_code": qr_data["qr_code_url"],
        "payment_id": qr_data["payment_id"],
        "expires_at": qr_data["expires_at"]
    }

# Create the payment
payment_info = create_premium_enhancement_payment()
print(json.dumps(payment_info, indent=2))

Line-by-line breakdown: - Lines 8-12: Initialize gateway with merchant credentials from environment - Lines 16-28: Create a PaymentRequest object with amount, description, and reference ID - Line 31: Call create_payment_request() to generate VietQR code - Line 33-40: Returns structured payment info including QR code URL

The QR code is now ready to show the user. They scan it with their banking app, confirm the 50,000 VND transfer, and your bank account receives the money.

Example 2: Confirm Settlement & Unlock Feature

import asyncio
from agentpay_vn import PaymentGateway

gateway = PaymentGateway(
    merchant_id="MERCHANT_ID",
    bank_account="1234567890",
    bank_code="970012"
)

async def wait_for_payment_settlement(payment_id: str, timeout: int = 600):
    """
    Poll bank feed to confirm payment settlement.
    Returns True when 50,000 VND deposit is detected.
    """

    start_time = time.time()
    check_interval = 5  # Poll every 5 seconds

    while (time.time() - start_time) < timeout:
        # Check bank feed for incoming transfer matching payment_id
        settlement = await gateway.await_settlement(
            payment_id=payment_id,
            expected_amount=50000
        )

        if settlement["status"] == "confirmed":
            # Payment received! Unlock the feature
            return {
                "success": True,
                "transaction_id": settlement["transaction_id"],
                "amount_received": settlement["amount"],
                "timestamp": settlement["settled_at"]
            }

        # Not yet confirmed, wait and retry
        await asyncio.sleep(check_interval)

    # Timeout reached
    return {"success": False, "error": "Payment not received within timeout"}

# In your MCP handler
async def handle_premium_enhancement_request(image_url, payment_id):
    # Wait for payment to settle
    settlement = await wait_for_payment_settlement(payment_id)

    if settlement["success"]:
        # Process premium enhancement
        enhanced_image = process_4k_upscaling(image_url)
        return {
            "status": "completed",
            "image_url": enhanced_image,
            "paid_at": settlement["timestamp"]
        }
    else:
        return {"status": "payment_timeout", "error": settlement["error"]}

# Call it
result = asyncio.run(
    handle_premium_enhancement_request(
        "https://example.com/image.jpg",
        "enhance_img_001"
    )
)
print(result)

Key points: - Lines 11-35: await_settlement() polls your bank feed (via bank API) for incoming transfers - Line 22: Matches incoming transfer amount and reference ID - Lines 24-28: Returns settlement confirmation with transaction ID - Lines 33-45: Once payment is confirmed, unlock premium feature (e.g., 4K upscaling) - No webhook complexity: You pull data from the bank, not push/handle webhooks

Claude MCP Configuration: Connect Your Server

Now configure Claude to call your MCP server. Add this to ~/.claude/mcp_servers.json:

{
  "mcpServers": {
    "agentpay-image-bot": {
      "command": "python",
      "args": ["-m", "agentpay_vn.mcp_server"],
      "env": {
        "VIETQR_MERCHANT_ID": "your_merchant_id",
        "MERCHANT_BANK_ACCOUNT": "1234567890",
        "MERCHANT_BANK_CODE": "970012",
        "FEATURE_PRICING": "{\"premium_enhancement\": 50000, \"batch_processing\": 150000}"
      }
    }
  }
}

Clause will now recognize tools like create_payment and confirm_settlement.

Real-World Walkthrough: Online Course Bot

Imagine you're building an AI tutoring agent that offers: - Free tier: Basic concept explanations - Premium tier: Personalized problem sets, live code review ($5/month = ~125,000 VND)

User interaction:

User: "I'm stuck on async/await in Python."

Bot: "Here's a free explanation...\n\nWant me to generate 10 personalized 
practice problems with solutions? That's a premium feature ($5).\n\n[QR Code Image]\n
Scan to pay. Once settled, I'll generate your problem set."

User: Scans QR → Pays from banking app

Bot: (Polls settlement) → "Payment confirmed! Here are your 10 problems..."

Code snippet:

class TutoringAgent:
    def __init__(self, gateway):
        self.gateway = gateway
        self.user_limits = {}  # Track free tier usage

    async def handle_request(self, user_id, request_type):
        if request_type == "basic_explanation":
            return await self.free_tier_explanation()

        elif request_type == "problem_set":
            # Check if user already paid this month
            if self.user_has_active_subscription(user_id):
                return await self.generate_problems(user_id)

            # Create payment for problem set
            payment = await self.gateway.create_payment_request(
                PaymentRequest(
                    amount=125000,
                    description="Premium Problem Set - Python Async/Await",
                    reference_id=f"course_{user_id}_{int(time.time())}"
                )
            )

            return {
                "status": "payment_required",
                "message": "Unlock 10 personalized problems",
                "qr_code": payment["qr_code_url"],
                "payment_id": payment["payment_id"]
            }

This pattern scales to SaaS, consulting bots, data access, and more.

Common Patterns: Do's and Don'ts

Do Don't
✅ Show QR code before asking user to pay ❌ Auto-charge without confirmation
✅ Set 5-10 min QR expiry (user pays quickly) ❌ Keep QR valid for 24+ hours (security risk)
✅ Store payment_id and transaction_id for audit ❌ Rely on memory; lose receipts on restart
✅ Poll bank feed every 5-10 seconds ❌ Expect instant settlement (banks take 30-60s)
✅ Provide fallback for payment timeout ❌ Hang forever waiting for payment
✅ Include merchant name in payment description ❌ Use generic "Payment" (confuses users)

Advanced Tips

Tip 1: Batch Payments for Team Features

# Charge $10 once for a 5-person team
payment = gateway.create_payment_request(
    PaymentRequest(
        amount=250000,  # ~$10
        description="Team License - 5 seats - valid 1 year",
        reference_id=f"team_license_{team_id}"
    )
)

Tip 2: Retry Logic for Network Hiccups

async def robust_await_settlement(payment_id, retries=3):
    for attempt in range(retries):
        try:
            return await gateway.await_settlement(payment_id)
        except ConnectionError:
            if attempt < retries - 1:
                await asyncio.sleep(2 ** attempt)  # Exponential backoff
            else:
                raise

Tip 3: Log Everything for Reconciliation

import logging

logger = logging.getLogger("payments")

logger.info(f"Payment created: {payment_id}, amount: {amount}")
logger.info(f"Settlement confirmed: {payment_id}, txn: {transaction_id}")

# Later: Export logs to CSV for accounting

FAQ

Q: Is AgentPay VN safe? Does it hold my money? A: No—AgentPay VN is open-source (MIT license) and never touches your money. The QR code points directly to your merchant bank account. Settlement happens via your bank's infrastructure, not a third party.

Q: Can I use this outside Vietnam? A: VietQR is Vietnam-specific. If you're outside Vietnam, you'd need a Vietnamese bank account. The SDK is global-ready; regional support depends on your payment method.

Q: How fast does payment settle? A: Most Vietnamese banks settle within 30-90 seconds during business hours. The await_settlement() function polls your bank feed and detects transfers automatically.

Q: What if a user scans the QR but closes it? A: The QR expires after your configured time (default 5-10 minutes). They can generate a new payment request. All payment requests are logged, so you can always reconcile.

Q: Do I need a webhook endpoint? A: No. AgentPay VN uses a pull model—you poll the bank feed. This is simpler and more reliable than managing webhooks.

Key Takeaways

Get Started Now

Your first paid MCP server is 5 minutes away:

# 1. Install
pip install agentpay-vn

# 2. Start MCP server
agentpay-mcp --port 3000

# 3. Add to Claude config (see JSON above)
# 4. Build your payment flow (see code examples)

Resources: - 📚 Full Documentation: https://agentpay.servicesai.vn/v1/docs - 🔗 GitHub Repository: https://github.com/phuocdu/agentpay-vn - 💬 Questions? Check the docs or open an issue on GitHub

Monetize your AI agents today. No PCI compliance, no escrow, no redirects—just clean, agent-first payment flows.

Get started →

← All posts