Skip to content

Commit 5926e26

Browse files
authored
Merge branch 'main' into dependabot/npm_and_yarn/vite-7.1.6
2 parents 2ca7bed + 8ffc8e4 commit 5926e26

16 files changed

Lines changed: 848 additions & 90 deletions

File tree

.axe-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.1.1

.github/workflows/release.yml

Lines changed: 69 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -101,60 +101,6 @@ jobs:
101101
env:
102102
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
103103

104-
- name: Setup Go (for MCP Publisher)
105-
if: github.event_name == 'push'
106-
uses: actions/setup-go@v5
107-
with:
108-
go-version: '1.22'
109-
110-
- name: Install MCP Publisher
111-
if: github.event_name == 'push'
112-
run: |
113-
echo "📥 Fetching MCP Publisher"
114-
git clone https://github.com/modelcontextprotocol/registry publisher-repo
115-
cd publisher-repo
116-
make publisher
117-
# The publisher binary is output to bin/mcp-publisher by the Makefile
118-
cp bin/mcp-publisher ../mcp-publisher
119-
cd ..
120-
chmod +x mcp-publisher
121-
122-
- name: Login to MCP Registry (DNS)
123-
if: github.event_name == 'push'
124-
env:
125-
MCP_DNS_PRIVATE_KEY: ${{ secrets.MCP_DNS_PRIVATE_KEY }}
126-
run: |
127-
echo "🔐 Using DNS authentication for com.xcodebuildmcp/* namespace"
128-
if [ -z "${MCP_DNS_PRIVATE_KEY}" ]; then
129-
echo "❌ Missing secrets.MCP_DNS_PRIVATE_KEY"
130-
echo "Add your DNS private key (hex) as a GitHub secret named MCP_DNS_PRIVATE_KEY."
131-
echo "Generate/extract with:"
132-
echo " openssl genpkey -algorithm Ed25519 -out key.pem"
133-
echo " openssl pkey -in key.pem -noout -text | grep -A3 'priv:' | tail -n +2 | tr -d ' :\\n'"
134-
exit 1
135-
fi
136-
./mcp-publisher login dns --domain xcodebuildmcp.com --private-key "${MCP_DNS_PRIVATE_KEY}"
137-
138-
- name: Publish to MCP Registry
139-
if: github.event_name == 'push'
140-
run: |
141-
echo "🚢 Publishing to MCP Registry with retries..."
142-
attempts=0
143-
max_attempts=5
144-
delay=5
145-
until ./mcp-publisher publish; do
146-
rc=$?
147-
attempts=$((attempts+1))
148-
if [ $attempts -ge $max_attempts ]; then
149-
echo "❌ Publish failed after $attempts attempts (exit $rc)"
150-
exit $rc
151-
fi
152-
echo "⚠️ Publish failed (exit $rc). Retrying in ${delay}s... (attempt ${attempts}/${max_attempts})"
153-
sleep $delay
154-
delay=$((delay*2))
155-
done
156-
echo "✅ Publish succeeded."
157-
158104
- name: Create GitHub Release (production releases only)
159105
if: github.event_name == 'push'
160106
uses: softprops/action-gh-release@v1
@@ -198,5 +144,73 @@ jobs:
198144
echo "🎉 Production release completed!"
199145
echo "Version: ${{ steps.get_version.outputs.VERSION }}"
200146
echo "📦 NPM: https://www.npmjs.com/package/xcodebuildmcp/v/${{ steps.get_version.outputs.VERSION }}"
201-
echo "📚 MCP Registry: published via mcp-publisher"
147+
echo "📚 MCP Registry: publish attempted in separate job (mcp_registry)"
202148
fi
149+
150+
mcp_registry:
151+
if: github.event_name == 'push'
152+
needs: release
153+
runs-on: ubuntu-latest
154+
env:
155+
MCP_DNS_PRIVATE_KEY: ${{ secrets.MCP_DNS_PRIVATE_KEY }}
156+
steps:
157+
- name: Checkout code
158+
uses: actions/checkout@v4
159+
with:
160+
fetch-depth: 0
161+
162+
- name: Get version from tag
163+
id: get_version_mcp
164+
run: |
165+
VERSION=${GITHUB_REF#refs/tags/v}
166+
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
167+
echo "🚢 MCP publish for version: $VERSION"
168+
169+
- name: Missing secret — skip MCP publish
170+
if: env.MCP_DNS_PRIVATE_KEY == ''
171+
run: |
172+
echo "⚠️ Skipping MCP Registry publish: secrets.MCP_DNS_PRIVATE_KEY is not set."
173+
echo "This is optional and does not affect the release."
174+
175+
- name: Setup Go (for MCP Publisher)
176+
if: env.MCP_DNS_PRIVATE_KEY != ''
177+
uses: actions/setup-go@v5
178+
with:
179+
go-version: '1.22'
180+
181+
- name: Install MCP Publisher
182+
if: env.MCP_DNS_PRIVATE_KEY != ''
183+
run: |
184+
echo "📥 Fetching MCP Publisher"
185+
git clone https://github.com/modelcontextprotocol/registry publisher-repo
186+
cd publisher-repo
187+
make publisher
188+
cp bin/mcp-publisher ../mcp-publisher
189+
cd ..
190+
chmod +x mcp-publisher
191+
192+
- name: Login to MCP Registry (DNS)
193+
if: env.MCP_DNS_PRIVATE_KEY != ''
194+
run: |
195+
echo "🔐 Using DNS authentication for com.xcodebuildmcp/* namespace"
196+
./mcp-publisher login dns --domain xcodebuildmcp.com --private-key "${MCP_DNS_PRIVATE_KEY}"
197+
198+
- name: Publish to MCP Registry (best-effort)
199+
if: env.MCP_DNS_PRIVATE_KEY != ''
200+
run: |
201+
echo "🚢 Publishing to MCP Registry with retries..."
202+
attempts=0
203+
max_attempts=5
204+
delay=5
205+
until ./mcp-publisher publish; do
206+
rc=$?
207+
attempts=$((attempts+1))
208+
if [ $attempts -ge $max_attempts ]; then
209+
echo "⚠️ MCP Registry publish failed after $attempts attempts (exit $rc). Skipping without failing workflow."
210+
exit 0
211+
fi
212+
echo "⚠️ Publish failed (exit $rc). Retrying in ${delay}s... (attempt ${attempts}/${max_attempts})"
213+
sleep $delay
214+
delay=$((delay*2))
215+
done
216+
echo "✅ MCP Registry publish succeeded."

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,4 @@ bundled/
107107
/.mcpregistry_github_token
108108
/.mcpregistry_registry_token
109109
/key.pem
110+
.mcpli

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ The XcodeBuildMCP server provides the following tool capabilities:
8686
- **Log Capture**: Capture run-time logs from a simulator
8787
- **UI Automation**: Interact with simulator UI elements
8888
- **Screenshot**: Capture screenshots from a simulator
89+
- **Video Capture**: Start/stop simulator video capture to MP4 (AXe v1.1.0+)
8990

9091
### Device management
9192
- **Device Discovery**: List connected physical Apple devices over USB or Wi-Fi
@@ -117,7 +118,9 @@ For clients that support MCP resources XcodeBuildMCP provides efficient URI-base
117118
- Xcode 16.x or later
118119
- Node 18.x or later
119120

120-
### Configure your MCP client
121+
> Video capture requires the bundled AXe binary (v1.1.0+). Run `npm run bundle:axe` once locally before using `record_sim_video`. This is not required for unit tests.
122+
123+
Configure your MCP client
121124

122125
#### One click install
123126

docs/TOOLS.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# XcodeBuildMCP Tools Reference
22

3-
XcodeBuildMCP provides 60 tools organized into 12 workflow groups for comprehensive Apple development workflows.
3+
XcodeBuildMCP provides 61 tools organized into 12 workflow groups for comprehensive Apple development workflows.
44

55
## Workflow Groups
66

@@ -19,7 +19,7 @@ XcodeBuildMCP provides 60 tools organized into 12 workflow groups for comprehens
1919
- `stop_app_device` - Stops an app running on a physical Apple device (iPhone, iPad, Apple Watch, Apple TV, Apple Vision Pro). Requires deviceId and processId.
2020
- `test_device` - Runs tests for an Apple project or workspace on a physical device (iPhone, iPad, Apple Watch, Apple TV, Apple Vision Pro) using xcodebuild test and parses xcresult output. Provide exactly one of projectPath or workspacePath.
2121
### iOS Simulator Development (`simulator`)
22-
**Purpose**: Complete iOS development workflow for both .xcodeproj and .xcworkspace files targeting simulators. Build, test, deploy, and interact with iOS apps on simulators. (11 tools)
22+
**Purpose**: Complete iOS development workflow for both .xcodeproj and .xcworkspace files targeting simulators. Build, test, deploy, and interact with iOS apps on simulators. (12 tools)
2323

2424
- `boot_sim` - Boots an iOS simulator. After booting, use open_sim() to make the simulator visible.
2525
- `build_run_sim` - Builds and runs an app from a project or workspace on a specific simulator by UUID or name. Provide exactly one of projectPath or workspacePath, and exactly one of simulatorId or simulatorName.
@@ -30,6 +30,7 @@ XcodeBuildMCP provides 60 tools organized into 12 workflow groups for comprehens
3030
- `launch_app_sim` - Launches an app in an iOS simulator by UUID or name. If simulator window isn't visible, use open_sim() first. or launch_app_sim({ simulatorName: 'iPhone 16', bundleId: 'com.example.MyApp' })
3131
- `list_sims` - Lists available iOS simulators with their UUIDs.
3232
- `open_sim` - Opens the iOS Simulator app.
33+
- `record_sim_video` - Starts or stops video capture for an iOS simulator using AXe. Provide exactly one of start=true or stop=true. On stop, outputFile is required. fps defaults to 30.
3334
- `stop_app_sim` - Stops an app running in an iOS simulator by UUID or name. or stop_app_sim({ simulatorName: "iPhone 16", bundleId: "com.example.MyApp" })
3435
- `test_sim` - Runs tests on a simulator by UUID or name using xcodebuild test and parses xcresult output. Works with both Xcode projects (.xcodeproj) and workspaces (.xcworkspace).
3536
### Log Capture & Management (`logging`)
@@ -68,7 +69,7 @@ XcodeBuildMCP provides 60 tools organized into 12 workflow groups for comprehens
6869
### Simulator Management (`simulator-management`)
6970
**Purpose**: Tools for managing simulators from booting, opening simulators, listing simulators, stopping simulators, erasing simulator content and settings, and setting simulator environment options like location, network, statusbar and appearance. (5 tools)
7071

71-
- `erase_sims` - Erases simulator content and settings. Provide exactly one of: simulatorUuid or all=true. Optional: shutdownFirst to shut down before erasing.
72+
- `erase_sims` - Erases simulator content and settings. Provide exactly one of: simulatorUdid or all=true. Optional: shutdownFirst to shut down before erasing.
7273
- `reset_sim_location` - Resets the simulator's location to default.
7374
- `set_sim_appearance` - Sets the appearance mode (dark/light) of an iOS simulator.
7475
- `set_sim_location` - Sets a custom GPS location for the simulator.
@@ -103,9 +104,9 @@ XcodeBuildMCP provides 60 tools organized into 12 workflow groups for comprehens
103104

104105
## Summary Statistics
105106

106-
- **Total Tools**: 60 canonical tools + 22 re-exports = 82 total
107+
- **Total Tools**: 61 canonical tools + 22 re-exports = 83 total
107108
- **Workflow Groups**: 12
108109

109110
---
110111

111-
*This documentation is automatically generated by `scripts/update-tools-docs.ts` using static analysis. Last updated: 2025-09-21*
112+
*This documentation is automatically generated by `scripts/update-tools-docs.ts` using static analysis. Last updated: 2025-09-22*

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "xcodebuildmcp",
3-
"version": "1.13.0",
3+
"version": "1.13.1",
44
"mcpName": "com.xcodebuildmcp/XcodeBuildMCP",
55
"iOSTemplateVersion": "v1.0.8",
66
"macOSTemplateVersion": "v1.0.5",

scripts/bundle-axe.sh

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ AXE_TEMP_DIR="/tmp/axe-download-$$"
1313

1414
echo "🔨 Preparing AXe artifacts for bundling..."
1515

16+
# Single source of truth for AXe version (overridable)
17+
# 1) Use $AXE_VERSION if provided in env
18+
# 2) Else, use repo-level pin from .axe-version if present
19+
# 3) Else, fall back to default below
20+
DEFAULT_AXE_VERSION="1.1.1"
21+
VERSION_FILE="$PROJECT_ROOT/.axe-version"
22+
if [ -n "${AXE_VERSION}" ]; then
23+
PINNED_AXE_VERSION="${AXE_VERSION}"
24+
elif [ -f "$VERSION_FILE" ]; then
25+
PINNED_AXE_VERSION="$(cat "$VERSION_FILE" | tr -d ' \n\r')"
26+
else
27+
PINNED_AXE_VERSION="$DEFAULT_AXE_VERSION"
28+
fi
29+
echo "📌 Using AXe version: $PINNED_AXE_VERSION"
30+
1631
# Clean up any existing bundled directory
1732
if [ -d "$BUNDLED_DIR" ]; then
1833
echo "🧹 Cleaning existing bundled directory..."
@@ -22,41 +37,41 @@ fi
2237
# Create bundled directory
2338
mkdir -p "$BUNDLED_DIR"
2439

25-
# Use local AXe build if available, otherwise download from GitHub releases
26-
if [ -d "$AXE_LOCAL_DIR" ] && [ -f "$AXE_LOCAL_DIR/Package.swift" ]; then
40+
# Use local AXe build if available (unless AXE_FORCE_REMOTE=1), otherwise download from GitHub releases
41+
if [ -z "${AXE_FORCE_REMOTE}" ] && [ -d "$AXE_LOCAL_DIR" ] && [ -f "$AXE_LOCAL_DIR/Package.swift" ]; then
2742
echo "🏠 Using local AXe source at $AXE_LOCAL_DIR"
2843
cd "$AXE_LOCAL_DIR"
29-
44+
3045
# Build AXe in release configuration
3146
echo "🔨 Building AXe in release configuration..."
3247
swift build --configuration release
33-
48+
3449
# Check if build succeeded
3550
if [ ! -f ".build/release/axe" ]; then
3651
echo "❌ AXe build failed - binary not found"
3752
exit 1
3853
fi
39-
54+
4055
echo "✅ AXe build completed successfully"
41-
56+
4257
# Copy binary to bundled directory
4358
echo "📦 Copying AXe binary..."
4459
cp ".build/release/axe" "$BUNDLED_DIR/"
45-
60+
4661
# Fix rpath to find frameworks in Frameworks/ subdirectory
4762
echo "🔧 Configuring AXe binary rpath for bundled frameworks..."
4863
install_name_tool -add_rpath "@executable_path/Frameworks" "$BUNDLED_DIR/axe"
49-
64+
5065
# Create Frameworks directory and copy frameworks
5166
echo "📦 Copying frameworks..."
5267
mkdir -p "$BUNDLED_DIR/Frameworks"
53-
68+
5469
# Copy frameworks with better error handling
5570
for framework in .build/release/*.framework; do
5671
if [ -d "$framework" ]; then
5772
echo "📦 Copying framework: $(basename "$framework")"
5873
cp -r "$framework" "$BUNDLED_DIR/Frameworks/"
59-
74+
6075
# Only copy nested frameworks if they exist
6176
if [ -d "$framework/Frameworks" ]; then
6277
echo "📦 Found nested frameworks in $(basename "$framework")"
@@ -66,30 +81,30 @@ if [ -d "$AXE_LOCAL_DIR" ] && [ -f "$AXE_LOCAL_DIR/Package.swift" ]; then
6681
done
6782
else
6883
echo "📥 Downloading latest AXe release from GitHub..."
69-
70-
# Get latest release download URL
71-
LATEST_RELEASE_URL="https://github.com/cameroncooke/AXe/releases/download/v1.0.0/AXe-macOS-v1.0.0.tar.gz"
72-
84+
85+
# Construct release download URL from pinned version
86+
AXE_RELEASE_URL="https://github.com/cameroncooke/AXe/releases/download/v${PINNED_AXE_VERSION}/AXe-macOS-v${PINNED_AXE_VERSION}.tar.gz"
87+
7388
# Create temp directory
7489
mkdir -p "$AXE_TEMP_DIR"
7590
cd "$AXE_TEMP_DIR"
76-
91+
7792
# Download and extract the release
78-
echo "📥 Downloading AXe release archive..."
79-
curl -L -o "axe-release.tar.gz" "$LATEST_RELEASE_URL"
80-
93+
echo "📥 Downloading AXe release archive ($AXE_RELEASE_URL)..."
94+
curl -L -o "axe-release.tar.gz" "$AXE_RELEASE_URL"
95+
8196
echo "📦 Extracting AXe release archive..."
8297
tar -xzf "axe-release.tar.gz"
83-
98+
8499
# Find the extracted directory (might be named differently)
85100
EXTRACTED_DIR=$(find . -type d -name "*AXe*" -o -name "*axe*" | head -1)
86101
if [ -z "$EXTRACTED_DIR" ]; then
87102
# If no AXe directory found, assume files are in current directory
88103
EXTRACTED_DIR="."
89104
fi
90-
105+
91106
cd "$EXTRACTED_DIR"
92-
107+
93108
# Copy binary
94109
if [ -f "axe" ]; then
95110
echo "📦 Copying AXe binary..."
@@ -104,11 +119,11 @@ else
104119
ls -la
105120
exit 1
106121
fi
107-
122+
108123
# Copy frameworks if they exist
109124
echo "📦 Copying frameworks..."
110125
mkdir -p "$BUNDLED_DIR/Frameworks"
111-
126+
112127
if [ -d "Frameworks" ]; then
113128
cp -r Frameworks/* "$BUNDLED_DIR/Frameworks/"
114129
elif [ -d "lib" ]; then
@@ -153,4 +168,4 @@ BUNDLE_SIZE=$(du -sh "$BUNDLED_DIR" | cut -f1)
153168
echo "📊 Final bundle size: $BUNDLE_SIZE"
154169

155170
echo "🎉 AXe bundling completed successfully!"
156-
echo "📁 Bundled artifacts location: $BUNDLED_DIR"
171+
echo "📁 Bundled artifacts location: $BUNDLED_DIR"

scripts/release.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,14 @@ if [[ -n "$RUN_ID" ]]; then
344344
echo ""
345345
echo "❌ CI workflow failed!"
346346
echo ""
347+
# Prefer job state: if the primary 'release' job succeeded, treat as success.
348+
RELEASE_JOB_CONCLUSION=$(gh run view "$RUN_ID" --json jobs --jq '.jobs[] | select(.name=="release") | .conclusion')
349+
if [ "$RELEASE_JOB_CONCLUSION" = "success" ]; then
350+
echo "⚠️ Workflow reported failure, but primary 'release' job concluded SUCCESS."
351+
echo "✅ Treating release as successful. Tag v$VERSION is kept."
352+
echo "📦 Verify on NPM: https://www.npmjs.com/package/xcodebuildmcp/v/$VERSION"
353+
exit 0
354+
fi
347355
echo "🧹 Cleaning up tags only (keeping version commit)..."
348356

349357
# Delete remote tag

server.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
"source": "github",
99
"id": "945551361"
1010
},
11-
"version": "1.13.0",
11+
"version": "1.13.1",
1212
"packages": [
1313
{
1414
"registry_type": "npm",
1515
"registry_base_url": "https://registry.npmjs.org",
1616
"identifier": "xcodebuildmcp",
17-
"version": "1.13.0",
17+
"version": "1.13.1",
1818
"transport": {
1919
"type": "stdio"
2020
},

0 commit comments

Comments
 (0)