@kya-os/mcp-i-cloudflare
v1.9.7
Published
Cloudflare Workers adapter for MCP-I framework
Readme
@kya-os/mcp-i-cloudflare
Cloudflare Workers runtime for MCP-I (Model Context Protocol with Identity). Deploy cryptographically-signed MCP servers to Cloudflare's edge network with full identity support.
Overview
This package provides a Next.js-style architecture for building MCP-I agents on Cloudflare Workers. All framework complexity is hidden within the package, leaving your scaffolded code clean and focused on business logic.
Key Features
- ✅ MCPICloudflareServer: Central server class that handles all framework routing
- ✅ Service Architecture: Delegation, Proof, Admin, and Consent services
- ✅ defineConfig: Smart configuration with sensible defaults
- ✅ Identity Management: DID-based identity with Ed25519 keys
- ✅ Cryptographic Proofs: Sign tool responses with detached proofs
- ✅ Session Management: Stateless sessions with nonce protection
- ✅ KV Storage: Use Workers KV for nonce cache and identity
- ✅ Audit Logging: Track all operations with configurable logging
- ✅ CSRF Protection: Secure OAuth state validation with server-side storage
- ✅ Security Event Logging: Comprehensive observability for security events
Quick Start
1. Create a new project
npx @kya-os/create-mcpi-app my-agent --platform cloudflare
cd my-agent2. Run setup script
npm run setupThis interactive script will:
- Create KV namespaces
- Update
wrangler.tomlwith namespace IDs - Set up environment variables
- Configure secrets
3. Start development
npm run devArchitecture
Why McpAgent + CloudflareRuntime?
The scaffolded code uses two complementary components:
McpAgent(fromagents/mcp): Handles the MCP protocol transport layer- Provides SSE (Server-Sent Events) and HTTP streaming transports
- Required for Cloudflare Workers compatibility
- Manages Durable Objects for stateful session management
- ⚠️ Version Requirement: Use
agents@^0.2.21or later. Constructor signature changed - now only accepts(state, env)
CloudflareRuntime(from@kya-os/mcp-i-cloudflare): Provides MCP-I features- Identity management (DID generation and storage)
- Cryptographic proof generation
- Delegation verification
- Session management with nonce protection
Together, they provide full MCP + MCP-I functionality on Cloudflare Workers. The MCPICloudflareServer class orchestrates framework-specific routes (health, admin, consent, OAuth), while McpAgent handles the MCP protocol endpoints (/sse, /mcp).
MCPICloudflareServer
The main server class that orchestrates all framework functionality:
import { MCPICloudflareServer } from "@kya-os/mcp-i-cloudflare";
import { getRuntimeConfig } from "./mcpi-runtime-config";
export default {
async fetch(
request: Request,
env: CloudflareEnv,
ctx: ExecutionContext
): Promise<Response> {
const server = new MCPICloudflareServer({
env,
config: getRuntimeConfig(env),
});
return server.handleRequest(request, ctx);
},
};defineConfig
Simplified configuration with smart defaults:
import { defineConfig } from "@kya-os/mcp-i-cloudflare";
export function getRuntimeConfig(env: CloudflareEnv) {
return defineConfig({
// Only specify overrides - defaults are handled automatically
vars: {
ENVIRONMENT: env.ENVIRONMENT || "development",
AGENTSHIELD_API_KEY: env.AGENTSHIELD_API_KEY,
},
// Optional: Enable admin endpoints
admin: {
enabled: true,
apiKey: env.ADMIN_API_KEY,
},
});
}Services
The package provides several services that handle framework functionality:
- DelegationService: Token retrieval, verification, and cache management
- ProofService: Proof submission to AgentShield
- AdminService: Admin endpoints for cache management (optional)
- ConsentService: Consent page rendering (Phase 0 placeholder)
All services are automatically initialized by MCPICloudflareServer and hidden from your code.
API Reference
MCPICloudflareServer
class MCPICloudflareServer {
constructor(options: {
env: CloudflareEnv;
config: CloudflareRuntimeConfig;
runtime?: CloudflareRuntime;
});
async handleRequest(
request: Request,
ctx?: ExecutionContext
): Promise<Response>;
async handleScheduled(event: ScheduledEvent): Promise<void>;
// Service accessors (for advanced use cases)
getDelegationService(): DelegationService;
getProofService(): ProofService;
getAdminService(): AdminService | undefined;
getConsentService(): ConsentService;
}defineConfig
function defineConfig(
config: Partial<CloudflareRuntimeConfig>
): CloudflareRuntimeConfig;Merges user configuration with smart defaults. Only specify what you want to override.
Constants
export const DEFAULT_AGENTSHIELD_URL = "https://kya.vouched.id";
export const DEFAULT_SESSION_TTL = 30 * 60 * 1000; // 30 minutes
export const DEFAULT_DELEGATION_TTL = 7 * 24 * 60 * 60; // 7 days
export const DEFAULT_CACHE_TTL = 5 * 60 * 1000; // 5 minutes
export const DEFAULT_VERIFICATION_CACHE_TTL = 60; // 1 minute
export const DEFAULT_SESSION_CACHE_TTL = 300; // 5 minutesConsent Configuration
The consent service automatically fetches configuration from AgentShield API and caches it for 5 minutes. You can customize the consent page appearance and behavior through the AgentShield dashboard.
Consent Config Structure
{
branding?: {
primaryColor?: string; // Hex color (e.g., "#2563eb")
logoUrl?: string; // Logo image URL
companyName?: string; // Company name
theme?: 'light' | 'dark' | 'auto';
};
terms?: {
text?: string; // Terms text
url?: string; // Terms URL
version?: string; // Terms version
required?: boolean; // Require acceptance
};
customFields?: Array<{
name: string;
label: string;
type: 'text' | 'textarea' | 'checkbox' | 'select';
required: boolean;
placeholder?: string;
options?: Array<{ value: string; label: string }>;
}>;
ui?: {
theme?: 'light' | 'dark' | 'auto';
popupEnabled?: boolean;
autoClose?: boolean;
autoCloseDelay?: number;
};
}Consent URL Auto-Detection
The consent service automatically detects the server URL from incoming requests, ensuring consent URLs point to your server-hosted page. Priority:
- Request Origin (auto-detected) - Best for local development
- MCP_SERVER_URL env var - Explicit configuration
- AgentShield Dashboard - Fallback for backward compatibility
Example Consent Flow
// 1. Tool requires delegation
const result = await runtime.processToolCall(
"checkout",
args,
handler,
session
);
// Returns DelegationRequiredError with consentUrl
// 2. User visits consent URL
// GET /consent?tool=checkout&scopes=checkout:execute&agent_did=...&session_id=...&project_id=...
// 3. User approves
// POST /consent/approve with approval data
// 4. Delegation created and token stored
// Token stored in KV: agent:did:delegation and session:id
// 5. Tool call retried with delegation token
// Should succeedEndpoints
/health (GET)
Health check endpoint.
/consent/* (GET/POST)
Consent page endpoints for user authorization flows.
Endpoints:
GET /consent- Render consent page with tool and scope informationPOST /consent/approve- Handle user approval and create delegationGET /consent/success- Display success page after approval
Query Parameters (GET /consent):
tool- Tool name requiring delegationscopes- Comma-separated list of required scopesagent_did- Agent DID identifiersession_id- Session ID for trackingproject_id- AgentShield project ID
Request Body (POST /consent/approve):
{
"tool": "checkout",
"scopes": ["checkout:execute", "payment:process"],
"agent_did": "did:key:z6Mk...",
"session_id": "session_123",
"project_id": "proj_123",
"termsAccepted": true,
"customFields": {
"email": "[email protected]"
}
}Response (POST /consent/approve):
{
"success": true,
"delegation_id": "del_abc123",
"delegation_token": "token_xyz789"
}Features:
- Server-hosted consent pages (HTTP/SSE transports)
- Dashboard-hosted fallback (STDIO transport)
- XSS prevention with HTML escaping and CSP headers
- Customizable branding and terms via AgentShield API
- Custom fields support for additional user data
- Automatic token storage in KV with dual keys
/admin/* (POST)
Admin endpoints for cache management (optional, requires admin.enabled: true).
/oauth/callback (GET)
OAuth callback handler for delegation flow.
Security Features
CSRF Protection for OAuth Flows
The framework includes built-in CSRF (Cross-Site Request Forgery) protection for OAuth authorization flows. This prevents attackers from tricking users into authorizing unintended actions.
How It Works
State Generation: When initiating an OAuth flow, the framework generates a cryptographically secure random state value (32 bytes).
Secure Storage: The state value and associated OAuth parameters (project ID, agent DID, session ID, etc.) are stored securely in KV storage with a 10-minute TTL.
State Validation: On OAuth callback, the framework retrieves and validates the state from secure storage before processing the authorization code.
One-Time Use: State values are deleted immediately after retrieval, preventing replay attacks.
CSRF Detection: If the state is missing, expired, or invalid, the callback is rejected with a clear error message indicating a potential CSRF attack.
Configuration
CSRF protection is automatically enabled when DELEGATION_STORAGE KV namespace is configured. Optional token encryption can be enabled by setting OAUTH_ENCRYPTION_SECRET:
# wrangler.toml
[env.production.vars]
OAUTH_ENCRYPTION_SECRET = "your-encryption-secret-here"Backward Compatibility
If OAuthSecurityService is not available (e.g., DELEGATION_STORAGE not configured), the framework falls back to base64-encoded state parameters. This maintains backward compatibility but provides less security. For production deployments, always configure DELEGATION_STORAGE.
Example
// OAuth URL generation (automatic CSRF protection)
const oauthUrl = await consentService.buildOAuthUrl(
projectId,
agentDid,
sessionId,
scopes,
serverUrl,
oauthSecurityService // Automatically created if DELEGATION_STORAGE is configured
);
// OAuth callback (automatic CSRF validation)
const handler = createOAuthCallbackHandler({
agentShieldApiUrl: env.AGENTSHIELD_API_URL,
delegationStorage: env.DELEGATION_STORAGE,
oauthSecurityService, // Automatically created if DELEGATION_STORAGE is configured
});Security Event Logging
All security-critical events are logged with structured data for monitoring and observability. Security events are prefixed with 🔒 SECURITY EVENT: for easy filtering.
Logged Events
- OAuth Provider Errors: Errors returned by OAuth providers
- CSRF Protection: State validation success/failure, expired states, invalid states
- OAuth Code Exchange: Token exchange start, success, and failure
- Delegation Storage: Token storage events (user+agent scoped, legacy, session cache)
- OAuth Identity Linking: User DID linking with OAuth identities
- Storage Errors: Non-fatal storage errors that don't block operations
Log Format
All security events include:
{
timestamp: string; // ISO timestamp
eventType: string; // Event type identifier (e.g., 'csrf_protection_failed')
severity?: 'error' | 'warning' | 'info';
// ... event-specific fields
}Example Logs
// CSRF protection success
[OAuth] 🔒 SECURITY EVENT: State validated successfully: {
projectId: 'project-123',
agentDid: 'did:key:z6Mk...',
sessionId: 'session-123...',
timestamp: '2025-01-21T10:30:00.000Z',
eventType: 'csrf_protection_success'
}
// CSRF attack detected
[OAuth] 🔒 SECURITY EVENT: State validation failed - state not found or expired: {
stateParam: 'invalid-state-value...',
timestamp: '2025-01-21T10:30:00.000Z',
eventType: 'csrf_protection_failed',
reason: 'state_not_found_or_expired'
}
// Delegation token stored
[OAuth] 🔒 SECURITY EVENT: Delegation token stored with user+agent DID: {
key: 'delegation:user:did:key:z6Mk...',
ttl: 604800,
agentDid: 'did:key:z6Mk...',
userDid: 'did:key:z6Mk...',
timestamp: '2025-01-21T10:30:00.000Z',
eventType: 'delegation_token_stored',
storageType: 'user_agent_scoped'
}Monitoring
Security events can be monitored using:
- Cloudflare Workers Logs: View logs in real-time with
wrangler tail - Log Aggregation: Forward logs to external services (Datadog, Splunk, etc.)
- Alerting: Set up alerts for critical security events (CSRF failures, token exchange failures)
Privacy
All security logs redact sensitive information:
- DIDs are truncated (first 20 characters + "...")
- Tokens are never logged in full
- OAuth subjects are hashed or truncated
- PII is redacted before logging
Migration from v1.x
If you're upgrading from v1.x, see the migration guide below.
Breaking Changes
- Architecture: Complete refactor to Next.js-style architecture
- Scaffolded Output: Simplified from ~826 lines to ~100 lines
- Configuration: New
defineConfig()API with smart defaults - Services: All framework logic moved to package services
Migration Steps
- Update
@kya-os/mcp-i-cloudflareto 1.4.0 - Replace
index.tswith new simplified version - Replace
mcpi-runtime-config.tswith new simplified version usingdefineConfig() - Remove any custom service implementations (now in package)
- Run
npm run setupto configure
License
MIT
