A standalone SwiftUI preview host for humans and AI agents.
Run, snapshot, and interact with #Preview blocks from the command line or over MCP — no Xcode process required.
git clone https://github.com/obj-p/PreviewsMCP.git
cd PreviewsMCP
swift run previewsmcp examples/spm/Sources/ToDo/ToDoView.swiftA live macOS preview window opens. Edit the source file and the window hot-reloads.
PreviewsMCP compiles your #Preview closure into a dylib and loads it into a real app process (macOS NSApplication or iOS simulator UIApplication) with hot-reload — driven entirely from the command line or over MCP. No Xcode process required.
That makes it a standalone, extensible preview workflow:
- CLI and MCP-native — preview, snapshot, and iterate from the terminal or let an AI agent drive the loop
- Hot-reload — edit a file, see changes immediately, with
@Statepreserved across literal edits - Trait and variant sweeps — render one preview across color schemes, dynamic type sizes, locales, and layout directions in a single call
- iOS interaction — walk the accessibility tree and inject taps/swipes through an in-simulator touch bridge
- Build system flexible — works with SPM, Xcode projects (
.xcodeproj/.xcworkspace), and Bazel
Xcode previews run your code inside Apple's preview agent — a real app process, but an opaque one. You can't hook into its lifecycle, run your own initialization, or extend it. FirebaseApp.configure(), custom font registration, auth setup, and DI containers have nowhere to run. The ecosystem answer is "mock everything," and at scale teams maintain micro apps — standalone app targets that render a single feature with controlled dependencies. Airbnb's dev apps drive over 50% of local iOS builds. Point-Free's isowords has 9 preview apps. Every team pays the maintenance tax: separate targets, schemes, and mock setups that drift.
Because PreviewsMCP hosts your preview in its own app process, you can extend that process. The setup plugin provides the hook: a PreviewSetup protocol where setUp() runs once per session (SDK init, auth, font registration, DI container) and wrap() surrounds every preview render (themes, environment values). It's the micro app's dependency layer extracted into a reusable framework — without maintaining a separate app target.
brew tap obj-p/tap
brew install previewsmcpgit clone https://github.com/obj-p/PreviewsMCP.git
cd PreviewsMCP
swift build -c releaseThe binary is at .build/release/previewsmcp.
- macOS 14+
- Xcode 16+ (for iOS simulator support)
- Apple Silicon
- Live previews — hot-reload SwiftUI on macOS or a real iOS simulator, preserving
@Statewhere it can. - Variant & trait sweeps — render one preview across many trait combinations (
colorScheme,dynamicTypeSize,locale,layoutDirection,legibilityWeight) in a single call, with presets for light/dark,xSmall–accessibility5,rtl,ltr, andboldText. - Multi-preview selection —
#Previewmacros and legacyPreviewProvider, with mid-session switching. - iOS interaction — walk the accessibility tree and inject taps/swipes through an in-simulator touch bridge.
- Setup plugin — one-time SDK init, auth, and DI registration via
setUp(), per-render theme/environment wrapping viawrap(). See the full integration guide. - Project config —
.previewsmcp.jsonfor per-project defaults (platform, device, traits, quality, setup target).
previewsmcp help # top-level overview
previewsmcp help <subcommand> # full options for run / snapshot / variants / list / serveA few common invocations:
previewsmcp MyView.swift # live macOS preview window
previewsmcp MyView.swift --platform ios # iOS simulator
previewsmcp snapshot MyView.swift -o preview.png # one-shot screenshot
previewsmcp list MyView.swift # enumerate #Preview blocksDrop a .previewsmcp.json at your project root to set defaults for every CLI command and MCP tool call (see examples/.previewsmcp.json for the canonical shape):
{
"platform": "ios",
"device": "iPhone 16 Pro",
"traits": { "colorScheme": "dark", "locale": "en" }
}Explicit CLI/MCP parameters override config values. The config is auto-discovered by walking up from the source file directory.
Add to your agent's MCP config — same mcpServers shape whether it lands in .mcp.json (Claude Code), ~/.cursor/mcp.json (Cursor), .vscode/mcp.json (VS Code), or claude_desktop_config.json (Claude Desktop):
{
"mcpServers": {
"previews": {
"command": "/path/to/previewsmcp",
"args": ["serve"]
}
}
}Once connected, ask your agent "what previews tools are available?" — it will describe them directly from the server's registered schemas, including snapshotting, variant capture, accessibility-tree inspection, and touch injection.
