Skip to main content
Glama
README.md
<div align="center">

# Xcode MCP Server

**Model Context Protocol Server for the Apple Ecosystem**

*Connect OpenCode, Codex and Claude Code to Xcode β€” 52 professional tools in a single `index.js`*

[![CI](https://github.com/YanxReal/Xcode-MPC/actions/workflows/ci.yml/badge.svg)](https://github.com/YanxReal/Xcode-MPC/actions)
[![Node >=18](https://img.shields.io/badge/node-%3E%3D18-339933?logo=node.js&logoColor=white)](https://nodejs.org)
[![Yarn 4](https://img.shields.io/badge/yarn-4.18-2C8EBB?logo=yarn&logoColor=white)](https://yarnpkg.com)
[![MCP](https://img.shields.io/badge/MCP-Stdio_Transport-7B68EE)](https://modelcontextprotocol.io)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Version](https://img.shields.io/badge/version-1.4.0-blue.svg)](package.json)

> 🌐 **Language:** **English** | [Español](README.es.md)

[Installation](#-step-by-step-installation) β€’ [Tools](#-tools-52) β€’ [OpenCode](docs/opencode.md) β€’ [Codex](docs/codex.md) β€’ [Claude Code](docs/claude-code.md) β€’ [Docs](docs/architecture.md)

</div>

---

## What is this?

**Xcode MCP Server** is a **serious, production-ready** bridge between your **AI IDE** (OpenCode / Codex / Claude Code) and **Xcode + Apple Dev Tools**.

> An LLM no longer just writes Swift: it **builds, tests, profiles, manages simulators, physical devices, signing and even opens Xcode on the exact line** β€” all via MCP `stdio` with no HTTP server.

**Stack:** `ES Modules` Β· `@modelcontextprotocol/sdk@1.30` Β· `StdioServerTransport` Β· `promisify(exec)` Β· `Yarn 4 Berry` Β· `Make`

<details>
<summary><strong>Why this server and not another?</strong></summary>

- βœ… **Single-file `index.js` (2250 lines)** β€” no build step, no compile, auditable in one file. Shebang `#!/usr/bin/env node`, ready for `node`, `yarn start` or `npx`.
- βœ… **52 tools with strict JSON Schema** (`additionalProperties:false`) + global `try/catch`. Each tool returns `content: [{type:"text"}]` and `isError:true` on failure β€” no `// TODO`.
- βœ… **Full Apple coverage:** `xcodebuild`, `simctl` (9), `devicectl` (2), `xctrace` (5 templates), `agvtool`, `security`, `osascript/xed`.
- βœ… **Modern DX:** Vendored Yarn 4 (`.yarn/releases`), self-documenting `Makefile` with `help`, modular `docs/`, macOS CI + `make test` smoke.
- βœ… **Multi-client:** same `index.js` works with **OpenCode**, **Codex** and **Claude Code** without changes.

</details>

---

## ✨ Features

| Category | Tools | Description |
|---|---|---|
| **Build** | 6 | `xcode_build`, `xcode_clean` (+ purge DerivedData), `xcode_list_schemes`, `xcode_analyze`, `xcode_archive_export` (`.ipa`), `swift_format_lint` |
| **Tests** | 2 | `xcode_run_tests` (`onlyTesting` filter), `xcode_test_coverage` (`xccov --json`) |
| **Simulators** | 9 | `simctl_list`, `lifecycle` (boot/shutdown/erase), `install_launch`, `media_capture`, `push_notification`, `location_mock`, `privacy_control`, `ui_appearance`, `open_url` |
| **Devices** | 2 | `devicectl_list`, `devicectl_logs` (N-second streaming) |
| **Profiling** | 1 | `xctrace_profile` (Time Profiler, Allocations, Leaks, System Trace…) |
| **Versions** | 2 | `agvtool_version_bump`, `xcode_certificates_check` |
| **Editor** | 2 | `xcode_get_active_file` (AppleScript), `xcode_open_at_line` (`xed` β†’ `xcode://`) |
| **Localization** | 1 | `xcode_sync_strings` (`.xcstrings` β†’ missing/pending/empty) |
| **Assets** | 6 | `asset_list_contents`, `asset_manage_color` (Light/Dark), `asset_manage_image` (1x/2x/3x/vector), `asset_read_info`, `asset_delete`, `asset_validate_actool` (`actool`) |
| **AppIcon** | 1 | `asset_generate_appicon` (ALL Apple OS: iOS, macOS, watchOS, tvOS, visionOS + `sips` resize) |
| **Package / SPM** | 11 | `package_resolve`, `package_update`, `package_list_dependencies`, `package_read_resolved`, `package_reset_cache`, `package_compute_checksum`, `spm_add_dependency`, `spm_remove_dependency`, `cocoapods_manage`, `carthage_manage`, `cocoapods_to_spm_migrate` |
| **Vision/UI** | 4 | `simctl_get_screen_analysis` (sips + `imagePath`), `simctl_inspect_ui_tree` (accessibility tree), `simctl_tap_by_text` (smart tap), `simctl_fill_field` (smart type) |
| **Simctl Extra** | 5 | `simctl_set_appearance` (light/dark), `simctl_set_dynamic_type` (Dynamic Type), `simctl_manage_storekit` (load/clear/buy/refund), `simctl_simulate_event` (call/network), `simctl_send_push` (APNs object) |

---

## πŸ“‹ Table of Contents

1. [Requirements](#-requirements)
2. [Step-by-step Installation](#-step-by-step-installation)
3. [Verification](#-verification)
4. [Usage with OpenCode / Codex / Claude Code](#-usage-with-opencode--codex--claude-code)
5. [Tools (52)](#-tools-52)
6. [Make Commands](#-make-commands)
7. [Documentation](#-documentation)
8. [Architecture](#-architecture)
9. [Contributing](#-contributing)

---

## πŸ“¦ Requirements

| Dependency | Version | Install | Required |
|---|---|---|---|
| **macOS** | 13+ (14+ recommended) | β€” | βœ… for `xcodebuild`/`simctl` |
| **Xcode** | 15+ | App Store β†’ `xcode-select --install` | βœ… |
| **Node.js** | β‰₯ 18 | `brew install node` β†’ `node --version` | βœ… |
| **Yarn** | 4.x Berry | `corepack enable && corepack prepare yarn@stable --activate` | βœ… |
| **make** | 3.81+ | `xcode-select --install` (includes make) | βœ… |
| **swift-format** | latest | `brew install swift-format` | ◻️ optional |
| **swiftlint** | latest | `brew install swiftlint` | ◻️ optional |

> **Linux/Windows:** only `make lint` works (no Xcode). CI runs a `syntax-linux` job for that.

---

## πŸš€ Step-by-step Installation

Follow **exactly** in this order. Copy and paste block by block.

### Step 0 β€” Verify Xcode and Node

```bash
xcodebuild -version
# Xcode 15.4  Build version 15F31d

node --version
# v20.11.0 (or newer)

yarn --version
# 4.18.0 β€” if "command not found", run:
corepack enable
corepack prepare yarn@stable --activate
yarn --version
```

### Step 1 β€” Clone the repository

```bash
git clone https://github.com/YanxReal/Xcode-MPC.git
cd Xcode-MPC
```

### Step 2 β€” Install dependencies

**Option A β€” with Make (recommended, modern):**

```bash
make install
```

What `make install` does:
1. Detects `yarn`, installs via `corepack` if missing
2. Runs `yarn install` (reads `yarn.lock`, installs `@modelcontextprotocol/sdk`)
3. Runs `chmod +x index.js`

Expected output:
```
➀ YN0000: · Yarn 4.18.0
➀ YN0000: β”Œ Resolution step
➀ YN0000: β”” Completed
➀ YN0000: · Done with warnings in 3s
βœ“ dependencies installed
```

**Option B β€” with Yarn directly:**

```bash
yarn install
chmod +x index.js
```

**If you come from npm:**

```bash
rm -f package-lock.json
yarn install
```

### Step 3 β€” Verify the environment

```bash
make doctor
```

Should show:
```
Node: v20.x
Yarn: 4.18.0
Xcode: Xcode 15.x
xcrun: xcrun version 70
...
βœ“ doctor complete
```

If you see `xcodebuild: command not found`:
```bash
sudo xcode-select -s /Applications/Xcode.app
```

### Step 4 β€” Validate the MCP server

```bash
make lint
# ➜ node --check index.js
# βœ“ lint ok

make test
# ➜ smoke test MCP...
# βœ“ tools/list: 52 tools
# βœ“ xcode_sync_strings OK
# βœ“ xcode_certificates_check OK
# βœ“ smoke test PASSED
```

Or manually:
```bash
python3 scripts/smoke_test.py
# or
node scripts/smoke_test.mjs
```

### Step 5 β€” Configure your AI client

Pick **one** (or all three β€” same `index.js` works everywhere):

| Client | Config file | Command |
|---|---|---|
| **OpenCode** | `~/.config/opencode/opencode.json` | `node /.../Xcode-MPC/index.js` |
| **Codex** | `~/.codex/config.toml` | `[mcp_servers.xcode] command="node"` |
| **Claude Code** | `claude mcp add xcode -- node ...` | CLI or `.mcp.json` |

Full step-by-step with copy-paste JSON/TOML:

- πŸ“˜ **[OpenCode β†’ docs/opencode.md](docs/opencode.md)**
- πŸ“— **[Codex β†’ docs/codex.md](docs/codex.md)**
- πŸ“™ **[Claude Code β†’ docs/claude-code.md](docs/claude-code.md)**

### Step 6 β€” Restart and test

Restart OpenCode / Codex / Claude Code and type:

```
list the xcode tools
```

You should see **52 tools** and in the log:

```
βœ… Xcode MCP Server started (stdio) β€” 52 tools registered
```

Done! Now you can say:

```
Build MyApp with xcode_build scheme MyApp destination "platform=iOS Simulator,name=iPhone 15"
```

---

## βœ… Verification

```bash
# 1. Syntax
make lint

# 2. Smoke MCP (no Xcode needed, just Node)
make test

# 3. Apple environment
make doctor
# Checks: node, yarn, xcodebuild, xcrun, simctl, swiftlint, security, osascript

# 4. Visual inspector (optional)
make inspect
# or
yarn inspect
# Open http://localhost:6274 β†’ tools/list β†’ tools/call
```

---

## πŸ”§ Usage with OpenCode / Codex / Claude Code

### OpenCode

`~/.config/opencode/opencode.json`:

```json
{
  "mcpServers": {
    "xcode": {
      "command": "node",
      "args": ["/Users/YanxReal/Dev/Tools/Xcode-MPC/index.js"],
      "env": {}
    }
  }
}
```

### Codex (OpenAI)

`~/.codex/config.toml`:

```toml
[mcp_servers.xcode]
command = "node"
args = ["/Users/YanxReal/Dev/Tools/Xcode-MPC/index.js"]
```

### Claude Code (Anthropic)

```bash
claude mcp add xcode -- node /Users/YanxReal/Dev/Tools/Xcode-MPC/index.js
# verify
claude mcp list
# xcode: connected β€” 52 tools
```

Or per-project with `.mcp.json`:

```json
{
  "mcpServers": {
    "xcode": {
      "command": "node",
      "args": ["/Users/YanxReal/Dev/Tools/Xcode-MPC/index.js"]
    }
  }
}
```

> Prompt examples for each client β†’ [`docs/opencode.md`](docs/opencode.md) Β· [`docs/codex.md`](docs/codex.md) Β· [`docs/claude-code.md`](docs/claude-code.md) Β· Templates: [`.mcp.json.example`](.mcp.json.example) Β· [`.codex-config.toml.example`](.codex-config.toml.example)

---

## πŸ› οΈ Tools (52)

### 1. Build, Diagnostics & Clean

| Tool | `xcrun` / `xcodebuild` | Key args |
|---|---|---|
| `xcode_build` | `xcodebuild build` | `scheme*`, `workspace`, `project`, `destination`, `configuration` |
| `xcode_clean` | `xcodebuild clean` + `rm -rf DerivedData` | `purgeDerivedData:boolean` |
| `xcode_list_schemes` | `xcodebuild -list -json` | `workspace`, `project`, `directory` |
| `xcode_analyze` | `xcodebuild analyze` | `scheme`, `workspace`, `project` |
| `xcode_archive_export` | `archive` + `-exportArchive` | `scheme*`, `exportOptionsPlist*`, `archivePath`, `exportPath` |
| `swift_format_lint` | `swift-format` β†’ `swiftlint` | `path`, `mode: lint|format`, `tool: auto` |

### 2. Tests & Coverage

| Tool | `xcodebuild` | Key args |
|---|---|---|
| `xcode_run_tests` | `xcodebuild test` | `scheme*`, `destination*`, `onlyTesting`, `enableCodeCoverage` |
| `xcode_test_coverage` | `xcrun xccov view --report --json` | `xcresultPath` (auto-finds in DerivedData) |

### 3. Simulators `xcrun simctl` (9)

`simctl_list` (filter `booted`), `simctl_lifecycle` (`boot|shutdown|erase`), `simctl_install_launch`, `simctl_media_capture` (`screenshot|record`), `simctl_push_notification`, `simctl_location_mock`, `simctl_privacy_control`, `simctl_ui_appearance` (`light|dark`), `simctl_open_url`

### 4. Physical Devices `xcrun devicectl` (2)

`devicectl_list` (`--json`), `devicectl_logs` (`deviceUdid*`, `durationSeconds`)

### 5. Profiling `xcrun xctrace` (1)

`xctrace_profile` (`template: Time Profiler|Allocations|Leaks|System Trace`, `timeLimitSeconds`, `outputFilePath*`)

### 6. Versions & Security (2)

`agvtool_version_bump` (`bump_build|set_version|set_build`), `xcode_certificates_check` (`security find-identity`)

### 7. Xcode GUI Editor (2)

`xcode_get_active_file` (AppleScript `osascript`), `xcode_open_at_line` (`filePath*`, `line*`, `column` β€” `xed` β†’ `xcode://`)

### 8. Localization (1)

`xcode_sync_strings` (`.xcstrings` β†’ `missing` / `pendingTranslation` / `emptyValues`)

### 9. Assets `Assets.xcassets` + `actool` (6)

`asset_list_contents` (list `*.colorset/*.imageset`), `asset_manage_color` (`#RRGGBB` Light + Dark), `asset_manage_image` (scales/vector + `preserves-vector-representation`), `asset_read_info` (`Contents.json`), `asset_delete` (safe), `asset_validate_actool` (`xcrun actool --compile`)

### 10. AppIcon ALL Apple OS (1)

`asset_generate_appicon` (iOS, macOS, watchOS, tvOS, visionOS β€” 42 slots, `sips -z` if `baseImagePath`)

### 11. Package SPM / CocoaPods / Carthage (11)

`package_resolve`/`update`/`list`/`read_resolved`/`reset_cache`/`compute_checksum`, `spm_add/remove_dependency`, `cocoapods_manage`, `carthage_manage`, `cocoapods_to_spm_migrate` (Podfile→Package.swift)

### 12. Vision / Smart UI (4)

`simctl_get_screen_analysis` (sips β†’ `imagePath` + `resolution` for Vision LLM), `simctl_inspect_ui_tree` (accessibility tree with `center`), `simctl_tap_by_text` (`exact`/`partial` + center click), `simctl_fill_field` (`clearFirst` + `keystroke`)

### 13. Simctl Extra (5)

`simctl_set_appearance` (light/dark β€” `xcrun simctl ui appearance`), `simctl_set_dynamic_type` (Dynamic Type 12 categories), `simctl_manage_storekit` (`load`/`clear`/`buy`/`refund`), `simctl_simulate_event` (`incoming_call`/`network_offline`/`online`), `simctl_send_push` (APNs object β†’ `simctl push`)

> Full reference with JSON Schema + copy-paste examples β†’ [`docs/tools.md`](docs/tools.md)

---

## πŸ“– Make Commands

```bash
make help          # Show this pretty help (colors)
make install       # yarn install + chmod +x
make reinstall     # clean + install (from scratch)
make lint          # node --check index.js
make doctor        # Check Node/Yarn/Xcode/simctl/swiftlint/osascript
make test          # Smoke test MCP (52 tools + 2 calls)
make start         # yarn start (stdio)
make dev           # yarn dev (--watch)
make inspect       # MCP Inspector at http://localhost:6274
make clean         # Remove node_modules/.yarn/cache/build
make fmt           # prettier if available
make release VERSION=1.0.1  # bump + tag + push
```

Details β†’ [`docs/development.md`](docs/development.md)

---

## πŸ“š Documentation

| Doc | Audience | Covers |
|---|---|---|
| [`installation.md`](docs/installation.md) | Everyone | Yarn Berry, Corepack, `yarnPath` vendored, troubleshooting |
| [`tools.md`](docs/tools.md) | LLM / Dev | All 52 tools, JSON Schema, copy-paste JSON examples |
| [`opencode.md`](docs/opencode.md) | OpenCode | `opencode.json` global/local, prompts, `DEVELOPER_DIR` env |
| [`codex.md`](docs/codex.md) | Codex | `config.toml` (`mcp_servers.xcode`), `codex mcp list` |
| [`claude-code.md`](docs/claude-code.md) | Claude Code | `claude mcp add` / `.mcp.json`, permissions, trust |
| [`development.md`](docs/development.md) | Contributors | Structure, adding a tool, CI, release |
| [`architecture.md`](docs/architecture.md) | Curious | Why single-file, helpers, dispatcher, stdio flow |
| [`skills.md`](docs/skills.md) | Everyone | 5 skills (52 tools): `xcode-mpc`, `xcode-build`, `xcode-simulator-vision`, `xcode-assets`, `xcode-package` β€” `make install-skills` |

---

## 🧩 Skills (5 Skills, 52 Tools)

Modular packs that teach your AI agent when to use each tool. Easy installer via Make:

```bash
make install          # 1. MCP server (Yarn)
make install-skills   # 2. Skills β†’ ~/.agents/skills, ~/.claude/skills, ~/.codex/skills, ~/.config/opencode/skills
make test             # 3. Verify 52 tools
make list-skills      # list installed
make uninstall-skills # uninstall
```

Includes: `xcode-mpc` (52, main), `xcode-build` (8), `xcode-simulator-vision` (20), `xcode-assets` (7), `xcode-package` (11). See [`skills/README.md`](skills/README.md) and [`docs/skills.md`](docs/skills.md). Manual: `./scripts/install-skills.sh --dry-run`.

---

## πŸ§ͺ Manual Smoke Test

```bash
# Without Make:
python3 scripts/smoke_test.py
# STDERR: βœ… Xcode MCP Server started β€” 52 tools
# βœ“ tools/list: 52 tools
# βœ“ xcode_sync_strings OK
# βœ“ smoke test PASSED

# With Make:
make test
```

---

## πŸ—οΈ Architecture

```
index.js (2250 lines, 1 file)
β”œβ”€β”€ Shebang + Imports (MCP SDK, promisify(exec), fs, path, os)
β”œβ”€β”€ Helpers: shellEscape, expandTilde, runCommand (try/catch + 10MB buffer), formatResult
β”œβ”€β”€ TOOLS[52]: Strict JSON Schema (additionalProperties:false)
β”œβ”€β”€ Handlers[52]: async handle_* with validation + fallbacks (xedβ†’xcode://, swift-formatβ†’swiftlint)
β”œβ”€β”€ Dispatcher: HANDLERS map + ListTools/CallTool (try/catch β†’ isError:true)
└── Server: StdioServerTransport (stdin JSON-RPC, stdout JSON-RPC, stderr logs)
```

See [`docs/architecture.md`](docs/architecture.md) for single-file decision, `OpenCode β†’ stdin β†’ handler β†’ xcrun β†’ stdout` flow.

---

## 🀝 Contributing

```bash
# 1. Fork and branch
git checkout -b feat/my-tool

# 2. Develop: add to TOOLS + Handler + HANDLERS in index.js
make install && make lint && make test

# 3. Document in docs/tools.md + README.md

# 4. PR
```

Issues: [Bug Report](.github/ISSUE_TEMPLATE/bug_report.md) Β· [Feature Request](.github/ISSUE_TEMPLATE/feature_request.md) Β· [PR Template](.github/pull_request_template.md)

CI runs on `macos-14` and `ubuntu-latest` β€” your PR is tested automatically.

---

## πŸ“„ License

MIT Β© [YanxReal](https://github.com/YanxReal) β€” see [LICENSE](LICENSE).

---

## πŸ”— Links

- **Repo:** https://github.com/YanxReal/Xcode-MPC
- **MCP Spec:** https://modelcontextprotocol.io
- **SDK:** https://github.com/modelcontextprotocol/typescript-sdk
- **Yarn Berry:** https://yarnpkg.com/getting-started
- **Xcode:** https://developer.apple.com/xcode/

<div align="center">

**Made with ❀️ for the Apple ecosystem · Yarn 4 + Make + CI + Docs**

*If it helps you, leave a ⭐ on GitHub*

</div>