Skip to content
reaatechREAATECH

@reaatech/mcp-gateway-gateway

npm v1.0.0

Provides a full-featured Model Context Protocol (MCP) gateway server as an Express 5 application, complete with built-in authentication, rate limiting, schema validation, and OpenTelemetry observability. It includes a `createApp()` factory for programmatic configuration and a CLI binary for managing deployments, diagnostics, and health checks.

@reaatech/mcp-gateway-gateway

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Production-grade MCP Gateway server. This is the full Express 5-based gateway that wires together authentication, rate limiting, schema validation, tool allowlists, fan-out routing, response caching, audit trail logging, and OpenTelemetry observability into a single createApp() factory. Ships with a CLI binary for start, health check, config validation, and diagnostics.

Installation

terminal
npm install @reaatech/mcp-gateway-gateway
# or
pnpm add @reaatech/mcp-gateway-gateway

Quick Start

CLI

terminal
npx mcp-gateway start --port 8080 --config gateway.yaml
terminal
# Other CLI commands
mcp-gateway validate-config --config gateway.yaml
mcp-gateway health --url http://localhost:8080 --deep
mcp-gateway list-tenants
mcp-gateway list-upstreams --tenant acme-corp
mcp-gateway rate-limit-status --tenant acme-corp
mcp-gateway cache-stats --url http://localhost:8080

Programmatic

typescript
import { createApp } from "@reaatech/mcp-gateway-gateway";
 
const gateway = createApp();
 
gateway.app.listen(8080, () => {
  console.log("MCP Gateway listening on :8080");
});
 
// Graceful shutdown
process.on("SIGTERM", async () => {
  await gateway.close();
  process.exit(0);
});

Feature Overview

  • Full middleware pipeline — auth → rate limit → validation → allowlist → cache → fan-out → upstream
  • MCP JSON-RPC endpointPOST /mcp with complete protocol handling
  • Admin APIGET /api/v1/tenants, /api/v1/upstreams, /api/v1/cache/stats, /api/v1/rate-limits/status, /api/v1/audit
  • Health endpointsGET /health (liveness), GET /health/deep (deep probes)
  • CLI binarymcp-gateway with 7 subcommands for diagnostics and management
  • Graceful shutdown — drains in-flight requests, closes Redis connections, flushes OTel telemetry
  • Configurable via YAMLgateway.yaml for server config, per-tenant YAML files for routing/auth/limits
  • Dual ESM/CJS output — works with import and require

API Reference

createApp(options?): GatewayApp

Factory function that builds the Express application with the full middleware pipeline.

typescript
const gateway = createApp({
  rateLimiter: myCustomLimiter,      // Pre-configured rate limiter (optional)
  cacheManager: myCustomCache,        // Pre-configured cache manager (optional)
  auditStorage: myStorage,            // Pre-configured audit storage (optional)
  upstreamCaller: myCaller,           // Custom upstream caller (optional, for tests)
});

CreateAppOptions

PropertyTypeDescription
rateLimiterRateLimiterPre-configured rate limiter. If omitted, created from env config.
cacheManagerCacheManagerPre-configured cache manager. Created from config if omitted.
auditStorageMemoryAuditStoragePre-configured audit storage. File-backed from config if omitted.
upstreamCallerUpstreamCallerCustom upstream caller for fan-out (injects test doubles).

GatewayApp

Property / MethodDescription
appExpress 5 application instance
rateLimiterActive rate limiter
cacheManagerActive cache manager
auditStorageActive audit storage
emitAudit(type, data?)Emit an audit event programmatically
close()Graceful shutdown — closes rate limiter, cache, file watchers

Middleware Pipeline

Requests to POST /mcp flow through this pipeline:

code
1. express.json()        → Parse JSON body (10 MB limit)
2. authMiddleware()      → API key / JWT / OAuth / OIDC validation
3. Rate limit check      → Per-tenant token bucket + daily quota
4. Schema validation     → JSON-RPC 2.0 structure + MCP method params
5. Allowlist check       → Tool access control (for tools/call only)
6. Cache check           → Return cached response if hit (skips upstream)
7. Fan-out router        → Broadcast to upstreams, aggregate responses
8. Error handler         → Catch AuthenticationError, validation errors, etc.

Endpoints

MethodPathDescription
GET/healthLiveness check (always returns 200 while process is alive)
GET/health/deepDeep health — runs all registered probes, returns per-component status
POST/mcpMain MCP JSON-RPC endpoint (requires auth)
GET/api/v1/tenantsList all tenants (requires auth. Admin scope sees all, tenant scope sees self)
GET/api/v1/tenants/:idGet a specific tenant
GET/api/v1/upstreams?tenant_id=...List upstreams for a tenant
GET/api/v1/cache/statsCache statistics (hits, misses, size)
GET/api/v1/rate-limits/status?tenant_id=...Rate limit status for a tenant
GET/api/v1/audit?tenant_id=...&event_type=...&limit=...Query audit events

CLI Reference

CommandDescription
startStart the gateway server (--port, --config)
validate-configValidate gateway and tenant YAML configs (--config, --tenant-dir)
healthCheck gateway health (--url, --deep, --api-key)
cache-statsShow cache statistics (--url, --api-key)
list-tenantsList configured tenants
list-upstreamsList upstream servers (--tenant)
rate-limit-statusShow rate limit status (--tenant)

Usage Patterns

Custom upstream caller (test doubles)

typescript
import { createApp, type UpstreamCaller } from "@reaatech/mcp-gateway-gateway";
 
const mockCaller: UpstreamCaller = async (upstream, request) => ({
  upstream: upstream.name,
  response: { jsonrpc: "2.0", id: "1", result: { content: [] } },
  success: true,
  latencyMs: 5,
});
 
const gateway = createApp({ upstreamCaller: mockCaller });
// → Fan-out uses mockCaller instead of real HTTP

Pre-configured rate limiter

typescript
import { createRateLimiter } from "@reaatech/mcp-gateway-rate-limit";
import { createApp } from "@reaatech/mcp-gateway-gateway";
import { createClient } from "redis";
 
const redis = createClient({ url: "redis://localhost:6379" });
await redis.connect();
 
const limiter = createRateLimiter("redis", {
  requestsPerMinute: 1000,
  requestsPerDay: 100000,
  burstSize: 50,
}, redis);
 
const gateway = createApp({ rateLimiter: limiter });

Graceful shutdown

typescript
import { createApp } from "@reaatech/mcp-gateway-gateway";
 
const gateway = createApp();
const server = gateway.app.listen(8080);
 
const shutdown = async (signal: string) => {
  console.log(`${signal} received — shutting down gracefully`);
  await new Promise((resolve) => server.close(resolve));
  await gateway.close();
  process.exit(0);
};
 
process.on("SIGTERM", () => shutdown("SIGTERM"));
process.on("SIGINT", () => shutdown("SIGINT"));

License

MIT