# MCP - Model Context Protocol

### 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

| Concept             | Description                                                                             |
| ------------------- | --------------------------------------------------------------------------------------- |
| **MCP Server**      | Process that exposes capabilities (tools, resources) through the MCP protocol via stdio |
| **MCP Tools**       | Functions that the AI model can invoke (e.g., `create_payment_link`)                    |
| **MCP Resources**   | Data that the server can provide to the model (e.g., cryptocurrency catalog)            |
| **stdio Transport** | Communication 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](https://modelcontextprotocol.io/)
{% endhint %}

***

### Quick Start (5 minutes)

#### Step 1: Get your credentials

1. Create an account at [Bitnovo Pay](https://www.bitnovo.com/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):

```json
{
  "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 %}

| Requirement                  | Description                                                    | Needed for                      |
| ---------------------------- | -------------------------------------------------------------- | ------------------------------- |
| ✅ **Node.js 18+**            | JavaScript runtime                                             | Running MCP server              |
| ✅ **Bitnovo Pay Account**    | Registration at [bitnovo.com/pay](https://www.bitnovo.com/pay) | Obtain credentials              |
| ✅ **Device ID**              | Device identifier from dashboard                               | All operations                  |
| ⚠️ **Device Secret**         | HMAC secret (optional)                                         | Webhooks with validation        |
| ✅ **MCP Client**             | Claude, ChatGPT, or Gemini                                     | Interact with server            |
| ⚠️ **ngrok/zrok** (optional) | Tunnel for webhooks                                            | Local 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:

#### Option 1: Using npx (Recommended)

{% 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:

```bash
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:

```bash
# 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`

**Option A: Using npx (Recommended)**

```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)**:

```json
{
  "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`

**Option A: Using npx (Recommended)**

```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)**

```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"
      }
    }
  }
}
```

**Configuration with webhooks (local development with ngrok)**

```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",
        "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**

```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",
        "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**:

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

**Response**:

```json
{
  "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"

***

**2. create\_payment\_link**

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**:

```json
{
  "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**:

```json
{
  "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**:

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

**Response**:

```json
{
  "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**:

```json
{
  "filter_by_amount": 25.0
}
```

**Response**:

```json
{
  "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**:

```json
{
  "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**:

```json
{
  "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**:

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

**Response**:

```json
{
  "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**:

```json
{
  "validate": true
}
```

**Response**:

```json
{
  "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**:

```json
{
  "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**

| Provider   | Cost                   | Persistent URL          | Best For               | Stability        |
| ---------- | ---------------------- | ----------------------- | ---------------------- | ---------------- |
| **ngrok**  | Free (1 static domain) | ✅ Yes                   | Local development      | \~99% uptime     |
| **zrok**   | 100% Free              | ✅ Yes (reserved shares) | Open-source preference | Medium-high      |
| **manual** | Depends on hosting     | ✅ Yes                   | Servers with public IP | Server-dependent |

**1. ngrok (Recommended for Local Development)**

**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**:

```bash
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](https://dashboard.ngrok.com/signup)
2. Get authtoken from [dashboard](https://dashboard.ngrok.com/get-started/your-authtoken)
3. Claim free static domain at [domains](https://dashboard.ngrok.com/cloud-edge/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**:

```bash
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](https://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:

| Environment    | Detection Method                            |
| -------------- | ------------------------------------------- |
| **N8N**        | Variables `N8N_HOST` or `N8N_PROTOCOL`      |
| **Opal**       | Variables `OPAL_WEBHOOK_URL` or `OPAL_HOST` |
| **Kubernetes** | Variable `KUBERNETES_SERVICE_HOST`          |
| **Docker**     | File `/.dockerenv` or `DOCKER_HOST`         |
| **VPS/Server** | Multiple indicators (systemd, PM2, etc.)    |

**Configuration**:

```bash
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

| Feature                      | create\_payment\_onchain         | create\_payment\_link                 |
| ---------------------------- | -------------------------------- | ------------------------------------- |
| **Returns**                  | Crypto address + QR              | Web URL                               |
| **Customer chooses crypto?** | No (fixed)                       | Yes (in gateway)                      |
| **Best for**                 | Crypto-specific payments         | Generic payments (DEFAULT)            |
| **Sharing method**           | Show QR/address                  | Send link                             |
| **Redirects**                | N/A                              | Yes (url\_ok/url\_ko)                 |
| **Use when**                 | User specifies crypto            | NO 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**:

```json
{
  "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**:

```json
{
  "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**:

```json
{
  "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**:

```json
{
  "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`

```json
{
  "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`

```json
{
  "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`

```json
{
  "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`

```json
{
  "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`

```json
{
  "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**:

```javascript
// 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**:

```json
{
  "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

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

#### Webhook Variables (Optional)

```bash
# 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)

```bash
# 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:

```javascript
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**:

```bash
# 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:

| Scenario                          | Result                                         |
| --------------------------------- | ---------------------------------------------- |
| 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**:

```json
{
  "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**:

```json
// ❌ 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**:

```json
// 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**:

```json
{
  "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](https://dashboard.ngrok.com/cloud-edge/domains)
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

| Code                       | Description                | Recommended Action                      |
| -------------------------- | -------------------------- | --------------------------------------- |
| `INVALID_DEVICE_ID`        | Invalid Device ID          | Verify credentials in Bitnovo dashboard |
| `INVALID_DEVICE_SECRET`    | Incorrect Device Secret    | Verify 64-character hex format          |
| `CURRENCY_NOT_SUPPORTED`   | Unsupported cryptocurrency | Use `list_currencies_catalog`           |
| `AMOUNT_TOO_LOW`           | Amount below minimum       | Increase payment amount                 |
| `AMOUNT_TOO_HIGH`          | Amount above maximum       | Reduce amount or split payment          |
| `PAYMENT_NOT_FOUND`        | Payment not found          | Verify identifier                       |
| `PAYMENT_EXPIRED`          | Payment expired            | Create new payment                      |
| `WEBHOOK_NOT_ENABLED`      | Webhooks not enabled       | Configure `WEBHOOK_ENABLED=true`        |
| `TUNNEL_CONNECTION_FAILED` | Tunnel connection failed   | Verify ngrok/zrok credentials           |
| `INVALID_SIGNATURE`        | Invalid HMAC signature     | Verify BITNOVO\_DEVICE\_SECRET          |

#### Error Response Format

All errors follow this standard format:

```json
{
  "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

```bash
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

* **GitHub Repository**: [github.com/bitnovo/mcp-bitnovo-pay](https://github.com/bitnovo/mcp-bitnovo-pay)
* **Issues**: [github.com/bitnovo/mcp-bitnovo-pay/issues](https://github.com/bitnovo/mcp-bitnovo-pay/issues)
* **Bitnovo Support**: [bitnovo.com](https://www.bitnovo.com/)
* **MCP Protocol**: [modelcontextprotocol.io](https://modelcontextprotocol.io/)
* **ngrok**: [ngrok.com](https://ngrok.com) | [docs](https://ngrok.com/docs)
* **zrok**: [zrok.io](https://zrok.io) | [docs](https://docs.zrok.io)

### 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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://bitnovo.gitbook.io/pay/bitnovo-pay/integrations/mcp-model-context-protocol.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
