This guide covers building signed release versions of SpeakMCP for distribution.
- Node.js 18+ and pnpm
- Rust toolchain (for the keyboard/input binary)
- Xcode (for macOS builds)
- Apple Developer Account (for code signing)
First, list your available code signing certificates:
security find-identity -v -p codesigningYou'll see output like:
1) XXXXXXXX "Apple Development: your@email.com (XXXXXXXX)"
2) XXXXXXXX "Developer ID Application: Your Name (TEAMID)"
3) XXXXXXXX "3rd Party Mac Developer Application: Your Name (TEAMID)"
For distribution outside the App Store, you need "Developer ID Application".
Important: Use only the name portion WITHOUT the "Developer ID Application:" prefix.
# ✅ CORRECT - Just the name and team ID
export CSC_NAME="Your Name (TEAMID)"
# ❌ WRONG - Don't include the prefix
# export CSC_NAME="Developer ID Application: Your Name (TEAMID)"Required variables for signed builds:
export CSC_NAME="Your Name (TEAMID)" # For app signing
export APPLE_DEVELOPER_ID="Your Name (TEAMID)" # For Rust binary signing
export ENABLE_HARDENED_RUNTIME=true # Required for notarizationAdditional variables for notarization (recommended for public distribution):
export APPLE_TEAM_ID="TEAMID" # Your 10-character Team ID
export APPLE_ID="your@email.com" # Your Apple ID email
export APPLE_APP_SPECIFIC_PASSWORD="xxxx-xxxx-xxxx-xxxx" # From appleid.apple.comGenerating App-Specific Password: Go to https://appleid.apple.com → Sign In → App-Specific Passwords → Generate a password for "SpeakMCP Notarization"
cd apps/desktop
pnpm run build-rsThis builds and signs the native keyboard/input binary.
# Build the app (skips type checking for faster builds)
npx electron-vite build
# Build signed DMG, ZIP, and PKG for both Intel and Apple Silicon
npx electron-builder --mac --config electron-builder.config.cjs --publish=neverBuilt artifacts will be in apps/desktop/dist/:
SpeakMCP-X.X.X-arm64.dmg- Apple Silicon DMGSpeakMCP-X.X.X-x64.dmg- Intel DMGSpeakMCP-X.X.X-arm64.zip- Apple Silicon ZIP (for auto-updates)SpeakMCP-X.X.X-x64.zip- Intel ZIPSpeakMCP-X.X.X-arm64.pkg- Apple Silicon installerSpeakMCP-X.X.X-x64.pkg- Intel installer
For a complete signed build (replace with your actual name and team ID):
cd apps/desktop && \
export CSC_NAME="Your Name (TEAMID)" && \
export APPLE_DEVELOPER_ID="Your Name (TEAMID)" && \
export ENABLE_HARDENED_RUNTIME=true && \
pnpm run build-rs && \
npx electron-vite build && \
npx electron-builder --mac --config electron-builder.config.cjs --publish=neverYou included the certificate type prefix. Use just the name:
# Wrong
export CSC_NAME="Developer ID Application: John Doe (ABC123XYZ)"
# Correct
export CSC_NAME="John Doe (ABC123XYZ)"Your certificate isn't installed or doesn't match. Run:
security find-identity -v -p codesigningThis happens when APPLE_TEAM_ID, APPLE_ID, or APPLE_APP_SPECIFIC_PASSWORD aren't set.
The app will still be signed but users may see Gatekeeper warnings on first launch.
The pnpm build:mac:signed command runs type checking which may fail due to dependency
version mismatches. Use the direct commands above which skip type checking:
npx electron-vite build # Builds without type checking
npx electron-builder --mac --config electron-builder.config.cjs --publish=neverFor convenience, there's a build script that handles all platforms:
# Build all platforms
./scripts/build-release.sh
# macOS only
./scripts/build-release.sh --mac-only
# Skip specific platforms
./scripts/build-release.sh --skip-ios --skip-androidSee the script header for all required environment variables.