Skip to main content
Glama
aspiring-100x

mpp-mcp-gateway

mpp-mcp-gateway

Monetarisieren Sie jeden MCP-Server mit Stablecoin-Mikrozahlungen über das Machine Payments Protocol (MPP) auf der Tempo-Blockchain.

Erstellen Sie MCP-Tool-Server, die KI-Agenten pro Aufruf, pro Sitzung oder über Zugriffsschlüssel abrechnen – abgerechnet in pathUSD und anderen TIP-20-Stablecoins. Erstellen Sie KI-Agent-Clients, die für diese Tools automatisch mit konfigurierbaren Ausgabenobergrenzen bezahlen.

License: MIT

Inhaltsverzeichnis

Related MCP server: MCP Server TypeScript

Übersicht

mpp-mcp-gateway ist eine TypeScript-Bibliothek, die MCP-Servern (Model Context Protocol) eine Zugangskontrolle per Stablecoin-Mikrozahlungen hinzufügt. Wenn ein KI-Agent ein kostenpflichtiges Tool aufruft, sendet der Server eine Challenge mit dem Status 402 Payment Required. Der Client des Agenten signiert eine Zahlungstransaktion auf der Tempo-Blockchain, wiederholt den Aufruf mit einem Berechtigungsnachweis, und der Server verifiziert die Abrechnung, bevor er den Handler ausführt und das Ergebnis mit einer Quittung zurückgibt.

Hauptfunktionen:

  • Vier Preismodelle — pro Aufruf, gestaffelt, Sitzung (Zahlungskanäle) und Zugriffsschlüssel (Abonnements)

  • Multi-Währungs-Unterstützung — mehrere TIP-20-Stablecoins pro Tool akzeptieren

  • Exakte Umsatzverfolgung — BigInt-Arithmetik verhindert Float-Drift bei Millionen von Sub-Cent-Zahlungen

  • Austauschbarer Speicher — In-Memory, Upstash Redis (atomares CAS), Cloudflare KV oder eigener Speicher

  • Ratenbegrenzung — Token-Bucket (In-Memory oder Redis-gestützt) mit Überschreibungen pro Tool

  • Auth-Middleware — Bearer-Token, API-Schlüssel, HTTP Basic, signierte URLs, CORS – alles timing-sicher

  • Prometheus-Metriken/metrics-Endpunkt, keine Abhängigkeiten

  • OpenTelemetry-Tracing — optionaler Span-Baum pro kostenpflichtigem Aufruf, keine Kosten, wenn deaktiviert

  • Webhooks — HMAC-signierter Event-Push mit Wiederholung, Backoff und Dead-Letter-Hooks

  • Service-Discovery — OpenAPI 3.1 mit x-payment-info-Erweiterungen (von mpp.land gecrawlt)

  • Dashboard — React-UI + JSON-API für Live-Umsatz- und Aufrufüberwachung

  • Graceful Shutdown — laufende Aufrufe abwickeln, Hooks auslösen, Webhooks zustellen

  • Laufzeitportabel — funktioniert auf Node.js 20+, Cloudflare Workers, Vercel Edge, Deno, Bun

So funktioniert es

┌─────────────┐         402 Challenge         ┌──────────────────┐
│  AI Agent   │ ────────────────────────────── │  Paid MCP Server │
│  (Client)   │                                │  (Gateway)       │
│             │ ◄── Payment Required (-32042)  │                  │
│             │                                │                  │
│  Signs tx   │ ── Credential (signed payment) │  Verifies on     │
│  via mppx   │                            ──► │  Tempo chain     │
│             │                                │                  │
│             │ ◄── Tool Result + Receipt      │  Runs handler    │
└─────────────┘                                └──────────────────┘
  1. Der Agent ruft ein kostenpflichtiges Tool über MCP auf

  2. Der Server antwortet mit dem MCP-Fehlercode -32042, der eine MPP-Challenge enthält

  3. Der Client setzt Ausgabenobergrenzen durch, signiert die Zahlung und wiederholt den Aufruf mit einem Berechtigungsnachweis

  4. Der Server verifiziert die On-Chain-Abrechnung über mppx

  5. Der Handler wird ausgeführt, das Ergebnis wird mit einer Zahlungsquittung (Transaktions-Hash, Zeitstempel) zurückgegeben

Installation

npm install mpp-mcp-gateway

Peer-Abhängigkeiten (nur installieren, was Sie verwenden):

# For HTTP/Express transports and dashboard
npm install express

# For Upstash Redis stores / rate limiting
npm install @upstash/redis

# For OpenTelemetry tracing
npm install @opentelemetry/api

# For Cloudflare Workers KV store
npm install @cloudflare/workers-types

Schnellstart

Server (Tool-Anbieter)

import { createPaidMcpServer } from 'mpp-mcp-gateway/server'
import { z } from 'zod'

const server = createPaidMcpServer({
  name: 'my-api',
  version: '1.0.0',
  recipient: '0xYourWalletAddress',
  secretKey: process.env.PAYMENT_SECRET_KEY!,
  network: 'testnet',
  tools: [
    {
      name: 'get_weather',
      description: 'Get weather for a city. $0.001 per call.',
      inputSchema: { city: z.string() },
      pricing: { type: 'per-call', amount: '0.001' },
      handler: async ({ city }) => ({
        content: [{ type: 'text', text: `Weather in ${city}: 72°F, sunny` }],
      }),
    },
    {
      name: 'ping',
      description: 'Free liveness check.',
      inputSchema: {},
      // No pricing = free tool
      handler: async () => ({
        content: [{ type: 'text', text: 'pong' }],
      }),
    },
  ],
})

await server.startStdio()

Client (KI-Agent)

import { createPaidMcpClient } from 'mpp-mcp-gateway/client'
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'

const client = createPaidMcpClient({
  name: 'my-agent',
  version: '1.0.0',
  privateKey: process.env.AGENT_PRIVATE_KEY! as `0x${string}`,
  maxPerCall: '0.10',    // safety cap: max $0.10 per single call
  maxTotal: '10.00',     // safety cap: max $10.00 total spend
  network: 'testnet',
})

const transport = new StdioClientTransport({
  command: 'node',
  args: ['server.js'],
})
await client.connect(transport)

// Free call — no payment required
const ping = await client.callTool('ping')
console.log(ping.content[0].text) // "pong"
console.log(ping.paid)            // false

// Paid call — automatic 402 → sign → retry
const weather = await client.callTool('get_weather', { city: 'Tokyo' })
console.log(weather.content[0].text) // "Weather in Tokyo: 72°F, sunny"
console.log(weather.paid)            // true
console.log(weather.receipt?.reference) // "0xabc...def" (tx hash)

await client.close()

Preismodelle

Pro Aufruf

Fester Preis pro Aufruf. Eine On-Chain-Transaktion pro Aufruf.

pricing: { type: 'per-call', amount: '0.001' }

Gestaffelt

Der Preis sinkt (oder steigt) basierend auf der kumulierten Anzahl der Aufrufe.

pricing: {
  type: 'tiered',
  tiers: [
    { upTo: 100, amount: '0.01' },
    { upTo: 1000, amount: '0.005' },
    { upTo: 'unlimited', amount: '0.001' },
  ],
}

Sitzung (Zahlungskanäle)

Der Agent öffnet einmalig einen On-Chain-Escrow-Kanal. Nachfolgende Aufrufe übermitteln signierte Vouchers off-chain. Der Server begleicht den höchsten Voucher, wenn der Kanal geschlossen wird. Am besten geeignet für Streaming- oder hochfrequente Tools.

pricing: {
  type: 'session',
  amount: '0.0005',          // per-unit price
  unitType: 'request',       // informational label
  suggestedDeposit: '0.50',  // hint for initial channel funding
}

Clientseitige Sitzungsverwaltung:

// Make multiple calls against the same channel
await client.callTool('think', { topic: 'AI alignment' })
await client.callTool('think', { topic: 'quantum computing' })

// Cooperatively close and settle on-chain
const result = await client.closeSession('think')
console.log(result.receipt.reference) // settlement tx hash

Zugriffsschlüssel (Abonnements)

Der Agent zahlt einmalig im Voraus und erhält einen undurchsichtigen Token. Nachfolgende Aufrufe präsentieren den Token – keine weitere Zahlung, bis der Schlüssel abläuft oder aufgebraucht ist. Am besten geeignet für die UX „Tagespass kaufen“ oder „N Aufrufe kaufen“.

pricing: {
  type: 'access-key',
  amount: '0.01',       // upfront cost
  validFor: '1d',       // time limit (supports: 60s, 30m, 4h, 7d)
  maxCalls: 100,        // call limit (at least one of validFor/maxCalls required)
}

Der Client übernimmt das Caching automatisch:

// First call: pays $0.01, receives access key
const r1 = await client.callTool('premium_data', { query: 'foo' })
console.log(r1.paid)                    // true
console.log(r1.accessKey?.justIssued)   // true
console.log(r1.accessKey?.remainingCalls) // 99

// Subsequent calls: free (key presented in _meta)
const r2 = await client.callTool('premium_data', { query: 'bar' })
console.log(r2.paid)  // false

Multi-Währung

Jedes Preismodell kann mehrere TIP-20-Stablecoins akzeptieren:

pricing: {
  type: 'per-call',
  amount: '0.001',
  accept: [
    { currency: '0x20c0...0000', amount: '0.001' }, // pathUSD
    { currency: '0x20c0...0001', amount: '0.001' }, // alphaUSD
  ],
}

Server-API

import { createPaidMcpServer, PaidMcpServer } from 'mpp-mcp-gateway/server'

const server = createPaidMcpServer(config)

// Start on stdio (for CLI / subprocess use)
await server.startStdio()

// Or access the underlying McpServer for custom transports
const mcpServer = server.server
await mcpServer.connect(someTransport)

// Runtime inspection
server.getStats()           // GatewayStats (calls, revenue, sessions, keys)
server.listTools()          // tool names, descriptions, current prices
server.getRecentCalls(100)  // last N calls from the ring buffer
server.getInFlightCount()   // currently active handlers
server.isShuttingDown()     // true after close() begins
server.describe()           // full descriptor for discovery/OpenAPI

// Access-key management
await server.listAccessKeys()          // live keys issued by this instance
await server.revokeAccessKey(token)    // { revoked: boolean }

// Graceful shutdown
await server.close({ timeoutMs: 25_000 })

Client-API

import { createPaidMcpClient, PaidMcpClient } from 'mpp-mcp-gateway/client'

const client = createPaidMcpClient(config)

await client.connect(transport)
await client.listTools()
const result = await client.callTool('tool_name', { arg: 'value' })

// Spending state
client.getSpending()    // { totalSpent, remaining, maxTotal, maxPerCall, ... }
client.resetSpending()  // reset cumulative counter (for tests)

// Access key management
client.getAccessKeys()          // cached keys by tool name
client.clearAccessKey('tool')   // force re-payment on next call
client.clearAccessKeys()        // drop all cached keys

// Session management
client.getOpenSessions()        // open channels by tool name
await client.closeSession('tool') // settle channel on-chain

await client.close()

Transports

Das Gateway funktioniert mit jedem MCP-Transport. Beispiele sind enthalten:

Transport

Anwendungsfall

Beispiel

stdio

CLI-Tools, Subprozess-Spawning

examples/paid-weather-mcp/

Streamable HTTP

Netzwerkserver (modern)

examples/paid-weather-http/

SSE (veraltet)

Ältere MCP-Clients

examples/paid-weather-sse/

In-Memory

Tests, gleicher Prozess

examples/in-memory-demo/

Store-Adapter

Das Gateway verwendet eine austauschbare MppMcpStore-Schnittstelle zum Speichern von Zugriffsschlüssel-Datensätzen und Sitzungskanal-Zuständen.

import { Store } from 'mpp-mcp-gateway/stores'

Adapter

Atomarität

Anwendungsfall

Store.memory()

Atomar (Promise-Kette)

Tests, lokale Entwicklung, Einzelinstanz

Store.upstash(redis)

Atomar (Lua-CAS)

Produktion, Multi-Instanz

Store.cloudflareKv(ns)

Best-effort

Edge-Zugriffsschlüssel (nicht für Sitzungen)

Store.bridge(legacy)

Best-effort

Abwärtskompatibilität mit mppx-Stores

Upstash-Beispiel

import { Redis } from '@upstash/redis'
import { createUpstashStore } from 'mpp-mcp-gateway/stores'

const store = createUpstashStore(
  new Redis({ url: process.env.UPSTASH_URL!, token: process.env.UPSTASH_TOKEN! }),
  { keyPrefix: 'mppmcp:', ttlSeconds: 30 * 24 * 3600 }
)

const server = createPaidMcpServer({
  // ...
  accessKeyStore: store,
  sessionStore: store,
})

Eigener Store

Implementieren Sie die Schnittstelle mit vier Methoden:

interface MppMcpStore {
  get<T>(key: string): Promise<T | null>
  put(key: string, value: unknown): Promise<void>
  delete(key: string): Promise<void>
  update<T>(key: string, transform: (current: T | null) => T | null): Promise<T | null>
}

Die update-Methode muss ein atomares Read-Modify-Write garantieren. Der transform-Callback kann bei Konflikten mehrfach aufgerufen werden (CAS-basierte Backends).

Ratenbegrenzung

Die Ratenbegrenzung greift vor der Zahlungs- und Handler-Logik – abgelehnte Aufrufe lösen niemals eine 402 aus und führen Ihren Handler nicht aus.

const server = createPaidMcpServer({
  // ...
  rateLimit: {
    refillPerMinute: 60,   // sustained rate
    capacity: 10,          // burst capacity
    perTool: {
      expensive_ai: { refillPerMinute: 5, capacity: 2 },
      cheap_lookup:  { refillPerMinute: 600, capacity: 100 },
    },
    // Custom bucketing (e.g. per-session on HTTP transports)
    keyExtractor: (toolName, extra) => `${toolName}:${extra.sessionId ?? 'default'}`,
  },
})

Für Multi-Instanz-Bereitstellungen verwenden Sie den Upstash-gestützten Limiter:

import { upstashTokenBucketLimiter } from 'mpp-mcp-gateway/rate-limit'

const limiter = upstashTokenBucketLimiter(redis, {
  keyPrefix: 'mppmcp:rl:',
  refillPerMinute: 120,
  capacity: 20,
})

const server = createPaidMcpServer({
  // ...
  rateLimit: { limiter },
})

Authentifizierungs-Middleware

Fünf Express-Middleware-Fabriken zum Schutz von Dashboard-, Metrik- und Discovery-Endpunkten:

import { auth } from 'mpp-mcp-gateway'

// Bearer token (constant-time comparison)
mountDashboard(server, app, {
  middleware: auth.bearerToken(process.env.DASHBOARD_TOKEN!, { realm: 'admin' }),
})

// API key in custom header
mountMetrics(server, app, {
  middleware: auth.apiKey({ header: 'x-api-key', value: process.env.METRICS_KEY! }),
})

// HTTP Basic Auth (multi-user)
mountDashboard(server, app, {
  middleware: auth.basicAuth({ users: { admin: 'secret' }, realm: 'gateway' }),
})

// HMAC-signed URLs with TTL
mountDashboard(server, app, {
  middleware: auth.signedQuery({ secret: process.env.URL_SECRET!, ttlSeconds: 300 }),
})

// Public CORS for registry crawlers
mountDiscovery(server, app, {
  middleware: auth.publicCors(),
})

Dashboard & Monitoring

JSON-API

import { mountDashboard } from 'mpp-mcp-gateway'

mountDashboard(server, app, { prefix: '/api' })

Bietet:

Endpunkt

Antwort

GET /api/stats

{ stats: GatewayStats } — Aufrufe, Umsatz, Sitzungen, Schlüssel, Betriebszeit

GET /api/tools

{ tools: [{ name, description, price }] }

GET /api/calls?limit=N

{ calls: CallLogEntry[] } — neueste zuerst

GET /api/keys

{ keys: AccessKeyListEntry[] } — aktive Zugriffsschlüssel

DELETE /api/keys/:token

{ revoked: boolean } — Schlüssel widerrufen (verändernd; mit Middleware schützen)

Prometheus-Metriken

import { mountMetrics } from 'mpp-mcp-gateway'

mountMetrics(server, app, {
  middleware: auth.bearerToken(process.env.METRICS_TOKEN!),
})

Bereitgestellte Metriken:

  • mppmcp_calls_total{tool} — Zähler nach Tool

  • mppmcp_calls_by_mode_total{mode} — paid, free, session, access_key, total

  • mppmcp_revenue_micro_usd_total{tool} — kumulativer Umsatz in micro-USD

  • mppmcp_in_flight_calls — Messgröße (Gauge) für aktive Handler

  • mppmcp_access_keys_issued_total / expired_total

  • mppmcp_sessions_opened_total / closed_total

  • mppmcp_rate_limited_total — Aufrufe, die von der Ratenbegrenzung abgelehnt wurden

  • mppmcp_rejected_shutting_down_total — Aufrufe, die während des Herunterfahrens abgelehnt wurden

  • mppmcp_uptime_seconds

  • mppmcp_shutting_down

React-Dashboard

Ein vorgefertigtes React- + Vite-Dashboard befindet sich in dashboard/. Es fragt die JSON-API alle 2 Sekunden ab und zeigt:

  • Umsatzzähler und Tool-Tabelle, sortiert nach Umsatz

  • Live-Aufrufprotokoll, farbcodiert nach Zahlungsmodus

  • Zugriffsschlüssel- und Sitzungsstatistiken

cd dashboard
npm install
npm run build

Stellen Sie dashboard/dist/ als statische Dateien über Ihre Express-App bereit.

Service-Discovery

Generieren und stellen Sie ein OpenAPI-3.1-Dokument mit x-payment-info-Erweiterungen gemäß dem MPP-Service-Discovery-IETF-Entwurf bereit. Öffentliche Registries wie mpp.land crawlen dies automatisch.

import { mountDiscovery } from 'mpp-mcp-gateway'

mountDiscovery(server, app, {
  baseUrl: 'https://api.example.com',
  categories: ['data', 'search'],
  docs: { homepage: 'https://example.com/docs' },
})
// GET /openapi.json → OpenAPI 3.1 with x-payment-info per tool

Webhooks

Senden Sie Ereignisse mit HMAC-SHA-256-Signaturen an eine URL. Die Zustellung erfolgt fire-and-forget (nicht blockierend), mit Wiederholung und exponentiellem Backoff.

const server = createPaidMcpServer({
  // ...
  webhooks: {
    url: 'https://example.com/webhook',
    secret: process.env.WEBHOOK_SECRET!,
    events: ['payment.received', 'session.closed'], // or omit for all
    maxAttempts: 3,
    onDrop: async (event, lastError) => {
      // Dead-letter: persist to DB for replay
      await db.insert('webhook_dlq', { event, error: lastError })
    },
  },
})

Ereignistypen: payment.received, access-key.issued, access-key.expired, session.opened, session.closed, call.failed

Empfängerverifizierung:

import { createHmac } from 'node:crypto'

function verify(req) {
  const expected = 'sha256=' + createHmac('sha256', WEBHOOK_SECRET)
    .update(`${req.headers['x-mppmcp-timestamp']}.${req.body}`)
    .digest('hex')
  return timingSafeEqual(Buffer.from(expected), Buffer.from(req.headers['x-mppmcp-signature']))
}

OpenTelemetry-Tracing

Opt-in. Übergeben Sie einen Tracer, um einen Span-Baum pro kostenpflichtigem Aufruf zu erhalten. Kein Overhead, wenn deaktiviert.

import { trace } from '@opentelemetry/api'

const server = createPaidMcpServer({
  // ...
  tracer: trace.getTracer('mpp-mcp-gateway', '1.0.0'),
})

Span-Baum:

mppmcp.tool.call (root)
├── mppmcp.payment.charge   (or mppmcp.session.advance, mppmcp.access-key.redeem)
└── mppmcp.handler.run

Attribute: mppmcp.tool.name, mppmcp.pricing.type, mppmcp.amount, mppmcp.payment.mode, mppmcp.payment.tx-hash, mppmcp.session.action, mppmcp.error.code

Operator-CLI

Bereitgestellte Gateways über die Befehlszeile inspizieren und verwalten:

npx mpp-mcp inspect https://my-gateway.fly.dev --token=secret123
npx mpp-mcp stats https://api.example.com
npx mpp-mcp tools https://api.example.com
npx mpp-mcp calls https://api.example.com --limit=50
npx mpp-mcp keys list https://api.example.com --token=admin
npx mpp-mcp keys revoke mppmcp_abc123... https://api.example.com --token=admin

Konfigurationsreferenz

Server (PaidMcpServerConfig)

Feld

Typ

Standard

Beschreibung

name

string

required

Server-Name, der Clients angezeigt wird

version

string

required

Serverversion

recipient

0x${string}

required

Wallet-Adresse, die Zahlungen empfängt

secretKey

string

required

HMAC-Schlüssel zum Binden von Zahlungs-Challenges

tools

PaidToolDefinition[]

required

Tool-Definitionen mit Handlern

currency

0x${string}

pathUSD

TIP-20-Stablecoin-Vertragsadresse

network

'mainnet' | 'testnet'

'testnet'

Tempo-Netzwerk

feePayerKey

0x${string}

Vom Server übernommene Gasgebühren (privater Schlüssel des Fee Payers)

sessionAccountKey

0x${string}

Operator-Schlüssel, der für die Sitzungsabrechnung erforderlich ist

escrowContract

0x${string}

netzwerkabhängiger Standard

Escrow-Vertrag für Sitzungen

accessKeyStore

MppMcpStore

in-memory

Persistenz für Zugriffsschlüssel

sessionStore

MppMcpStore

in-memory

Persistenz für Sitzungskanäle

accessKeyBinding

'none' | 'wallet'

'none'

Schlüssel an die zahlende Wallet binden

callLogSize

number

1000

Ringpufferkapazität (0 = deaktiviert)

logger

Logger

console+redaction

Strukturierter Logger

drainTimeoutMs

number

30000

Timeout für Graceful Shutdown

onShutdown

() => void

Hook, der ausgelöst wird, wenn das Abdrainen beginnt

rateLimit

object

60/min pro Tool

Konfiguration der Ratenbegrenzung

tracer

Tracer

OpenTelemetry-Tracer (Opt-in)

webhooks

WebhookConfig

Konfiguration für Event-Push

Client (PaidMcpClientConfig)

Feld

Typ

Standard

Beschreibung

name

string

erforderlich

Client-Name

version

string

erforderlich

Client-Version

privateKey

0x${string}

erforderlich

Privater Schlüssel der Agent-Wallet

maxPerCall

string

'1.00'

Maximale Ausgabe pro einzelnem Aufruf (USD)

maxTotal

string

'100.00'

Maximale kumulative Ausgabe (USD)

maxSessionDeposit

string

'1.00'

Maximale Kanaleinzahlung (USD)

network

'mainnet' | 'testnet'

'testnet'

Tempo-Netzwerk

logger

Logger

console+redaction

Strukturierter Logger

verifySettlement

boolean

false

Sitzungsabrechnungstransaktion on-chain verifizieren

Beispiele

Beispiel

Preisgestaltung

Transport

Was es demonstriert

in-memory-demo

pro Aufruf

InMemory

Vollständiger 402-Roundtrip in einem Prozess

paid-weather-mcp

pro Aufruf

stdio

Agent startet Server als Unterprozess

paid-weather-http

pro Aufruf

Streamable HTTP

Netzwerkserver auf Express

paid-weather-sse

pro Aufruf

SSE (Legacy)

Abwärtskompatibler SSE-Transport

paid-weather-dashboard

pro Aufruf + Zugriffsschlüssel

Streamable HTTP

Kombiniertes MCP + Dashboard + Discovery

paid-streaming-mcp

Sitzung

stdio

Zahlungskanäle, Gutscheine, Schließen

paid-subscription-mcp

Zugriffsschlüssel

stdio

Tagespass, nur Zeit, Anrufpakete

paid-peer-cash-mcp

pro Aufruf

stdio

Peer-Cash-Tools absichern, dann MPP-Einnahmen auszahlen

Führen Sie ein beliebiges Beispiel aus:

# In-memory demo (no wallet needed)
npm run example:demo

# Server + client pairs
npm run example:server      # then in another terminal:
npm run example:client

npm run example:http:server
npm run example:http:client

npm run example:streaming:server
npm run example:streaming:client

npm run example:subscription:server
npm run example:subscription:client

# Node.js 22+, Tempo mainnet
npm run example:peer-cash:server

# Dashboard (with all endpoints)
npm run example:dashboard:server

Test-Wallet aufladen

Bezahlte Beispiele erfordern eine finanzierte Wallet im Tempo-Testnetz. Das Peer-Cash-Beispiel ist die Ausnahme: Es verwendet das Tempo-Mainnet, da die Einnahmenroute nur live verfügbar ist.

cast rpc tempo_fundAddress 0xYourAddress --rpc-url https://rpc.moderato.tempo.xyz

Laufzeitkompatibilität

Die Kernbibliothek (Server, Client, Stores, Rate-Limit, Beträge, Zugriffsschlüssel) ist über Web Crypto laufzeitportabel:

Laufzeit

Unterstützung

Node.js 20+

Voll

Cloudflare Workers

Voll

Vercel Edge

Voll

Deno

Voll

Bun

Voll

Das Middleware-Modul auth.ts verwendet node:crypto und erfordert Node.js. Edge-Bereitstellungen verwenden stattdessen den nativen Router und die nativen Auth-Primitive ihrer Plattform.

Architektur

src/
├── server.ts          PaidMcpServer — payment gating, stats, shutdown, webhooks
├── client.ts          PaidMcpClient — auto-payment, caps, key caching, sessions
├── types.ts           Core interfaces (PricingModel, configs, stats, results)
├── index.ts           Barrel exports (11 subpath entry points)
├── access-keys.ts     Issue, redeem (atomic), validate, duration parsing
├── amounts.ts         BigInt <-> USD string conversion (exact arithmetic)
├── auth.ts            5 Express middleware factories (timing-safe)
├── cli.ts             Operator CLI (inspect, stats, tools, calls, keys)
├── constants.ts       Tempo networks, token addresses, escrow contracts
├── dashboard.ts       JSON API: /api/stats, /api/tools, /api/calls
├── discovery.ts       OpenAPI 3.1 generation with x-payment-info
├── errors.ts          9 typed error classes with stable codes
├── logger.ts          Logger interface + 4 implementations + redaction
├── metrics.ts         Prometheus /metrics (hand-formatted, zero deps)
├── rate-limit.ts      RateLimiter interface + 3 implementations
├── runtime.ts         Cross-runtime: randomHex, writeLogLine, hmacSha256Hex
├── tracing.ts         OTel span helpers (no-op when disabled)
├── webhooks.ts        HMAC-signed event push with retry + dead-letter
└── stores/
    ├── types.ts       MppMcpStore interface
    ├── index.ts       Store namespace + re-exports
    ├── memory.ts      In-memory (atomic via promise chains)
    ├── upstash.ts     Upstash Redis (atomic via Lua CAS)
    ├── cloudflare-kv.ts  Cloudflare KV (best-effort)
    └── bridge.ts      Legacy 3-method store adapter

Paket-Exporte

{
  ".": "Main barrel (everything)",
  "./server": "PaidMcpServer",
  "./client": "PaidMcpClient",
  "./dashboard": "mountDashboard",
  "./discovery": "mountDiscovery, buildOpenApi",
  "./stores": "Store adapters",
  "./rate-limit": "Rate limiter implementations",
  "./auth": "Auth middleware factories",
  "./metrics": "mountMetrics, formatMetrics",
  "./tracing": "startSpan, withSpan, TRACE_ATTRS",
  "./webhooks": "WebhookDispatcher, event types"
}

Design-Prinzipien

  • Umsatzgenauigkeit — Die gesamte Geldmathematik verwendet bigint-Basiseinheiten (6 Dezimalstellen). Kein Float-Drift nach Millionen von Operationen.

  • Null-Kosten-Opt-in — Tracing, Webhooks und Ratenbegrenzung sind No-ops, sofern nicht konfiguriert. Nicht getracete Bereitstellungen allozieren keine Spans.

  • Alles austauschbar — Stores, Logger, Ratenbegrenzer und Auth sind schnittstellenbasiert. Implementierungen austauschen, ohne Gateway-Code anzufassen.

  • Fail fast — Konfigurationsfehler werden zur Konstruktionszeit geworfen, nicht zur Anfragezeit.

  • Fehler sind Werte — Typisierte Fehlerklassen mit stabilen Codes. Verwenden Sie instanceof oder err.code für die programmatische Behandlung.

  • Ringpuffer-Anrufprotokoll — O(1) vorab allokiert, wächst nie. Kein GC-Druck bei hohem Durchsatz.

  • Sanfter Lebenszyklus — Das Shutdown-Gate lehnt neue Aufrufe ab, Drain wartet auf laufende, Webhook-Flush, dann Trennen.

Entwicklung

# Install dependencies
npm install

# Build
npm run build

# Type check
npm run typecheck

# Run tests
npm run test

# Run tests in watch mode
npm run test:watch

# Type tests (tsd)
npm run test:types

# Benchmarks
npm run bench

# Generate docs
npm run docs

Test-Suite

27+ Testdateien, die Folgendes abdecken:

  • Access-Key-Atomizität (gleichzeitige Einlösungen von N-Call-Keys)

  • Access-Key-Abläufe (Ausstellung → Einlösung → Erschöpfung → erneute Zahlung)

  • Betragsmathematik (BigInt-Konvertierungen, Randfälle)

  • Auth-Middleware (alle 5 Factories)

  • Call-Log-Ringpuffer (Überlauf, Kapazitätsgrenzen)

  • Sanftes Herunterfahren & Drain

  • Dashboard-API-Antworten

  • Discovery / OpenAPI-Generierung

  • Fehlertaxonomie

  • Kostenlose Tools (Pfad ohne Zahlung)

  • Logger (strukturierte Ausgabe, Schwärzung, Child-Logger)

  • Prometheus-Metrikenformatierung

  • Multi-Währungs-Discovery

  • Bezahlter Ablauf (402 → Credential → Quittung)

  • Preisberechnungen (gestaffelt, pro Aufruf)

  • Ratenbegrenzung (Token-Bucket, Ablehnung, Retry-After)

  • Umsatzgenauigkeit (BigInt-Akkumulation über viele Aufrufe)

  • Laufzeit-Helfer (randomHex, hmacSha256Hex)

  • Sitzungslebenszyklus (öffnen → Gutschein → schließen → abrechnen)

  • Ausgabengrenzen (pro Aufruf, gesamt, Sitzungseinzahlung)

  • OpenTelemetry-Tracing (Span-Attribute, Fehleraufzeichnung)

  • Webhooks (Zustellung, Wiederholung, HMAC-Signatur, Dead-Letter)

  • Typtests (über tsd)

  • Durchsatz-Benchmarks (über vitest bench)

Sanftes Herunterfahren

Binden Sie close() an das Herunterfahrsignal Ihres Containers:

process.on('SIGTERM', async () => {
  try {
    await server.close({ timeoutMs: 25_000 })
    process.exit(0)
  } catch {
    process.exit(1) // drain timed out
  }
})

Strukturierte Protokollierung

Die Bibliothek enthält eine austauschbare Logger-Schnittstelle. Standard: JSON nach stderr mit automatischer Schwärzung von Geheimnissen (private Schlüssel, Anmeldedaten, signierte Transaktionen).

import { consoleLogger, silentLogger, withRedaction } from 'mpp-mcp-gateway'

// Custom logger
const server = createPaidMcpServer({
  // ...
  logger: withRedaction(consoleLogger({ level: 'debug', pretty: true })),
})

// Silence for tests
const server = createPaidMcpServer({
  // ...
  logger: silentLogger(),
})

Passen Sie es an pino, winston oder eine beliebige Logging-Bibliothek an:

const adapter: Logger = {
  debug: (m, c) => pino.debug(c, m),
  info: (m, c) => pino.info(c, m),
  warn: (m, c) => pino.warn(c, m),
  error: (m, c) => pino.error(c, m),
  child: (bindings) => /* wrap pino.child(bindings) */,
}

Lizenz

MIT — Gaurav Pant

A
license - permissive license
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • -
    license
    Not graded
    quality
    Not graded
    maintenance
    A production-ready TypeScript MCP server providing basic tools (add, echo, timestamp), resources (server info, greetings, data access), and prompt templates (analyze, code-review, summarize). Serves as a foundation for building custom MCP servers with extensible architecture.
    225
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for AgentPay — the payment gateway for autonomous AI agents. Fund a wallet once, give your agent the key, and it discovers, provisions, and pays for tool APIs on its own. One key, every tool.
    112
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Simplifies creating MCP servers in TypeScript with an Express-like API and experimental decorators, enabling quick definition of tools, resources, and prompts.
    26
    196
    MIT

View all related MCP servers

Related MCP Connectors

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/aspiring-100x/mpp-mcp-gateway'

If you have feedback or need assistance with the MCP directory API, please join our Discord server