Files
upstream-tldraw/apps/mcp-app/dev-tunnel.sh
upstream-mirror a774ac673a
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
2026-09-23 16:12:52 +05:00

89 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
# Starts a named cloudflared tunnel (stable per-user hostname) + wrangler dev,
# wiring the stable tunnel hostname into the worker as WORKER_ORIGIN.
#
# Unlike a quick tunnel (random *.trycloudflare.com URL each run), the named
# tunnel always serves at the same hostname, so you register the URL in
# ChatGPT / other hosted MCP clients once and never touch it again.
#
# Usage: ./dev-tunnel.sh
# Env overrides:
# MCP_TUNNEL_USER - slug used in the tunnel name/hostname (default: whoami)
# MCP_TUNNEL_ZONE - DNS zone for the hostname
# PORT - local worker port (default: 8787)
set -euo pipefail
PORT="${PORT:-8787}"
USER_SLUG="${MCP_TUNNEL_USER:-$(whoami)}"
ZONE="${MCP_TUNNEL_ZONE:-tldraw.xyz}"
TUNNEL_NAME="${USER_SLUG}-mcp-app-dev"
HOSTNAME="${TUNNEL_NAME}.${ZONE}"
TUNNEL_URL="https://${HOSTNAME}"
CRED_FILE="$HOME/.cloudflared/${TUNNEL_NAME}.json"
# 0. Require cloudflared and a one-time login
if ! command -v cloudflared >/dev/null 2>&1; then
echo "ERROR: cloudflared is not installed."
echo "See https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/"
exit 1
fi
if [ ! -f "$HOME/.cloudflared/cert.pem" ]; then
echo "You are not logged in to cloudflared. Run this once, then re-run this script:"
echo " cloudflared tunnel login"
echo "(choose the ${ZONE} zone when prompted)"
exit 1
fi
# 1. Ensure the tunnel exists and we have local credentials for it.
# If the tunnel already exists in the account but the local credentials file
# is gone (e.g. you wiped ~/.cloudflared or switched machines), re-download
# it with `tunnel token` instead of failing in `tunnel run`.
if cloudflared tunnel info "$TUNNEL_NAME" >/dev/null 2>&1; then
if [ ! -f "$CRED_FILE" ]; then
echo "Restoring credentials for existing tunnel ${TUNNEL_NAME}..."
cloudflared tunnel token --cred-file "$CRED_FILE" "$TUNNEL_NAME"
fi
else
echo "Creating tunnel ${TUNNEL_NAME}..."
cloudflared tunnel create --credentials-file "$CRED_FILE" "$TUNNEL_NAME"
fi
# 2. Make sure the stable hostname routes to this tunnel. --overwrite-dns makes
# the specific record win over any *.${ZONE} wildcard and re-points it if the
# tunnel was ever recreated.
echo "Ensuring DNS route ${HOSTNAME} -> ${TUNNEL_NAME}..."
if ! ROUTE_OUT=$(cloudflared tunnel route dns --overwrite-dns "$TUNNEL_NAME" "$HOSTNAME" 2>&1); then
echo "ERROR: failed to route ${HOSTNAME} to ${TUNNEL_NAME}:"
echo "$ROUTE_OUT"
echo "Make sure ${ZONE} is a Cloudflare-hosted zone in your account and you ran 'cloudflared tunnel login'."
exit 1
fi
# Build widget first
echo "Building widget..."
yarn build:widget
# 3. Start cloudflared in the background, forwarding the tunnel to the local worker
cloudflared tunnel --url "http://localhost:$PORT" run --cred-file "$CRED_FILE" "$TUNNEL_NAME" &
CF_PID=$!
cleanup() {
echo "Stopping cloudflared (pid $CF_PID)..."
kill "$CF_PID" 2>/dev/null || true
}
trap cleanup EXIT
echo ""
echo "==================================="
echo "Stable tunnel URL: $TUNNEL_URL"
echo "==================================="
echo ""
echo "Register this once in ChatGPT / claude_desktop_config.json:"
echo " \"args\": [\"-y\", \"mcp-remote\", \"$TUNNEL_URL/mcp\"]"
echo ""
# 4. Start wrangler with the stable tunnel URL as WORKER_ORIGIN in dev mode.
# Runs in the foreground; the EXIT trap stops cloudflared when wrangler exits.
wrangler dev --port "$PORT" --var "WORKER_ORIGIN:$TUNNEL_URL" --var "MCP_IS_DEV:true"