npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-chaos-monkey

v1.0.0

Published

Chaos/fault injection framework for MCP (Model Context Protocol) projects

Readme

mcp-chaos-monkey (TypeScript)

Chaos/fault injection framework for MCP (Model Context Protocol) projects. Inject faults at the transport level so resilience wrappers (circuit breakers, retries, timeouts) exercise naturally.

Zero runtime dependencies. Optional peer deps for Express and Redis interceptors.

Installation

npm install mcp-chaos-monkey

Quick Start

import { ChaosController } from 'mcp-chaos-monkey';
import { createChaosAwareFetch } from 'mcp-chaos-monkey/interceptors/http';

// Inject a fault
const controller = ChaosController.getInstance();
const faultId = controller.inject('weather-api', {
  type: 'error',
  statusCode: 503,
  message: 'Service unavailable',
});

// Wrap fetch — faults are applied automatically
const fetch = createChaosAwareFetch('weather-api');
const response = await fetch('https://api.weather.com/forecast');
// → Response { status: 503 }

// Clean up
controller.clear(faultId);

Architecture

Faults are injected at the transport level, sitting between your application code and the real service. This means resilience wrappers (circuit breakers, retries, timeouts) exercise naturally without mocking:

┌─────────────────────────────────────────────────────┐
│  Application Code                                   │
│  (MCP client, agent, tool handler)                  │
├─────────────────────────────────────────────────────┤
│  Resilience Layer                                   │
│  (circuit breaker, retry, timeout)                  │
├─────────────────────────────────────────────────────┤
│  ★ mcp-chaos-monkey ★                              │
│  (fault injection at transport level)               │
├─────────────────────────────────────────────────────┤
│  Transport                                          │
│  (fetch, Redis, auth middleware)                    │
├─────────────────────────────────────────────────────┤
│  External Service                                   │
│  (API, database, auth provider)                     │
└─────────────────────────────────────────────────────┘

The key insight: faults are injected below the resilience layer so that circuit breakers, retries, and timeouts trigger organically — exactly as they would in a real outage.

Production Safety

The framework refuses to run in production. Two hard guards must both pass:

  1. NODE_ENV must not be "production" — throws immediately
  2. CHAOS_ENABLED must be "true" — prevents accidental activation
// These checks happen automatically when ChaosController is created.
// You can also call them explicitly:
import { assertChaosAllowed } from 'mcp-chaos-monkey';
assertChaosAllowed(); // throws if unsafe

Fault Types

| Type | Description | Key Fields | |------|-------------|------------| | latency | Adds delay before real call | delayMs | | error | Returns fake error response | statusCode, message? | | timeout | Hangs then throws AbortError | hangMs | | malformed | Returns corrupted response body | corruptResponse | | connection-refused | Throws TypeError (network error) | -- | | connection-drop | Starts real request, aborts mid-stream | afterBytes? | | rate-limit | Returns 429 with Retry-After | retryAfterSeconds | | schema-mismatch | Strips fields from real response | missingFields |

All fault types support an optional probability field (0--1) for probabilistic injection.

API Reference

ChaosController

import { ChaosController } from 'mcp-chaos-monkey';

const controller = ChaosController.getInstance(); // singleton

// Inject a fault — returns a unique fault ID
const faultId = controller.inject('weather-api', {
  type: 'latency',
  delayMs: 2000,
}, 30_000); // optional: auto-expire after 30s

// Query faults
const fault = controller.getFault('weather-api');   // FaultConfig | null
const all = controller.getActiveFaults();            // readonly snapshot

// Clean up
controller.clear(faultId);  // remove one
controller.clearAll();       // remove all

// Test isolation
ChaosController.reset(); // destroy singleton + clear all faults

HTTP Interceptor

Wraps fetch to apply faults for a given target:

import { createChaosAwareFetch } from 'mcp-chaos-monkey/interceptors/http';

// Wrap globalThis.fetch (default)
const fetch = createChaosAwareFetch('weather-api');

// Or wrap a custom fetch
const fetch = createChaosAwareFetch('weather-api', myCustomFetch);

Redis Interceptor

Wraps Redis commands (get, set, del, hget, hset, expire, ttl, keys, mget):

import { wrapRedisWithChaos } from 'mcp-chaos-monkey/interceptors/redis';

const unwrap = wrapRedisWithChaos(redisClient, 'redis');

// Later: restore original methods
unwrap();

Auth Interceptor

Express middleware that intercepts auth-related faults:

import { chaosAuthMiddleware, createChaosAuthMiddleware } from 'mcp-chaos-monkey/interceptors/auth';

// Fixed target: 'oauth-token'
app.use(chaosAuthMiddleware);

// Configurable target
app.use(createChaosAuthMiddleware('api-key'));

Custom Targets with TypeScript Type Safety

FaultTarget is an open string type, so you can inject faults for any target. For project-specific type safety, define your own union:

import type { FaultTarget } from 'mcp-chaos-monkey';
import { ChaosController } from 'mcp-chaos-monkey';

// Your project's targets
type MyTarget = 'weather-api' | 'flight-api' | 'redis' | 'oauth-token';

function injectTypedFault(target: MyTarget, ...args: Parameters<ChaosController['inject']> extends [any, ...infer R] ? R : never) {
  return ChaosController.getInstance().inject(target, ...args);
}

// Type-safe: only your targets accepted
injectTypedFault('weather-api', { type: 'error', statusCode: 503 });
// injectTypedFault('typo-api', ...); // TypeScript error

You can also create a stricter type guard:

const MY_TARGETS = ['weather-api', 'flight-api', 'redis', 'oauth-token'] as const;
type MyTarget = typeof MY_TARGETS[number];

function isMyTarget(value: unknown): value is MyTarget {
  return typeof value === 'string' && (MY_TARGETS as readonly string[]).includes(value);
}

Express Admin Endpoints

Register REST endpoints for runtime fault management:

import { registerChaosEndpoint } from 'mcp-chaos-monkey/admin';

registerChaosEndpoint(app);

This registers 4 routes:

| Method | Path | Description | |--------|------|-------------| | GET | /chaos/status | List all active faults | | POST | /chaos/inject | Inject a new fault | | POST | /chaos/clear | Clear a specific fault | | POST | /chaos/clear-all | Clear all faults |

Example requests:

# Check status
curl http://localhost:3000/chaos/status

# Inject a fault
curl -X POST http://localhost:3000/chaos/inject \
  -H 'Content-Type: application/json' \
  -d '{"target":"weather-api","config":{"type":"error","statusCode":503}}'

# Clear a fault
curl -X POST http://localhost:3000/chaos/clear \
  -H 'Content-Type: application/json' \
  -d '{"faultId":"weather-api-1234-abc"}'

# Clear all
curl -X POST http://localhost:3000/chaos/clear-all

CLI Usage

The package ships a CLI tool for managing faults from the terminal:

# Install globally or use npx
npx mcp-chaos inject <target> <type> [--status N] [--delay N] [--duration N]
npx mcp-chaos clear <faultId>
npx mcp-chaos clear-all
npx mcp-chaos status

Examples:

# Inject a 503 error on weather-api
npx mcp-chaos inject weather-api error --status 503

# Inject latency with auto-expiry after 30s
npx mcp-chaos inject redis latency --delay 2000 --duration 30

# Check what's active
npx mcp-chaos status

# Clean up
npx mcp-chaos clear-all

Note: CHAOS_ENABLED=true and NODE_ENV!=production must be set in the environment.

Scenario Builder

Define reproducible chaos scenarios for structured testing:

import { defineScenario } from 'mcp-chaos-monkey';
import type { ChaosScenario } from 'mcp-chaos-monkey';

const apiTimeout: ChaosScenario = defineScenario({
  name: 'weather-api-timeout',
  description: 'Weather API hangs for 10s — timeout fires, retries exhaust',
  faults: [
    { target: 'weather-api', config: { type: 'timeout', hangMs: 10_000 } },
  ],
  expectedBehavior: 'Each attempt times out at 5s. Retries fire and all fail.',
  assertions: [
    'Each retry attempt hits timeout at 5s',
    'Total latency bounded by retry * timeout',
    'Partial response includes flight data',
  ],
});

// Cascading failure — multiple faults
const cascading: ChaosScenario = defineScenario({
  name: 'cascading-redis-then-api',
  description: 'Redis drops, then weather API starts failing',
  faults: [
    { target: 'redis', config: { type: 'connection-refused' } },
    { target: 'weather-api', config: { type: 'error', statusCode: 503 } },
  ],
  expectedBehavior: 'System degrades to flight-only without cache.',
  assertions: [
    'System remains responsive',
    'Flight queries still work end-to-end',
  ],
});

// Temporary fault with auto-expiry
const recovery: ChaosScenario = defineScenario({
  name: 'api-recovery',
  description: 'API fails then recovers — circuit should close',
  faults: [
    { target: 'weather-api', config: { type: 'error', statusCode: 503 }, durationMs: 35_000 },
  ],
  expectedBehavior: 'Circuit opens, fault expires, circuit closes.',
  assertions: ['Circuit transitions: CLOSED -> OPEN -> HALF_OPEN -> CLOSED'],
});

Pluggable Logger

By default, the library logs to console.*. To use your own logger (e.g., pino), call configureChaosLogger once at startup:

import { configureChaosLogger } from 'mcp-chaos-monkey';
import pino from 'pino';

// Pino's Logger satisfies ChaosLogger directly — no adapter needed
configureChaosLogger((name) => pino({ name }));

The ChaosLogger interface requires debug, info, warn, error methods with pino-compatible signatures.

License

MIT