ipedro/inspector/inspector-mcp
Claude Code and agent skill by ipedro/inspector
- community
Checking that the SKILL.md file is still in the repository.
Use when an agent needs to inspect a live iOS app through the Inspector MCP bridge, register or troubleshoot InspectorMCPServer for a consumer Xcode project, or query, resolve, and snapshot the live UIKit hierarchy on Simulator. Especially useful when Inspector is a SwiftPM dependency of another app and the Inspector package path must be derived from Xcode DerivedData instead of assumed from the current repo.
Install
npx vskill@latest install ipedro/inspector/inspector-mcpSKILL.md
Inspector MCP
Overview
Use this skill to set up and use the Inspector MCP bridge against a running iOS Simulator app. Prefer this when the task is live UI inspection, not static source reading.
Workflow
1. Find the Inspector package path first
Do not assume Inspector lives in the current repo. In consumer apps it is often checked out under Xcode DerivedData.
Use the bundled helper first:
Or for workspaces:
If that fails:
- Check whether the app uses a local package reference instead of a DerivedData checkout.
- If you already know the Inspector repo path, use that as
--package-path. - Read consumer-app-setup.md for the fallback flow.
2. Derive the app launch inputs
You need:
- Xcode project or workspace path
- scheme
- bundle identifier
Bundle identifier pattern:
Use -workspace instead of -project when appropriate.
3. Confirm the app enables the bridge
The app must opt in before Inspector.start().
Minimum pattern:
If the app does not enable the bridge, MCP setup is blocked. For full consumer-side wiring, use the sibling inspector-mcp-consumer skill.
4. Register the MCP server in the client
Codex:
Claude Code:
If you are inside the Inspector repo itself, you can also point the client at:
<Inspector repo>/Examples/MCP/run-inspector-mcp.sh- or use the example config at
<Inspector repo>/Examples/MCP/codex-inspector-mcp.json(replace thecwdplaceholder).
5. Use the tools effectively
Tool order matters:
queryresolve/refresh_handlesubtree/list_actions/list_propertiessnapshotcapture_state/diff_states/save_scenario/diff_scenariowhen debugging semantic state drift
Start narrow. Prefer:
accessibilityIdentifierEqualsclassNameContainsdisplayNameContainselementNameContainsnodeKind
Good first query:
Avoid broad snapshots first. First get a stable handle with query, confirm the node with resolve, then call snapshot.
For longer exploration sessions, save the node's semanticReference from query/resolve results. If a handle goes stale, prefer:
with refresh_handle.
Important semantics:
- refresh is best-effort rebinding for exploration
- mutation still requires a currently valid live handle
- if rebinding is ambiguous or the logical node is gone, the call fails instead of guessing
For depth-limited app-owned tree inspection, use:
with subtree.
For interactive sessions, chain query → inspect to open the Inspector UI focused on a view:
Response: {"handle":"...", "presented": true}. presented: true means the Inspector UI dispatch was accepted — the modal animates in asynchronously. Consecutive inspect calls stack modals; Inspector's native back affordance dismisses them.
For the first write-side app interaction primitive, use query → tap on exact-handle button-like controls:
Response: {"handle":"...", "dispatched": true}. dispatched: true means Inspector synchronously fired one supported control action for that exact-handle UIControl. This is semantic activation, not synthetic touch injection:
- no hit-test simulation
- no gesture-recognizer dispatch for plain
UIViews - no ancestor promotion from child handle to parent button
MVP limitations:
- succeeds only for exact-handle, visible, enabled
UIControls wired for.primaryActionTriggeredor.touchUpInside - fails for gesture-backed non-controls, sliders/switches/date pickers, hidden/disabled/detached controls, and stale handles
- after any successful mutation, prefer a fresh
querybefore the next action because the UI may have changed and invalidated handles
For semantic UI operations beyond tap, use query → list_actions → perform_action:
list_actions returns opaque actionRef values for currently available actions such as:
- Inspector panel opens (
inspect) - per-element highlight toggles (
showHighlight/hideHighlight)
Then call:
Response:
Because action refs are ephemeral, rediscover them after a successful action before chaining the next semantic operation.
For broader property-driven mutation, use query → list_properties → set_property:
list_properties returns editable descriptors plus opaque propertyRef values. set_property then applies exactly one typed value field:
boolValuenumberValuestringValueselectionIndex
Example:
MVP limitations:
- this reuses Inspector's existing property handlers without presenting Inspector UI
- supported kinds are scalar/editor-like properties only (
switch,stepper,textField,textView, selection lists/groups) - property refs are ephemeral and should be rediscovered after any successful mutation
- unsupported property kinds and malformed values fail fast server-side
For named semantic baselines, use:
with:
save_scenario→ capture the current live hierarchy under a stable namelist_scenarios→ enumerate saved baselinesdiff_scenario→ compare the current hierarchy against that named baselinedelete_scenario→ remove obsolete baselines
capture_state / diff_states are still better for short-lived ad-hoc before/after comparisons inside one session. save_scenario is for longer-lived named references such as “clean screen”, “keyboard shown”, or “quicktype visible”.
5a. Controlling view-hierarchy layers (v2.2)
Call list_layers to see which built-in highlight layers are populated on the current screen, along with their active state:
Response (success envelope):
Flip a layer on or off by name — toggle_layer returns the intended post-toggle state immediately (install/remove is async on the UI thread):
Response: {"name":"Wireframes","active":true}. If the name does not match any populated layer, the response is an internalFailure envelope whose details.message names the offending input — call list_layers first to copy the exact name.
6. Reading snapshot results (v2)
Snapshot request:
Response:
After receiving the response, read the PNG with your file-reading tool (Claude Code: Read pngPath). Do not base64-decode — the bytes live on disk, not inline.
7. Handle stale handles correctly
There is no host-side auto-recovery.
If you get staleHandle:
- issue a fresh
query - take the new handle
- re-run
resolveorsnapshot
Do not retry the stale handle repeatedly.
8. Respect runtime constraints
Current constraints:
- exactly one booted simulator
- fixed localhost endpoint
127.0.0.1:49321 - single app on that port at a time
- launcher rejects attach if the process on the port does not match the requested bundle id
- v1: read-only (query, resolve, snapshot only)
- v2.1:
inspectadds write-side dispatch (presents Inspector UI); all other tools remain non-mutating - v2.2+:
list_layers(read-only) andtoggle_layer(write-side) add layer-highlight control - v2.3+:
tapadds exact-handle semantic activation for button-likeUIControls - v2.4+:
list_properties+set_propertyadd typed property mutation by reusing Inspector property handlers - v2.5+:
list_actions+perform_actionadd generic semantic action discovery/invocation over Inspector's existing action model - v2.6+:
save_scenario/list_scenarios/delete_scenario/diff_scenarioadd named semantic baselines on top of state capture - v2.7+:
refresh_handle/subtreeadd stable-enough exploration across time and bulk subtree inspection for app-owned UI
If startup says the endpoint is occupied by the wrong app:
- shut down the simulator or other app
- relaunch with the intended target
Verification
If you are working in the Inspector repo, prefer:
For direct package verification of the iOS target:
For the host executable:
References
Read these only when needed:
- consumer-app-setup.md for deriving the package path from DerivedData and wiring Codex/Claude
- inspection-patterns.md for effective query/resolve/snapshot usage and stale-handle recovery
- troubleshooting.md when
/mcpreports "Failed to reconnect" with the bridge actually up, whenRead pngPathreturns stale/empty files, or whensnapshotfails withcaptureFailed
Breaking changes
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingPlugins/inspector-mcp/skills/inspector-mcp/SKILL.md
Popularity
- Repository stars
- 171
- Repository forks
- 14
- 7-day trend score
- 0
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/ipedro/inspector/inspector-mcp)