Terraform for Apple development. An MCP server that lets Claude Code build, sign, and deploy iOS/macOS/visionOS apps without Xcode project files.
xclaude is an MCP (Model Context Protocol) server that gives Claude Code the ability to:
- Create iOS/macOS apps from scratch
- Build and deploy to simulators and physical devices
- Automatically discover and configure code signing
- Run tests, capture screenshots, read logs
- Generate SwiftData models, widgets, and API clients
- Archive and upload to the App Store
All without ever opening Xcode or creating an .xcodeproj file.
End-to-end App Store workflow now works! Build → Sign → Archive → Validate → Upload to TestFlight, all from Claude.
- Dev ↔ Distribution switching: Dual signing config (
[signing.iOS.development]and[signing.iOS.distribution]), automatic profile type detection - Proper IPA signing: Fixed AppleDouble resource fork contamination that broke code signatures
- Device family targeting:
devices = ["iphone"]in xclaude.toml correctly sets UIDeviceFamily - Better error handling: Upload tool now properly detects altool errors even when exit code is 0
- Profile name collision fix: Profiles filtered by team ID and type, not just display name
mint install bmdragos/xclaudeThis installs both xclaude and swift-bundler to ~/.mint/bin/.
Note: First install takes 3-5 minutes to compile dependencies. Subsequent updates are faster.
git clone https://github.com/bmdragos/xclaude.git
cd xclaude
swift build -c releaseThe binaries will be at .build/release/xclaude and .build/release/swift-bundler.
Add to your Claude Code MCP settings (~/.claude/settings.json or project .claude/settings.json):
{
"mcpServers": {
"xclaude": {
"command": "~/.mint/bin/xclaude"
}
}
}Or if you built from source:
{
"mcpServers": {
"xclaude": {
"command": "/path/to/xclaude/.build/release/xclaude"
}
}
}Restart Claude Code to load the MCP server.
Once configured, just ask Claude:
"Create a new iOS app called TaskMaster and deploy it to my iPhone"
Claude will use xclaude to:
- Create the project structure
- Generate
Package.swiftandxclaude.toml - Scaffold SwiftUI app code
- Discover signing credentials
- Build and deploy to your device
For physical devices: You'll need an Apple Developer account with provisioning profiles set up. Run
configure_signingto auto-discover and apply credentials.
xclaude uses conventions:
MyApp/
├── xclaude.toml # Simple config (the only config you need)
├── icon.png # 1024x1024 app icon
├── Package.swift # Swift Package Manager manifest
├── Sources/MyApp/
│ ├── MyAppApp.swift # @main entry point
│ └── ContentView.swift
└── .xclaude/ # Generated (gitignored)
└── derived/ # Bundler.toml, entitlements, etc.
xclaude.toml is intentionally minimal:
[app]
name = "MyApp"
# bundle_id = "com.company.myapp" # Optional, derived from name
# version = "1.0.0" # Optional, defaults to 1.0.0
[signing]
# team = "ABC123XYZ" # Optional, auto-discovered
# identity = "Apple Development" # Optional, auto-discovered
# profile = "iOS Team Provisioning" # Optional, auto-discoveredMost projects only need the app name. Everything else is auto-discovered.
| Category | Tools |
|---|---|
| Project | create_project, init_project, get_config, update_config |
| Signing | discover_signing, get_signing_status, configure_signing |
| Build | build, build_start, build_status, build_logs, build_cancel |
| Deploy | deploy, run, watch, stop_watch |
| Devices | list_simulators, list_devices, reset_simulator |
| Debug | screenshot, get_logs, get_crash_logs, diagnose |
| Test | test |
| Dependencies | add_dependency |
| Capabilities | add_capability, remove_capability, list_capabilities |
| Distribution | archive, validate, upload |
| Scaffolding | generate_icon, add_model, add_extension, generate_api_client |
| App Store Connect | asc_configure, asc_status, asc_list_devices, asc_register_device, asc_list_profiles, asc_create_profile, asc_delete_profile, asc_download_profile, asc_regenerate_profile, asc_list_certificates, asc_create_certificate, asc_revoke_certificate, asc_list_apps, asc_list_bundle_ids, asc_create_bundle_id, asc_create_app, asc_list_builds, asc_list_groups, asc_create_group, asc_add_build_to_group, asc_list_testers, asc_add_tester, asc_remove_tester, asc_set_whats_new |
| Info | get_version |
For long-running builds, use the async pattern:
build_start() → { job_id: "build-1" } # defaults to iOS device
build_status(job_id: "build-1") → { status: "running", appPath: ".build/bundler/MyApp.app" }
build_logs(job_id: "build-1") → { lines: [...], status: "success" }
deploy(app_path: "...") → { success: true } # bundle_id auto-detected
Options:
build_start(clean: true)- delete.build/before buildingbuild_logs(clear: true)- clear buffer after reading (default: preserves buffer)deployauto-detectsbundle_idfrom xclaude.toml, defaults to device target
Create and run a new app:
"Create an iOS app called WeatherApp and deploy it to my iPhone"
Build for Mac:
"Build and run my app on macOS"
Add a SwiftData model:
"Add a SwiftData model called Task with properties: id (UUID), title (String), isComplete (Bool), dueDate (Date?)"
Add a widget:
"Add a widget extension to my app"
Prepare for App Store:
"Archive my app for App Store submission"
Debug issues:
"Take a screenshot and show me the recent logs"
Add macOS automation capability:
"Add the apple-events capability so my app can control other apps"
add_capability stores capabilities in xclaude.toml and handles Info.plist usage descriptions:
add_capability("apple-events")
↓
┌─────────────────────────────────────────────────────────────┐
│ xclaude.toml: │
│ [capabilities] │
│ apple-events = true │
│ │
│ [info_plist] │
│ NSAppleEventsUsageDescription = "This app needs to..." │
└─────────────────────────────────────────────────────────────┘
↓
build (macOS) → entitlements generated fresh, app signed
Entitlements.plist is regenerated fresh each build from [capabilities], avoiding cross-platform contamination.
iOS/Shared: push-notifications, app-groups, icloud, keychain, healthkit, homekit, in-app-purchase, siri, wallet, background-modes, and more.
macOS: apple-events, hardened-runtime, camera, microphone, location, files-read-write, system-extension, network-client, network-server, bluetooth, usb, print, serial, app-sandbox, and more.
Continuity/Ecosystem: handoff, associated-domains, sign-in-with-apple, shareplay, nfc, carplay, weatherkit, and more.
Notifications: critical-alerts, time-sensitive, communication-notifications.
Newer APIs: shazamkit, musickit, push-to-talk, matter, financekit, devicecheck.
Performance: increased-memory-limit, extended-virtual-addressing.
Other: personal-vpn, data-protection, family-controls, autofill-credentials, maps-routing.
Run list_capabilities to see all 61 with platform info.
Automate device registration, provisioning profiles, and TestFlight distribution:
Setup (one-time):
- Go to App Store Connect → Users and Access → Keys
- Generate an API Key (Admin role recommended)
- Download the
.p8private key (only available once!) - Configure:
asc_configure(issuer_id: "...", key_path: "/path/to/AuthKey_XXX.p8")
Register a new device:
asc_register_device(udid: "00008130-...", name: "Test iPhone")
asc_regenerate_profile(bundle_id: "com.example.myapp")
# Profile now includes the new device
Deploy to TestFlight:
# 1. Archive and upload
archive() → .ipa file
upload(path: "MyApp.ipa") # Auto-uses ASC credentials
# 2. Wait for processing (~5-10 min)
asc_list_builds(app_id: "...") # Check for new build
# 3. Distribute to testers
asc_add_build_to_group(group_id: "...", build_id: "...")
asc_set_whats_new(build_id: "...", whats_new: "Bug fixes and improvements")
Known limitations:
- Cannot create apps via API (Apple limitation) -
asc_create_appreturns manual steps - The
uploadtool auto-uses credentials fromasc_configure
xclaude automatically discovers:
- Signing identities from your keychain
- Provisioning profiles from
~/Library/Developer/Xcode/UserData/Provisioning Profiles/ - Simulators via
xcrun simctl - Physical devices via
xcrun devicectl
Run configure_signing to see available options and auto-apply the best match.
- iOS / iPadOS
- macOS
- tvOS
- visionOS
- macOS 13+
- Xcode Command Line Tools
- Mint (for easy installation):
brew install mint - For physical devices: Apple Developer account with provisioning profiles
xclaude is built on top of Swift Bundler, a tool for building Swift apps without Xcode. xclaude adds:
- MCP interface - JSON-RPC 2.0 protocol for Claude Code integration
- Auto-discovery - Automatic signing credential detection
- Config translation - Simple
xclaude.toml→ Swift Bundler'sBundler.toml - Scaffolding - Project, model, extension, and API client generation
- Developer tools - Screenshots, logs, diagnostics
Run discover_signing to see available identities, or:
security find-identity -v -p codesigningFor simulators, no profile is needed. For devices:
- Open Xcode → Settings → Accounts
- Add your Apple ID and download provisioning profiles
- Run
configure_signingin xclaude
See Apple's Distributing Your App to Registered Devices guide for detailed setup.
Run diagnose to check your environment:
- Xcode installation
- Package.swift validity
- Icon presence
- Signing status
This usually means one of:
-
Certificate not in profile: The profile was created before your signing certificate existed
- Go to Apple Developer Portal → Profiles → Edit your profile
- Check your certificate is selected
- Regenerate and reinstall the profile
-
Device not in profile: Your device isn't registered to the profile
- Check Portal → Devices for your device
- Device UDIDs differ between formats:
devicectlshows CoreDevice UUID, Portal shows hardware UDID - Both refer to the same device - use
xcrun devicectl device info details --device <udid>to see hardware UDID
-
Entitlement mismatch: App has entitlements the profile doesn't allow
- macOS sandbox entitlements (
com.apple.security.*) don't work on iOS - xclaude v3.7.0+ regenerates entitlements fresh each build, auto-filtering by platform
- macOS sandbox entitlements (
If Xcode shows your certificate but security find-identity -v -p codesigning doesn't:
- The private key wasn't saved when the cert was created
- Fix: In Xcode → Settings → Accounts → Manage Certificates, delete the cert and create a new one
- Or manually: Generate CSR in Keychain Access, upload to Portal, download and import the .cer
Apple certificates embed the team ID in the Common Name (CN), but organizational certs may show a different team ID than the organization:
# Certificate might show:
"Apple Development: Your Name (PERSONAL_TEAM_ID)"
# But actually belong to:
OU=ORGANIZATION_TEAM_ID
xclaude will match based on the provisioning profile's team. Use discover_signing to see all available identities and profiles.
xclaude supports building for multiple platforms from the same project:
# Build for iOS
build(platform: "iOS")
# Build for macOS
build(platform: "macOS")Platform-specific entitlements are handled automatically:
- Entitlements regenerated fresh each build from
[capabilities]in xclaude.toml - macOS-only capabilities filtered out for iOS builds (and vice versa)
- Info.plist usage descriptions added for iOS capabilities (camera, bluetooth, etc.)
MIT
Built on Swift Bundler by stackotter.