Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/googlecolab/colab-mcp/llms.txt

Use this file to discover all available pages before exploring further.

When the proxy is enabled, colab-mcp starts a local WebSocket server that the Colab notebook running in your browser connects to. Because this server bridges your browser to a local AI agent, it is protected by multiple layered security controls: it binds exclusively to localhost, validates a per-process secret token on every connection attempt, enforces strict origin checking, and allows only one client to hold the connection at a time.

Token authentication

At startup, ColabWebSocketServer generates a cryptographically random token using Python’s secrets module:
self.token = secrets.token_urlsafe(16)
This token is unique to each server process — restarting colab-mcp produces a new token. Every incoming WebSocket connection must prove knowledge of this token before the handshake completes. The server checks for the token in two places, in this order:
  1. URL query parameter — if the request path contains access_token=<token>, the connection is allowed without inspecting headers.
  2. Authorization header — the header must follow the Bearer scheme: Authorization: Bearer <token>.
Connections that fail authentication receive one of the following HTTP error responses before the WebSocket upgrade completes:
ResponseMeaning
401 UnauthorizedNo Authorization header was present and no access_token query parameter was found.
400 Bad RequestThe Authorization header was malformed (wrong scheme or could not be parsed).
403 ForbiddenThe header was well-formed but the token value was incorrect.

Origin validation

The WebSocket server uses the websockets library’s built-in origin enforcement, configured with an explicit allowlist:
self.allowed_origins = [COLAB, COLAB_ALT_DOMAIN]
# COLAB          = "https://colab.research.google.com"
# COLAB_ALT_DOMAIN = "https://colab.google.com"
Only WebSocket upgrade requests that present an Origin header matching one of these two values are accepted. Any other origin — including an absent Origin header — causes the server to reject the connection before the handler is invoked.

Single-client exclusivity

The server uses an asyncio.Lock (connection_lock) to guarantee that at most one WebSocket client is active at any time:
if self.connection_lock.locked():
    await websocket.close(code=1013, reason="Server is busy")
    return

async with self.connection_lock:
    ...
If a second client attempts to connect while the lock is held, it receives WebSocket close code 1013 (“Try Again Later / Server is busy”) immediately. This prevents a rogue page from hijacking an active session.

Localhost binding

The WebSocket server binds to localhost only (the default host="localhost" passed to websockets.serve). This means the listening port is never exposed on any network interface — it is unreachable from another machine or from the wider internet. Only a browser running on the same physical machine as colab-mcp can establish a connection.
The proxy is always enabled in the current implementation. The --enable-proxy flag uses action="store_true" with default=True, so passing it is a no-op and there is no supported way to disable the proxy via CLI flags. The security controls described on this page are therefore always active when colab-mcp is running.
The secret token is delivered to the Colab notebook via the URL fragment, not the URL path or query string — for example, https://colab.research.google.com/notebooks/empty.ipynb#mcpProxyToken=...&mcpProxyPort=.... URL fragments are never sent to the server in HTTP requests, so the token is not transmitted to Google’s servers when the notebook page loads. The notebook’s JavaScript reads the fragment client-side and uses it when opening the local WebSocket connection.

Build docs developers (and LLMs) love