# Cloudflare Workers Compatibility Review
**Date**: 2025-11-12
**Project**: dadosbr-mcp
**Reviewer**: Deep Code Analysis
**Status**: ā ļø CRITICAL ISSUES FOUND
---
## Executive Summary
The project has **critical architectural conflicts** that will prevent successful deployment to Cloudflare Workers. There are two incompatible worker implementations trying to coexist, and the entry point configuration doesn't match the actual code structure.
### Severity Levels
- š“ **CRITICAL**: Blocks deployment completely
- š” **WARNING**: May cause runtime issues
- š¢ **OK**: Compatible with Cloudflare Workers
---
## š“ CRITICAL ISSUES
### 1. Dual Worker Architecture Conflict
**Problem**: Two incompatible worker implementations exist:
#### Implementation A: MCP Agent (Durable Objects)
- **File**: `lib/workers/mcp-agent.ts`
- **Approach**: Uses Cloudflare Agents SDK with Durable Objects
- **Entry Point**: `DadosBRMCP.mount("/sse")`
- **Configured in**: `wrangler.toml` as `main = "build/lib/workers/mcp-agent.js"`
```typescript
export class DadosBRMCP extends McpAgent<DadosBRMCPEnv> {
server = new McpServer({...});
// Durable Object implementation
}
export default DadosBRMCP.mount("/sse");
```
#### Implementation B: Traditional Worker (Fetch Handler)
- **File**: `lib/workers/worker.ts`
- **Approach**: Traditional fetch handler with routing
- **Entry Point**: `export default { async fetch(...) {...} }`
- **NOT referenced in wrangler.toml**
```typescript
export default {
async fetch(request: Request, env: Env, _ctx: ExecutionContext): Promise<Response> {
// Route handling for /mcp, /sse, /oauth, etc.
}
} satisfies WorkerExportedHandler<Env>;
```
**Impact**:
- ā ļø wrangler.toml points to `mcp-agent.js` which only exports a Durable Object class
- ā ļø `worker.ts` has all the HTTP routing logic but is never imported or used
- ā ļø The MCP Agent approach only handles `/sse` endpoint
- ā ļø All other endpoints (`/mcp`, `/oauth`, `/health`, REST APIs) are unreachable
**Resolution Required**:
Choose ONE architecture and implement it consistently:
**Option A: Durable Objects + MCP Agent** (Current wrangler.toml)
- Use only `mcp-agent.ts` as entry point
- Migrate all routes to the MCP Agent class
- Remove `worker.ts` entirely
**Option B: Traditional Worker** (Full feature set)
- Change wrangler.toml to point to `worker.ts`
- Keep `mcp-agent.ts` only for MCP Agent-specific logic
- Remove Durable Objects configuration if not needed
### 2. Missing Environment Variable Injection in worker.ts
**Problem**: `TAVILY_API_KEY` injection differs between implementations
**mcp-agent.ts** (ā Correct):
```typescript
async init() {
if (this.env.TAVILY_API_KEY) {
process.env.TAVILY_API_KEY = this.env.TAVILY_API_KEY;
}
// ...
}
```
**worker.ts** (ā Missing):
```typescript
export default {
async fetch(request: Request, env: Env, _ctx: ExecutionContext): Promise<Response> {
// NO injection of env.TAVILY_API_KEY into process.env
// This will cause cnpj_intelligence tool to fail
}
}
```
**Impact**:
- Intelligence search will fail with "TAVILY_API_KEY not configured"
- cnpj_search tool may fail depending on provider selection
**Resolution**: Add at start of fetch handler:
```typescript
if (env.TAVILY_API_KEY) {
process.env.TAVILY_API_KEY = env.TAVILY_API_KEY;
}
```
### 3. Entry Point Mismatch
**Current wrangler.toml**:
```toml
main = "build/lib/workers/mcp-agent.js"
```
**What mcp-agent.js exports**:
```typescript
export default DadosBRMCP.mount("/sse"); // Only handles /sse endpoint
```
**What worker.js exports**:
```typescript
export default {
async fetch(request: Request, env: Env, _ctx: ExecutionContext): Promise<Response> {
// Handles ALL endpoints: /mcp, /sse, /oauth, /health, REST APIs
}
}
```
**Impact**:
- Current configuration only exposes `/sse` endpoint via MCP Agent
- All other endpoints (`/mcp`, `/oauth/*`, `/health`, REST APIs) are completely inaccessible
- ChatGPT integration will not work (needs OAuth endpoints)
- REST API integration will not work
- Health checks will fail
**Resolution**: Update wrangler.toml:
```toml
main = "build/lib/workers/worker.js"
```
---
## š” WARNING ISSUES
### 4. NodeJS Compatibility Dependencies
**Status**: ā Partially Addressed
**wrangler.toml** includes:
```toml
compatibility_flags = ["nodejs_compat"]
```
**Uses NodeJS APIs**:
- `setTimeout`, `setInterval`, `clearTimeout`, `clearInterval`
- `process.env` for environment variables
- `Buffer` (if used anywhere)
**Impact**:
- With `nodejs_compat` flag, these should work
- Monitor for any edge cases or performance issues
- Some NodeJS APIs have limitations in Workers runtime
### 5. Timeout Configuration Conflicts
**Cloudflare Workers Limits**:
- **CPU Time**: 50 seconds maximum (10ms on free tier)
- **Wall Clock**: 30 seconds for HTTP requests
- **Subrequests**: 50 per request (free tier), 1000 (paid)
**Current Configuration** (timeouts.ts):
- `INTELLIGENCE_TOTAL_MS`: 25000ms (25s) ā Under limit
- `SSE_CONNECTION_MS`: 50000ms (50s) ā ļø At CPU limit
- `SEARCH_REQUEST_MS`: 10000ms (10s) ā OK
- `HTTP_REQUEST_MS`: 8000ms (8s) ā OK
**Concerns**:
- Intelligence search with multiple concurrent requests may hit CPU limit
- SSE connection at exactly 50s is risky (leaves no margin)
- Concurrent searches (3 by default) may accumulate CPU time
**Recommendations**:
1. Reduce `SSE_CONNECTION_MS` to 45000ms (45s) for safety margin
2. Set `INTELLIGENCE_TOTAL_MS` to 20000ms (20s) to be conservative
3. Monitor CPU time usage in production
4. Consider implementing request queuing for complex operations
### 6. Durable Objects Usage Uncertainty
**Configured in wrangler.toml**:
```toml
[[durable_objects.bindings]]
name = "MCP_OBJECT"
class_name = "DadosBRMCP"
[[migrations]]
tag = "v1"
new_sqlite_classes = ["DadosBRMCP"]
```
**Usage**:
- Only used by `mcp-agent.ts`
- NOT used by `worker.ts`
- If using worker.ts as entry point, Durable Objects are unnecessary
- Adds complexity and cost if not needed
**Impact**:
- If switching to `worker.ts`, remove Durable Objects config
- If keeping `mcp-agent.ts`, ensure migrations are properly handled
---
## š¢ COMPATIBLE FEATURES
### 7. KV Namespace Integration ā
**Configuration**:
```toml
[[kv_namespaces]]
binding = "MCP_CACHE"
id = "9e3f2b99610b4c67abb1080b5f927efa"
[[kv_namespaces]]
binding = "MCP_KV"
id = "9e3f2b99610b4c67abb1080b5f927efa"
```
**Implementation** (cache.ts):
```typescript
export class KVCache implements Cache {
constructor(private kv: KVNamespace, private ttl: number) {}
async get<T>(key: string): Promise<T | null> {
const cached = await this.kv.get(key);
// Proper async/await usage ā
}
async set<T>(key: string, data: T): Promise<void> {
await this.kv.put(key, JSON.stringify({...}));
}
}
```
**Status**: ā Correctly implemented
- Proper async/await patterns
- JSON serialization handled correctly
- TTL management included
- No blocking operations
### 8. HTTP Client with Circuit Breaker ā
**Implementation** (http-client.ts):
```typescript
const circuitBreaker = new CircuitBreaker({
failureThreshold: 5,
resetTimeoutMs: 30000,
halfOpenMaxAttempts: 3,
});
async function executeWithRetry(fn: () => Promise<HttpResponse>, maxRetries = 3)
```
**Status**: ā Workers-compatible
- Uses native `fetch` API
- Proper abort controller usage
- No blocking operations
- Good error handling
### 9. Request Deduplication ā
**Implementation** (tools.ts):
```typescript
const pendingRequests = new Map<string, PendingRequest>();
async function deduplicate<T>(key: string, fn: () => Promise<T>): Promise<T> {
const existing = pendingRequests.get(key);
if (existing) return existing.promise;
// ...
}
```
**Status**: ā Works in Workers
- Uses Map for in-memory storage
- Proper promise management
- Timeout cleanup included
### 10. SSE Implementation ā
**Implementation** (sse.ts):
```typescript
export async function handleSSEEndpoint(request: Request, env: Env): Promise<Response> {
const { readable, writable } = new TransformStream();
const writer = writable.getWriter();
// Immediate connection event
await sendSSEMessage({type: "connection", ...}, "connection");
// Heartbeat with 30s interval
pingInterval = setInterval(async () => {...}, 30000);
// 50s timeout (respects Workers CPU limit)
timeoutHandle = setTimeout(() => {...}, 50000);
}
```
**Status**: ā Well-implemented
- Proper TransformStream usage
- Early response to prevent timeout
- Heartbeat mechanism
- Graceful shutdown
- **Minor concern**: 50s timeout is at the edge of CPU limit
---
## Secrets Management
### Required Secrets
**TAVILY_API_KEY** (Critical):
- Used by: `cnpj_intelligence`, `cnpj_search` tools
- Must be set via: `wrangler secret put TAVILY_API_KEY`
- Fallback: Uses server configuration if not provided per-request
**Optional Secrets**:
- `MCP_API_KEY`: For authentication (if enabled)
- Custom API keys for CNPJ/CEP providers (if not using defaults)
### Secret Injection Status
ā **mcp-agent.ts**: Properly injects TAVILY_API_KEY
ā **worker.ts**: Missing TAVILY_API_KEY injection
ā **adapters/cloudflare.ts**: Missing TAVILY_API_KEY injection
---
## Build Process
### Current Configuration ā
**tsconfig.worker.json**:
```json
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"lib": ["ES2022", "WebWorker"],
"types": ["@cloudflare/workers-types"]
}
}
```
**Status**: ā Correct
- Targets ES2022 (Workers-compatible)
- Uses WebWorker types
- Bundler module resolution
**Build Command**:
```bash
npm run build:worker # Compiles to build/lib/workers/
```
**Output**: ā Verified
- All .js and .d.ts files generated
- Source maps included
- No compilation errors
---
## Recommended Action Plan
### Phase 1: Critical Fixes (MUST DO)
1. **Resolve Architecture Conflict**
- [ ] Choose between MCP Agent or Traditional Worker
- [ ] Update wrangler.toml entry point accordingly
- [ ] Remove unused implementation
2. **Fix Environment Variable Injection**
- [ ] Add TAVILY_API_KEY injection to chosen entry point
- [ ] Test cnpj_intelligence tool
3. **Deploy Secrets**
- [ ] Run: `wrangler secret put TAVILY_API_KEY`
- [ ] Verify secret is accessible in worker
### Phase 2: Testing (SHOULD DO)
4. **Local Testing**
- [ ] Run: `wrangler dev`
- [ ] Test all endpoints: /health, /mcp, /sse, /oauth
- [ ] Test tools: cnpj_lookup, cep_lookup, cnpj_search, cnpj_intelligence
5. **Staging Deployment**
- [ ] Run: `npm run deploy:staging`
- [ ] Monitor logs: `wrangler tail --env staging`
- [ ] Load test with expected traffic
### Phase 3: Production (COULD DO)
6. **Optimization**
- [ ] Reduce timeout values for safety
- [ ] Monitor CPU time usage
- [ ] Optimize concurrent requests if needed
7. **Production Deployment**
- [ ] Run: `npm run deploy`
- [ ] Set up monitoring/alerting
- [ ] Document deployment process
---
## Deployment Checklist
### Pre-Deployment
- [ ] Build succeeds: `npm run build:worker`
- [ ] Entry point is correct in wrangler.toml
- [ ] KV namespaces are created
- [ ] Secrets are deployed: `wrangler secret list`
- [ ] Environment variables are configured
### Deployment
- [ ] Staging deployment successful
- [ ] All endpoints accessible
- [ ] Tools execute successfully
- [ ] Logs show no errors
- [ ] Response times acceptable
### Post-Deployment
- [ ] Production deployment successful
- [ ] Health check passing: `curl https://your-worker.workers.dev/health`
- [ ] MCP endpoint working
- [ ] SSE endpoint working
- [ ] OAuth endpoints working (if using ChatGPT integration)
---
## Conclusion
**Current Status**: ā NOT READY FOR DEPLOYMENT
**Blockers**:
1. Architectural conflict between two worker implementations
2. Entry point mismatch in wrangler.toml
3. Missing environment variable injection
**Estimated Time to Fix**: 2-4 hours
- 1 hour: Resolve architecture and update configuration
- 1 hour: Testing and verification
- 1-2 hours: Deployment and monitoring
**Recommendation**: Fix critical issues in Phase 1 before attempting deployment. The build is successful but the runtime configuration is incorrect.