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

@listo-ai/mcp-ip-guard

v0.2.2

Published

IP allowlist guard for MCP servers. Ships with OpenAI/ChatGPT egress IP ranges and supports custom CIDR ranges. Zero dependencies.

Readme

@listo-ai/mcp-ip-guard

IP allowlist guard for MCP servers. Ships with OpenAI/ChatGPT egress IP ranges, Anthropic/Claude outbound IPs, Fastly CDN ranges, and Microsoft Azure public cloud ranges for ChatGPT developer mode. Supports custom CIDR ranges. Zero production dependencies.

Install

npm install @listo-ai/mcp-ip-guard

Quick Start

import { createIpGuard } from '@listo-ai/mcp-ip-guard';

// Creates a guard with all OpenAI/ChatGPT IPs pre-loaded
const guard = createIpGuard();

// In your HTTP handler:
const { allowed, clientIp } = guard.handleRequest(req, res);
if (!allowed) return; // 403 already sent

Options

const guard = createIpGuard({
  // Include OpenAI/ChatGPT egress IPs (default: true)
  includeOpenAiRanges: true,

  // Include Azure public cloud IPs for ChatGPT developer mode (default: false)
  includeAzureRanges: false,

  // Include Fastly CDN IPs — OpenAI's edge CDN (default: false)
  includeFastlyRanges: false,

  // Include Anthropic/Claude outbound IPs (default: false)
  includeAnthropicRanges: false,

  // Add your own IPs/CIDR ranges
  additionalRanges: [
    '10.0.0.0/8',        // CIDR range
    '192.168.1.100',     // Single IP (treated as /32)
  ],

  // Allow localhost in non-production (default: true)
  allowLocalhostInDev: true,

  // Number of trusted reverse proxies (default: 1)
  // See "Reverse Proxy Configuration" section below
  trustedProxyDepth: 1,

  // Log blocked IPs to stdout (default: false)
  debug: false,

  // Hook for telemetry / custom logging
  onBlocked: (clientIp, path) => {
    console.log(`Blocked ${clientIp} on ${path}`);
  },
});

API

createIpGuard(options?): IpGuard

Creates a new guard instance.

guard.isAllowed(ip: string): boolean

Check if a raw IP address string is in the allowlist.

guard.getClientIp(req: IncomingMessage): string

Extract the client IP from an HTTP request. Uses X-Forwarded-For[-trustedProxyDepth] to select the IP added by the outermost trusted proxy.

guard.handleRequest(req, res): GuardResult

Full request gate. Extracts IP, checks allowlist. If blocked, sends a 403 JSON response automatically. Returns { allowed: boolean, clientIp: string }.

guard.rangeCount: number

Total number of parsed CIDR ranges in the allowlist.

OPENAI_IP_RANGES: readonly string[]

The raw list of OpenAI/ChatGPT egress IP ranges in CIDR notation. Useful if you need to inspect or use them directly.

AZURE_IP_RANGES: readonly string[]

Microsoft Azure public cloud IPv4 ranges (10,360 CIDRs). Used when ChatGPT developer mode routes requests through Azure infrastructure instead of dedicated OpenAI egress IPs.

FASTLY_IP_RANGES: readonly string[]

Fastly CDN public IPv4 ranges (19 CIDRs). OpenAI uses Fastly as their edge CDN.

ANTHROPIC_IP_RANGES: readonly string[]

Anthropic (Claude) outbound IPv4 ranges. Used when Claude makes MCP tool calls to your server.

Low-level utilities

import { parseCidr, parseIpv4, ipMatchesRange } from '@listo-ai/mcp-ip-guard';

Usage with MCP Server

import http from 'node:http';
import { createIpGuard } from '@listo-ai/mcp-ip-guard';

const guard = createIpGuard({
  debug: process.env.TELEMETRY_DEBUG === 'true',
  onBlocked: (ip, path) => {
    observability.recordBusinessEvent('ip_blocked', {
      properties: { ip, path },
      status: 'error',
      category: 'system',
    });
  },
});

const server = http.createServer((req, res) => {
  const url = new URL(req.url ?? '/', `http://${req.headers.host}`);

  // Only guard MCP endpoints
  if (url.pathname === '/mcp' || url.pathname === '/mcp/messages') {
    const { allowed } = guard.handleRequest(req, res);
    if (!allowed) return;
  }

  // ... handle request
});

Reverse Proxy Configuration

The guard extracts the client IP from the X-Forwarded-For header using trustedProxyDepth to select the correct entry. Getting this value wrong means the guard checks the wrong IP — either a proxy's IP (too shallow) or a spoofable client-supplied IP (too deep).

How trustedProxyDepth works

Each reverse proxy in the chain appends the connecting IP to X-Forwarded-For. The guard reads from the right side of the header, skipping trustedProxyDepth entries from the end:

X-Forwarded-For: <client_ip>, <proxy1_ip>, <proxy2_ip>
                  depth=3 ──┘    depth=2 ──┘    depth=1 ──┘

Common deployments

| Platform | Proxy chain | Depth | XFF example | |---|---|---|---| | Railway | Client → Fastly CDN → Railway proxy → App | 3 | 52.173.123.5, 140.248.67.158, 167.82.233.39 | | Cloudflare only | Client → Cloudflare → App | 2 | 52.173.123.5, 172.70.x.x | | Single LB | Client → Load Balancer → App | 2 | 52.173.123.5, 10.0.0.1 | | Direct | Client → App | 1 | 52.173.123.5 |

Railway example

Railway routes all traffic through Fastly CDN and its own internal proxy, producing 3 hops. With the default trustedProxyDepth: 1, the guard would see Railway's proxy IP — not the actual caller:

// WRONG — checks Railway's internal proxy IP
const guard = createIpGuard();

// CORRECT — skips Railway proxy + Fastly CDN to reach the real caller
const guard = createIpGuard({ trustedProxyDepth: 3 });

How to find the right depth

Add a temporary debug endpoint to inspect the raw headers:

app.get('/debug/ip', (req, res) => {
  res.json({
    xff: req.headers['x-forwarded-for'],
    remote: req.socket.remoteAddress,
    clientIp: guard.getClientIp(req),
  });
});

Then curl https://your-app.example.com/debug/ip and count the entries in xff. The real client IP is the leftmost entry; set trustedProxyDepth to the total number of entries to reach it. Remove this endpoint before going to production.

ChatGPT Developer Mode

When connecting an MCP server directly to ChatGPT in developer mode, requests may come from Azure infrastructure IPs or Fastly CDN IPs rather than the dedicated OpenAI egress IPs:

const guard = createIpGuard({
  includeAzureRanges: true,   // Azure infrastructure IPs (~10,360 ranges)
  includeFastlyRanges: true,  // Fastly CDN edge IPs (19 ranges)
});

Only enable these when you need developer-mode compatibility — in production with ChatGPT's public integration, the default OpenAI ranges are sufficient.

Claude (Anthropic) MCP Tool Calls

When Claude makes MCP tool calls to your server, requests come from Anthropic's outbound IP range:

const guard = createIpGuard({
  includeAnthropicRanges: true,  // Anthropic outbound IPs (160.79.104.0/21)
});

To allow both ChatGPT and Claude:

const guard = createIpGuard({
  includeOpenAiRanges: true,      // ChatGPT (default)
  includeAnthropicRanges: true,   // Claude
  trustedProxyDepth: 3,           // Railway deployment
});

Environment

  • NODE_ENV — When set to "production", localhost is blocked (unless allowLocalhostInDev is false).

IP Ranges Sources

  • OpenAI — Published egress IPs (2026-03-03). Includes /28, /26, and /32 entries covering all ChatGPT outbound traffic to MCP servers.
  • Azure — Microsoft Azure Service Tags – Public Cloud (2026-03-02). The AzureCloud service tag with 10,360 IPv4 CIDR ranges covering all Azure datacenter egress.
  • Fastly — Fastly CDN public IP list (2026-03-04). 19 IPv4 ranges covering all Fastly edge nodes.
  • Anthropic — Published outbound IPs (2026-03-04). The 160.79.104.0/21 range used for Claude MCP tool calls.

License

MIT