Skip to main content
Glama
aspiring-100x

mpp-mcp-gateway

mpp-mcp-gateway

Monetize any MCP server with stablecoin micropayments via the Machine Payments Protocol (MPP) on the Tempo blockchain.

Build MCP tool servers that charge AI agents per-call, per-session, or via access keys — settled in pathUSD and other TIP-20 stablecoins. Build AI-agent clients that pay for those tools automatically with configurable spending caps.

License: MIT

Table of Contents

Related MCP server: AgentPay

Overview

mpp-mcp-gateway is a TypeScript library that adds stablecoin micropayment gating to MCP (Model Context Protocol) servers. When an AI agent calls a paid tool, the server issues a 402 Payment Required challenge. The agent's client signs a payment transaction on the Tempo blockchain, retries the call with a credential, and the server verifies settlement before running the handler and returning the result with a receipt.

Key capabilities:

  • Four pricing models — per-call, tiered, session (payment channels), and access-key (subscriptions)

  • Multi-currency support — accept multiple TIP-20 stablecoins per tool

  • Exact revenue tracking — BigInt arithmetic prevents float drift across millions of sub-cent payments

  • Pluggable storage — in-memory, Upstash Redis (atomic CAS), Cloudflare KV, or bring your own

  • Rate limiting — token bucket (in-memory or Redis-backed) with per-tool overrides

  • Auth middleware — bearer token, API key, HTTP Basic, signed URLs, CORS — all timing-safe

  • Prometheus metrics/metrics endpoint, zero dependencies

  • OpenTelemetry tracing — opt-in span tree per paid call, zero cost when disabled

  • Webhooks — HMAC-signed event push with retry, backoff, and dead-letter hooks

  • Service discovery — OpenAPI 3.1 with x-payment-info extensions (crawled by mpp.land)

  • Dashboard — React UI + JSON API for live revenue and call monitoring

  • Graceful shutdown — drain in-flight calls, fire hooks, settle webhooks

  • Runtime-portable — works on Node.js 20+, Cloudflare Workers, Vercel Edge, Deno, Bun

How It Works

┌─────────────┐         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. Agent calls a paid tool via MCP

  2. Server responds with MCP error code -32042 containing an MPP challenge

  3. Client enforces spending caps, signs the payment, retries with a credential

  4. Server verifies on-chain settlement via mppx

  5. Handler runs, result is returned with a payment receipt (tx hash, timestamp)

Installation

npm install mpp-mcp-gateway

Peer dependencies (install only what you use):

# 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

Quick Start

Server (tool provider)

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

Pricing Models

Per-Call

Fixed price per invocation. One on-chain transaction per call.

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

Tiered

Price decreases (or increases) based on cumulative call count.

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

Session (Payment Channels)

Agent opens an on-chain escrow channel once. Subsequent calls submit signed vouchers off-chain. Server settles the highest voucher when the channel closes. Best for streaming or high-frequency tools.

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

Client-side session management:

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

Access Key (Subscriptions)

Agent pays once upfront and receives an opaque token. Subsequent calls present the token — no further payment until the key expires or is exhausted. Best for "buy a day pass" or "buy N calls" UX.

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

The client handles caching automatically:

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

Any pricing model can accept multiple TIP-20 stablecoins:

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

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

The gateway works with any MCP transport. Examples included:

Transport

Use Case

Example

stdio

CLI tools, subprocess spawning

examples/paid-weather-mcp/

Streamable HTTP

Network servers (modern)

examples/paid-weather-http/

SSE (legacy)

Older MCP clients

examples/paid-weather-sse/

In-Memory

Testing, same-process

examples/in-memory-demo/

Store Adapters

The gateway uses a pluggable MppMcpStore interface for persisting access-key records and session channel state.

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

Adapter

Atomicity

Use Case

Store.memory()

Atomic (promise-chain)

Tests, local dev, single-instance

Store.upstash(redis)

Atomic (Lua CAS)

Production, multi-instance

Store.cloudflareKv(ns)

Best-effort

Edge access keys (not for sessions)

Store.bridge(legacy)

Best-effort

Backward compat with mppx stores

Upstash Example

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

Custom Store

Implement the four-method interface:

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

The update method must guarantee atomic read-modify-write. The transform callback may be called multiple times under contention (CAS-style backends).

Rate Limiting

Rate limiting fires before payment and handler logic — denied calls never issue a 402 or run your handler.

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

For multi-instance deployments, use the Upstash-backed 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 },
})

Authentication Middleware

Five Express middleware factories for protecting dashboard, metrics, and discovery endpoints:

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

Exposes:

Endpoint

Response

GET /api/stats

{ stats: GatewayStats } — calls, revenue, sessions, keys, uptime

GET /api/tools

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

GET /api/calls?limit=N

{ calls: CallLogEntry[] } — newest first

Prometheus Metrics

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

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

Exposed metrics:

  • mppmcp_calls_total{tool} — counter by tool

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

  • mppmcp_revenue_micro_usd_total{tool} — cumulative revenue in micro-USD

  • mppmcp_in_flight_calls — gauge of active handlers

  • mppmcp_access_keys_issued_total / expired_total

  • mppmcp_sessions_opened_total / closed_total

  • mppmcp_uptime_seconds

  • mppmcp_shutting_down

React Dashboard

A pre-built React + Vite dashboard lives in dashboard/. It polls the JSON API every 2 seconds and displays:

  • Revenue counters and tool table sorted by revenue

  • Live call log color-coded by payment mode

  • Access key and session statistics

cd dashboard
npm install
npm run build

Serve dashboard/dist/ as static files from your Express app.

Service Discovery

Generate and serve an OpenAPI 3.1 document with x-payment-info extensions per the MPP service-discovery IETF draft. Public registries like mpp.land crawl this automatically.

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

Push events to a URL with HMAC-SHA-256 signatures. Delivery is fire-and-forget (non-blocking), with retry and exponential 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 })
    },
  },
})

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

Receiver verification:

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. Pass a tracer to get a span tree per paid call. Zero overhead when disabled.

import { trace } from '@opentelemetry/api'

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

Span tree:

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

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

Operator CLI

Inspect and manage deployed gateways from the command line:

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

Configuration Reference

Server (PaidMcpServerConfig)

Field

Type

Default

Description

name

string

required

Server name advertised to clients

version

string

required

Server version

recipient

0x${string}

required

Wallet address receiving payments

secretKey

string

required

HMAC key for binding payment challenges

tools

PaidToolDefinition[]

required

Tool definitions with handlers

currency

0x${string}

pathUSD

TIP-20 stablecoin contract address

network

'mainnet' | 'testnet'

'testnet'

Tempo network

feePayerKey

0x${string}

Server-sponsored gas (fee payer private key)

escrowContract

0x${string}

per-network default

Session escrow contract

accessKeyStore

MppMcpStore

in-memory

Persistence for access keys

sessionStore

MppMcpStore

in-memory

Persistence for session channels

accessKeyBinding

'none' | 'wallet'

'none'

Bind keys to paying wallet

callLogSize

number

1000

Ring buffer capacity (0 = disabled)

logger

Logger

console+redaction

Structured logger

drainTimeoutMs

number

30000

Graceful shutdown timeout

onShutdown

() => void

Hook fired when drain begins

rateLimit

object

60/min per tool

Rate limit configuration

tracer

Tracer

OpenTelemetry tracer (opt-in)

webhooks

WebhookConfig

Event push configuration

Client (PaidMcpClientConfig)

Field

Type

Default

Description

name

string

required

Client name

version

string

required

Client version

privateKey

0x${string}

required

Agent wallet private key

maxPerCall

string

'1.00'

Max spend per single call (USD)

maxTotal

string

'100.00'

Max cumulative spend (USD)

maxSessionDeposit

string

'1.00'

Max channel deposit (USD)

network

'mainnet' | 'testnet'

'testnet'

Tempo network

logger

Logger

console+redaction

Structured logger

verifySettlement

boolean

false

Verify session settlement tx on-chain

Examples

Example

Pricing

Transport

What it demonstrates

in-memory-demo

per-call

InMemory

Full 402 round-trip in one process

paid-weather-mcp

per-call

stdio

Agent spawns server as subprocess

paid-weather-http

per-call

Streamable HTTP

Network server on Express

paid-weather-sse

per-call

SSE (legacy)

Backward-compatible SSE transport

paid-weather-dashboard

per-call + access-key

Streamable HTTP

Combined MCP + dashboard + discovery

paid-streaming-mcp

session

stdio

Payment channels, vouchers, close

paid-subscription-mcp

access-key

stdio

Day pass, time-only, call packs

Run any example:

# 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

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

Funding a Test Wallet

Paid examples require a funded wallet on Tempo testnet:

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

Runtime Compatibility

The core library (server, client, stores, rate limit, amounts, access keys) is runtime-portable via Web Crypto:

Runtime

Support

Node.js 20+

Full

Cloudflare Workers

Full

Vercel Edge

Full

Deno

Full

Bun

Full

The auth.ts middleware module uses node:crypto and requires Node.js. Edge deployments use their platform's native router and auth primitives instead.

Architecture

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

Package Exports

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

  • Revenue exactness — all money math uses bigint base units (6 decimals). No float drift after millions of operations.

  • Zero-cost opt-in — tracing, webhooks, and rate limiting are no-ops unless configured. Non-traced deployments allocate no spans.

  • Pluggable everything — stores, loggers, rate limiters, and auth are interface-based. Swap implementations without touching gateway code.

  • Fail fast — configuration errors throw at construction time, not at request time.

  • Errors are values — typed error classes with stable codes. Use instanceof or err.code for programmatic handling.

  • Ring buffer call log — O(1) pre-allocated, never grows. No GC pressure under high throughput.

  • Graceful lifecycle — shutdown gate rejects new calls, drain waits for in-flight, webhook flush, then disconnect.

Development

# 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+ test files covering:

  • Access-key atomicity (concurrent redeems of N-call keys)

  • Access-key flows (issue → redeem → exhaust → re-pay)

  • Amount math (BigInt conversions, edge cases)

  • Auth middleware (all 5 factories)

  • Call-log ring buffer (wrap-around, capacity limits)

  • Graceful shutdown & drain

  • Dashboard API responses

  • Discovery / OpenAPI generation

  • Error taxonomy

  • Free tools (no-payment path)

  • Logger (structured output, redaction, child loggers)

  • Prometheus metrics formatting

  • Multi-currency discovery

  • Paid flow (402 → credential → receipt)

  • Pricing calculations (tiered, per-call)

  • Rate limiting (token bucket, denial, retry-after)

  • Revenue exactness (BigInt accumulation across many calls)

  • Runtime helpers (randomHex, hmacSha256Hex)

  • Session lifecycle (open → voucher → close → settle)

  • Spending caps (per-call, total, session deposit)

  • OpenTelemetry tracing (span attributes, error recording)

  • Webhooks (delivery, retry, HMAC signature, dead-letter)

  • Type tests (via tsd)

  • Throughput benchmarks (via vitest bench)

Graceful Shutdown

Wire close() to your container's shutdown signal:

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

Structured Logging

The library ships a pluggable Logger interface. Default: JSON to stderr with automatic redaction of secrets (private keys, credentials, signed transactions).

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

Adapt to pino, winston, or any logging library:

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

License

MIT — Gaurav Pant

A
license - permissive license
-
quality - not tested
C
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.

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