Skip to content

Workspaces

Kelly Ferrone edited this page Oct 9, 2026 · 1 revision

Workspaces

Name your workspace, and the browser that belongs to that name is yours.

Two words, two things:

  • A workspace is what you name: the box that lasts. It holds your flows, your files, your saved site data, where you have been, and the settings your browser opens with. It is never deleted, only forgotten after it goes unused for WORKSPACE_TTL.
  • A session is the live browser open in a workspace — at most one at a time. open_session starts it; end_browser, an operator's End, or the Grid reaping an idle browser ends it. A workspace with no session open is an ordinary state.

Every workspace is named, by you

There is no session id anywhere in this API. No tool takes one, no endpoint takes one, no result carries one. You say who you are and the server hands you the browser that name is holding.

How to name it Looks like Use it when
a URL parameter …/mcp?workspace=research-bot the usual case — one credential, each caller named in its own URL
a header X-Workspace: research-bot an operator pins one workspace to one credential, or a client may only send approved headers (Claude.ai custom connectors)
stdio nothing to do one process serves one client, and it is named stdio

The old names are refused. ?session= and X-Session-Key are a 400 that names the new spelling — even beside a new name — so a client wired the old way finds out on its first call.

Sending both is a 400. Not a precedence one of them wins: a request carrying two names has two ideas about who is calling, and quietly picking one hides that from whoever wired it up. A repeated name with two values is refused the same way.

Sending neither is a 400 on anything touching a browser, with a message saying how to fix it. The one exception is the flow library, which falls back to the shared global library — which everyone may read and run, and nobody may write.

The name has to be usable as a directory name, because it is one: it is where your flows, your screenshots and your Files live — see Files. Letters, digits, dots, dashes and underscores, starting with a letter or digit, 64 characters at most. stdio and global are reserved.

n8n opens a new MCP transport for every tool call, so nothing the transport negotiates is ever the same twice. Name the workspace in the URL and it simply works. See Installing.

A workspace name is an address, not a secret. The bearer token (or a JWT from your identity provider) is the credential; anyone holding one who knows your workspace's name can drive your browser. Sharing a workspace is deliberate and by name; doing it by accident is easy, which is worth knowing.

open_session always comes first

Nothing opens a browser implicitly. That is deliberate: open_session is the only place a window size and the timeouts can be chosen, and hiding the call hid the settings with it.

Call it again later with the same name — after a reconnect, a client restart, a week — and you are back on the same browser at the same page.

Where am I?

workspace://current reports the workspace name, which browser it is running, the page it is on, whether a session is open at all (live), whether you are inside a frame, and the window size. Reading it never opens a browser.

A client whose model cannot read MCP resources reads it with read_resource(uri="workspace://current"). Over HTTP it is GET /browser. A session:// URI from before the rename is refused with its workspace:// spelling, so a saved flow that names one says how to fix it.

What happens when the browser goes away

The Grid reaps idle browsers on its own timeout, so a remembered id can name one that is already gone. The next call notices, reopens, and returns to the page it was last on with the same settings — the refresh is invisible.

"The same settings" includes which browser it was. That is why the choice is stored as a setting rather than beside them: a Firefox session that came back as Chrome would be exactly the silent change of shape the stored settings exist to prevent. workspace://current reports it as browser.

A workspace is not a browser

The workspace outlives the sessions it holds. live is false when no session is open — after the Grid reaps one, or an operator ends one from the admin UI — and that is an ordinary state.

What survives is the context: the browser choice, the window, the last page. So the recovery is always the same one call:

open_session()      # same browser, same window, back where you were

Which is also why you are never told "your browser was taken". You are told no session is open, which is the branch you already handle.

Workspaces themselves expire on WORKSPACE_TTL, slid forward on every use — a day by default. Nothing else removes one.

There is one distinction that matters here, because getting it wrong strands browsers. A browser that fails to answer is not necessarily gone:

The Grid says Means
200 healthy
500 unexpected alert open alive, and blocked by a dialog — answer it with dialog
404 invalid session id genuinely reaped

Only the last one counts as gone. Anything else, including a Grid that cannot be reached right now, is assumed alive: a wrong "alive" surfaces as a real error on the next call, while a wrong "dead" silently abandons a working browser and leaks its slot.

How long things last

Who owns it Typical
how long a session's browser lives idle the Grid — SE_NODE_SESSION_TIMEOUT 300s idle
how long a workspace is remembered WORKSPACE_TTL 86400s, slid forward on every call
where that is remembered WORKSPACE_STORE memory, or redis to share it

Nothing runs a cleanup loop, and nothing should — the Grid expires browsers, the store expires its own keys.

Always close

end_browser frees the slot, and slots are the scarce resource: the Grid runs a handful of browsers in total and an abandoned one holds its place until it is reaped. Close on failure paths too. It ends the session, never the workspace.

If you are mid-task and the caller may come back, leaving it open is the right call — just know you are holding capacity while you do.

Clone this wiki locally