Skip to main content
Glama
aspiring-100x

mpp-mcp-gateway

mpp-mcp-gateway

Монетизируйте любой MCP-сервер с помощью микроплатежей в стейблкоинах через протокол Machine Payments Protocol (MPP) в блокчейне Tempo.

Создавайте MCP-серверы инструментов, которые взимают с AI-агентов плату за вызов, за сессию или через ключи доступа — с расчётом в pathUSD и других TIP-20 стейблкоинах. Создавайте клиенты AI-агентов, которые автоматически платят за эти инструменты с настраиваемыми лимитами расходов.

License: MIT

Table of Contents

Related MCP server: MCP Server TypeScript

Обзор

mpp-mcp-gateway — это библиотека TypeScript, которая добавляет шлюз микроплатежей в стейблкоинах к MCP-серверам (Model Context Protocol). Когда AI-агент вызывает платный инструмент, сервер отвечает ошибкой 402 Payment Required. Клиент агента подписывает платёжную транзакцию в блокчейне Tempo, повторяет вызов с учётными данными, а сервер проверяет расчёт перед запуском обработчика и возвращает результат с чеком.

Ключевые возможности:

  • Четыре модели ценообразования — за вызов, многоуровневая, сессионная (платёжные каналы) и по ключам доступа (подписки)

  • Поддержка нескольких валют — приём нескольких TIP-20 стейблкоинов для каждого инструмента

  • Точный учёт выручки — арифметика BigInt предотвращает дрейф чисел с плавающей запятой при миллионах платежей меньше цента

  • Подключаемое хранилище — in-memory, Upstash Redis (атомарный CAS), Cloudflare KV или своё собственное

  • Ограничение частоты запросов — token bucket (в памяти или на базе Redis) с переопределениями для отдельных инструментов

  • Промежуточное ПО аутентификации — bearer-токен, API-ключ, HTTP Basic, подписанные URL, CORS — всё с защитой от timing-атак

  • Метрики Prometheus — эндпоинт /metrics, без зависимостей

  • Трассировка OpenTelemetry — опциональное дерево спанов для каждого платного вызова, нулевая стоимость при отключении

  • Вебхуки — отправка событий с подписью HMAC, повторами, экспоненциальной задержкой и dead-letter хуками

  • Обнаружение сервисов — OpenAPI 3.1 с расширениями x-payment-info (сканируется mpp.land)

  • Панель мониторинга — React UI + JSON API для мониторинга выручки и вызовов в реальном времени

  • Плавное завершение работы — ожидание завершения выполняющихся вызовов, запуск хуков, обработка вебхуков

  • Переносимость между средами — работает на Node.js 20+, Cloudflare Workers, Vercel Edge, Deno, Bun

Как это работает

┌─────────────┐         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. Агент вызывает платный инструмент через MCP

  2. Сервер отвечает кодом ошибки MCP -32042, содержащим MPP-челлендж

  3. Клиент соблюдает лимиты расходов, подписывает платёж и повторяет запрос с учётными данными

  4. Сервер проверяет расчёт в блокчейне через mppx

  5. Выполняется обработчик, результат возвращается с платёжным чеком (хэш транзакции, метка времени)

Установка

npm install mpp-mcp-gateway

Пировые зависимости (устанавливайте только то, что используете):

# 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

Быстрый старт

Сервер (поставщик инструментов)

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()

Клиент (AI-агент)

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()

Модели ценообразования

За вызов

Фиксированная цена за вызов. Одна транзакция в блокчейне за вызов.

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

Многоуровневая

Цена уменьшается (или увеличивается) в зависимости от накопленного количества вызовов.

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

Сессия (платёжные каналы)

Агент один раз открывает эскроу-канал в блокчейне. Последующие вызовы отправляют подписанные ваучеры вне блокчейна. Сервер закрывает канал, забирая наибольший ваучер. Лучше всего подходит для потоковых инструментов или инструментов с высокой частотой вызовов.

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

Управление сессией на стороне клиента:

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

Ключ доступа (подписки)

Агент платит один раз заранее и получает непрозрачный токен. Последующие вызовы предъявляют токен — дальнейших платежей не требуется, пока ключ не истечёт или не будет исчерпан. Лучше всего подходит для UX «купить дневной пропуск» или «купить N вызовов».

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)
}

Клиент автоматически обрабатывает кэширование:

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

Несколько валют

Любая модель ценообразования может принимать несколько TIP-20 стейблкоинов:

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

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 })

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()

Транспорты

Шлюз работает с любым MCP-транспортом. Включены примеры:

Транспорт

Вариант использования

Пример

stdio

CLI-инструменты, запуск подпроцессов

examples/paid-weather-mcp/

Streamable HTTP

Сетевые серверы (современные)

examples/paid-weather-http/

SSE (legacy)

Старые MCP-клиенты

examples/paid-weather-sse/

In-Memory

Тестирование, в рамках одного процесса

examples/in-memory-demo/

Адаптеры хранилища

Шлюз использует подключаемый интерфейс MppMcpStore для сохранения записей ключей доступа и состояния сессионных каналов.

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

Адаптер

Атомарность

Вариант использования

Store.memory()

Атомарная (цепочка промисов)

Тесты, локальная разработка, один инстанс

Store.upstash(redis)

Атомарная (Lua CAS)

Продакшен, несколько инстансов

Store.cloudflareKv(ns)

Best-effort

Ключи доступа на периферии (не для сессий)

Store.bridge(legacy)

Best-effort

Обратная совместимость с хранилищами mppx

Пример с Upstash

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,
})

Собственное хранилище

Реализуйте интерфейс из четырёх методов:

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

Метод update должен гарантировать атомарное чтение-изменение-запись. Колбэк transform может вызываться несколько раз при конкуренции (CAS-подобные бэкенды).

Ограничение частоты запросов

Ограничение частоты запросов срабатывает до логики платежей и обработчиков — отклонённые вызовы никогда не выдают 402 и не запускают ваш обработчик.

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'}`,
  },
})

Для развёртываний с несколькими инстансами используйте ограничитель на базе Upstash:

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

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

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

Промежуточное ПО аутентификации

Пять фабрик промежуточного ПО Express для защиты эндпоинтов панели мониторинга, метрик и обнаружения:

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(),
})

Панель мониторинга и наблюдение

JSON API

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

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

Предоставляет:

Эндпоинт

Ответ

GET /api/stats

{ stats: GatewayStats } — вызовы, выручка, сессии, ключи, время работы

GET /api/tools

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

GET /api/calls?limit=N

{ calls: CallLogEntry[] } — сначала новые

GET /api/keys

{ keys: AccessKeyListEntry[] } — активные ключи доступа

DELETE /api/keys/:token

{ revoked: boolean } — отозвать ключ (изменяющий; защитите с помощью промежуточного ПО)

Метрики Prometheus

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

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

Предоставляемые метрики:

  • mppmcp_calls_total{tool} — счётчик по инструментам

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

  • mppmcp_revenue_micro_usd_total{tool} — суммарная выручка в микро-USD

  • mppmcp_in_flight_calls — датчик активных обработчиков

  • mppmcp_access_keys_issued_total / expired_total

  • mppmcp_sessions_opened_total / closed_total

  • mppmcp_rate_limited_total — вызовы, отклонённые ограничителем частоты

  • mppmcp_rejected_shutting_down_total — вызовы, отклонённые при завершении работы

  • mppmcp_uptime_seconds

  • mppmcp_shutting_down

Панель на React

Готовая панель на React + Vite находится в dashboard/. Она опрашивает JSON API каждые 2 секунды и отображает:

  • Счётчики выручки и таблицу инструментов, отсортированную по выручке

  • Живой журнал вызовов с цветовой кодировкой по режиму оплаты

  • Статистику по ключам доступа и сессиям

cd dashboard
npm install
npm run build

Отдавайте dashboard/dist/ как статические файлы из вашего Express-приложения.

Обнаружение сервисов

Создавайте и отдавайте документ OpenAPI 3.1 с расширениями x-payment-info в соответствии с черновиком IETF по обнаружению сервисов MPP. Публичные реестры, такие как mpp.land, автоматически сканируют его.

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

Вебхуки

Отправляйте события на URL с подписями HMAC-SHA-256. Доставка выполняется по принципу fire-and-forget (неблокирующая), с повторами и экспоненциальной задержкой.

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 })
    },
  },
})

Типы событий: payment.received, access-key.issued, access-key.expired, session.opened, session.closed, call.failed

Проверка получателем:

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

Опционально. Передайте трассировщик, чтобы получать дерево спанов для каждого платного вызова. Нулевые накладные расходы при отключении.

import { trace } from '@opentelemetry/api'

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

Дерево спанов:

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

Атрибуты: mppmcp.tool.name, mppmcp.pricing.type, mppmcp.amount, mppmcp.payment.mode, mppmcp.payment.tx-hash, mppmcp.session.action, mppmcp.error.code

CLI оператора

Просматривайте и управляйте развёрнутыми шлюзами из командной строки:

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

Справочник по конфигурации

Сервер (PaidMcpServerConfig)

Поле

Тип

По умолчанию

Описание

name

string

обязательно

Имя сервера, сообщаемое клиентам

version

string

обязательно

Версия сервера

recipient

0x${string}

обязательно

Адрес кошелька для получения платежей

secretKey

string

обязательно

HMAC-ключ для привязки платёжных челленджей

tools

PaidToolDefinition[]

обязательно

Определения инструментов с обработчиками

currency

0x${string}

pathUSD

Адрес контракта TIP-20 стейблкоина

network

'mainnet' | 'testnet'

'testnet'

Сеть Tempo

feePayerKey

0x${string}

Газ за счёт сервера (приватный ключ плательщика комиссии)

sessionAccountKey

0x${string}

Ключ оператора, необходимый для расчёта по сессиям

escrowContract

0x${string}

по умолчанию для сети

Эскроу-контракт сессии

accessKeyStore

MppMcpStore

в памяти

Хранилище для ключей доступа

sessionStore

MppMcpStore

в памяти

Хранилище для сессионных каналов

accessKeyBinding

'none' | 'wallet'

'none'

Привязка ключей к платящему кошельку

callLogSize

number

1000

Ёмкость кольцевого буфера (0 = отключено)

logger

Logger

console+redaction

Структурированный логгер

drainTimeoutMs

number

30000

Тайм-аут плавного завершения работы

onShutdown

() => void

Хук, вызываемый при начале завершения

rateLimit

object

60/min per tool

Конфигурация ограничения частоты

tracer

Tracer

Трассировщик OpenTelemetry (опционально)

webhooks

WebhookConfig

Конфигурация отправки событий

Клиент (PaidMcpClientConfig)

Поле

Тип

По умолчанию

Описание

name

string

обязательно

Имя клиента

version

string

обязательно

Версия клиента

privateKey

0x${string}

обязательно

Приватный ключ кошелька агента

maxPerCall

string

'1.00'

Максимальный расход за один вызов (USD)

maxTotal

string

'100.00'

Максимальный суммарный расход (USD)

maxSessionDeposit

string

'1.00'

Максимальный депозит канала (USD)

network

'mainnet' | 'testnet'

'testnet'

Сеть Tempo

logger

Logger

console+redaction

Структурированный логгер

verifySettlement

boolean

false

Проверять транзакцию расчёта сессии в блокчейне

Примеры

Пример

Ценообразование

Транспорт

Что демонстрирует

in-memory-demo

за вызов

InMemory

Полный цикл 402 в одном процессе

paid-weather-mcp

за вызов

stdio

Агент запускает сервер как подпроцесс

paid-weather-http

за вызов

Streamable HTTP

Сетевой сервер на Express

paid-weather-sse

за вызов

SSE (устаревший)

Обратно совместимый SSE-транспорт

paid-weather-dashboard

за вызов + ключ доступа

Streamable HTTP

Комбинированный MCP + дашборд + discovery

paid-streaming-mcp

сессия

stdio

Платёжные каналы, ваучеры, закрытие

paid-subscription-mcp

ключ доступа

stdio

Дневной пропуск, только по времени, пакеты вызовов

paid-peer-cash-mcp

за вызов

stdio

Доступ к инструментам Peer Cash, затем вывод дохода MPP

Запустите любой пример:

# 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

Пополнение тестового кошелька

Платные примеры требуют пополненного кошелька в тестовой сети Tempo. Пример Peer Cash — исключение: он использует основную сеть Tempo, поскольку маршрут дохода доступен только в live-режиме.

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

Совместимость сред выполнения

Базовая библиотека (сервер, клиент, хранилища, ограничение скорости, суммы, ключи доступа) переносима между средами выполнения через Web Crypto:

Среда выполнения

Поддержка

Node.js 20+

Полная

Cloudflare Workers

Полная

Vercel Edge

Полная

Deno

Полная

Bun

Полная

Модуль промежуточного слоя auth.ts использует node:crypto и требует Node.js. Edge-развёртывания вместо этого используют нативный роутер и примитивы аутентификации своей платформы.

Архитектура

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

Экспорт пакета

{
  ".": "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"
}

Принципы проектирования

  • Точность расчётов — все денежные вычисления используют базовые единицы bigint (6 десятичных знаков). Никакого дрейфа чисел с плавающей точкой после миллионов операций.

  • Подключение без затрат — трассировка, вебхуки и ограничение скорости являются no-op, если не настроены. Развёртывания без трассировки не выделяют спаны.

  • Всё подключаемо — хранилища, логгеры, ограничители скорости и аутентификация основаны на интерфейсах. Меняйте реализации, не трогая код шлюза.

  • Быстрый отказ — ошибки конфигурации выбрасываются в момент создания, а не в момент запроса.

  • Ошибки — это значения — типизированные классы ошибок со стабильными кодами. Используйте instanceof или err.code для программной обработки.

  • Кольцевой буфер журнала вызовов — O(1) с предварительным выделением памяти, никогда не растёт. Нет нагрузки на GC при высокой пропускной способности.

  • Плавный жизненный цикл — шлюз завершения отклоняет новые вызовы, drain ожидает выполняющиеся, сброс вебхуков, затем отключение.

Разработка

# 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

Набор тестов

27+ тестовых файлов, покрывающих:

  • Атомарность ключей доступа (одновременные погашения ключей на N вызовов)

  • Потоки ключей доступа (выпуск → погашение → исчерпание → повторная оплата)

  • Математика сумм (конвертации BigInt, крайние случаи)

  • Промежуточный слой аутентификации (все 5 фабрик)

  • Кольцевой буфер журнала вызовов (переполнение, ограничения ёмкости)

  • Плавное завершение и drain

  • Ответы API дашборда

  • Генерация Discovery / OpenAPI

  • Таксономия ошибок

  • Бесплатные инструменты (путь без оплаты)

  • Логгер (структурированный вывод, редактирование, дочерние логгеры)

  • Форматирование метрик Prometheus

  • Мультивалютный discovery

  • Платный поток (402 → учётные данные → квитанция)

  • Расчёт цен (тарифы, за вызов)

  • Ограничение скорости (token bucket, отказ, retry-after)

  • Точность расчётов (накопление BigInt при множестве вызовов)

  • Хелперы среды выполнения (randomHex, hmacSha256Hex)

  • Жизненный цикл сессии (открытие → ваучер → закрытие → расчёт)

  • Лимиты расходов (за вызов, суммарный, депозит сессии)

  • Трассировка OpenTelemetry (атрибуты спанов, запись ошибок)

  • Вебхуки (доставка, повтор, подпись HMAC, dead-letter)

  • Тесты типов (через tsd)

  • Бенчмарки пропускной способности (через vitest bench)

Плавное завершение

Подключите close() к сигналу завершения вашего контейнера:

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

Структурированное логирование

Библиотека поставляется с подключаемым интерфейсом Logger. По умолчанию: JSON в stderr с автоматическим редактированием секретов (приватные ключи, учётные данные, подписанные транзакции).

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(),
})

Адаптируйте под pino, winston или любую библиотеку логирования:

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) */,
}

Лицензия

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