Configuration & Deployment
Server configuration, deployment, and management
Complete guide to configuring, deploying, and managing MCP.do server.
Server Configuration
Environment Variables
# OAuth Configuration
OAUTH_SERVER_URL=https://oauth.do
# Rate Limiting
ANON_RATE_LIMIT=10 # Anonymous: 10 req/min
AUTH_RATE_LIMIT=100 # Authenticated: 100 req/min
# Timeouts
ANON_TIMEOUT_MS=10000 # Anonymous: 10 seconds
AUTH_TIMEOUT_MS=30000 # Authenticated: 30 seconds
# Human Functions
HUMAN_WORKER_URL=https://humans.do
# Admin Access
ADMIN_ROLE=admin # Role name for admin usersWrangler Configuration
wrangler.jsonc:
{
"name": "mcp",
"main": "src/index.ts",
"compatibility_date": "2024-01-15",
"node_compat": true,
"vars": {
"OAUTH_SERVER_URL": "https://oauth.do",
"ANON_RATE_LIMIT": "10",
"AUTH_RATE_LIMIT": "100",
"ANON_TIMEOUT_MS": "10000",
"AUTH_TIMEOUT_MS": "30000",
"HUMAN_WORKER_URL": "https://humans.do"
},
"durable_objects": {
"bindings": [
{
"name": "MCP_OBJECT",
"class_name": "PublicMcpAgent",
"script_name": "mcp"
},
{
"name": "rateLimiter",
"class_name": "RateLimiter",
"script_name": "mcp"
}
]
},
"services": [
{
"binding": "api",
"service": "api",
"environment": "production"
}
],
"routes": [
{
"pattern": "mcp.do/*",
"zone_name": "do"
}
]
}Local Development
Installation
# Clone repository
git clone https://github.com/youraccount/platform
cd platform/workers/mcp
# Install dependencies
pnpm installRunning Locally
# Start development server
pnpm dev
# Server runs at http://localhost:8787Testing Locally
# Run unit tests
pnpm test
# Run integration tests
pnpm test:integration
# Test MCP connection
node test-mcp.jsTest Script
test-mcp.js:
import { MCPClient } from '@modelcontextprotocol/sdk/client/index.js'
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js'
const transport = new SSEClientTransport(new URL('http://localhost:8787'), {})
const client = new MCPClient({ name: 'test-client', version: '1.0.0' }, {})
await client.connect(transport)
// List tools
const tools = await client.listTools()
console.log('Available tools:', tools)
// Execute do tool
const result = await client.callTool('do', {
script: 'await db.list("Business")',
})
console.log('Result:', result)
await client.close()Deployment
Deploy to Cloudflare
# Deploy to production
pnpm deploy
# Deploy with specific environment
pnpm deploy:production
# Deploy with environment variables
wrangler deploy --var ANON_RATE_LIMIT:20CI/CD Deployment
GitHub Actions workflow:
.github/workflows/deploy-mcp.yml:
name: Deploy MCP
on:
push:
branches: [main]
paths:
- 'workers/mcp/**'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
- name: Install dependencies
run: pnpm install
- name: Run tests
run: pnpm test
working-directory: workers/mcp
- name: Deploy
run: pnpm deploy
working-directory: workers/mcp
env:
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}Staged Deployment
Deploy to staging first:
# Deploy to staging
wrangler deploy --env staging
# Test staging
curl https://staging.mcp.do/health
# Promote to production
wrangler deploy --env productionCustom Domains
Add Custom Domain
# Add route in wrangler.jsonc
{
"routes": [
{
"pattern": "mcp.yourdomain.com/*",
"zone_name": "yourdomain.com"
}
]
}
# Deploy
wrangler deploySSL Configuration
SSL is automatic via Cloudflare:
- Automatic HTTPS
- HTTP/2 and HTTP/3 support
- SSL certificates managed by Cloudflare
Admin Subdomain
Configure admin-only subdomain:
DNS Configuration
# Add CNAME record
admin.mcp.do -> CNAME -> mcp.doAccess Control
// In worker
if (url.hostname === 'admin.mcp.do' && !auth.isAdmin) {
return new Response(
JSON.stringify({
error: 'forbidden',
error_description: 'Admin access required',
}),
{ status: 403 }
)
}Monitoring
Health Checks
# Health endpoint
curl https://mcp.do/health
# Response
{
"status": "ok",
"timestamp": "2024-01-15T10:30:00Z"
}Metrics Dashboard
Monitor in Cloudflare dashboard:
- Request rate
- Error rate
- Response time (p50, p95, p99)
- Durable Object usage
Analytics
# View analytics
wrangler tail --format=pretty
# Filter errors
wrangler tail --format=pretty --status=error
# View specific requests
wrangler tail --format=pretty --search="tools/call"Custom Logging
// In worker
console.log('Tool call:', {
tool: toolName,
auth: auth.type,
userId: auth.id,
duration: Date.now() - startTime,
})Scaling
Automatic Scaling
Cloudflare Workers scale automatically:
- No configuration needed
- Handles millions of requests
- Global distribution
Rate Limit Scaling
Adjust rate limits based on load:
# Increase auth rate limit
wrangler secret put AUTH_RATE_LIMIT
# Enter: 200
# Deploy changes
wrangler deployDurable Object Scaling
Durable Objects scale per user:
- One rate limiter per user
- One sandbox per request
- Automatic cleanup
Backup & Recovery
Configuration Backup
# Backup wrangler.jsonc
cp wrangler.jsonc wrangler.jsonc.backup
# Backup environment variables
wrangler secret list > secrets.txtDurable Object Backup
# Export Durable Object data
wrangler d1 export mcp-do-data
# Import on recovery
wrangler d1 import mcp-do-data < backup.sqlSecurity Hardening
API Key Rotation
# Generate new admin key
wrangler secret put ADMIN_API_KEY
# Revoke old keys in admin dashboardRate Limit Tuning
# Stricter anonymous limits
ANON_RATE_LIMIT=5
# Monitor and adjust
wrangler tail --format=pretty --status=429IP Allowlisting
Add IP restrictions in Cloudflare:
// In worker
const allowedIPs = ['1.2.3.4', '5.6.7.8']
const clientIP = request.headers.get('CF-Connecting-IP')
if (!allowedIPs.includes(clientIP)) {
return new Response('Forbidden', { status: 403 })
}Troubleshooting
Common Issues
Issue: Rate limit exceeded
# Check rate limiter state
wrangler tail --format=pretty --search="rate limit"
# Increase limit temporarily
wrangler secret put AUTH_RATE_LIMITIssue: Timeout errors
# Increase timeout
wrangler secret put AUTH_TIMEOUT_MS
# Enter: 60000 (60 seconds)Issue: OAuth validation failing
# Check OAuth server connectivity
curl https://oauth.do/health
# Verify environment variable
wrangler secret list | grep OAUTHDebug Mode
Enable debug logging:
// In wrangler.jsonc
{
"vars": {
"DEBUG": "true"
}
}View logs:
wrangler tail --format=prettyPerformance Profiling
# Monitor response times
wrangler tail --format=pretty --search="duration"
# Identify slow operations
wrangler tail --format=pretty --search="timeout"Cost Optimization
Workers Pricing
Cloudflare Workers:
- Free tier: 100,000 requests/day
- Paid: $5/month for 10M requests
- Durable Objects: $0.15/million requests
Optimization Tips
- Cache documentation responses:
// Note: Use KV or Durable Objects for persistent caching across requests
// KV example:
if (script.endsWith('.md')) {
const cached = await env.CACHE_KV.get(script)
if (cached) return JSON.parse(cached)
// ... generate response ...
await env.CACHE_KV.put(script, JSON.stringify(response), {
expirationTtl: 3600, // 1 hour
})
}- Batch operations:
// Use ai.batch() instead of multiple ai.generate() calls
await ai.batch(requests)- Limit result sizes:
// Limit list queries
await db.list('Order', { limit: 100 })Next Steps
- Integration Guide - Client integration patterns
- Debugging - Advanced debugging techniques
- Authentication - Security configuration