Skip to content
reaatech

@reaatech/mcp-gateway-cache

npm v1.1.0

A cache manager for MCP Gateway responses, providing in-memory LRU or Redis backends with per-tool TTL strategies, `Cache-Control` bypass support, and standard `X-Cache` headers, exposed as a class (`CacheManager`) and an Express middleware function.

@reaatech/mcp-gateway-cache

npm version License: MIT CI

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

Response caching for the MCP Gateway. Supports in-memory LRU and Redis backends with per-tool cache strategies, Cache-Control bypass, and standard X-Cache response headers.

Installation

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

For Redis support:

terminal
npm install redis

Feature Overview

  • Two storage backends — in-memory LRU (Map-based) and Redis
  • Per-tool cache strategies — different TTLs per tool pattern (e.g. glean_* → 60s, *_static → 3600s)
  • Cache bypass — clients send Cache-Control: no-cache to skip the cache
  • Standard HTTP headersX-Cache: HIT \| MISS, X-Cache-TTL, X-Cache-Key
  • Express middlewarecacheMiddleware() wraps the cache manager for drop-in use
  • Dual ESM/CJS output — works with import and require

Quick Start

typescript
import { CacheManager, cacheMiddleware } from "@reaatech/mcp-gateway-cache";
import express from "express";
 
// In-memory cache with 5-minute default TTL
const cache = new CacheManager({
  store: "memory",
  ttlSeconds: 300,
});
 
const app = express();
app.use(cacheMiddleware(cache));
typescript
// Redis-backed cache with per-tool strategies
import { createClient } from "redis";
import { CacheManager, DEFAULT_CACHE_STRATEGIES } from "@reaatech/mcp-gateway-cache";
 
const redis = createClient({ url: "redis://localhost:6379" });
await redis.connect();
 
const cache = new CacheManager({
  store: "redis",
  redisClient: redis,
  ttlSeconds: 300,
  strategies: [
    ...DEFAULT_CACHE_STRATEGIES,
    { tools: ["my_custom_tool"], ttlSeconds: 120 },
  ],
});

API Reference

CacheManager (class)

MethodDescription
get(key)Retrieve a cached response
set(key, value, toolName?)Store a response (respects per-tool TTL)
delete(key)Remove a specific entry
clear()Clear all entries
getStats()Get cache statistics
getTtlForTool(toolName)Get TTL for a specific tool
shouldBypass(headers)Check Cache-Control header for bypass
generateKey(method, params, tenantId)Generate a cache key
setStrategies(strategies)Update cache strategies at runtime
isEnabledWhether caching is enabled

MemoryCache (class)

In-memory LRU cache. Same interface as CacheManager minus tools/strategies.

MethodDescription
get(key)Retrieve a cached entry
set(key, value, ttlMs?)Store an entry
delete(key)Remove an entry
has(key)Check if key exists
clear()Clear all entries
getStats()Get stats: hits, misses, size, evictions
static generateKey(...)Utility to generate hash keys

RedisCache (class)

Redis-backed cache.

Same interface as MemoryCache. Constructor takes a Redis client.

Cache Strategies

ExportDescription
createCacheStrategies(config?)Create strategies array from config
shouldCacheTool(toolName, strategies)Check if tool matches any strategy
DEFAULT_CACHE_STRATEGIESBuilt-in defaults: glean_search/serval_query (60s), *_static/*_readonly (3600s)

Middleware

ExportDescription
cacheMiddleware(cacheManager)Express middleware — checks cache, sets X-Cache headers, caches responses

Types

TypeDescription
CacheEntry{ key, value, expiresAt, createdAt, tool?, tenantId? }
CacheConfig{ enabled, defaultTtlSeconds, maxEntries?, store, redisClient? }
CacheStats{ hits, misses, size, evictions }
ToolCacheStrategy{ tools: string[], ttlSeconds: number }

Cache Response Headers

HeaderDescription
X-CacheHIT or MISS
X-Cache-TTLRemaining TTL in seconds
X-Cache-KeyCache key used (for debugging)

Usage Patterns

Cache bypass via header

typescript
// Client request
fetch("/mcp", {
  headers: { "Cache-Control": "no-cache" },
  body: JSON.stringify({ jsonrpc: "2.0", method: "tools/call", ... }),
});
// → cacheMiddleware skips lookup and storage

Programmatic cache usage

typescript
import { MemoryCache } from "@reaatech/mcp-gateway-cache";
 
const cache = new MemoryCache({ maxEntries: 1000 });
await cache.set("key1", { result: "cached data" }, 60000);
 
const entry = await cache.get("key1");
console.log(entry?.value.result); // "cached data"
console.log(cache.getStats());   // { hits: 1, misses: 0, size: 1, evictions: 0 }

Fastify

The cache orchestration is framework-agnostic (cacheLookup / cacheStore over a CacheController). The Express middleware is memory-backed via CacheManager; the Fastify plugin wires the existing RedisCache so the Fastify path is Redis-backed.

typescript
import Fastify from "fastify";
import { fastifyAuth } from "@reaatech/mcp-gateway-auth/fastify";
import { RedisCache } from "@reaatech/mcp-gateway-cache";
import { fastifyCache } from "@reaatech/mcp-gateway-cache/fastify";
 
const app = Fastify();
const redis = new RedisCache(redisClient);
 
await app.register(fastifyAuth);
await app.register(fastifyCache, {
  redis,
  config: { enabled: true, defaultTtlSeconds: 300 },
});
 
app.post("/mcp", async () => callUpstream());

On a cache HIT the plugin calls reply.hijack() and writes the stored body/headers (X-Cache: HIT, X-Cache-TTL, X-Cache-Key) directly to the raw socket, so Fastify does not re-serialize the payload. On a MISS an onSend hook captures the response and stores successful (non-error) results. Pass { manager } instead of { redis } for an in-memory backend, or { controller } for a custom one. fastify is an optional peer dependency.

Registration order: auth → rate-limit → allowlist → audit → cache — register fastifyCache last so it caches only requests that passed every gate.

License

MIT