Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

- Added `xcodebuildmcp purge` to report and explicitly clean XcodeBuildMCP-managed workspace storage, including opt-in DerivedData cleanup with dry-run and confirmation safeguards.
- Added `extraArgs` as a first-class session-default value. Repo config or runtime defaults can now carry common `xcodebuild` flags (for example `-skipPackagePluginValidation` or `-disableAutomaticPackageResolution`) so they don't need repeating on every build or test call. Per-call `extraArgs` replace matching configured flags or build settings and append after non-matching defaults, while an explicit empty array (`extraArgs: []`) clears the defaults for a single call. The session management tools show, set, sync, and clear `extraArgs` alongside the other defaults.
- Added reusable test preparation to the existing simulator, device, and macOS build tools. Builds can now return a portable `.xctestproducts` artifact, and test tools can run that artifact—or an advanced `.xctestrun` input—without rebuilding before producing a new `.xcresult` ([#450](https://github.com/getsentry/XcodeBuildMCP/issues/450)).

### Changed

- Tool manifests can now conditionally expose static next steps using handler-activated condition keys, while runtime-generated parameters continue to flow through the existing next-step parameter contract.

### Fixed

Expand Down Expand Up @@ -694,4 +699,3 @@ Please note that the UI automation features are an early preview and currently i
## [v1.0.1] - 2025-04-02
- Initial release of XcodeBuildMCP
- Basic support for building iOS and macOS applications

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ xcodebuildmcp tools

# Build for simulator
xcodebuildmcp simulator build --scheme MyApp --project-path ./MyApp.xcodeproj

# Prepare portable test products without running tests
xcodebuildmcp simulator build --scheme MyApp --project-path ./MyApp.xcodeproj --simulator-name "iPhone 17" --build-for-testing --test-products-path ./MyApp.xctestproducts

# Run previously prepared test products
xcodebuildmcp simulator test --test-products-path ./MyApp.xctestproducts --simulator-name "iPhone 17"
```

Check for updates and upgrade in place:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ import OSLog
import CalculatorAppFeature

private let logger = Logger(subsystem: "io.sentry.calculatorapp", category: "lifecycle")
private let snapshotScrollSurfaceArgument = "--snapshot-scroll-surface"

@main
struct CalculatorApp: App {
@Environment(\.scenePhase) private var scenePhase

var body: some Scene {
WindowGroup {
ContentView()
if ProcessInfo.processInfo.arguments.contains(snapshotScrollSurfaceArgument) {
SnapshotScrollSurface()
} else {
ContentView()
}
}
.onChange(of: scenePhase) { _, newPhase in
switch newPhase {
Expand All @@ -25,6 +30,21 @@ struct CalculatorApp: App {
}
}

private struct SnapshotScrollSurface: View {
var body: some View {
ScrollView {
LazyVStack(spacing: 16) {
ForEach(0..<30, id: \.self) { index in
Text("Snapshot row \(index)")
.frame(maxWidth: .infinity, minHeight: 44)
}
}
.padding()
}
.accessibilityIdentifier("snapshot-scroll-surface")
}
}

#Preview {
ContentView()
}
Expand Down
5 changes: 5 additions & 0 deletions manifests/tools/batch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
7 changes: 6 additions & 1 deletion manifests/tools/build_device.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Build for device.
outputSchema:
schema: xcodebuildmcp.output.build-result
version: "2"
version: '3'
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand All @@ -19,3 +19,8 @@ nextSteps:
toolId: get_device_app_path
priority: 1
when: success
condition: app_build_succeeded
- label: Run prepared tests
toolId: test_device
when: success
condition: prepared_tests_available
7 changes: 6 additions & 1 deletion manifests/tools/build_macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Build macOS app.
outputSchema:
schema: xcodebuildmcp.output.build-result
version: "2"
version: '3'
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand All @@ -19,3 +19,8 @@ nextSteps:
toolId: get_mac_app_path
priority: 1
when: success
condition: app_build_succeeded
- label: Run prepared tests
toolId: test_macos
when: success
condition: prepared_tests_available
7 changes: 6 additions & 1 deletion manifests/tools/build_sim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Build for iOS sim (compile-only, no launch).
outputSchema:
schema: xcodebuildmcp.output.build-result
version: "2"
version: '3'
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand All @@ -19,3 +19,8 @@ nextSteps:
toolId: get_sim_app_path
priority: 1
when: success
condition: app_build_succeeded
- label: Run prepared tests
toolId: test_sim
when: success
condition: prepared_tests_available
5 changes: 5 additions & 0 deletions manifests/tools/button.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/drag.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/gesture.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/key_press.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/key_sequence.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/long_press.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/swipe.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/tap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
2 changes: 1 addition & 1 deletion manifests/tools/test_device.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Test on device.
outputSchema:
schema: xcodebuildmcp.output.test-result
version: "2"
version: "3"
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand Down
2 changes: 1 addition & 1 deletion manifests/tools/test_macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Test macOS target.
outputSchema:
schema: xcodebuildmcp.output.test-result
version: "2"
version: "3"
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand Down
2 changes: 1 addition & 1 deletion manifests/tools/test_sim.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ names:
description: Test on iOS sim.
outputSchema:
schema: xcodebuildmcp.output.test-result
version: "2"
version: "3"
predicates:
- hideWhenXcodeAgentMode
annotations:
Expand Down
5 changes: 5 additions & 0 deletions manifests/tools/touch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
5 changes: 5 additions & 0 deletions manifests/tools/type_text.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ annotations:
readOnlyHint: true
destructiveHint: false
openWorldHint: false
nextSteps:
- label: Refresh after UI action
toolId: snapshot_ui
when: success
condition: ui_action_needs_refresh
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,10 @@
"knip": "knip",
"test": "vitest run",
"test:schema-fixtures": "vitest run src/snapshot-tests/__tests__/json-fixture-schema.test.ts",
"test:snapshot": "npm run build && node build/cli.js daemon stop 2>/dev/null; vitest run --config vitest.snapshot.config.ts",
"test:snapshot": "npm run build && vitest run --config vitest.snapshot.config.ts",
"test:snapshots": "npm run test:snapshot",
"test:snapshot:device": "npm run build && node build/cli.js daemon stop 2>/dev/null; vitest run --config vitest.snapshot.config.ts src/snapshot-tests/__tests__/device.snapshot.test.ts && vitest run --config vitest.snapshot.config.ts src/snapshot-tests/__tests__/cli-json-fixture-parity.snapshot.test.ts src/snapshot-tests/__tests__/mcp-json-fixture-parity.snapshot.test.ts -t 'device workflow'",
"test:snapshot:update": "npm run build && node build/cli.js daemon stop 2>/dev/null; UPDATE_SNAPSHOTS=1 vitest run --config vitest.snapshot.config.ts",
"test:snapshot:device": "npm run build && vitest run --config vitest.snapshot.config.ts src/snapshot-tests/__tests__/device.snapshot.test.ts && vitest run --config vitest.snapshot.config.ts src/snapshot-tests/__tests__/cli-json.snapshot.test.ts src/snapshot-tests/__tests__/mcp-json.snapshot.test.ts -t 'device workflow'",
"test:snapshot:update": "npm run build && UPDATE_SNAPSHOTS=1 vitest run --config vitest.snapshot.config.ts",
"test:snapshots:update": "npm run test:snapshot:update",
"test:smoke": "npm run build && vitest run --config vitest.smoke.config.ts",
"test:watch": "vitest",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://xcodebuildmcp.com/schemas/structured-output/xcodebuildmcp.output.build-result/3.schema.json",
"type": "object",
"additionalProperties": false,
"allOf": [
{
"$ref": "https://xcodebuildmcp.com/schemas/structured-output/_defs/common.schema.json#/$defs/errorConsistency"
}
],
"$defs": {
"buildInvocationRequest": {
"type": "object",
"additionalProperties": false,
"properties": {
"buildForTesting": { "type": "boolean" },
"scheme": { "type": "string" },
"workspacePath": { "type": "string" },
"projectPath": { "type": "string" },
"packagePath": { "type": "string" },
"targetName": { "type": "string" },
"configuration": { "type": "string" },
"platform": { "type": "string" },
"target": {
"enum": ["simulator", "device", "macos", "swift-package"]
},
"simulatorName": { "type": "string" },
"simulatorId": { "type": "string" },
"deviceId": { "type": "string" },
"executableName": { "type": "string" },
"arch": { "type": "string" },
"derivedDataPath": { "type": "string" },
"testProductsPath": { "type": "string" },
"xctestrunPath": { "type": "string" },
"onlyTesting": {
"type": "array",
"items": { "type": "string" }
},
"skipTesting": {
"type": "array",
"items": { "type": "string" }
}
}
}
},
"properties": {
"schema": {
"const": "xcodebuildmcp.output.build-result"
},
"schemaVersion": {
"const": "3"
},
"didError": {
"type": "boolean"
},
"error": {
"type": ["string", "null"]
},
"data": {
"anyOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"request": {
"$ref": "#/$defs/buildInvocationRequest"
},
"summary": {
"type": "object",
"additionalProperties": false,
"properties": {
"status": {
"enum": ["SUCCEEDED", "FAILED"]
},
"durationMs": {
"type": "integer",
"minimum": 0
},
"target": {
"enum": ["simulator", "device", "macos", "swift-package"]
}
},
"required": ["status"]
},
"artifacts": {
"type": "object",
"additionalProperties": false,
"properties": {
"appPath": { "type": "string" },
"bundleId": { "type": "string" },
"buildLogPath": { "type": "string" },
"packagePath": { "type": "string" },
"workspacePath": { "type": "string" },
"scheme": { "type": "string" },
"configuration": { "type": "string" },
"platform": { "type": "string" },
"testProductsPath": { "type": "string" },
"xctestrunPaths": {
"type": "array",
"items": { "type": "string" }
}
},
"required": [],
"minProperties": 1
},
"diagnostics": {
"$ref": "https://xcodebuildmcp.com/schemas/structured-output/_defs/common.schema.json#/$defs/basicDiagnostics"
}
},
"required": ["summary", "artifacts", "diagnostics"]
},
{
"type": "null"
}
]
},
"nextSteps": {
"$ref": "https://xcodebuildmcp.com/schemas/structured-output/_defs/common.schema.json#/$defs/nextSteps"
}
},
"required": ["schema", "schemaVersion", "didError", "error", "data"]
}
Loading
Loading