Sponsored by Deepsite.site

Bitnovo Pay

Created By
bitnovo2 months ago
MCP server for Bitnovo Pay integration with AI agents. Provides cryptocurrency payment capabilities through Bitnovo Pay API. Features include payment creation, status checking, QR code generation, and webhook management with support for multiple tunnel providers (ngrok, zrok, manual).
Content

Bitnovo Pay - MCP Integration

Table of Contents

  1. Introduction
  2. What is MCP?
  3. Quick Start (5 minutes)
  4. Main Features
  5. Prerequisites
  6. Installation
  7. Platform Configuration
  8. MCP Tools Reference
  9. Webhooks and Tunnels System
  10. Security
  11. Usage Examples
  12. Troubleshooting

Introduction

The Bitnovo Pay MCP server allows AI agents to interact with the Bitnovo Pay API to create and manage cryptocurrency payments autonomously. This integration facilitates crypto payment automation in applications using language models like ChatGPT, Claude, or Gemini.

{% hint style="success" %} Current version: v1.1.0 | Last update: September 30, 2025 {% endhint %}


What is MCP?

Model Context Protocol (MCP) is an open standard protocol that allows AI models to access external tools and services in a structured and secure manner.

Key MCP Concepts

ConceptDescription
MCP ServerProcess that exposes capabilities (tools, resources) through the MCP protocol via stdio
MCP ToolsFunctions that the AI model can invoke (e.g., create_payment_link)
MCP ResourcesData that the server can provide to the model (e.g., cryptocurrency catalog)
stdio TransportCommunication between MCP client and server using standard input/output

The Bitnovo Pay MCP server implements this protocol to expose 8 MCP tools that enable complete crypto payment management from any compatible MCP client.

{% hint style="info" %} Official specification: modelcontextprotocol.io {% endhint %}


Quick Start (5 minutes)

Step 1: Get your credentials

  1. Create an account at Bitnovo Pay
  2. Obtain your Device ID from the Bitnovo dashboard
  3. (Optional) Generate Device Secret for webhooks

Step 2: Configure your MCP client

Add this configuration to your MCP client (example for Claude Desktop):

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["-y", "@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com"
      }
    }
  }
}

{% hint style="warning" %} Configuration file location:

  • Claude Desktop (macOS): ~/Library/Application Support/Claude/claude_desktop_config.json
  • Claude Desktop (Windows): %APPDATA%\Claude\claude_desktop_config.json
  • OpenAI ChatGPT: ~/.config/openai/mcp-config.json
  • Google Gemini: ~/.config/gemini/mcp-config.json {% endhint %}

Step 3: Restart your MCP client

Restart Claude Desktop, ChatGPT, or your MCP client to load the server.

Step 4: Test it!

Ask your AI assistant:

"Create a payment for 10 euros"

✅ You should receive a payment URL ready to share.


Main Features

  • 8 MCP tools for complete payment management:

    • create_payment_onchain - Generate cryptocurrency addresses for direct payments
    • create_payment_link - Create web payment URLs with redirect management
    • get_payment_status - Query payment status with detailed information
    • list_currencies_catalog - Get supported cryptocurrencies with filtering
    • generate_payment_qr - Generate custom QR codes from existing payments
    • get_webhook_events - Query webhook events received in real-time
    • get_webhook_url - Get the public webhook URL with configuration instructions
    • get_tunnel_status - Diagnose tunnel connection status
  • Automatic webhook system with 3 tunnel providers:

    • 🔗 ngrok: Free persistent URL (1 static domain per account)
    • 🌐 zrok: 100% free open-source with persistent URLs
    • 🏢 manual: For servers with public IP (N8N, Opal, VPS)
  • Compatible with multiple LLMs:

    • 🤖 OpenAI ChatGPT (GPT-5, GPT-4o, Responses API, Agents SDK)
    • 🧠 Google Gemini (Gemini 2.5 Flash/Pro Sept 2025, CLI, FastMCP)
    • 🔮 Claude (Claude Desktop, Claude Code)
  • High-quality QR codes (v1.1.0+):

    • 📱 Default resolution of 512px (improved from 300px) for modern displays
    • 🖨️ Support up to 2000px for professional printing
    • ✨ Sharp edges with optimized interpolation algorithms
    • 🎨 Custom Bitnovo Pay branding with smooth logo scaling
  • Security and privacy:

    • Mandatory HTTPS communication
    • HMAC signature validation for webhooks
    • Replay attack prevention with nonce cache
    • Sensitive data masked in logs
    • No local storage (stateless operation)

Prerequisites

{% hint style="info" %} Before starting, make sure you have: {% endhint %}

RequirementDescriptionNeeded for
Node.js 18+JavaScript runtimeRunning MCP server
Bitnovo Pay AccountRegistration at bitnovo.com/payObtain credentials
Device IDDevice identifier from dashboardAll operations
⚠️ Device SecretHMAC secret (optional)Webhooks with validation
MCP ClientClaude, ChatGPT, or GeminiInteract with server
⚠️ ngrok/zrok (optional)Tunnel for webhooksLocal development with webhooks

{% hint style="success" %} Quick start: You only need Node.js 18+ and Bitnovo credentials to begin. Webhooks are optional. {% endhint %}

Installation

There are two ways to install the Bitnovo Pay MCP server:

{% hint style="success" %} Recommended for most users - Simplest way and always up-to-date {% endhint %}

No prior installation required, just configure your MCP client (see "Platform Configuration" section below) using:

npx -y @bitnovopay/mcp-bitnovo-pay

✅ Advantages:

  • Always get the latest published version
  • No need to clone the repository
  • No need to compile the code
  • Automatic updates on each execution
  • Perfect for end users

Option 2: Clone the repository (For development)

{% hint style="warning" %} For developers only - Requires TypeScript and Node.js knowledge {% endhint %}

If you need to modify the code or contribute to the project:

# Clone the repository
git clone https://github.com/bitnovo/mcp-bitnovo-pay.git
cd mcp-bitnovo-pay

# Install dependencies
npm install

# Build the project
npm run build

# Run in development mode
npm run dev

✅ Advantages:

  • Full control of source code
  • Allows modifications and local development
  • Ideal for contributing to the project

Credentials Configuration

Get your credentials from the Bitnovo Pay dashboard:

  • Device ID: Unique identifier for your merchant
  • Device Secret: (Required for webhooks) For HMAC signature validation
  • Base URL: Environment URL (development or production)

Platform Configuration

OpenAI ChatGPT

To integrate with ChatGPT (GPT-4o, GPT-5), create or edit your configuration file:

Location: ~/.config/openai/mcp-config.json

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex"
      }
    }
  }
}

{% hint style="info" %} With webhooks enabled (local development with ngrok):

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["-y", "@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex",
        "WEBHOOK_ENABLED": "true",
        "TUNNEL_ENABLED": "true",
        "TUNNEL_PROVIDER": "ngrok",
        "NGROK_AUTHTOKEN": "your_ngrok_token",
        "NGROK_DOMAIN": "bitnovo-dev.ngrok-free.app"
      }
    }
  }
}

{% endhint %}

Supported since: March 2025 (GPT-5 since August 2025)

Google Gemini

To integrate with Gemini 2.5, configure the FastMCP file:

Location: ~/.config/gemini/mcp-config.json

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex"
      }
    }
  }
}

Supported since: April 2025 (Sept 2025 Models)

Claude (Anthropic)

To integrate with Claude Desktop or Claude Code:

macOS Location: ~/Library/Application Support/Claude/claude_desktop_config.json Windows Location: %APPDATA%\Claude\claude_desktop_config.json

Basic configuration (without webhooks)

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex"
      }
    }
  }
}

Configuration with webhooks (local development with ngrok)

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex",
        "WEBHOOK_ENABLED": "true",
        "TUNNEL_ENABLED": "true",
        "TUNNEL_PROVIDER": "ngrok",
        "NGROK_AUTHTOKEN": "your_ngrok_token",
        "NGROK_DOMAIN": "bitnovo-dev.ngrok-free.app"
      }
    }
  }
}

Configuration for N8N/Opal/Server

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com",
        "BITNOVO_DEVICE_SECRET": "your_device_secret_hex",
        "WEBHOOK_ENABLED": "true",
        "TUNNEL_ENABLED": "false",
        "WEBHOOK_PUBLIC_URL": "https://n8n.company.com"
      }
    }
  }
}

Supported since: 2025

MCP Tools Reference

Payment Tools (5)

1. create_payment_onchain

Creates a payment with a specific cryptocurrency address for direct blockchain transactions.

Use when: User specifies a concrete cryptocurrency (Bitcoin, ETH, USDC, etc.)

Parameters:

{
  "amount_eur": 50.0,
  "input_currency": "BTC",
  "fiat": "EUR",
  "notes": "Coffee payment",
  "include_qr": true
}

Response:

{
  "identifier": "abc-123-def",
  "payment_uri": "bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa?amount=0.001",
  "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "qr_address": "data:image/png;base64,...",
  "qr_payment_uri": "data:image/png;base64,...",
  "expected_output_amount": "0.001",
  "currency_id": "BTC",
  "fiat_amount": "50.00",
  "status": "PE"
}

Usage examples:

  • "Create a Bitcoin payment for 50 euros"
  • "Generate ETH address for 100 euros"
  • "I need a USDC QR for 25 euros"

Creates a web payment URL where the customer can choose their preferred cryptocurrency.

Use when: Generic payment request without specific cryptocurrency mentioned (DEFAULT OPTION)

Parameters:

{
  "amount_eur": 50.0,
  "fiat": "EUR",
  "url_ok": "https://mystore.com/success",
  "url_ko": "https://mystore.com/cancelled",
  "notes": "Order #1234",
  "include_qr": true
}

Response:

{
  "identifier": "abc-123-def",
  "web_url": "https://payments.bitnovo.com/pay/abc-123-def",
  "qr_web_url": "data:image/png;base64,...",
  "fiat_amount": "50.00",
  "fiat_currency": "EUR",
  "status": "PE"
}

Usage examples:

  • "Create a payment for 50 euros"
  • "Generate QR to collect 100 euros"
  • "Give me the payment link for 25 euros"

3. get_payment_status

Queries the current status of a payment with detailed information.

Parameters:

{
  "identifier": "abc-123-def"
}

Response:

{
  "identifier": "abc-123-def",
  "status": "CO",
  "status_description": "Completed",
  "fiat_amount": "50.00",
  "crypto_amount": "0.001",
  "currency_id": "BTC",
  "created_at": "2025-01-15T10:30:00Z",
  "updated_at": "2025-01-15T10:35:00Z"
}

Possible statuses:

  • NR (Not Ready): Pre-payment created, no crypto assigned
  • PE (Pending): Waiting for customer payment
  • AC (Awaiting Completion): Crypto detected in mempool
  • CO (Completed): Payment confirmed on blockchain
  • EX (Expired): Payment time limit exceeded
  • CA (Cancelled): Payment cancelled
  • FA (Failed): Transaction failed to confirm

Usage examples:

  • "What's the status of payment abc-123-def?"
  • "Was the payment completed?"
  • "Check payment status"

4. list_currencies_catalog

Gets the catalog of available cryptocurrencies with optional amount filtering.

Parameters:

{
  "filter_by_amount": 25.0
}

Response:

{
  "currencies": [
    {
      "symbol": "BTC",
      "name": "Bitcoin",
      "blockchain": "Bitcoin",
      "min_amount": "0.0001",
      "max_amount": "10.0",
      "decimals": 8
    },
    {
      "symbol": "ETH",
      "name": "Ethereum",
      "blockchain": "Ethereum",
      "min_amount": "0.001",
      "max_amount": "100.0",
      "decimals": 18
    }
  ]
}

Usage examples:

  • "What cryptocurrencies are available?"
  • "Which coins accept payments of 50 euros?"
  • "Show crypto catalog"

5. generate_payment_qr

Generates custom QR codes from existing payments.

Parameters:

{
  "identifier": "abc-123-def",
  "qr_type": "both",
  "size": 512,
  "style": "branded",
  "branding": true
}

qr_type options:

  • address: Only crypto address (customer enters amount manually)
  • payment_uri: Address + amount included (recommended)
  • both: Generates both types (recommended)
  • gateway_url: QR of payment gateway URL

Response:

{
  "qr_address": "data:image/png;base64,...",
  "qr_payment_uri": "data:image/png;base64,...",
  "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
  "payment_uri": "bitcoin:1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa?amount=0.001"
}

Usage examples:

  • "Generate larger QR for the payment"
  • "Create QR without branding"
  • "I need a 500px QR"

Webhook Tools (3)

6. get_webhook_events

Queries webhook events received in real-time from Bitnovo Pay API.

Available when: WEBHOOK_ENABLED=true

Parameters:

{
  "identifier": "abc-123-def",
  "limit": 50,
  "validated_only": true
}

Response:

{
  "events": [
    {
      "event_id": "abc-123:1234567890",
      "identifier": "abc-123-def",
      "status": "CO",
      "received_at": "2025-09-30T10:30:00.000Z",
      "validated": true,
      "payload": {
        "identifier": "abc-123-def",
        "status": "CO",
        "confirmed_amount": 0.0012,
        "crypto_amount": 0.0012
      }
    }
  ],
  "total_count": 1
}

Usage examples:

  • "Has any webhook arrived for payment abc-123?"
  • "Show all webhook events"
  • "Was payment confirmation received?"

7. get_webhook_url

Gets the public webhook URL with configuration instructions for the Bitnovo dashboard.

Available when: WEBHOOK_ENABLED=true

Parameters:

{
  "validate": true
}

Response:

{
  "webhook_url": "https://bitnovo-dev.ngrok-free.app/webhook/bitnovo",
  "provider": "ngrok",
  "validated": true,
  "instructions": "✅ ngrok tunnel active with persistent URL.\n\nConfiguration steps:\n1. Copy this URL: https://bitnovo-dev.ngrok-free.app/webhook/bitnovo\n2. Go to https://pay.bitnovo.com\n3. Navigate to: Settings → Merchant → Devices\n4. Select device\n5. Configure 'notification_url' with the URL\n\nNote: This URL is persistent and won't change between restarts."
}

Usage examples:

  • "What's my webhook URL?"
  • "Give me the URL to configure in Bitnovo"
  • "How do I set up webhooks?"

8. get_tunnel_status

Diagnoses the tunnel connection status (ngrok, zrok, or manual).

Available when: WEBHOOK_ENABLED=true

Parameters: None

Response:

{
  "enabled": true,
  "provider": "ngrok",
  "status": "connected",
  "public_url": "https://bitnovo-dev.ngrok-free.app",
  "connected_at": "2025-09-30T10:30:00.000Z",
  "last_error": null,
  "reconnect_attempts": 0,
  "health_check_enabled": true,
  "context_detected": {
    "execution_context": "local",
    "confidence": 0.7,
    "suggested_provider": "ngrok",
    "indicators": ["Local development environment detected"]
  }
}

Connection statuses:

  • disconnected: Tunnel not started
  • connecting: Tunnel initializing
  • connected: Tunnel active and healthy
  • reconnecting: Connection lost, attempting to reconnect
  • error: Failed after maximum retries

Usage examples:

  • "Is the webhook tunnel working?"
  • "What's the connection status?"
  • "Diagnose tunnel issues"

Webhooks and Tunnels System

Dual-Server Architecture

The MCP server can run two servers simultaneously:

┌─────────────────────────────────────────────────────────┐
│             MCP Bitnovo Pay Server                      │
│                                                         │
│  ┌──────────────┐  ┌──────────────────┐ ┌────────────┐│
│  │ MCP Server   │  │ Webhook Server   │ │  Tunnel    ││
│  │ (stdio)      │  │ (HTTP :3000)     │ │  Manager   ││
│  └──────┬───────┘  └────────┬─────────┘ └──────┬─────┘│
│         │                   │                   │      │
│         │    Event Store    │     Public URL    │      │
│         │   (in-memory)     │   (ngrok/zrok)    │      │
│         └──────────┬────────┴──────────┬────────┘      │
└────────────────────┼───────────────────┼───────────────┘
                     │                   │
            ┌────────┴────────┐  ┌───────┴────────┐
            │                 │  │                │
       Claude Desktop   Bitnovo API    Tunnel Provider
       (MCP Tools)      (Webhooks)    (ngrok/zrok/manual)

Tunnel Providers

Provider Comparison

ProviderCostPersistent URLBest ForStability
ngrokFree (1 static domain)✅ YesLocal development~99% uptime
zrok100% Free✅ Yes (reserved shares)Open-source preferenceMedium-high
manualDepends on hosting✅ YesServers with public IPServer-dependent

Features:

  • Free static domain (1 per account since 2023)
  • Persistent URL (doesn't change on restarts)
  • High reliability (~99% uptime)
  • 24-hour timeout (auto-reconnection handles this)

Configuration:

TUNNEL_ENABLED=true
TUNNEL_PROVIDER=ngrok
NGROK_AUTHTOKEN=your_ngrok_token
NGROK_DOMAIN=bitnovo-dev.ngrok-free.app  # Your free static domain

Setup:

  1. Create account at ngrok.com
  2. Get authtoken from dashboard
  3. Claim free static domain at domains

2. zrok (Open-Source Alternative)

Features:

  • 100% Free (no limits on reserved shares)
  • Persistent URL with unique-name
  • Open-source (built on OpenZiti)
  • Medium-high stability (improving with each release)

Configuration:

TUNNEL_ENABLED=true
TUNNEL_PROVIDER=zrok
ZROK_TOKEN=your_zrok_token
ZROK_UNIQUE_NAME=bitnovo-webhooks  # Your reserved share name

# Results in persistent URL:
# https://bitnovo-webhooks.share.zrok.io/webhook/bitnovo

Setup:

  1. Create account at myzrok.io
  2. Install zrok CLI: brew install openziti/zrok/zrok
  3. Enable account: zrok enable YOUR_TOKEN
  4. Reserve share: zrok reserve public --unique-name bitnovo-webhooks 3000

3. manual (Servers with Public IP)

Best For:

  • N8N instances
  • Opal deployments
  • VPS/cloud servers
  • Docker with ingress
  • Kubernetes with LoadBalancer

Environment Auto-detection:

The system automatically detects these environments:

EnvironmentDetection Method
N8NVariables N8N_HOST or N8N_PROTOCOL
OpalVariables OPAL_WEBHOOK_URL or OPAL_HOST
KubernetesVariable KUBERNETES_SERVICE_HOST
DockerFile /.dockerenv or DOCKER_HOST
VPS/ServerMultiple indicators (systemd, PM2, etc.)

Configuration:

WEBHOOK_ENABLED=true
TUNNEL_ENABLED=false  # or TUNNEL_PROVIDER=manual
WEBHOOK_PUBLIC_URL=https://n8n.company.com  # Server's public URL

Webhook Security

HMAC-SHA256 Validation

All webhooks are validated using:

signature = hex(hmac_sha256(device_secret, nonce + raw_body))

Validation process:

  1. Extract nonce and signature from headers X-NONCE and X-SIGNATURE
  2. Calculate expected signature using device_secret
  3. Compare using timing-safe comparison
  4. Reject if signatures don't match (401 Unauthorized)

Replay Attack Prevention

  • Nonce cache: Stores used nonces for 5 minutes
  • Duplicate detection: Rejects webhooks with already-used nonces
  • Event deduplication: Same event received multiple times stored once

Why Public URLs Are Secure?

Question: "Won't malicious actors send fake webhooks to my public URL?"

Answer: No, because:

  1. HMAC validation ensures only Bitnovo (with your device_secret) can create valid signatures
  2. Without the device_secret, attackers can't generate valid signatures
  3. All requests without valid signatures are rejected (401 Unauthorized)
  4. Replay prevention with nonces stops reuse of captured valid requests

Security Model:

Attacker sends fake webhook → Missing/invalid signature → 401 Rejected ✅
Attacker replays captured webhook → Nonce already used → 401 Rejected ✅
Bitnovo sends webhook → Valid signature + fresh nonce → 200 Accepted ✅

Decision Tree for LLM Payment Tool Selection

CRITICAL RULE: Does user explicitly mention a cryptocurrency?

User mentions specific crypto (Bitcoin, BTC, Ethereum, ETH, USDC, etc.)?

Use create_payment_onchain with that specific input_currency

User does NOT mention specific crypto

Use create_payment_link (DEFAULT OPTION)

Payment Methods Comparison Table

Featurecreate_payment_onchaincreate_payment_link
ReturnsCrypto address + QRWeb URL
Customer chooses crypto?No (fixed)Yes (in gateway)
Best forCrypto-specific paymentsGeneric payments (DEFAULT)
Sharing methodShow QR/addressSend link
RedirectsN/AYes (url_ok/url_ko)
Use whenUser specifies cryptoNO crypto mentioned
Examples"Bitcoin payment", "ETH address""Payment for 24 euros", "Generate QR"

Usage Examples

Example 1: Generic payment (without specific crypto)

User request:

"I need to create a payment for 50 euros"

Tool to use: create_payment_link

Command:

{
  "amount_eur": 50.0,
  "notes": "Generic payment"
}

Result: Web URL where customer can choose any available cryptocurrency.


Example 2: Bitcoin specific payment

User request:

"Create a Bitcoin payment for 100 euros"

Tool to use: create_payment_onchain

Command:

{
  "amount_eur": 100.0,
  "input_currency": "BTC",
  "notes": "Bitcoin payment"
}

Result: Specific Bitcoin address + QR with amount included.


Example 3: Verify payment with webhooks

User request:

"Was payment abc-123-def completed?"

Tool 1: get_webhook_events

Command:

{
  "identifier": "abc-123-def",
  "validated_only": true
}

Result: List of webhook events received showing real-time updated status.

Alternative - Tool 2: get_payment_status

Command:

{
  "identifier": "abc-123-def"
}

Result: Current payment status queried from API.


Example 4: Industry use cases

🛒 E-commerce: Checkout payment

Scenario: Customer completes €150 purchase, needs cryptocurrency flexibility

Tool: create_payment_link

{
  "amount_eur": 150.0,
  "url_ok": "https://store.com/order/12345/confirmed",
  "url_ko": "https://store.com/order/12345/cancelled",
  "notes": "Order #12345 - Bluetooth Headphones"
}

Flow:

  1. Customer confirms order → AI generates payment link
  2. Customer chooses preferred cryptocurrency in gateway
  3. Makes payment with wallet
  4. Gateway redirects to url_ok after confirmation
  5. System processes order automatically

☕ Cafe/Restaurant: Bitcoin tips

Scenario: Customer wants to leave €5 tip in Bitcoin

Tool: create_payment_onchain

{
  "amount_eur": 5.0,
  "input_currency": "BTC",
  "notes": "Tip - Table 7"
}

Flow:

  1. Waiter requests tip QR → AI generates BTC address
  2. Customer scans QR with Bitcoin wallet
  3. Payment confirms in minutes
  4. System notifies waiter via webhook

💼 Freelance: International invoice in stablecoins

Scenario: Freelancer charges $500 USD for project, prefers USDC

Tool: create_payment_onchain

{
  "amount_eur": 500.0,
  "input_currency": "USDC_ERC20",
  "fiat": "USD",
  "notes": "Invoice #2025-001 - Web development"
}

Flow:

  1. International client receives USDC address
  2. Transfers from exchange or wallet
  3. Blockchain confirmation
  4. Freelancer receives funds without intermediaries

🎮 Gaming: In-game purchases

Scenario: Player buys €25 skin, chooses cryptocurrency

Tool: create_payment_link

{
  "amount_eur": 25.0,
  "notes": "In-game purchase - Dragon Skin Legendary",
  "include_qr": true
}

Flow:

  1. Player selects skin → AI generates QR + link
  2. Pays with their preferred crypto (BTC, ETH, etc.)
  3. System detects payment via webhook
  4. Automatic item unlock in account

🏨 Hotel: Reservation with deposit

Scenario: Room reservation with €200 deposit

Tool: create_payment_link

{
  "amount_eur": 200.0,
  "url_ok": "https://hotel.com/bookings/confirm/789",
  "url_ko": "https://hotel.com/bookings/cancel/789",
  "notes": "Reservation deposit - Presidential Suite Oct 15-20"
}

Flow:

  1. Customer books → AI generates payment link
  2. Customer pays deposit in preferred cryptocurrency
  3. Automatic booking confirmation
  4. Frictionless check-in

Example 5: Real-time payment monitoring

Scenario: Point of sale system monitoring payments

Complete flow:

// 1. Create payment
create_payment_link({
  amount_eur: 50.0,
  notes: "POS Sale #4567"
})
// → Identifier: "abc-123-def"

// 2. Monitor with webhooks (recommended)
get_webhook_events({
  identifier: "abc-123-def",
  validated_only: true
})
// → Receives events in real-time

// 3. Manually verify status (alternative)
get_payment_status({
  identifier: "abc-123-def"
})
// → Status: "CO" (Completed)

// 4. Confirm payment completed
// → System updates inventory, prints receipt

Example 6: Configure webhooks

User request:

"How do I configure webhooks in Bitnovo?"

Tool: get_webhook_url

Command:

{
  "validate": true
}

Result: Webhook URL + step-by-step instructions to configure in Bitnovo dashboard.

Technical Architecture

System Layers

┌─────────────────┐
│   MCP Tools     │ ← 8 tools: 5 payment + 3 webhook
│ (src/tools/)    │
├─────────────────┤
│   Services      │ ← Business logic: PaymentService, CurrencyService
│ (src/services/) │
├─────────────────┤
│   API Client    │ ← Bitnovo API integration with retry logic
│ (src/api/)      │
├─────────────────┤
│ Webhook Server  │ ← Express HTTP server + Event Store + Tunnel Manager
│ (src/webhook-*) │
├─────────────────┤
│   Utilities     │ ← Logging, validation, error handling, crypto
│ (src/utils/)    │
└─────────────────┘

Data Flow

Payments:

  1. Tool Request → Validation → Service Layer → API Client → Bitnovo API
  2. Response → Error Handling → Data Transformation → JSON Response
  3. Logging: All operations logged with sensitive data masking

Webhooks:

  1. Bitnovo sends webhook → Tunnel (ngrok/zrok) → Webhook Server (HTTP :3000)
  2. HMAC Validation → Nonce verification → Event Store storage
  3. MCP Query → get_webhook_events → Event Store data

Environment Variables

Required Variables

BITNOVO_DEVICE_ID=your_device_id_here        # Required
BITNOVO_BASE_URL=https://pos.bitnovo.com     # Required

Webhook Variables (Optional)

# Enable webhooks
WEBHOOK_ENABLED=true
WEBHOOK_PORT=3000
WEBHOOK_HOST=0.0.0.0
WEBHOOK_PATH=/webhook/bitnovo

# Security
BITNOVO_DEVICE_SECRET=your_device_secret_hex   # Required for webhooks

# Event store
WEBHOOK_MAX_EVENTS=1000
WEBHOOK_EVENT_TTL_MS=3600000  # 1 hour

Tunnel Variables (Optional)

# Tunnel configuration
TUNNEL_ENABLED=true
TUNNEL_PROVIDER=ngrok  # Options: ngrok, zrok, manual

# ngrok specific
NGROK_AUTHTOKEN=your_ngrok_token
NGROK_DOMAIN=bitnovo-dev.ngrok-free.app  # Optional: free static domain

# zrok specific
ZROK_TOKEN=your_zrok_token
ZROK_UNIQUE_NAME=bitnovo-webhooks  # Your reserved share name

# manual provider
WEBHOOK_PUBLIC_URL=https://n8n.company.com  # For manual provider

# Health monitoring and reconnection
TUNNEL_HEALTH_CHECK_INTERVAL=60000       # 60 seconds (default)
TUNNEL_RECONNECT_MAX_RETRIES=10          # Maximum retry attempts
TUNNEL_RECONNECT_BACKOFF_MS=5000         # Initial backoff delay

🔒 Security

Security is a fundamental priority of the Bitnovo Pay MCP server. We implement multiple layers of protection to ensure secure transactions.

{% hint style="danger" %} IMPORTANT: Never expose your credentials in public repositories, logs, or shared configurations. {% endhint %}

🛡️ Implemented Security Principles

1. Secure Communication

  • Mandatory HTTPS: All API calls use HTTPS exclusively
  • No HTTP: HTTP requests are automatically rejected
  • TLS 1.2+: Encrypted communication with modern protocols

2. HMAC-SHA256 Webhook Validation

Webhooks are protected with HMAC cryptographic signatures:

signature = hex(hmac_sha256(device_secret, nonce + raw_body))

Validation process:

  1. Bitnovo sends webhook with headers X-NONCE and X-SIGNATURE
  2. Server calculates expected signature using BITNOVO_DEVICE_SECRET
  3. Timing-safe comparison between signatures
  4. Immediate rejection if they don't match (401 Unauthorized)

{% hint style="info" %} Do I need webhooks? Only if you require real-time notifications. For manual status queries, use get_payment_status. {% endhint %}

3. Replay Attack Prevention

  • Nonce cache: Stores used nonces for 5 minutes
  • Duplicate detection: Rejects webhooks with already-used nonces
  • Event deduplication: Same event received multiple times stored once

Example of rejected attack:

Attacker replays valid webhook → Nonce already used → 401 Rejected ✅

4. Data Privacy

  • Masked logs: Device IDs, secrets, and crypto addresses partially hidden
  • No exchange rates: Rates not exposed to prevent inaccuracies
  • Stateless design: No local persistence, real-time API queries
  • Minimal data: Only necessary data requested for operation

Example of masked log:

[INFO] Payment created for device: 12345678-****-****-****-********90ab
[INFO] Webhook validated with signature: a3f2c1...******

5. Resilience and Availability

  • Timeouts: 5 seconds maximum per API operation
  • Smart retries: Maximum 2 retries with exponential backoff
  • Tunnel auto-reconnection: Exponential backoff up to 10 retries
  • Health monitoring: Tunnel connection verification every 60 seconds

🔐 Secure Credentials Configuration

{% hint style="warning" %} Security best practices:

  • ✅ Use environment variables, never hardcode secrets
  • ✅ Rotate BITNOVO_DEVICE_SECRET regularly
  • ✅ Use production URLs (https://pos.bitnovo.com) in production environments
  • ✅ Limit access to MCP configuration file (permissions 600)
  • ❌ NEVER share BITNOVO_DEVICE_SECRET in logs, repos, or messages {% endhint %}

Recommended permissions for configuration file:

# Claude Desktop config (macOS)
chmod 600 ~/Library/Application\ Support/Claude/claude_desktop_config.json

# OpenAI ChatGPT config
chmod 600 ~/.config/openai/mcp-config.json

🌐 Public Tunnel Security

Common question: "Isn't it insecure to expose a public URL for webhooks?"

Answer: No, thanks to HMAC validation:

ScenarioResult
Attacker sends fake webhook❌ Invalid signature → 401 Rejected
Attacker replays captured webhook❌ Nonce already used → 401 Rejected
Bitnovo sends legitimate webhook✅ Valid signature + fresh nonce → 200 Accepted

Conclusion: Only Bitnovo (with your BITNOVO_DEVICE_SECRET) can generate valid webhooks.

📋 Security Checklist

Before using in production, verify:

  • BITNOVO_DEVICE_SECRET configured and rotated regularly
  • Configuration file permissions restricted (600)
  • Using production BITNOVO_BASE_URL (https://pos.bitnovo.com)
  • Logs don't expose sensitive data
  • Tunnels with persistent URLs (ngrok domain or zrok unique-name)
  • Webhooks validated with HMAC enabled
  • Configuration backups stored securely

🔧 Troubleshooting

Common Problems and Solutions

{% hint style="info" %} Tip: Check MCP server logs for detailed diagnostics. Logs include masked security information. {% endhint %}

❌ Error: "MCP server not found" or "Server failed to start"

Cause: MCP server cannot initialize.

Solutions:

  1. Verify Node.js 18+ is installed: node --version
  2. Try running manually: npx -y @bitnovopay/mcp-bitnovo-pay
  3. Check environment variables are correctly configured
  4. Look for errors in MCP client logs (Claude Desktop: ~/Library/Logs/Claude/)

Example of correct configuration:

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": ["-y", "@bitnovopay/mcp-bitnovo-pay"],
      "env": {
        "BITNOVO_DEVICE_ID": "12345678-abcd-...",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com"
      }
    }
  }
}

❌ Error: INVALID_DEVICE_ID

Cause: Incorrect or invalid Device ID.

Solutions:

  1. Copy Device ID from Bitnovo Pay dashboard
  2. Verify it's a valid UUID (format: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)
  3. Ensure no spaces before/after the ID
  4. Confirm you're using the correct device for the environment (dev/prod)

❌ Error: CURRENCY_NOT_SUPPORTED

Cause: Requested cryptocurrency not available.

Solutions:

  1. Use list_currencies_catalog to see available options
  2. Verify exact symbol (e.g., BTC, not Bitcoin or btc)
  3. Confirm currency is active in your Bitnovo account

Example:

// ❌ Incorrect
{ "input_currency": "Bitcoin" }

// ✅ Correct
{ "input_currency": "BTC" }

❌ Error: AMOUNT_TOO_LOW / AMOUNT_TOO_HIGH

Cause: Amount outside cryptocurrency limits.

Solutions:

  1. Check limits with list_currencies_catalog
  2. Adjust amount within allowed range
  3. For large payments, consider splitting into multiple transactions

Example of limits query:

// Request
{ "filter_by_amount": 50.0 }

// Response shows min_amount and max_amount
[
  {
    "symbol": "BTC",
    "min_amount": 0.01,
    "max_amount": null  // No upper limit
  }
]

❌ Error: PAYMENT_EXPIRED

Cause: Payment exceeded expiration time limit.

Solutions:

  1. Create new payment with create_payment_onchain or create_payment_link
  2. Warn your customer about time limit before it expires
  3. Use get_payment_status to monitor expires_at field

{% hint style="warning" %} Important: Onchain payments with specific cryptocurrency start their timer immediately upon creation. Communicate this to the user. {% endhint %}


❌ Error: WEBHOOK_NOT_ENABLED

Cause: Attempting to use webhook tools without enabling them.

Solutions:

  1. Add "WEBHOOK_ENABLED": "true" to configuration
  2. (Optional) Configure tunnel with TUNNEL_ENABLED and provider
  3. Restart MCP server

Minimal webhook configuration:

{
  "env": {
    "BITNOVO_DEVICE_ID": "...",
    "BITNOVO_BASE_URL": "...",
    "BITNOVO_DEVICE_SECRET": "...",
    "WEBHOOK_ENABLED": "true"
  }
}

❌ Error: TUNNEL_CONNECTION_FAILED

Cause: Failed to connect with ngrok or zrok.

ngrok Solutions:

  1. Verify your authtoken: ngrok config check
  2. Confirm your static domain is claimed in ngrok dashboard
  3. Test manually: ngrok http --domain=your-domain.ngrok-free.app 3000

zrok Solutions:

  1. Verify zrok is enabled: zrok status
  2. Confirm reserved share exists: zrok share reserved
  3. Test connection: zrok share reserved your-share-name

❌ Error: INVALID_SIGNATURE (webhooks)

Cause: Webhook HMAC signature doesn't match.

Solutions:

  1. Verify BITNOVO_DEVICE_SECRET is correct (64 hex characters)
  2. Confirm it's the same secret configured in Bitnovo dashboard
  3. Don't modify webhook body before validation
  4. Ensure using correct device secret (dev/prod)

Complete Error Codes

CodeDescriptionRecommended Action
INVALID_DEVICE_IDInvalid Device IDVerify credentials in Bitnovo dashboard
INVALID_DEVICE_SECRETIncorrect Device SecretVerify 64-character hex format
CURRENCY_NOT_SUPPORTEDUnsupported cryptocurrencyUse list_currencies_catalog
AMOUNT_TOO_LOWAmount below minimumIncrease payment amount
AMOUNT_TOO_HIGHAmount above maximumReduce amount or split payment
PAYMENT_NOT_FOUNDPayment not foundVerify identifier
PAYMENT_EXPIREDPayment expiredCreate new payment
WEBHOOK_NOT_ENABLEDWebhooks not enabledConfigure WEBHOOK_ENABLED=true
TUNNEL_CONNECTION_FAILEDTunnel connection failedVerify ngrok/zrok credentials
INVALID_SIGNATUREInvalid HMAC signatureVerify BITNOVO_DEVICE_SECRET

Error Response Format

All errors follow this standard format:

{
  "error": {
    "code": "CURRENCY_NOT_SUPPORTED",
    "message": "The specified currency is not supported",
    "details": {
      "input_currency": "INVALID_COIN",
      "supported_currencies": ["BTC", "ETH", "USDC", "..."]
    }
  }
}

Development

Available Commands

npm run build        # Compile TypeScript to JavaScript
npm run dev          # Development server with hot reload
npm start            # Start production server

Performance

Event Store

  • Storage: In-memory (fast, no persistence)
  • Capacity: 1000 events (configurable)
  • TTL: 1 hour (configurable)
  • Cleanup: Automatic every 5 minutes
  • Indexing: Fast search by payment identifier

Tunnels

  • ngrok: ~99% uptime, ~10-50ms added latency
  • zrok: Medium-high uptime, ~20-100ms added latency
  • manual: Server-dependent, no tunnel overhead

Memory Usage

Event Store:

  • Estimated memory per event: ~2KB
  • 1000 events ≈ 2MB
  • 10000 events ≈ 20MB

Tunnel Manager:

  • ngrok: ~5-10MB overhead
  • zrok: ~10-20MB overhead (includes OpenZiti)
  • manual: ~0MB (no tunnel process)

Support and Resources

Known Limitations

  • Single-tenant operation: One Device ID per server instance
  • No local persistence: All queries are real-time to API
  • No exchange rates: For privacy and accuracy, exchange rates not exposed
  • Timeouts: 5 seconds maximum per API operation
  • Retries: Maximum 2 retries with exponential backoff
  • Event Store: In-memory (lost on restart)
  • Free tunnels: Each provider's limitations apply

Changelog

v1.1.0 (2025-09-30) - Tunnel System

  • Automatic tunnel management with 3 providers (ngrok, zrok, manual)
  • Context auto-detection (N8N, Opal, Docker, Kubernetes, VPS, local)
  • Persistent URLs with free ngrok static domains and zrok reserved shares
  • Auto-reconnection with exponential backoff (up to 10 retries)
  • Health monitoring every 60 seconds with automatic recovery
  • New MCP tools: get_webhook_url, get_tunnel_status
  • Zero configuration for common deployment scenarios

v1.0.0 (2025-09-28) - Initial Webhook Implementation

  • ✅ Initial webhook implementation
  • ✅ Event store (in-memory)
  • ✅ HMAC signature validation
  • ✅ Replay attack prevention
  • ✅ Dual-server mode (stdio + HTTP)
  • ✅ New MCP tool: get_webhook_events
  • ✅ Health check and stats endpoints

License

This project is licensed under the MIT License - see the LICENSE file for details.


Last updated: September 30, 2025 Server version: v1.1.0

Server Config

{
  "mcpServers": {
    "bitnovo-pay": {
      "command": "npx",
      "args": [
        "-y",
        "@bitnovopay/mcp-bitnovo-pay"
      ],
      "env": {
        "BITNOVO_DEVICE_ID": "your_device_id_here",
        "BITNOVO_BASE_URL": "https://pos.bitnovo.com"
      }
    }
  }
}
Recommend Servers
TraeBuild with Free GPT-4.1 & Claude 3.7. Fully MCP-Ready.
WindsurfThe new purpose-built IDE to harness magic
Amap Maps高德地图官方 MCP Server
TimeA Model Context Protocol server that provides time and timezone conversion capabilities. This server enables LLMs to get current time information and perform timezone conversions using IANA timezone names, with automatic system timezone detection.
DeepChatYour AI Partner on Desktop
Zhipu Web SearchZhipu Web Search MCP Server is a search engine specifically designed for large models. It integrates four search engines, allowing users to flexibly compare and switch between them. Building upon the web crawling and ranking capabilities of traditional search engines, it enhances intent recognition capabilities, returning results more suitable for large model processing (such as webpage titles, URLs, summaries, site names, site icons, etc.). This helps AI applications achieve "dynamic knowledge acquisition" and "precise scenario adaptation" capabilities.
Baidu Map百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Tavily Mcp
EdgeOne Pages MCPAn MCP service designed for deploying HTML content to EdgeOne Pages and obtaining an accessible public URL.
Serper MCP ServerA Serper MCP Server
ChatWiseThe second fastest AI chatbot™
Visual Studio Code - Open Source ("Code - OSS")Visual Studio Code
AiimagemultistyleA Model Context Protocol (MCP) server for image generation and manipulation using fal.ai's Stable Diffusion model.
Context7Context7 MCP Server -- Up-to-date code documentation for LLMs and AI code editors
CursorThe AI Code Editor
MiniMax MCPOfficial MiniMax Model Context Protocol (MCP) server that enables interaction with powerful Text to Speech, image generation and video generation APIs.
MCP AdvisorMCP Advisor & Installation - Use the right MCP server for your needs
Howtocook Mcp基于Anduin2017 / HowToCook (程序员在家做饭指南)的mcp server,帮你推荐菜谱、规划膳食,解决“今天吃什么“的世纪难题; Based on Anduin2017/HowToCook (Programmer's Guide to Cooking at Home), MCP Server helps you recommend recipes, plan meals, and solve the century old problem of "what to eat today"
Jina AI MCP ToolsA Model Context Protocol (MCP) server that integrates with Jina AI Search Foundation APIs.
BlenderBlenderMCP connects Blender to Claude AI through the Model Context Protocol (MCP), allowing Claude to directly interact with and control Blender. This integration enables prompt assisted 3D modeling, scene creation, and manipulation.
Playwright McpPlaywright MCP server