Automation
The hard part of giving ChatGPT a shell is the trust boundary
What changed when I stopped treating an MCP-to-WSL bridge as a connectivity problem and separated files, Bash, code intelligence, terminal lifetime, browser control, and constrained-client access into explicit authority boundaries.
Date
Updated
August 24, 2026Read
4 minRepository snapshot
WebSession MCP Bridge
Authenticated AI-to-WSL access with explicit trust boundaries.
- Commits
- 192
- Trust domains
- 3
- Access
- OAuth + MCP
Work done
Getting a model to run bash was not the milestone. The milestone was being able to answer one boring question: what can this session actually do?
A web AI session, an OAuth callback, a Linux user, a repository search tool, and a persistent terminal all have different authority. Treating them as one generic “connected machine” made the system easier to demo and harder to trust.
In 30 seconds
- Problem: remote development access becomes ambiguous when files, native shell execution, repository intelligence, browser state, and long-lived terminals all look like the same permission.
- Decision: split the bridge into explicit trust profiles and capability domains, then make persistence and human handoff first-class boundaries.
- Proof: WebSession MCP Bridge routes a narrow HTTPS/OAuth edge into separate Dev, Code, Terminal, and Local/Browser surfaces, with smaller public profiles and a fuller private personal profile.
Connectivity was the easy problem
The first useful prototype only needed a path:
ChatGPT -> HTTPS -> MCP -> WSL
That proves connectivity. It says almost nothing about authority.
Can the session read one workspace or the whole Linux account? Can it run arbitrary Bash? Can it control authenticated browser state? Can it start a process that outlives the current MCP request? Can it hand an interactive terminal to a human without opening a second shell? Can a constrained client reach the same tools without creating a second permission model?
Those questions became the architecture.
I stopped treating every tool as equivalent
The private harness now has three direct domains plus one stable Local broker domain:
Dev files, Bash, durable waits, explicit host sleep
Code repository-rooted code intelligence
Terminal persistent interactive PTYs
Local stable discovery/schema/call -> Browser facade
That split sounds simple, but it removes a lot of ambiguity.
A file edit and a terminal session do not have the same lifecycle. A semantic code search and unrestricted Bash do not have the same trust boundary. Browser control can reach authenticated native Windows Chrome state, so it should not be hidden inside a generic shell tool. A readiness wait should not consume terminal output just because both involve a running process.
Local keeps that browser surface small. The model sees three stable broker actions for discovery, schema lookup, and calls; a private inner 1MCP and resource-local Browser facade own the Windows-versus-WSLg routing behind them.
Once those differences were explicit, routing became easier to reason about. The question for an agent changed from “which of these many tools could do this?” to “which boundary owns this kind of work?”
Trust profiles made the dangerous part visible
The public side of the bridge does not need the same authority as my personal WSL setup.
The restricted profile keeps ordinary file operations workspace-bounded. trusted-dev deliberately adds native Bash for a dedicated development host. The private personal composition can expose broader WSL paths, code intelligence, durable terminals, and explicitly authorized browser control.
The names matter less than the contract: more convenience should require a more explicit grant of authority.
That also changed setup. Preparing the personal runtime and enabling persistent startup are separate actions. A bootstrap can qualify and render the environment without silently deciding that services should come back forever.
Long-running work needed its own lifetime
MCP calls are request-shaped. Development work often is not.
A server, build, REPL, or interactive TUI may need to survive a provider restart or a later human handoff. Keeping those processes inside the lifetime of one connector call made them fragile.
The bridge instead gives Terminal its own durable PTY lifetime under tmux. The model can start work, observe the same process later, and yield the exact terminal when a human needs to type a password or make an interactive decision.
That removes a bad escape hatch: opening some second, hidden shell because the original one became inconvenient.
Constrained clients needed another transport, not another authority model
Native MCP remains the normal path through 1MCP. The repository also has an optional WebSession adapter for clients that can make HTTPS requests but cannot speak MCP directly.
The adapter runs separately from the normal bridge lifecycle. Its readable-GET and bearer-authenticated JSON POST facades normalize into one durable SQLite operation core, then authenticate back through 1MCP. It mirrors the live tool descriptors and calls the exact upstream tools; it does not bypass the gateway or invent a parallel permission system.
That boundary matters more than the transport format. Adding compatibility should not duplicate authorization policy.
Public and private should not be the same artifact by accident
My personal harness includes implementation and evidence that only makes sense for my machine. The repository therefore keeps a publication boundary around private-only paths instead of assuming an open-source checkout should reproduce my authority model exactly.
That is a small lesson I keep rediscovering in agent tooling: a working internal composition is not automatically a safe default for somebody else.
The useful metric is clarity of authority
I could describe WebSession MCP Bridge as Cloudflare + OAuth + MCP + WSL. That stack list is accurate and not very informative.
The project became more useful when I could describe the failure modes instead:
- a bounded profile should not quietly inherit unrestricted shell access;
- a long-running terminal should not disappear with a short request;
- a human handoff should keep the same PTY;
- code intelligence should stay rooted in a real repository;
- browser control should require its own explicit scope and resource-local owner;
- a compatibility adapter should reuse 1MCP authority instead of bypassing it;
- public installation should not silently copy private-machine authority.
The tunnel connects the system. Those boundaries make it understandable.