vibeos-mcp
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
vibeos-mcp
A throwaway Linux box your coding agent can wreck. vibeos-mcp wires your own
MCP client — Claude Code, Cursor, Codex — to a vibeOS
desktop: a real machine your agent can edit, run commands on, and break, with
nothing of yours on it. You bring the agent; vibeOS brings the tools and the box —
no API key pasted into a browser.
claude mcp add vibeos -- npx vibeos-mcpThat is the whole install. Then ask your agent to pair vibeos — it answers
with a link — https://vibeos.sh/app#pair=… — open it, read the warning, accept,
and the desktop is paired: its tools appear in the agent without a restart. The
link reaches the agent, not your terminal, so it surfaces only when you ask for
it; pair vibeos is the shortest phrase that gets it, and works on a freshly
started client before anything is paired. The token behind the link is minted on your machine and
remembered in ~/.vibeos-mcp/token.json for seven days (the desktop remembers
it for the same seven — reloads and closed tabs keep the pairing); the token
rides the link's fragment, so it stays out of the HTTP request — access logs,
proxies, Referer never see it. It is still sent, once, in the pairing hello
over the websocket to whichever relay is selected, so that relay's operator sees
it (vibeos.sh on the default relay; you, on a self-hosted one). npx vibeos-mcp forget
drops it. Starting from the desktop instead — Settings › Capabilities › Pair
— still works: paste the command it shows, which carries --token. Forget this
agent in the desktop ends a pairing at once.
Whoever opens the link hands their desktop to your agent, root included, so
the warning is on the page before anything dials. Clients that do not show a
server's instructions get a single pair_desktop tool that returns the link
until a desktop is paired.
Why a relay exists
An MCP client spawns a subprocess or POSTs to an endpoint. A browser tab can do
neither — it cannot listen, only dial out. So both ends dial the same relay and
it pairs them by token and copies frames, parsing nothing beyond the first frame.
(An unconnected socket still holds a pairing slot and can ping; two sockets that
present the same token pair with each other, so a token is a shared secret,
not a name — it reaches no desktop but the one whose tab holds it.)
The default relay is wss://2yetm9bvy2.execute-api.us-east-1.amazonaws.com/prod
(API Gateway + DynamoDB: pairing is durable, so it does not matter which server
each side lands on), with wss://vibeos.sh/api/mcp/relay as fallback. The
Capabilities pane's command carries --relay <url> when the tab is on a
non-default one.
Related MCP server: Remote Link Local MCP
Security
The token is root on the desktop. The tool set includes edit_file on
system/os.js and vm_exec, so anything holding it can rewrite the OS and run
commands in the VM. It is sent as the first frame over the websocket, never in a URL, because URLs
reach access logs, proxies and Referer headers — the websocket reaches only
the relay operator, who sees it either way.
The relay sees the token and every tool call in plaintext. Assume the operator of the relay you select (vibeos.sh by default) can read what your agent does on your desktop, and pick a self-hosted relay if that is not acceptable.
Frame contract
Between the tab and this package. The relay does not interpret any of it.
Direction | Frame | Meaning |
both → relay |
| first frame, pairs the socket |
agent → tab |
| sent on every (re)connect, and again after MCP initialize once the client's name and capabilities are known; |
tab → agent |
| an app's |
agent → tab |
| the model's text, or why not (client cannot sample, 120 s deadline) — |
tab → agent |
|
|
agent → tab |
| a call |
tab → agent |
| its answer; any |
read_desktop's no-arg overview returns an errors array (newest 10, {time, message, source, shown}, redacted) — the agent-readable twin of the red "vibeOS hit an error" bar. It rides inside result, so the frame contract is unchanged and the package forwards it verbatim (the call result is JSON-stringified whole); nothing in this package needed changing to carry it.
| relay → either | {"paired":true\|false,"instance":"<id>"} | the relay's answer to the hello: is the other side already there, and which relay function instance this is (tab and agent must land on the same one) |
| agent → relay | {"ping":N} | every 30 s; a relay that names its instance must answer within 10 s or this side redials |
| relay → agent | {"pong":N,"instance":"<id>"} | the relay's answer, never forwarded to the tab |
| relay → either | {"bye":4001\|4003,"reason":"…"} | sent just before a normal close by a relay that cannot send custom close codes (API Gateway); means exactly what the close code would |
| relay → either | {"error":"peer not connected","code":4002} | the other end is gone (unscoped: every in-flight call fails) |
| relay → either | {"error":"peer not connected","code":4002,"scope":"settle"\|"reattach"\|"call","id"?} | a brief peer gap while the tab re-helloes the same token; only the named id fails, the pairing and tool list stay |
| tab → relay | {"revoke":true} | byte-exact; the relay closes both ends 4003 and forgets the token |
| tab → relay | {"ping":<ms>} | every 30 s, answered by the relay the same way |
The tab also sends {"tools":...} unsolicited when it connects. That is not
enough on its own: this package usually pairs after the tab, and reconnects
roughly every 800 s when the serverless function reaches its limit — so it asks
on every connect and the tab must answer want.
A self-hosted desktop (the vibeOS container) runs its own relay: start the
agent with --relay wss://<that host>/… and the pair link carries it as
&relay=. A link with no &relay= means the public default; a container
desktop refuses a link whose relay is not its own, naming the --relay to use,
rather than silently pairing through infrastructure you do not run.
--relay (or VIBEOS_RELAY) takes a comma-separated list: a relay that cannot
be reached at all falls through to the next; one that was open and dropped is
redialed as is. A call whose frame exceeds 128 KB is refused with an error naming
the size (API Gateway closes the sender above that); the tab does the same for
results. An API Gateway {"message":"Internal server error",…} frame (a
throttled lambda) fails in-flight calls loudly rather than vanishing.
Seeing the desktop
read_desktop returns the open windows (top first, with geometry), the dock
and the machine state as structured text; {window} gives one window's body as
text (password and hidden values never), {window, dom:true} its sanitised
outerHTML, and {screen:"image"} the machine's screen (the VM's VGA canvas) as
a JPEG at most 1024 wide and under about 110 KB for the relay, with the text
console's rows alongside. The desktop's own windows are DOM, which the tab
cannot rasterise without a large vendor library, so they come back as text, not
pixels. list_themes, list_files and search_file over a directory or glob
(in a worker, 3 s deadline) complete the picture; the chat log and machine
snapshots under system/ are the person's and are not readable.
initialize waits up to 3.5 s (VIBEOS_INIT_WAIT_MS) for the tab's first tools
frame so the instructions can ride the initialize result — MCP has no second
chance to send them. A tab that pairs later gets them to the next client that
connects; the current one works from the tool descriptions, and stderr says so once.
Failure behaviour
Calls fail; they never hang. An MCP client waiting forever is indistinguishable from one doing slow work, and the user cannot tell the difference.
Relay drops mid-call (the ~800 s cut): in-flight calls reject with a note that the desktop may still have run the tool. The socket redials in place.
The tab never answers (its main thread is busy — a catastrophic regex in
search_filemeasured about 50 s): the call fails at a deadline, 120 s by default (VIBEOS_CALL_TIMEOUT_MS), ortimeout_s+ 30 s forvm_exec, with a note that the desktop may still finish it.No tab paired:
tools/listanswers within 2 s with an empty list — Claude Code gives up on a slow list and shows the server as broken — and sendsnotifications/tools/list_changedthe moment the tab's schemas arrive. Atools/callin the gap errors with the relay instance id, so it can be compared with the one the Capabilities pane shows.The tab's socket dies with a call in flight: the relay tells this side
4002at once (not on the next send), so the call fails with the same note.A second
vibeos-mcpon the same token (close code 4001): final for the first one. Stop one, or pair a new token.The pairing outlives the tab. The token is remembered in that browser for seven days:
reload_os, a hand reload or a closed tab only open a gap — calls in it fail withpeer not connected— and a tab back on the same token answers again; this package reconnects on its own. A second tab of the same browser offers Take over here rather than dialing over the first, and the first is told. Forget this agent in the pane, or the expiry, ends it: a connected package reads revoked (4003); one that dials afterwards finds no tab.Revoked in Settings (close code 4003): final. No redial; every later call and
tools/listsay the desktop revoked the token.
Development
node e2e.mjs # real relay, fake tab, this package over real MCP stdioThis server cannot be deployed
Maintenance
Related MCP Connectors
Build, deploy, and operate hosted web apps on VibeKit (vibekit.bot) from any MCP client.
Remote MCP server for Tandem docs, install guides, SDKs, workflows, and agent setup help.
Use a person's computer after they approve it there: files, Terminal, browser, local MCP.
Start and manage Reason cloud coding agents, projects and sessions from any MCP client.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables MCP clients to execute shell commands, manage long-running processes, and read/write files on the host machine with the permissions of the user running the server.2 npmMIT
- AlicenseAqualityBmaintenanceEnables MCP clients to access a local computer through a controlled, permission-based tool surface for read-only or developer-mode file, process, and terminal operations.6MIT
- AlicenseNot gradedqualityBmaintenanceEnables an AI client to inspect and control an interactive Windows desktop, including screenshots, mouse and keyboard input, Windows UI Automation, PowerShell commands with managed jobs, and authenticated file uploads/downloads. Connects over remote MCP Streamable HTTP or local stdio without a separate host-side gateway.Apache 2.0
- AlicenseNot gradedqualityBmaintenanceEnables MCP clients on Windows 10/11 to control an interactive desktop through screenshots, mouse and keyboard actions, window management, UI Automation, clipboard access, and multi-display switching. Supports batched actions, application access controls, and visual or text-based desktop interaction.377 npm1MIT