Production-grade MCP authentication with managed security, monitoring, and compliance.
Warpy Cloud Shield is a managed security layer for MCP (Model Context Protocol) agent authentication that provides enterprise-grade protection, monitoring, and compliance features. Instead of managing your own authentication infrastructure, Shield handles token provisioning, validation, authorization, and execution through a secure cloud endpoint with automatic fallback to self-hosted mode.
Cloud Shield is ideal for:
createMCPTools() without Shield for local JWT-based authentication. See Tools Reference for details.Sign up for a free Warpy Cloud account at platform.warpy.co and generate an API key from your dashboard.
Add your API key to your environment variables:
Set your Warpy API key
# .env.local (Next.js) or .env
AUTH_SECRET=your-jwt-secret-key-min-32-chars
WARPY_API_KEY=warpy_api_key_xxxxxxxxxxxxx
# Optional: Customize Shield behavior
WARPY_BASE_URL=https://platform.warpy.co/api/v1 # Default
WARPY_TIMEOUT_MS=5000 # Request timeout in milliseconds
WARPY_MAX_RETRIES=3 # Number of retry attempts on transient errorsMinimal configuration with env-based setup
import { createMCPShield } from '@warpy-auth-sdk/core';
// Zero-config: reads WARPY_API_KEY from environment
const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!
});
// Cloud mode automatically enabled when WARPY_API_KEY is present
// Falls back to self-host mode if API key is missingFull configuration with explicit options
import { createMCPShield } from '@warpy-auth-sdk/core';
const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!,
// Warpy Cloud configuration
warpy: {
apiKey: process.env.WARPY_API_KEY, // Or read from env
baseUrl: process.env.WARPY_BASE_URL, // Custom endpoint (e.g., EU region)
timeoutMs: 5000, // Request timeout
maxRetries: 3 // Retry attempts on transient errors
},
// Metrics and analytics
metrics: {
enabled: true, // Enable metrics collection
flushIntervalMs: 10000, // Send metrics every 10 seconds
bufferSize: 100 // Buffer up to 100 events before forcing flush
}
});
// Use with Vercel AI SDK or any LLM framework
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
const { text } = await generateText({
model: openai('gpt-4-turbo'),
tools: mcpTools,
prompt: 'Login as user-123 with debug and read scopes'
});For HTTP-based agent access, create an endpoint to handle MCP tool calls:
Expose MCP tools via HTTP API
// app/api/mcp/route.ts
import { createMCPShield } from '@warpy-auth-sdk/core';
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
const mcp = createMCPShield({
secret: process.env.AUTH_SECRET!,
metrics: { enabled: true }
});
export async function POST(req: NextRequest) {
try {
const { tool, args } = await req.json();
if (!tool || !(tool in mcp)) {
return NextResponse.json(
{ error: 'Unknown tool', available: Object.keys(mcp) },
{ status: 400 }
);
}
// Execute tool through Shield
const toolDef = (mcp as any)[tool];
const result = await toolDef.execute(args || {});
return NextResponse.json(result, { status: 200 });
} catch (error) {
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
// Optional: Add authentication to the endpoint
// export const runtime = 'nodejs'; // Required for Next.jsCloud Shield wraps each MCP tool call in a three-stage security pipeline:
Three-stage protection for every tool call
```mermaid
sequenceDiagram
participant Agent
participant Shield (Client)
participant Warpy Cloud
participant Your API
Agent->>Shield (Client): Call agent_login tool
Shield (Client)->>Warpy Cloud: Stage 1: Validate<br/>(token verification)
Warpy Cloud-->>Shield (Client): Token valid
Shield (Client)->>Warpy Cloud: Stage 2: Check Authorization<br/>(scopes + intent scan)
Warpy Cloud-->>Shield (Client): Authorized (no threats detected)
Shield (Client)->>Warpy Cloud: Stage 3: Proxy Execution<br/>(secure tool execution)
Warpy Cloud->>Your API: Execute with validated context
Your API-->>Warpy Cloud: Result
Warpy Cloud-->>Shield (Client): Filtered result
Shield (Client)-->>Agent: Success response
```
**Comparison: Cloud vs Self-Host**
| Stage | Cloud Shield | Self-Host Mode |
|-------|-------------|----------------|
| **1. Authentication** | Remote validation via Warpy | Local JWT verification |
| **2. Authorization** | Scope check + intent scanning | Scope check only |
| **3. Execution** | Secure proxy execution | Direct tool invocation |
| **Metrics** | Centralized dashboard | Not collected |
| **Rate Limiting** | Global edge protection | Not included |
| **Audit Logs** | 30-day retention (Pro: 1 year) | Manual implementation |Before any tool execution, Shield verifies the authenticity of tokens:
After authentication, Shield performs authorization checks and threat analysis:
Finally, the tool is executed in a secure environment:
Complete type definitions for Shield configuration
interface MCPShieldConfig {
// Required: JWT secret for token signing/verification
secret: string;
// Warpy Cloud configuration
warpy?: {
// API key from https://platform.warpy.co (or WARPY_API_KEY env var)
apiKey?: string;
// Base URL for Warpy API (default: https://platform.warpy.co/api/v1)
// Use custom URL for:
// - EU region: https://eu.platform.warpy.co/api/v1
// - Self-hosted Warpy: https://your-instance.com/api/v1
baseUrl?: string;
// Request timeout in milliseconds (default: 5000)
timeoutMs?: number;
// Number of retry attempts on transient errors (default: 3)
maxRetries?: number;
// Custom retry strategy (default: exponential backoff)
retryStrategy?: 'exponential' | 'linear' | 'none';
};
// Metrics and analytics configuration
metrics?: {
// Enable metrics collection (default: false)
enabled: boolean;
// Flush interval in milliseconds (default: 10000)
// Metrics buffered and sent in batches for efficiency
flushIntervalMs?: number;
// Maximum buffer size before forcing flush (default: 100)
bufferSize?: number;
// Custom tags for filtering in dashboard
tags?: Record<string, string>;
// Sample rate (0.0 to 1.0, default: 1.0 = 100%)
sampleRate?: number;
};
// Optional: Database adapter for persistent token revocation
adapter?: Adapter;
}| Variable | Required | Description | Default |
|---|---|---|---|
AUTH_SECRET | Yes | JWT signing secret (min 32 characters) | - |
WARPY_API_KEY | No | Warpy Cloud API key (enables cloud mode) | - |
WARPY_BASE_URL | No | Warpy API endpoint | https://platform.warpy.co/api/v1 |
WARPY_TIMEOUT_MS | No | Request timeout in milliseconds | 5000 |
WARPY_MAX_RETRIES | No | Max retry attempts on transient errors | 3 |
When metrics are enabled, Shield collects detailed telemetry for monitoring and debugging:
Access your metrics dashboard at platform.warpy.co/dashboard:
Configure metrics with custom tags
const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!,
metrics: {
enabled: true,
flushIntervalMs: 10000, // Flush every 10 seconds
bufferSize: 100, // Or when buffer reaches 100 events
tags: {
environment: process.env.NODE_ENV || 'development',
service: 'api',
region: 'us-west-2'
},
sampleRate: 1.0 // 100% sampling (use 0.1 for 10% sampling in high-traffic apps)
}
});All cloud operations use a single endpoint: POST https://platform.warpy.co/api/v1/mcp/shield
Standard request structure
{
"action": "validate" | "check_authz" | "proxy" | "revoke",
"payload": {
// Action-specific data
},
"metadata": {
"toolName": "agent_login",
"timestamp": "2024-11-06T12:34:56.789Z",
"agentId": "claude-assistant",
"userId": "user-123"
}
}Standard response structure
// Success response
{
"success": true,
"data": {
// Action-specific result
},
"denied": false,
"reason": null,
"timestamp": "2024-11-06T12:34:56.890Z"
}
// Denied request
{
"success": false,
"data": null,
"denied": true,
"reason": "Scope 'admin:delete_users' not granted for this agent",
"timestamp": "2024-11-06T12:34:56.890Z"
}
// Error response
{
"success": false,
"error": "Token signature invalid",
"code": "INVALID_TOKEN",
"timestamp": "2024-11-06T12:34:56.890Z"
}Check token authenticity and expiration
// Request
{
"action": "validate",
"payload": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
},
"metadata": { "toolName": "get_session", ... }
}
// Response
{
"success": true,
"data": {
"valid": true,
"payload": {
"userId": "user-123",
"email": "user@example.com",
"scopes": ["debug", "read"],
"exp": 1699282496
}
},
"denied": false
}Validate scopes and scan for threats
// Request
{
"action": "check_authz",
"payload": {
"userId": "user-123",
"requestedScopes": ["debug", "read"],
"grantedScopes": ["read", "debug"],
"intent": "Agent wants to fetch user profile for debugging"
},
"metadata": { "toolName": "agent_login", ... }
}
// Response
{
"success": true,
"data": {
"authorized": true,
"threatsDetected": false,
"analysis": {
"scopeMatch": true,
"intentSafe": true,
"riskScore": 0.02
}
},
"denied": false
}Execute tool in secure environment
// Request
{
"action": "proxy",
"payload": {
"tool": "agent_login",
"args": {
"userId": "user-123",
"scopes": ["debug", "read"],
"agentId": "claude-assistant",
"expiresIn": "15m"
}
},
"metadata": { "toolName": "agent_login", ... }
}
// Response
{
"success": true,
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires": "2024-11-06T13:00:00.000Z",
"message": "Agent claude-assistant logged in as user user-123"
},
"denied": false
}| HTTP Status | Code | Description | Retry? |
|---|---|---|---|
| 401 | INVALID_API_KEY | API key is missing or invalid | No |
| 403 | DENIED | Request blocked by security policy | No |
| 429 | RATE_LIMITED | Too many requests, slow down | Yes (with backoff) |
| 500 | INTERNAL_ERROR | Transient server error | Yes |
| 503 | SERVICE_UNAVAILABLE | Temporary outage | Yes |
Shield automatically falls back to self-host mode when:
WARPY_API_KEY is not configuredIn self-host mode, Shield uses local implementations:
AUTH_SECRETBest of both worlds
import { createMCPShield } from '@warpy-auth-sdk/core';
import { PrismaAdapter } from '@warpy-auth-sdk/core/adapters/prisma';
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
const adapter = PrismaAdapter(prisma);
const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!,
// Cloud mode (preferred)
warpy: {
apiKey: process.env.WARPY_API_KEY,
maxRetries: 3 // Try 3 times before falling back
},
// Self-host fallback uses database for revocation
adapter,
metrics: {
enabled: true,
flushIntervalMs: 10000
}
});
// Behavior:
// 1. Try Cloud Shield (with retries)
// 2. On failure, use self-host mode with Prisma adapter
// 3. Token revocation persisted to database
// 4. Metrics still collected (buffered, sent when Cloud returns)Full implementation with all features
// File: lib/mcp.ts
import { createMCPShield } from '@warpy-auth-sdk/core';
import { PrismaAdapter } from '@warpy-auth-sdk/core/adapters/prisma';
import { prisma } from './prisma';
export const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!,
warpy: {
apiKey: process.env.WARPY_API_KEY,
baseUrl: process.env.WARPY_BASE_URL,
timeoutMs: 5000,
maxRetries: 3
},
metrics: {
enabled: process.env.NODE_ENV === 'production',
flushIntervalMs: 10000,
bufferSize: 100,
tags: {
environment: process.env.NODE_ENV!,
version: process.env.APP_VERSION || 'unknown'
}
},
adapter: PrismaAdapter(prisma)
});
// File: app/api/mcp/route.ts
import { mcpTools } from '@/lib/mcp';
import type { NextRequest } from 'next/server';
import { NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
try {
// Optional: Add your own auth check here
const authHeader = req.headers.get('authorization');
if (!authHeader) {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 401 }
);
}
const { tool, args } = await req.json();
if (!tool || !(tool in mcpTools)) {
return NextResponse.json(
{ error: 'Unknown tool', available: Object.keys(mcpTools) },
{ status: 400 }
);
}
// Execute through Shield
const toolDef = (mcpTools as any)[tool];
const result = await toolDef.execute(args || {});
// Log for debugging (Shield handles production metrics)
if (process.env.NODE_ENV === 'development') {
console.log('[MCP]', { tool, args, result });
}
return NextResponse.json(result, { status: 200 });
} catch (error) {
console.error('[MCP Error]', error);
return NextResponse.json(
{ error: 'Internal server error' },
{ status: 500 }
);
}
}
// File: app/api/agent-chat/route.ts (Using with Vercel AI SDK)
import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';
import { mcpTools } from '@/lib/mcp';
export async function POST(req: NextRequest) {
const { prompt } = await req.json();
const { text, toolCalls } = await generateText({
model: openai('gpt-4-turbo'),
tools: mcpTools,
prompt,
maxToolRoundtrips: 5
});
return NextResponse.json({
response: text,
toolCalls: toolCalls.map(tc => ({
tool: tc.toolName,
args: tc.args,
result: tc.result
}))
});
}Solution:
WARPY_API_KEY is set correctly in your environmentSolution:
timeoutMs if seeing timeout errorsSolution:
metrics.enabled is trueflushIntervalMs)bufferSizeSolution:
denialReasonDetailed logs for troubleshooting
// Add to your environment
DEBUG=warpy:shield,warpy:metrics
// Or in code (not recommended for production)
process.env.DEBUG = 'warpy:*';
const mcpTools = createMCPShield({
secret: process.env.AUTH_SECRET!,
warpy: { apiKey: process.env.WARPY_API_KEY },
metrics: { enabled: true }
});
// Console output will include:
// [warpy:shield] Validating token... (action: validate)
// [warpy:shield] Authorization check passed (action: check_authz)
// [warpy:shield] Proxying tool execution... (action: proxy)
// [warpy:metrics] Buffering metric (buffer size: 15/100)
// [warpy:metrics] Flushing 100 metrics to Warpy...