Skip to content

feat: add Cloudflare Tunnel support as alternative to ngrok#29

Open
yashbhutoria wants to merge 3 commits intoZeframLou:mainfrom
yashbhutoria:feature/cloudflare-tunnel-support
Open

feat: add Cloudflare Tunnel support as alternative to ngrok#29
yashbhutoria wants to merge 3 commits intoZeframLou:mainfrom
yashbhutoria:feature/cloudflare-tunnel-support

Conversation

@yashbhutoria
Copy link

@yashbhutoria yashbhutoria commented Jan 22, 2026

Summary

Adds Cloudflare Tunnel as an alternative tunnel provider to ngrok, giving users more flexibility in how they expose webhooks to phone providers.

  • Quick tunnels: No Cloudflare account required, instant setup
  • Named tunnels: Stable URL that never changes (set webhook once and forget)

Also includes critical fixes for MCP server stability and security improvements.

Fixes #18

Changes

Cloudflare Tunnel Support

  • Created tunnels/ directory with TunnelProvider abstraction
  • Refactored ngrok into NgrokTunnel class implementing TunnelProvider
  • Added CloudflareTunnel class that spawns cloudflared CLI
  • Configuration via CALLME_TUNNEL_PROVIDER env var (ngrok or cloudflare)

MCP Server Startup Fix

  • Connect MCP transport immediately for fast handshake (prevents timeout)
  • Start tunnel and HTTP server in background (deferred initialization)
  • Handle stdin close to clean up when parent process exits
  • Add shuttingDown flag to prevent race conditions
  • Tool calls wait for initialization with 30s timeout

This fixes the issue where restarting Claude Code would leave orphaned callme processes holding port 3333.

Security Improvements

  • Replace automatic ngrok URL-based security bypasses with explicit CALLME_ALLOW_UNSIGNED_WEBHOOKS env var
  • Add clear warnings when running in insecure mode
  • Properly reject unsigned webhooks by default

Code Quality

  • Extract magic numbers to AUDIO_CONSTANTS and TIMEOUT_CONSTANTS
  • Add TypeScript interfaces for TelnyxWebhookEvent and TwilioMediaMessage
  • Replace empty catch blocks with proper error logging
  • Extract audio utils to separate testable module (audio-utils.ts)

Bug Fixes

  • Fix memory leak in waitForHangup - interval now tracked and cleaned up
  • Fix incomplete cleanup on error - wsTokenToCallId mapping now deleted
  • Add cleanupCallState helper for consistent resource cleanup

Tests

  • Added 55 unit tests total (was 15)
  • tunnels/index.test.ts: Tunnel configuration, validation, factory (18 tests)
  • webhook-security.test.ts: Twilio/Telnyx signature validation, WebSocket tokens (19 tests)
  • audio-utils.test.ts: Resampling, mu-law encoding/decoding, pipeline (18 tests)

New Environment Variables

Variable Description
CALLME_TUNNEL_PROVIDER ngrok (default) or cloudflare
CALLME_CLOUDFLARE_TUNNEL_NAME Named tunnel name (optional)
CALLME_CLOUDFLARE_TUNNEL_DOMAIN Domain for named tunnel (required if name is set)
CALLME_ALLOW_UNSIGNED_WEBHOOKS Set to true to disable webhook signature validation (insecure, dev only)

Usage

Quick Tunnel (no auth needed)

CALLME_TUNNEL_PROVIDER=cloudflare

Named Tunnel (stable URL)

CALLME_TUNNEL_PROVIDER=cloudflare
CALLME_CLOUDFLARE_TUNNEL_NAME=callme
CALLME_CLOUDFLARE_TUNNEL_DOMAIN=callme.example.com

Test Plan

  • Unit tests pass (55 tests)
  • Tested Cloudflare quick tunnel end-to-end
  • Tested Cloudflare named tunnel end-to-end with Telnyx
  • Tested ngrok tunnel end-to-end
  • Verified phone call works through Cloudflare named tunnel
  • Verified MCP server starts quickly (no timeout)
  • Verified restarting Claude Code cleans up old processes
  • lsof -i :3333 shows only one process after restart

Yash Bhutoria added 3 commits January 22, 2026 13:27
- Create tunnels/ directory with TunnelProvider abstraction
- Refactor ngrok into NgrokTunnel class implementing TunnelProvider
- Add CloudflareTunnel class that spawns cloudflared CLI
- Support quick tunnels (no auth) and named tunnels (custom domain)
- Add factory with CALLME_TUNNEL_PROVIDER env var configuration
- Include 15 unit tests for validation, factory, and provider logic
- Update README with tunnel provider documentation

Resolves ZeframLou#18
- Connect MCP transport immediately for fast handshake
- Start tunnel and HTTP server in background (deferred init)
- Handle stdin close to clean up when parent process exits
- Tool calls wait for initialization with 30s timeout

This fixes the issue where restarting Claude Code would leave
orphaned callme processes holding port 3333.
Security improvements:
- Replace automatic ngrok URL-based security bypasses with explicit
  CALLME_ALLOW_UNSIGNED_WEBHOOKS env var opt-in
- Add clear warnings when running in insecure mode
- Properly reject unsigned webhooks by default

Code quality:
- Extract magic numbers to AUDIO_CONSTANTS and TIMEOUT_CONSTANTS
- Add TypeScript interfaces for TelnyxWebhookEvent and TwilioMediaMessage
- Replace empty catch blocks with proper error logging
- Extract audio utils to separate testable module (audio-utils.ts)

Bug fixes:
- Fix memory leak in waitForHangup - interval now tracked and cleaned up
- Fix incomplete cleanup on error - wsTokenToCallId mapping now deleted
- Add cleanupCallState helper for consistent resource cleanup

Tests (55 total):
- Add webhook-security.test.ts: Twilio/Telnyx signature validation,
  WebSocket token generation and validation
- Add audio-utils.test.ts: resample24kTo8k, pcmToMuLaw encoding,
  muLawToPcm decoding, end-to-end audio pipeline
xicv pushed a commit to xicv/call-me that referenced this pull request Feb 24, 2026
…m docs

Merge community PRs ZeframLou#29 (Cloudflare Tunnel) and ZeframLou#16 (Telegram messenger)
with fixes, plus documentation for issues ZeframLou#14, ZeframLou#15, ZeframLou#21, ZeframLou#25.

Cloudflare Tunnel (PR ZeframLou#29):
- Tunnel abstraction layer with TunnelProvider interface (ngrok + cloudflare)
- Deferred MCP initialization for fast handshake, fixes orphaned processes (ZeframLou#14)
- Explicit CALLME_ALLOW_UNSIGNED_WEBHOOKS replaces implicit ngrok bypass (ZeframLou#15, ZeframLou#21)
- Extract audio-utils.ts, webhook-security.ts with proper TypeScript interfaces
- Fix memory leak in waitForHangup, add cleanupCallState helper
- 55 unit tests (up from 15)

Telegram mode (PR ZeframLou#16):
- Free text-based alternative to phone calls via Telegram Bot API
- Separate MCP server entry point (index-telegram.ts)
- Tools: send_message, continue_chat, notify_user, end_chat, broadcast
- Fix JSON syntax errors in plugin.json and package.json

Documentation:
- Multi-platform support: Gemini CLI, OpenCode config examples (ZeframLou#25)
- Improved troubleshooting for Twilio auth errors (ZeframLou#15) and marketplace install (ZeframLou#13)
- Updated .env.example with tunnel, security, and Telegram options
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Support for Cloudflare Tunnels as an alternative to ngrok

1 participant