mac-mini-mcp
v0.1.0
Published
A Model Context Protocol (MCP) stdio server that gives Claude Code (or any MCP client) access to your Mac and its iOS Simulators via the [Hatch mac-mini-client](https://hatch-web.pages.dev).
Readme
mac-mini-mcp
A Model Context Protocol (MCP) stdio server that gives Claude Code (or any MCP client) access to your Mac and its iOS Simulators via the Hatch mac-mini-client.
It exposes one tool — exec — and a couple of read-only resources for
simulator state. That's it. See CLAUDE.md for the
philosophy.
What you get
exectool — run any allow-listed shell command (xcrun simctl ...,xcodebuild,swift build,bash -c '...') on the active Hatch resource. Returns{ stdout, stderr, exitCode }.simulator://devicesresource — JSON list of every simulator on the host (flattened fromxcrun simctl list devices -j).simulator://<udid>/screenshotresource — live PNG of a booted simulator on demand.- Auto-detect transport — connects directly to a local gateway when
mac-miniis running on the same machine; falls back to the Hatch Cloudflare relay when it isn't, so the same MCP server works on a laptop, a remote box, or in CI.
Setup
1. On the Mac that owns the simulators
bunx mac-mini login # one-time browser sign-in via Hatch
mac-mini # start the gateway2. Add to Claude Code
claude mcp add hatch -- bunx -p mac-mini-mcp hatch-mcpThat's it. Restart Claude Code and ask it to "list booted simulators" or "build the Xcode project at ~/dev/MyApp."
Flags
| Flag | Env | Default | Notes |
| --------------------- | ----------------------- | ------------ | -------------------------------------------------------------------------------- |
| --resource <id> | HATCH_RESOURCE_ID | first online | Pick a specific Mac when you have several. |
| --mode local\|relay | HATCH_MCP_MODE | auto | Force a transport. Auto probes localhost first. |
| --login | — | off | Run the device-code login flow on startup if no token is cached. Requires a TTY. |
| — | HATCH_TOKEN | — | Bearer token. Skips reading ~/.mac-mini/config.json. Useful for CI. |
| — | HATCH_ENV=development | — | Talk to http://localhost:3001 instead of production Hatch. |
How it picks a connection
- Reads
~/.mac-mini/config.json(orHATCH_TOKEN) for a Hatch access token, thenGET /api/resourcesto discover your Macs. - Picks
--resource <id>if given, else the first one withstatus === "online". - Probes the local companion port (
gatewayPort + 1) onlocalhost. If the gateway answers/status, it connects directly via WebSocket. - Otherwise it connects through the Hatch Cloudflare Durable Object relay
at
wss://hatch-auth.baconbrix.workers.dev/relay/<resourceId>, authenticating with the same access token.
This mirrors what apps/web/src/App.tsx does in the browser.
Examples for the agent
The model only ever calls exec. Some commands worth knowing:
# List all simulators (flattened, JSON)
xcrun simctl list devices -j
# Boot a specific simulator
xcrun simctl boot "iPhone 16"
# Install and launch a built .app
xcrun simctl install booted /path/to/MyApp.app
xcrun simctl launch booted com.example.MyApp
# Build an Xcode project for the simulator
xcodebuild -project MyApp.xcodeproj -scheme MyApp -sdk iphonesimulator -derivedDataPath build
# Type-check Swift code
swift build --package-path /path/to/pkg
swift test --package-path /path/to/pkg
# Write a file via base64 (handles binary safely)
bash -c 'echo SGVsbG8K | base64 -d > /tmp/hi.txt'Why only one tool
Read CLAUDE.md. The short version: agents already know
xcrun and xcodebuild; wrapping them adds surface area without adding
capability.
Verification
Smoke test against a local gateway:
# terminal 1
cd apps/cli && bun run dev -- --no-auth
# terminal 2 — manual JSON-RPC over stdio
HATCH_TOKEN=dummy HATCH_RESOURCE_ID=local \
bun run packages/mac-mini-mcp/src/index.ts --mode localEnd-to-end via Claude Code:
claude mcp add hatch-dev -- bun run packages/mac-mini-mcp/src/index.ts
# Then in a Claude Code session:
# "Use the hatch MCP to list booted iOS simulators."Stop mac-mini and re-ask the same question — the server should switch
to mode=relay and answer the same way.
