Skip to main content
Glama
conorluddy

XC-MCP: XCode CLI wrapper

by conorluddy

Inspect App Sandbox Container

simctl-container
Read-onlyIdempotent

Inspect an iOS simulator app's sandbox by bundle ID: list files, read plist or text contents, view UserDefaults, and locate Core Data stores.

Instructions

simctl-container

App sandbox inspector — list files, read file contents, inspect UserDefaults, and locate Core Data stores inside an iOS simulator app's data container.

What it does

Resolves the app data container via xcrun simctl get_app_container, then performs semantic file operations within that sandbox without needing to know the raw CoreSimulator path.

Parameters

  • bundleId (string, required): App bundle identifier (e.g. com.example.MyApp)

  • mode (string, required): Operation — ls | cat | userdefaults | coredata-path

  • udid (string, optional): Simulator UDID. Defaults to booted device.

  • path (string, optional): Sub-path for ls (subdir) or file path for cat

  • depth (number, optional): Recursion depth for ls (default: 3)

Modes

ls

Lists files in the container (or a sub-path) up to depth levels deep. Returns entries with path, kind (file/dir/symlink), and sizeBytes. Path traversal outside the container root is rejected.

cat

Reads a file at path (relative to container root).

  • Attempts plist decode first (binary and XML plists via plutil)

  • Falls back to UTF-8 text, then binary detection

  • Returns contentType: plist | text | binary

  • Files > 8 KB (text/plist) are stored in responseCache; returns cacheId + resourceLink

userdefaults

Reads Library/Preferences/<bundleId>.plist and returns decoded key/value pairs. Handles both binary and XML plist formats via plutil.

coredata-path

Searches Library/Application Support/ and Documents/ recursively for .sqlite, .sqlite-wal, and .sqlite-shm files. Returns { path, absolutePath, sizeBytes, type } for each store found.

Returns

JSON response with { mode, bundleId, success, ... } plus mode-specific fields and guidance.

Examples

List container root

await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'ls' })

List a sub-directory

await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'ls', path: 'Library/Caches' })

Read a JSON config file

await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'cat', path: 'Documents/config.json' })

Inspect UserDefaults

await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'userdefaults' })

Find Core Data stores

await simctlContainerTool({ bundleId: 'com.example.MyApp', mode: 'coredata-path' })

Error Handling

  • bundleId required: Rejects empty or missing bundleId

  • mode required: Rejects unknown or missing mode

  • path required for cat: Rejects cat without a path

  • container not found: InternalError with install suggestion

  • path escapes container: InvalidRequest with clear message

  • plist unreadable: InternalError with path context

Notes

  • Keychain is explicitly out of scope

  • Binary plist decoding uses plutil -convert json (macOS built-in)

  • Large text/plist files (> 8 KB) are cached; retrieve via cacheId using the cache tool

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
modeYes
pathNo
udidNo
depthNo
bundleIdYes

Schema Changelog

Changes observed during successful MCP inspections.

  1. Addedv4.1.0

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations (readOnlyHint=true, idempotentHint=true, destructiveHint=false) already establish the safety profile, and the description adds substantial context beyond them: the >8 KB files stored in responseCache (a meaningful side-effect of a read operation), the plist→text→binary decode fallback with contentType, path-traversal rejection, per-mode return shapes, and specific error conventions (InternalError with install suggestion). It also discloses the macOS plutil dependency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The document is long but proportionate to a 4-mode tool, and it is rigorously structured: one-line summary up front, followed by What-it-does, Parameters, per-mode behavior, Returns, code examples, Error Handling, and Notes. Headers, bullets, and TypeScript call examples make it highly scannable for an agent. Some redundancy exists between the parameter list and mode sections, but for LLM recall, prose-plus-example repetition earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With zero schema descriptions and no output schema, the description must be self-sufficient — and it is. It covers expected inputs per mode, mode-specific return fields, error cases, edge cases (large files, unreadable plists, path traversal), and operational caveats (macOS-only plutil, Keychain exclusion). The only mild gap is the generic top-level return shape ('{ mode, bundleId, success, ... }'), but each mode's specific fields are already described.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description carries the full burden — and it delivers. Each of the 5 parameters gets semantic meaning: bundleId format example, mode enum explained across four detailed sections, udid default ('Defaults to booted device'), path semantics per mode (subdir for ls vs file for cat), and depth default (3). This fully compensates for the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening line — 'list files, read file contents, inspect UserDefaults, and locate Core Data stores inside an iOS simulator app's data container' — states a specific verb+resource scope that clearly differentiates it from siblings like simctl-get-app-container (path resolution only) and simctl-list (device listing). The four modes are each named and their distinct purposes enumerated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides rich context: it states the tool wraps get_app_container 'without needing to know the raw CoreSimulator path' (implying the alternative raw-path workflow), explicitly scopes out Keychain, and routes large-file retrieval to 'the cache tool' via cacheId. However, it never explicitly names siblings as alternatives (e.g., 'if you only need the container path, use simctl-get-app-container'), so the when-vs-alternative guidance is implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.