The session proxy layer is the glue between the local FastMCP server and the live Google Colab notebook in your browser. It is responsible for starting the WebSocket server, managing the FastMCP client connection to Colab, creating a proxy server that dynamically reflects Colab’s tools, and running the middleware chain that keeps the MCP client aware of connection-state changes. Together, these components ensure that the MCP client always has a working tool list — even before Colab has connected — and that it instantly discovers new notebook tools the moment a browser session comes online.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.
Components
ColabSessionProxy
The top-level orchestrator, instantiated once at startup. Its
start_proxy_server() method:- Starts a
ColabWebSocketServeras an async context manager. - Starts a
ColabProxyClientbacked by that WebSocket server. - Creates a
FastMCPProxywhoseclient_factoryisproxy_client.client_factory— so it always routes tool calls to whichever client is currently live. - Builds the ordered middleware list and returns it so
__init__.pycan register it on the top-levelFastMCPinstance.
ColabSessionProxy also holds the AsyncExitStack that owns the lifetimes of the WebSocket server and proxy client; calling cleanup() tears them all down in reverse order.ColabProxyClient
Manages the When Colab is connected it returns
fastmcp.Client connection to Colab through a ColabTransport. On startup it fires an asyncio.Task (_start_proxy_client) that blocks — via ColabTransport.connect_session — until the WebSocket server receives its first authenticated connection. Once the Client context is entered, proxy_mcp_client is set.is_connected() requires both conditions to be true: wss.connection_live.is_set() (the WebSocket is currently open) and proxy_mcp_client is not None (the MCP client session has fully initialized). Either condition alone is not sufficient.The key method is client_factory():proxy_mcp_client, which has the full set of Colab notebook tools. When Colab is disconnected it returns stubbed_mcp_client — a Client wrapping an empty FastMCP() — so the proxy server never crashes on an absent backend.ColabTransport
A thin
ClientTransport implementation that bridges ColabWebSocketServer’s anyio memory streams to the mcp library’s ClientSession. Its connect_session context manager wires wss.read_stream and wss.write_stream directly into a ClientSession, giving ColabProxyClient a standard MCP session interface over the local WebSocket.ColabProxyMiddleware
Intercepts every MCP message processed by the FastMCP server. On each message it:
- Reads the current connection state from
ColabProxyClient.is_connected(). - Stores
fe_connected,proxy_token, andproxy_portin the FastMCP context so downstream tools can read them. - After the message is processed, checks whether the connection state has changed since the last message.
- If it has changed, calls
send_tool_list_changed()to emit anotifications/tools/list_changednotification to the MCP client.
on_call_tool is also overridden to handle the open_colab_browser_connection tool call specifically — see the tool flow section below.ToolInjectionMiddleware
A standard FastMCP
ToolInjectionMiddleware configured with the open_colab_browser_connection tool object. It intercepts every tools/list response and appends the injected tool, ensuring the MCP client always sees it regardless of whether a Colab session is connected.The open_colab_browser_connection Tool Flow
The injected open_colab_browser_connection tool is the entry point for establishing a Colab session. Its behavior depends on whether a connection is already live.
Tool is always present
Because
ToolInjectionMiddleware appends it to every tools/list response, the MCP client sees open_colab_browser_connection from the very first handshake — before any browser session has connected.Called while already connected
If
fe_connected is true in the current context, check_session_proxy_tool_fn returns True immediately. No browser window is opened.Called while not connected — open the browser
If This opens
fe_connected is false, the function calls webbrowser.open_new(...) with the Colab scratch notebook URL, embedding the token and port from context:https://colab.research.google.com/notebooks/empty.ipynb#mcpProxyToken=<token>&mcpProxyPort=<port> in the system browser. The underlying tool function returns False at this point, but ColabProxyMiddleware.on_call_tool intercepts the result before it is returned to the client and replaces it with the final outcome after waiting for the connection (see next step).ColabProxyMiddleware waits for connection
After
call_next completes (the browser has been opened), on_call_tool in ColabProxyMiddleware checks whether the proxy client is now connected. If not yet connected, it reports progress to the MCP client and waits:- 1/3 — “The user is not connected to the Colab UI”
- 2/3 — “Waiting for user to connect in Colab - will wait for 60s”
proxy_client.await_proxy_connection(), which uses asyncio.wait_for with a UI_CONNECTION_TIMEOUT of 60.0 seconds to await both wss.connection_live being set and the _start_proxy_client task completing.Connection confirmed or timed out
After the wait resolves, middleware checks
is_connected() once more:- Connected — reports progress 3/3 (“The Colab UI is successfully connected!”) and returns
ToolResultwith{"result": True}. - Timed out — reports progress 3/3 (“Timeout while waiting for the user to connect.”) and returns
ToolResultwith{"result": False}.
client_factory Fallback
FastMCPProxy calls client_factory() each time it needs to forward a tool call. When Colab is disconnected, ColabProxyClient.client_factory() returns a Client pointing at a stubbed empty FastMCP() server instead of raising an error or returning None.
open_colab_browser_connection, the factory begins returning proxy_mcp_client and all subsequent calls go to the live notebook.