Claude desktop teardown: MCP servers run outside the VM

When a Cowork session calls a local MCP server, the server runs as an ordinary macOS process, outside the Linux VM that Claude’s desktop app boots to isolate agent code. That is one finding of a teardown of build 1.40609.1 published on Telkins on September 8, which takes apart the 855 MB app bundle and the guest image the app downloads.
About 60% of the bundle is Electron and its Chromium resources. The native code sits in .node addons linked against Apple frameworks. The Swift addon links Apple’s Virtualization.framework and exposes the types that manage the VM.
What boots inside the guest
The app doesn’t ship the operating system. It downloads the guest at runtime. The author inspected the arm64 base image for a revision published August 13. Its manifest lists four artifacts: a root disk, a kernel, a standard initrd (the small filesystem a Linux kernel loads first at boot) and an initrd-micro for a fast-boot path. The root disk is 1.23 GB compressed and expands to a 10 GiB disk with a 99 MiB EFI partition and an ext4 root running Ubuntu 22.04.5 LTS on kernel 6.8.0-136-generic.
Inside are Node.js 22.23.2, Python 3.10.12, uv and /usr/local/bin/sdk-daemon, a stripped Go binary built with Go 1.25.12. A systemd unit, coworkd.service, describes it as a vsock RPC bridge for process management and runs it as root inside the guest. The rest of the image is a document toolkit: pdfplumber, camelot for PDF tables, pytesseract for OCR, headless LibreOffice through unoserver, markitdown and magika for file-type detection, along with an extract-text script that sends each format to MarkItDown, Pandoc or LibreOffice.
The bundle itself carries two 24 MB smol-bin images, one for arm64 and one for x64, because the app is universal. They aren’t bootable. The host attaches one to the VM as an extra virtual disk, and the coworkd updater mounts it and copies the bundled daemon into place. The two daemon copies the author compared had different hashes. The author thinks this keeps the host and guest sides of the protocol in step. It also lets Anthropic update the daemon without making users download the whole guest image again, since that image is versioned and cached separately.
How host and guest talk
A Swift class, CoworkVMRPCClient, exchanges JSON messages with the Go daemon over vsock, a socket channel between a host and its VM that doesn’t go over the network. Both ends have to agree on field names and types, and because the daemon ships with the app, the two sides can change together. Swift field records recovered from the addon show what those calls look like. SpawnProcessArgs carries a command with its working directory, environment variables, extra mounts and allowed domains. StartVMArgs carries memory, CPU and networking options. Events going back to the app include vmStartupStep, guestConnectionChanged and vmStopped.
Network traffic travels over vsock too. The guest daemon forwards packets from a virtual Ethernet interface to the host. On the host side, the Swift metadata references VZGvisorNetworking and a GvisorNetworkAttachment.swift source file. Together these suggest that a gVisor-based network stack runs on the Mac and connects to the outside world for the guest.
The allowlist and the proxy
The sandbox settings file inside smol-bin, srt-settings.json, allowlists npm, Yarn, PyPI, github.com, the Ubuntu archives, crates.io and Anthropic’s domains. Inside the guest, writes are allowed everywhere: allowWrite is set to ["/"]. Traffic to anthropic.com, claude.com and the frame.claudeusercontent.com hosts goes through a MITM proxy on /var/run/mitm-proxy.sock.
The proxy was added after a bug Anthropic described in its own write-up. A malicious file got Claude to upload workspace files to the attacker’s account through Anthropic’s API, and because that domain was on the allowlist, the request went through. The proxy now inspects requests to the API and requires the VM’s provisioned session token, so an attacker’s key is rejected. A domain allowlist alone couldn’t tell those requests apart.
Where the VM stops
To find out where MCP servers run, the author added a tiny Python server to Claude’s configuration and called it from a local Cowork session. The tool reported Darwin and PID 18717. The macOS process table showed the chain Claude (18616), then Contents/Helpers/disclaimer (18716), then the probe. The tool also returned a random value saved in /private/tmp, a file that was never shared with the VM. A local MCP server can read whatever its settings and macOS permissions allow, VM or not. In January, a write-up on Pvieito said MCP servers are passed through to the VM dynamically, though its diagram put them in the Electron app on the macOS host.
Coordination also runs outside the VM. The Mac app talks to the model, dispatches tool calls and collects the results. Anthropic first ran that inside the VM, but a failed VM boot could leave Claude unable to respond, and running it on the Mac lets Claude help diagnose the failure. Anthropic’s help center describes the same behaviour: when the VM can’t start, file and web tools keep working, and shell commands report “workspace unavailable” until the VM recovers. Commands sent to the daemon still run inside the guest. Shared host directories are the exception there. If one is writable, the agent can change or delete files in it, and stopping the process doesn’t undo those changes.
All of this describes the local path, which is no longer the default. The help center says Cowork sessions now run in the cloud by default, with local execution kept for existing desktop deployments, and that local MCP servers don’t run in cloud sessions. For machines that still run sessions locally, the author sums it up: “the VM’s protections apply to the tools running inside it, and don’t cover every action Claude can take.”
Up next
Anthropic walks away from the $6B Decart deal
Anthropic walked away from the $6 billion Decart acquisition, Bloomberg reports, dropping what would have been its largest known deal ahead of an IPO. The two may still find other ways to collaborate, one person says.
Related stories
- One email check hides Claude’s Android debug menu
- Claude Code Projects adds shared sessions and threads
- A browser inside Claude Desktop, always on in Cowork
- Claude Code shipped its own TypeScript in npm source maps
- Claude Duet won’t share your card number even if you ask
- Claude’s auto mode skips connector “Always ask” settings
Comments
No comments yet. Be the first.
Join the conversation
Sign in to leave a comment. It appears after moderation.

