Hyperbolic Gateway

Remote MCP gateway (experimental)

Experimental. Remote MCP, named Cloudflare Tunnel support and OAuth are new and their third-party client compatibility varies. Gemini Connected Apps is known to be flaky: it can show the connector as connected without injecting its tools into a conversation, and it may reuse stale state after a gateway restart. Keep remote access off unless you are actively testing it, and never expose it unattended.

The remote gateway exposes the browser MCP surface to remote clients through a loopback Streamable HTTP process. A named Cloudflare Tunnel publishes it on a hostname you control; the stdio servers are unchanged.

Status

The gateway is never a proxy for the raw bridge. It exposes only its MCP path; everything else returns 404.

Session model

The gateway is stateless by default: each POST gets a fresh MCP server and transport, and no Mcp-Session-Id is issued. This is the recommended mode for third-party clients, because it avoids session caps and stale session IDs. Browser state is held by the local bridge, not by the MCP session.

Set HB_REMOTE_STATEFUL=1 to opt into stateful sessions with a concurrent session cap and idle expiry. Stateful mode is useful for protocol debugging, not for the default remote deployment.

Authentication modes

The Remote panel has an authentication selector, defaulting to Bearer.

OAuth mode accepts OAuth access tokens, not the static bearer token. Switching modes restarts the gateway but leaves a running named tunnel connected.

Settings β†’ Remote

The panel can start and stop the gateway and the named tunnel, copy the bearer token or OAuth client credentials, rotate credentials, and disconnect sessions. The gateway and tunnel remain off after an app restart.

The bearer token is generated at app startup if absent and stored at <userData>/remote/token with owner-only permissions. The OAuth client is stored at <userData>/remote/oauth-client.json.

Named Cloudflare Tunnel

A named tunnel requires:

In the Cloudflare dashboard, create the tunnel and add a Public Hostname that routes to http://127.0.0.1:4112. Paste the hostname and tunnel token into Settings β†’ Remote. The app runs:

cloudflared tunnel --no-autoupdate run

with TUNNEL_TOKEN in the child environment. The token is stored at <userData>/remote/tunnel-token with owner-only permissions and is never returned to the renderer or logged.

OAuth on Cloudflare

Cloudflare Bot Fight Mode / WAF can block Google’s server-to-server OAuth token exchange even when the browser flow succeeds. If OAuth clients report account linking failures, add a skip/bypass rule for:

/oauth/token

or for the full public hostname used by the MCP gateway.

Managed cloudflared

The Remote panel can download the official cloudflared binary from Cloudflare GitHub releases into:

<userData>/remote/bin/cloudflared[.exe]

The download is explicit, SHA-256 verified against the GitHub release asset digest, and installed atomically. cloudflared is Apache-2.0 software from Cloudflare; the app downloads the official binary and does not redistribute it. The macOS .tgz is extracted in pure Node, so it does not depend on the host tar binary.

Update modes:

System binaries are left alone. HB_CLOUDFLARED_PATH takes precedence over the managed binary.

Architecture

remote MCP client
      |
      |  HTTPS + bearer/OAuth
      v
Cloudflare named tunnel
      |
      v
127.0.0.1:4112/mcp/browser
      |
      v
127.0.0.1:4111 local bridge

The reusable HTTP host and session lifecycle live in packages/mcp-http. The OAuth authorization server lives in packages/mcp-oauth. The named-tunnel process lifecycle lives in packages/cloudflared-tunnel, and the managed cloudflared downloader lives in packages/cloudflared. The Hyperbolic Gateway-specific entry points live in src/mcp/remote-server.ts and src/main/remote/service.ts.

Environment

Variable Meaning
HB_REMOTE_TOKEN_FILE Required. Path to the 64-hex-character remote token file.
HB_BRIDGE_URL Local bridge URL. The app passes this automatically.
HB_REMOTE_AUTH_MODE bearer (default) or oauth.
HB_OAUTH_CLIENT_FILE OAuth client JSON path. Required in oauth mode.
HB_OAUTH_REDIRECT_HOSTS Optional comma-separated additional callback hostnames.
HB_REMOTE_PORT Loopback port. Default 4112.
HB_REMOTE_HOST Loopback bind address. Default 127.0.0.1.
HB_REMOTE_PATH MCP path. Default /mcp/browser.
HB_REMOTE_STATEFUL Set to 1 to use stateful MCP sessions. Default is stateless, so no session cap or session expiry applies.
HB_REMOTE_MAX_SESSIONS Concurrent session cap in stateful mode. Default 8.
HB_REMOTE_IDLE_MS Idle session timeout in stateful mode. Default 15 minutes.
HB_REMOTE_MAX_BODY_BYTES POST body cap. Default 1 MiB.
HB_REMOTE_LOG_FILE JSONL diagnostics path.
HB_CLOUDFLARED_PATH Optional explicit path to the cloudflared executable.

The token is read from the file on every request, so rotation does not require restarting the gateway. A missing or malformed token produces 401.

Client shape

Bearer mode

{
  "mcpServers": {
    "hyperbolic-browser": {
      "httpUrl": "https://<public-hostname>/mcp/browser",
      "headers": {
        "Authorization": "Bearer <remote-token>"
      }
    }
  }
}

The local URL is http://127.0.0.1:4112/mcp/browser when the tunnel is stopped.

OAuth mode

In an OAuth-capable MCP client β€” for example Gemini Connected Apps or another custom connector β€” enter:

The gateway serves:

It does not advertise dynamic client registration, so clients that support a pre-registered client use the credentials entered under advanced settings. Authorization requires explicit approval on the local consent page. Access tokens are short-lived and refresh tokens rotate on use. OAuth tokens live in the gateway process, so restarting the gateway requires re-authorization.

Security boundaries

The public hostname is not authentication. Keep the bearer/OAuth requirement.

Verification

npm run test:mcp-http
npm run test:mcp-oauth
npm run test:cloudflared
npm run test:cloudflared-tunnel
npm run test:remote