@mgcrea/mcp-ios-simulator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +218 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +47 -0
- package/dist/cli.js.map +1 -0
- package/dist/config-C1TH-p-c.js +1553 -0
- package/dist/config-C1TH-p-c.js.map +1 -0
- package/dist/index.d.ts +475 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/package.json +81 -0
- package/scripts/wda.sh +145 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Olivier Louvignes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# @mgcrea/mcp-ios-simulator
|
|
2
|
+
|
|
3
|
+
Model Context Protocol server for driving an **iOS Simulator** from a model:
|
|
4
|
+
screenshot the screen, read its accessibility tree, tap, swipe, type, manage the
|
|
5
|
+
app under test — and stage the device itself, which is the part no physical
|
|
6
|
+
device can do.
|
|
7
|
+
|
|
8
|
+
No Apple Developer team. No code signing. No device trust. No tunnel. Nothing to
|
|
9
|
+
unlock. And **screenshots work with nothing installed at all**.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **See the screen, with zero setup.** `simctl` captures it directly, scaled to
|
|
14
|
+
exactly the device's point size, so a position read off the image is a tap
|
|
15
|
+
coordinate with no conversion. No WebDriverAgent needed for this.
|
|
16
|
+
- **Read the screen.** A flattened, pruned accessibility tree — type, label,
|
|
17
|
+
identifier and the precomputed tap point per element — instead of the tens of
|
|
18
|
+
KB of nested JSON WebDriverAgent actually returns.
|
|
19
|
+
- **Drive the screen.** Tap by coordinate or by accessibility label, swipe, type,
|
|
20
|
+
press Home. Every action returns the resulting screen by default, so a
|
|
21
|
+
mis-aimed tap is visible on the call that made it.
|
|
22
|
+
- **Stage the device.** Dark mode, Dynamic Type size, increased contrast, a
|
|
23
|
+
frozen 9:41 status bar, a simulated location, and app permissions granted or
|
|
24
|
+
denied without a prompt anyone has to tap. **None of this is possible on real
|
|
25
|
+
hardware.**
|
|
26
|
+
- **Push without APNs.** Deliver a real remote notification with no certificate
|
|
27
|
+
and no server.
|
|
28
|
+
- **Manage the app.** Install a build, launch it with fixture arguments,
|
|
29
|
+
terminate it, open a deep link. An app's data container is an ordinary path on
|
|
30
|
+
this Mac, so its database or logs are read directly — there is nothing to copy
|
|
31
|
+
off a device.
|
|
32
|
+
|
|
33
|
+
## Security
|
|
34
|
+
|
|
35
|
+
**Writes are on by default**, and that is deliberate. The rest of the fleet is
|
|
36
|
+
read-only until a flag is set because a mutating tool acts on someone's real
|
|
37
|
+
account or someone's real phone. A simulator is neither: it holds no person's
|
|
38
|
+
data, and `ios_simulator_erase` puts it back to factory in seconds.
|
|
39
|
+
|
|
40
|
+
What that still costs you, stated honestly:
|
|
41
|
+
|
|
42
|
+
- `install` and `launch` run code on your Mac. A simulated process is a host
|
|
43
|
+
process.
|
|
44
|
+
- The app's data container is a plain host path, readable by anything.
|
|
45
|
+
- `erase` is irreversible — it is the only tool behind an explicit `confirm`.
|
|
46
|
+
- `IOS_SIMULATOR_ALLOW_WRITES=0` restores the device server's posture in one
|
|
47
|
+
variable, and then the fourteen driving tools are **absent** from `tools/list`
|
|
48
|
+
rather than refused, because a refusal still lets a model try, retry and reason
|
|
49
|
+
about a way around it.
|
|
50
|
+
|
|
51
|
+
**Your credentials.** There are none. The server holds no tokens and talks to no
|
|
52
|
+
vendor API. Everything goes through `xcrun simctl` and a loopback HTTP server.
|
|
53
|
+
|
|
54
|
+
**Supply chain.** Three runtime dependencies: `@modelcontextprotocol/server`,
|
|
55
|
+
`zod`, and [`@mgcrea/mcp-ios-core`](../mcp-ios-core) — our own, and itself
|
|
56
|
+
dependent on only the first two. Scaling images uses `sips` and reading property
|
|
57
|
+
lists uses `plutil`, both of which ship with macOS, specifically so neither an
|
|
58
|
+
image library nor a plist parser has to be installed.
|
|
59
|
+
|
|
60
|
+
## How it reaches the simulator
|
|
61
|
+
|
|
62
|
+
| Lane | Carries | Needs |
|
|
63
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
64
|
+
| `xcrun simctl` | simulators, apps, install, launch, deep links, **the screenshot**, appearance, status bar, location, permissions, push, boot/shutdown/erase | Xcode. Nothing else. |
|
|
65
|
+
| WebDriverAgent over HTTP | the accessibility tree, tap, swipe, type, buttons | a runner started once with `scripts/wda.sh` |
|
|
66
|
+
|
|
67
|
+
The asymmetry with `mcp-ios-device` is worth stating plainly: there, _every_
|
|
68
|
+
pixel comes through WebDriverAgent, so nothing about the screen works until a
|
|
69
|
+
signed runner is installed and trusted on the phone. Here `simctl` captures the
|
|
70
|
+
screen itself, so **fourteen of the nineteen tools work with no runner at all**
|
|
71
|
+
— only `ios_simulator_ui_tree` and the five input tools need one, and building it
|
|
72
|
+
takes about two minutes with no Apple account.
|
|
73
|
+
|
|
74
|
+
`ios_simulator_diagnostics` reports both lanes separately, so "the simulator is
|
|
75
|
+
fine but the runner is not up" is a distinguishable answer rather than a generic
|
|
76
|
+
failure.
|
|
77
|
+
|
|
78
|
+
## Configure
|
|
79
|
+
|
|
80
|
+
| Variable | Default | What it does |
|
|
81
|
+
| ------------------------------ | --------------------------- | ----------------------------------------------------------------------------- |
|
|
82
|
+
| `IOS_SIMULATOR_ID` | the only booted simulator | UDID, name, or `booted`. Two booted and no value is an error that names them. |
|
|
83
|
+
| `IOS_SIMULATOR_ALLOW_WRITES` | **on** | `0` drops the fourteen driving tools from `tools/list`. |
|
|
84
|
+
| `IOS_SIMULATOR_LAUNCH_ARGS` | none | Launch arguments applied when `launch` passes none of its own. |
|
|
85
|
+
| `IOS_SIMULATOR_WDA_PORT` | `8100` | Must match the runner's `USE_PORT`. One port per simulator. |
|
|
86
|
+
| `IOS_SIMULATOR_WDA_URL` | `http://127.0.0.1:<port>` | Explicit override; rarely needed. |
|
|
87
|
+
| `IOS_SIMULATOR_MAX_TREE_BYTES` | `24000` | Byte cap on a `ui_tree` payload. |
|
|
88
|
+
| `IOS_SIMULATOR_TIMEOUT_MS` | `120000` | Budget for one `simctl` call; a boot is slow. |
|
|
89
|
+
| `IOS_SIMULATOR_WDA_TIMEOUT_MS` | `30000` | Budget for one WebDriverAgent call. |
|
|
90
|
+
| `IOS_SIMULATOR_OUTPUT_DIR` | `$TMPDIR/mcp-ios-simulator` | Screenshots, launch logs, the runner log. |
|
|
91
|
+
| `IOS_SIMULATOR_DEBUG` | off | Log every `simctl` and WebDriverAgent call to stderr. |
|
|
92
|
+
|
|
93
|
+
The same keys in camelCase can go in `~/.config/ios-simulator-mcp/config.json`
|
|
94
|
+
(`IOS_SIMULATOR_CONFIG` to move it). The environment wins **per field**, so a
|
|
95
|
+
one-off `IOS_SIMULATOR_ALLOW_WRITES=0` beats a file that says `true`. Unknown keys
|
|
96
|
+
in the file are an error rather than silently ignored — a typo that looks like
|
|
97
|
+
"that setting had no effect" is the worst way to learn where your configuration
|
|
98
|
+
came from.
|
|
99
|
+
|
|
100
|
+
See [.env.example](.env.example) for the annotated version.
|
|
101
|
+
|
|
102
|
+
## Quick start
|
|
103
|
+
|
|
104
|
+
Requires macOS with Xcode and a booted simulator.
|
|
105
|
+
|
|
106
|
+
### A. Everything except the tree and the taps, with no setup
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
npx -y @mgcrea/mcp-ios-simulator
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
`list`, `list_apps`, `screenshot`, `diagnostics`, `power`, `install`, `launch`,
|
|
113
|
+
`open_url`, `set_environment`, `push` and `erase` all work immediately.
|
|
114
|
+
|
|
115
|
+
### B. The input lane
|
|
116
|
+
|
|
117
|
+
`ui_tree`, `tap`, `tap_element`, `swipe`, `type` and `press_button` need a
|
|
118
|
+
WebDriverAgent runner. Build and start it — no team id, no signing, no prompt:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
scripts/wda.sh setup # ~2 minutes
|
|
122
|
+
scripts/wda.sh run # leave this running
|
|
123
|
+
scripts/wda.sh status # is it answering?
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Installed from npm, the same script is the `ios-simulator-wda` binary:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
npx -p @mgcrea/mcp-ios-simulator ios-simulator-wda setup
|
|
130
|
+
npx -p @mgcrea/mcp-ios-simulator ios-simulator-wda run
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### C. Wired into a client
|
|
134
|
+
|
|
135
|
+
See [.mcp.json.example](.mcp.json.example).
|
|
136
|
+
|
|
137
|
+
## Tools
|
|
138
|
+
|
|
139
|
+
Nineteen. Five are read-only; the other fourteen disappear with
|
|
140
|
+
`IOS_SIMULATOR_ALLOW_WRITES=0`.
|
|
141
|
+
|
|
142
|
+
| Tool | Writes? | What it does |
|
|
143
|
+
| ------------------------------- | ------------- | ------------------------------------------------------------------------ |
|
|
144
|
+
| `ios_simulator_list` | | Every simulator, with state and whether its runtime is installed |
|
|
145
|
+
| `ios_simulator_diagnostics` | | Both lanes, the resolved target, the geometry, and who owns the WDA port |
|
|
146
|
+
| `ios_simulator_list_apps` | | Installed apps, with bundle id and host-path data container |
|
|
147
|
+
| `ios_simulator_screenshot` | | The screen, in point space — **no runner needed** |
|
|
148
|
+
| `ios_simulator_ui_tree` | | Addressable elements with precomputed tap points |
|
|
149
|
+
| `ios_simulator_tap` | ✓ | Tap a point |
|
|
150
|
+
| `ios_simulator_tap_element` | ✓ | Tap by identifier, label or predicate |
|
|
151
|
+
| `ios_simulator_swipe` | ✓ | Drag between two points |
|
|
152
|
+
| `ios_simulator_type` | ✓ | Type into the focused field, or a named one |
|
|
153
|
+
| `ios_simulator_press_button` | ✓ | Home |
|
|
154
|
+
| `ios_simulator_power` | ✓ | Boot or shut down; never implicit |
|
|
155
|
+
| `ios_simulator_erase` | ✓ **confirm** | Wipe to factory — the only irreversible tool |
|
|
156
|
+
| `ios_simulator_install` | ✓ | Install a simulator `.app` |
|
|
157
|
+
| `ios_simulator_launch` | ✓ | Launch, with fixture arguments and captured output |
|
|
158
|
+
| `ios_simulator_terminate` | ✓ | Kill a running app |
|
|
159
|
+
| `ios_simulator_open_url` | ✓ | Deep links and universal links |
|
|
160
|
+
| `ios_simulator_set_environment` | ✓ | Appearance, Dynamic Type, contrast, status bar, location, permissions |
|
|
161
|
+
| `ios_simulator_push` | ✓ | A remote notification, with no APNs certificate |
|
|
162
|
+
| `ios_simulator_restart_wda` | ✓ | Start or restart the runner, detached |
|
|
163
|
+
|
|
164
|
+
Deliberately absent: `create`, `clone`, `delete`, `rename`, `upgrade` and `pair`
|
|
165
|
+
(fleet management, not driving, and `delete all` is a footgun with no upside);
|
|
166
|
+
`get_app_container` (`list_apps` already returns the path); `uninstall`
|
|
167
|
+
(`install` overwrites, and `erase` covers first-run properly); `addmedia`,
|
|
168
|
+
`keychain`, `pbcopy`, `spawn`, `diagnose` and `recordVideo` (real capabilities
|
|
169
|
+
that an agent would use approximately never, and every tool costs listing bytes
|
|
170
|
+
on every connect).
|
|
171
|
+
|
|
172
|
+
## Traps worth knowing
|
|
173
|
+
|
|
174
|
+
All measured on Xcode 26.6 (17F113).
|
|
175
|
+
|
|
176
|
+
- **`simctl io … screenshot -` does not write to stdout.** The help text says it
|
|
177
|
+
does. It creates a file literally named `-` in the current working directory
|
|
178
|
+
and prints `Wrote screenshot to: …` to stderr, exit 0. This server always
|
|
179
|
+
passes a real path.
|
|
180
|
+
- **`simctl io` on a simulator whose runtime is missing aborts** — SIGABRT, exit
|
|
181
|
+
134, an uncaught `NSInternalInconsistencyException` and a thirty-line stack
|
|
182
|
+
trace, not an error message. Availability is checked in the resolver, before
|
|
183
|
+
the call. On a typical machine a large fraction of simulators are in this
|
|
184
|
+
state.
|
|
185
|
+
- **`erase`, `delete` and `shutdown` all accept the literal `all`.** A target of
|
|
186
|
+
`"all"` reaching `simctl erase` wipes every simulator on the machine. Refused
|
|
187
|
+
in the resolver and again in the adapter.
|
|
188
|
+
- **`booted` is a coin flip.** simctl's own help: "If multiple devices are booted
|
|
189
|
+
… simctl will choose one of them." Resolved to a concrete UDID here first.
|
|
190
|
+
- **WebDriverAgent scans ports 8100-8199 when `USE_PORT` is unset.** With two
|
|
191
|
+
booted simulators, the second runner comes up healthy on 8101 and a server
|
|
192
|
+
pointed at 8100 drives the _first_ one while every call reports success.
|
|
193
|
+
`scripts/wda.sh` always pins `USE_PORT`, and `diagnostics` reports the port's
|
|
194
|
+
real owner via `SIMULATOR_UDID` from `ps -Eww`.
|
|
195
|
+
- **`listapps` returns an old-style NeXTSTEP plist, not JSON.** `--json` is a flag
|
|
196
|
+
on `list` and nothing else.
|
|
197
|
+
- **A status bar override survives a reboot.** Clear it or it quietly pollutes
|
|
198
|
+
every later screenshot.
|
|
199
|
+
- **`simctl launch` environment variables need a `SIMCTL_CHILD_` prefix** on the
|
|
200
|
+
calling process, not a flag.
|
|
201
|
+
- **`simctl install` wants a `.app` bundle directory** built for the simulator —
|
|
202
|
+
an `.ipa` or a device build fails with "No such file or directory", which reads
|
|
203
|
+
like a path typo.
|
|
204
|
+
- **`simctl boot` gives you no window.** It runs headless, which is what an agent
|
|
205
|
+
wants and confusing the first time; `power` opens Simulator.app by default.
|
|
206
|
+
- **Two runtimes can share one identifier**, so the key of `list devices` is not
|
|
207
|
+
a primary key.
|
|
208
|
+
|
|
209
|
+
## Develop
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
pnpm install
|
|
213
|
+
pnpm lint && pnpm format:check && pnpm typecheck && pnpm test && pnpm build
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## License
|
|
217
|
+
|
|
218
|
+
MIT — see [LICENSE](./LICENSE).
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { a as createServer, j as BUILD_INFO, n as loadConfig, t as defaultConfigPath } from "./config-C1TH-p-c.js";
|
|
3
|
+
import { ZodError } from "zod";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
5
|
+
//#region src/cli.ts
|
|
6
|
+
const stderrLogger = {
|
|
7
|
+
debug: (...args) => {
|
|
8
|
+
if (process.env.IOS_SIMULATOR_DEBUG) console.error("[ios-simulator-mcp]", ...args);
|
|
9
|
+
},
|
|
10
|
+
warn: (...args) => console.error("[ios-simulator-mcp]", ...args),
|
|
11
|
+
error: (...args) => console.error("[ios-simulator-mcp]", ...args)
|
|
12
|
+
};
|
|
13
|
+
/** Show a config mistake as its field messages, not 40 frames of zod internals. */
|
|
14
|
+
const describeFatal = (err) => {
|
|
15
|
+
if (err instanceof ZodError) return err.issues.map((issue) => {
|
|
16
|
+
const path = issue.path.join(".");
|
|
17
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
18
|
+
}).join("\n");
|
|
19
|
+
return err instanceof Error ? err.message : String(err);
|
|
20
|
+
};
|
|
21
|
+
const main = async () => {
|
|
22
|
+
stderrLogger.warn(`${BUILD_INFO.name}@${BUILD_INFO.version} (git ${BUILD_INFO.gitCommit} ${BUILD_INFO.gitCommitDate}, node ${process.version})`);
|
|
23
|
+
const configPath = defaultConfigPath();
|
|
24
|
+
const config = loadConfig(process.env, configPath);
|
|
25
|
+
const { server } = createServer({
|
|
26
|
+
config,
|
|
27
|
+
logger: stderrLogger
|
|
28
|
+
});
|
|
29
|
+
const transport = new StdioServerTransport();
|
|
30
|
+
await server.connect(transport);
|
|
31
|
+
stderrLogger.warn(`ios-simulator-mcp connected (simulator=${config.simulatorId ?? "auto"}, wda=${config.wdaUrl ?? `127.0.0.1:${config.wdaPort}`}, writes=${config.allowWrites ? "enabled" : "DISABLED"})`);
|
|
32
|
+
if (config.allowWrites && config.launchArgs.length > 0) stderrLogger.warn(`default launch arguments: ${config.launchArgs.join(" ")}`);
|
|
33
|
+
const shutdown = (signal) => {
|
|
34
|
+
stderrLogger.warn(`received ${signal}, shutting down`);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
};
|
|
37
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
38
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
39
|
+
};
|
|
40
|
+
main().catch((err) => {
|
|
41
|
+
console.error(`[ios-simulator-mcp] fatal: ${describeFatal(err)}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
//#endregion
|
|
45
|
+
export {};
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","names":[],"sources":["../src/cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { StdioServerTransport } from \"@modelcontextprotocol/server/stdio\";\nimport { ZodError } from \"zod\";\n\nimport { BUILD_INFO } from \"#/build-info\";\nimport { defaultConfigPath, loadConfig } from \"#/config\";\nimport { createServer } from \"#/server\";\n\n// Everything goes to stderr: stdout is the MCP protocol channel, and a stray\n// log line there corrupts the stream.\nconst stderrLogger = {\n debug: (...args: unknown[]) => {\n if (process.env.IOS_SIMULATOR_DEBUG) console.error(\"[ios-simulator-mcp]\", ...args);\n },\n warn: (...args: unknown[]) => console.error(\"[ios-simulator-mcp]\", ...args),\n error: (...args: unknown[]) => console.error(\"[ios-simulator-mcp]\", ...args),\n};\n\n/** Show a config mistake as its field messages, not 40 frames of zod internals. */\nconst describeFatal = (err: unknown): string => {\n if (err instanceof ZodError) {\n return err.issues\n .map((issue) => {\n const path = issue.path.join(\".\");\n return path ? `${path}: ${issue.message}` : issue.message;\n })\n .join(\"\\n\");\n }\n return err instanceof Error ? err.message : String(err);\n};\n\nconst main = async (): Promise<void> => {\n stderrLogger.warn(\n `${BUILD_INFO.name}@${BUILD_INFO.version} (git ${BUILD_INFO.gitCommit} ${BUILD_INFO.gitCommitDate}, node ${process.version})`,\n );\n const configPath = defaultConfigPath();\n const config = loadConfig(process.env, configPath);\n const { server } = createServer({ config, logger: stderrLogger });\n const transport = new StdioServerTransport();\n await server.connect(transport);\n // The banner is not decoration. It prints before anything can fail, and it is\n // the only place the resolved capability state is visible. Here the *unusual*\n // state is writes being off — they default on, because a simulator is\n // disposable — so `writes=DISABLED` is the one worth shouting: it is what\n // explains a tool being missing from tools/list.\n stderrLogger.warn(\n `ios-simulator-mcp connected (simulator=${config.simulatorId ?? \"auto\"}, ` +\n `wda=${config.wdaUrl ?? `127.0.0.1:${config.wdaPort}`}, ` +\n `writes=${config.allowWrites ? \"enabled\" : \"DISABLED\"})`,\n );\n if (config.allowWrites && config.launchArgs.length > 0) {\n stderrLogger.warn(`default launch arguments: ${config.launchArgs.join(\" \")}`);\n }\n\n const shutdown = (signal: string): void => {\n stderrLogger.warn(`received ${signal}, shutting down`);\n process.exit(0);\n };\n process.on(\"SIGINT\", () => shutdown(\"SIGINT\"));\n process.on(\"SIGTERM\", () => shutdown(\"SIGTERM\"));\n};\n\nmain().catch((err: unknown) => {\n console.error(`[ios-simulator-mcp] fatal: ${describeFatal(err)}`);\n process.exit(1);\n});\n"],"mappings":";;;;;AAUA,MAAM,eAAe;CACnB,QAAQ,GAAG,SAAoB;EAC7B,IAAI,QAAQ,IAAI,qBAAqB,QAAQ,MAAM,uBAAuB,GAAG,IAAI;CACnF;CACA,OAAO,GAAG,SAAoB,QAAQ,MAAM,uBAAuB,GAAG,IAAI;CAC1E,QAAQ,GAAG,SAAoB,QAAQ,MAAM,uBAAuB,GAAG,IAAI;AAC7E;;AAGA,MAAM,iBAAiB,QAAyB;CAC9C,IAAI,eAAe,UACjB,OAAO,IAAI,OACR,KAAK,UAAU;EACd,MAAM,OAAO,MAAM,KAAK,KAAK,GAAG;EAChC,OAAO,OAAO,GAAG,KAAK,IAAI,MAAM,YAAY,MAAM;CACpD,CAAC,CAAC,CACD,KAAK,IAAI;CAEd,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AACxD;AAEA,MAAM,OAAO,YAA2B;CACtC,aAAa,KACX,GAAG,WAAW,KAAK,GAAG,WAAW,QAAQ,QAAQ,WAAW,UAAU,GAAG,WAAW,cAAc,SAAS,QAAQ,QAAQ,EAC7H;CACA,MAAM,aAAa,kBAAkB;CACrC,MAAM,SAAS,WAAW,QAAQ,KAAK,UAAU;CACjD,MAAM,EAAE,WAAW,aAAa;EAAE;EAAQ,QAAQ;CAAa,CAAC;CAChE,MAAM,YAAY,IAAI,qBAAqB;CAC3C,MAAM,OAAO,QAAQ,SAAS;CAM9B,aAAa,KACX,0CAA0C,OAAO,eAAe,OAAO,QAC9D,OAAO,UAAU,aAAa,OAAO,UAAU,WAC5C,OAAO,cAAc,YAAY,WAAW,EAC1D;CACA,IAAI,OAAO,eAAe,OAAO,WAAW,SAAS,GACnD,aAAa,KAAK,6BAA6B,OAAO,WAAW,KAAK,GAAG,GAAG;CAG9E,MAAM,YAAY,WAAyB;EACzC,aAAa,KAAK,YAAY,OAAO,gBAAgB;EACrD,QAAQ,KAAK,CAAC;CAChB;CACA,QAAQ,GAAG,gBAAgB,SAAS,QAAQ,CAAC;CAC7C,QAAQ,GAAG,iBAAiB,SAAS,SAAS,CAAC;AACjD;AAEA,KAAK,CAAC,CAAC,OAAO,QAAiB;CAC7B,QAAQ,MAAM,8BAA8B,cAAc,GAAG,GAAG;CAChE,QAAQ,KAAK,CAAC;AAChB,CAAC"}
|