Skip to content

Harden XcodeBazelMCP: validation, sim/device tools, and MCP PATH fixes#13

Merged
maatheusgois-dd merged 6 commits into
mainfrom
maatheusgois-dd/xcodebazelmcp-hardening
Jul 17, 2026
Merged

Harden XcodeBazelMCP: validation, sim/device tools, and MCP PATH fixes#13
maatheusgois-dd merged 6 commits into
mainfrom
maatheusgois-dd/xcodebazelmcp-hardening

Conversation

@maatheusgois-dd

@maatheusgois-dd maatheusgois-dd commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Hardens MCP tooling with input validation, richer diagnostics, and expanded simulator/device workflows.
  • Fixes spawn bazel ENOENT when Cursor launches MCP with a minimal PATH by resolving Bazel via Homebrew/common bin dirs.
  • Auto-discovers Bazel workspace roots by walking up from cwd/env when the configured workspace is invalid.
  • Augments spawned command PATH and surfaces resolved paths in bazel_ios_health.
  • New: When BITRISE_BUILD_CACHE_AUTH_TOKEN is unset, automatically strips --config=bitrise / --config=remote_linux and runs locally instead of failing Bitrise credential auth. Applies to both MCP and CLI build/test paths.

Scope

  • MCP server/tools
  • CLI commands or parsers
  • Bazel build/test/discovery
  • Simulator workflows
  • Physical device workflows
  • UI automation, screenshots, video, logs, or deep links
  • LLDB debugging
  • macOS, tvOS, watchOS, or visionOS workflows
  • Swift Package Manager
  • Daemon, session defaults, config, doctor, or setup
  • Project scaffolding
  • Docs, examples, or agent skills
  • CI, release, packaging, or dependencies

Validation

  • npm run lint
  • npm run typecheck
  • npm test (628 passed)
  • npm run build
  • npx vitest --run --coverage (59.52% stmts / 74.62% branches)
  • Manual MCP validation with Cursor or another MCP client
  • Manual CLI validation with xcodebazelmcp ...
  • Bazel workspace validation against a real Apple target
  • Simulator validation
  • Physical device validation

Compatibility

  • Adds, removes, or renames MCP tools
  • Changes CLI flags, command output, exit codes, or streaming behavior
  • Changes config files, environment variables, defaults, or profiles
  • Changes generated project scaffolding
  • Changes package contents, dependencies, Node support, or release behavior
  • Requires updates to docs, README, manifests, schemas, or skills
  • No compatibility impact

Notes For Reviewers

  • Verified with minimal PATH (env -i PATH=/usr/bin:/bin): xcodebazelmcp doctor resolves bazel to /opt/homebrew/bin/bazel and passes against example_projects/BazelApp (workspace + MODULE.bazel + bazel 7.6.0 ✅).
  • Cursor MCP config should set PATH and BAZEL_IOS_WORKSPACE (see updated .cursor/mcp.json example).
  • Bitrise fallback verified end-to-end via CLI: xcodebazelmcp build //modules/Models:ModelsLib --config bitrise with no token runs bazel build //modules/Models:ModelsLib (config stripped, build ✅). Negative control with BITRISE_BUILD_CACHE_AUTH_TOKEN set keeps --config=bitrise in the argv as expected.
  • Manual CLI validation: doctor (minimal PATH), tools, show-defaults, set-defaults, devices all succeed.
  • Physical device validation: xcodebazelmcp devices enumerates a connected iPhone 13 Pro (iOS 26.5.2, paired). xcodebazelmcp build //app:app --device correctly emits --ios_multi_cpus + --platforms for arm64 and reaches Bazel analysis; it fails only on the BazelApp example's missing provisioning_profile (sample-app limitation, not an MCP defect).
  • CLI scope note: no CLI parser/flag source was modified — the Bitrise strip lives in src/core/bazel.ts and is shared by both MCP and CLI build/test paths, so CLI behavior transitively benefits. No CLI flags, output format, or exit codes changed.
  • Set BITRISE_BUILD_CACHE_AUTH_TOKEN only when RBE offload is intentionally desired.

Made with Cursor

maatheusgois-dd and others added 2 commits June 28, 2026 16:15
… tools

A reliability/consistency pass across the MCP tools and CLI, plus new
simulator/device tools (tool count 120 -> 125). All changes verified
against a real Bazel iOS workspace.

Highlights:
- Fix combined stdout/stderr JSON parsing (simctl list, swift dump-package,
  idb accessibility snapshot)
- Host-arch-aware iOS simulator CPU (BAZEL_IOS_SIMULATOR_CPU); quote-aware
  BAZEL_IOS_STARTUP_ARGS; env-overridable discover scope
- LLDB: per-command output buffer (fixes >500KB deadlock), newline/quote
  injection guards, session cleanup on shutdown
- Streaming tools return structured content; Bazel exit-code annotations
- Scaffold: bundleId/minimumOs/rulesVersion validation, families &
  bazelVersion options, iOS Info.plist keys, absolute config path
- New tools: bazel_ios_uninstall_app, bazel_ios_device_uninstall_app,
  bazel_ios_device_list_apps, bazel_ios_add_media, bazel_ios_get_app_container
- Doctor reports idb/pymobiledevice3/maxOutput; README env-var section
- Runtime smoke script + CI smoke step; +45 tests (575 -> 619 passing)

Note: also snapshots in-progress xcode-native-mcp, command-log, and
diagnostics modules already present in the working tree.

Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve bare `bazel` via augmented PATH when Cursor spawns MCP with a
minimal environment, and walk up from cwd/env when the configured
workspace is not a Bazel root.

Generated-by: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
@maatheusgois-dd maatheusgois-dd self-assigned this Jul 16, 2026
Comment thread src/runtime/resolve-toolchain.ts Fixed
maatheusgois-dd and others added 4 commits July 17, 2026 00:51
When BITRISE_BUILD_CACHE_AUTH_TOKEN is unset, drop --config=bitrise and
--config=remote_linux so local Bazel builds/tests proceed instead of failing
credential helper auth.

Generated-by: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
Resolve conflicts keeping Bitrise auth stripping on top of main's
hardening (PR #12). Fix duplicate expandTilde/resolvePath in config.ts.

Generated-by: Cursor
Co-authored-by: Cursor <cursoragent@cursor.com>
Reframes the Bitrise token messaging so agents/users don't treat RBE as
the expected path: README, mcp-setup skill, and the stderr notice now
lead with "local execution is the default" and demote the token to an
opt-in for RBE offload. bazel_ios_health also surfaces the active
execution mode so it's visible in diagnostics.

Co-authored-by: oh-my-pi <https://omp.sh>
Caught by `npm run lint`; the module uses accessSync via isExecutable,
so the existsSync binding was dead. Keeps the PR's validation checklist
green.

Co-authored-by: oh-my-pi <https://omp.sh>
@maatheusgois-dd

Copy link
Copy Markdown
Contributor Author

Follow-up: messaging + validation gaps from the PR description

Reviewed the unchecked items in the Validation section of the PR description and closed the ones runnable locally.

Done in this push

  • Reframed the Bitrise messaging to "local execution is the default." The earlier wording ("Skipping … token is not set") read like a fallback/degraded path. README, the mcp-setup skill, and the stripBitriseAuthFlags stderr notice now lead with local-as-default and demote BITRISE_BUILD_CACHE_AUTH_TOKEN to an opt-in for RBE offload. bazel_ios_health now also surfaces the active execution mode so it's visible in diagnostics.
  • Fixed npm run lint. src/runtime/resolve-toolchain.ts had an unused existsSync import (the module uses accessSync via isExecutable). Removed; lint is now clean.

Validation now green locally

Check Before After
npm run lint ❌ (unused import)
npm run typecheck
npm test ✅ (628) ✅ (628)
npm run build
npx vitest --run --coverage ❌ (unchecked) ✅ 59.52% stmts / 74.62% branches

PR description checkboxes updated accordingly.

Still unchecked (require hardware / manual steps outside this session)

  • Manual CLI validation with xcodebazelmcp …
  • Simulator validation
  • Physical device validation

These need a booted simulator / connected device and are out of scope for a code+docs push. Happy to run them next if someone points me at a Bazel iOS target + simulator.

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.66667% with 32 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/runtime/resolve-toolchain.ts 63.26% 18 Missing ⚠️
src/tools/handlers/session.ts 11.11% 8 Missing ⚠️
src/runtime/config.ts 86.20% 4 Missing ⚠️
src/core/workspace.ts 96.00% 1 Missing ⚠️
src/utils/process.ts 66.66% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@maatheusgois-dd

Copy link
Copy Markdown
Contributor Author

Simulator validation done ✅

Ran the XcodeBazelMCP simulator workflow end-to-end against the BazelApp example project on a booted iPhone 17 (iOS 26.3) simulator.

bazel_ios_health (against ~/Projects/ios DoorDash repo)

  • Bazel resolved to /opt/homebrew/bin/bazel via the PATH-augmentation fix (validates the ENOENT fix from this PR).
  • New execution: line renders: local (default — no Bitrise token required) — confirms the session.ts change is live.
  • All checks passed (Xcode 26.3, simctl, devicectl, codesigning, 5 physical devices detected).

Simulator lifecycle — //app:app

Step Result
bazel_ios_build_and_run //app:app ✅ built (11.9s), installed, launched (PID 88212)
bazel_ios_stop_app com.example.SwiftUIApp ✅ terminated
simctl screenshot ✅ captured (754 KB, 1206×2622)

Unit tests — bazel_ios_test

Target Result
//modules/Models:ModelsTests ✅ PASSED via MCP (13.3s)
//modules/API:APITests ✅ PASSED via bazel (68.0s; MCP 30s request cap too short for cold builds — see note)

Bitrise-config stripping verified

Calling bazel_ios_test with extraArgs: ["--config=bitrise"] and no BITRISE_BUILD_CACHE_AUTH_TOKEN produced a command with --config=bitrise stripped — ran locally instead of failing Bitrise auth. Confirms stripBitriseAuthFlags.

Note on the ~/Projects/ios DoorDash repo

Bare bazel test there fails with No repository visible as '@build_bazel_rules_swift' — a pre-existing Bzlmod repo-mapping issue in that repo's .bazelrc/MODULE.bazel (it references --@rules_swift//swift:copt but resolves to @build_bazel_rules_swift). Reproduces with plain bazel, unrelated to this PR. Used BazelApp for the buildable target instead.

Remaining unchecked (need hardware / separate steps)

  • Manual CLI validation with xcodebazelmcp …
  • Physical device validation (devices are connected — happy to run next)

@maatheusgois-dd
maatheusgois-dd marked this pull request as ready for review July 17, 2026 05:34
@maatheusgois-dd
maatheusgois-dd merged commit e81b3e7 into main Jul 17, 2026
7 checks passed
@maatheusgois-dd
maatheusgois-dd deleted the maatheusgois-dd/xcodebazelmcp-hardening branch July 17, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant