What Works in Browser
What’s Node-only
Request Context in the Browser
Every request runs in its ownFrontMcpContext (auth info, session, request-scoped providers), and tools see the tool they run as and the surface they were called on. On Node and Workers, AsyncLocalStorage keeps these apart for overlapping requests. A browser has no AsyncLocalStorage, so the browser build of @frontmcp/utils picks one of two modes (getAsyncContextMode()):
In
'serialized' mode:
- A request keeps its turn until it returns and everything it started has unwound. Background jobs, workflows and tasks take a turn of their own after the request that started them.
- A request that waits on its client (an elicitation answer, a
roots/listreply, the elicitation fallback) steps aside while it waits, so the client can call the server before answering. - Concurrent calls inside one request (a tool that starts two tool calls with
Promise.all) cannot be told apart once they overlap. They are refused withAsyncContextOverlapErrorinstead of reading each other’s context. Run such calls one after another. - A workflow runs its ready steps one at a time, whatever its
maxConcurrency: steps running at once would overlap in the workflow’s turn. Each step runs once, and the workflow takes about the sum of its steps. - A tool must not call its own server through a
DirectClientorDirectMcpServer; it would wait for its own turn. Call other tools throughthis.scopeflows instead. A request that waits more than 10 seconds for its turn logs a warning that says so. - Timers and promises a tool starts without awaiting run in whichever request holds the turn, so they must not read request context.
Up to 1.8.3, the browser build shared one context stack between all requests, so a request that awaited could continue with another request’s session, auth info and running tool.
Key Persistence in Browser
Key persistence auto-detects the best available backend: IndexedDB (preferred) → localStorage (fallback) → memory (last resort)Storage Adapters in Browser
Agent LLM Adapters in Browser
Both built-in adapters work in browser environments since they use HTTP-based APIs:ESM Dynamic Loading in Browser
TheApp.esm() API works in browser environments with these differences:
- Cache: Memory-only (no disk persistence). Bundles are stored in an in-memory
Map. - Module evaluation: Bundles are evaluated via
Blob+URL.createObjectURLinstead of writing to the file system. - Same API: No code changes needed — the environment is auto-detected.
Crypto Operations
All@frontmcp/utils crypto functions use the WebCrypto API in browser and node:crypto in Node.js: