Skip to content

Wire up Sparkle so the app actually checks for updates - #180

Merged
mattt merged 1 commit into
mattt:mainfrom
Arsey:fix/wire-up-sparkle-auto-updates
Sep 5, 2026
Merged

mattt merged 1 commit into
mattt:mainfrom
Arsey:fix/wire-up-sparkle-auto-updates

Conversation

@Arsey

@Arsey Arsey commented Aug 18, 2026 •

Copy link
Copy Markdown
Contributor

Summary

iMCP never checks for updates. Every install is stuck on whatever version it first shipped — silently, with no error, no in-app way to check, and no prompt when a fix ships.

Info.plist declares SUFeedURL, SUPublicEDKey, and SUEnableInstallerLauncherService — it looks like Sparkle is configured — but no target links the Sparkle package and no code constructs an updater, so those keys are dead. This PR links Sparkle and wires it up.

Root cause

Found on a real install stuck on v1.4.0 (Jan 2026 build), still hitting the ServiceGroupError fatal crash from #166 three months after the fix shipped in v1.4.1. There's no SPUStandardUpdaterController or equivalent anywhere in the codebase, so the Sparkle keys in Info.plist are config with nothing reading them.

Fix

  • Add the Sparkle SPM package to the iMCP app target.
  • Construct SPUStandardUpdaterController(startingUpdater: true, updaterDelegate: nil, userDriverDelegate: nil) in App.swift, using the existing SUFeedURL/SUPublicEDKey.
  • Add a "Check for Updates..." item to the menu bar dropdown, wired to updater.checkForUpdates().

Test plan

  • xcodebuild -resolvePackageDependencies resolves Sparkle (2.9.6) alongside existing deps
  • xcodebuild build -scheme iMCP -configuration Debug succeeds
  • Built app launches and stays running with Sparkle.framework loaded
  • xcodebuild test -scheme imcp-serverTests — all pass, including ServiceGroupConfigurationTests (unrelated, confirms no regression)
  • swift format lint --strict --recursive . — clean
  • Not verified: an actual update install against a live appcast, or a codesigned/notarized Release build. I don't hold the TTY35UM57S Developer ID or the WeatherKit entitlement, so CI's signed build is the real check for that.

Scope / non-goals

downloads.imcp.app (the configured SUFeedURL) doesn't resolve — NXDOMAIN. This makes the app actually attempt update checks, but they'll fail until that domain is live. No appcast.xml or publish workflow in this repo, so I can't tell if it's stale or just needs DNS pointed at wherever the appcast is hosted.

Closes #52.

Info.plist has declared SUFeedURL/SUPublicEDKey (and the entitlements
reserve Sparkle's -spks/-spki XPC mach ports) since day one, but no
target ever linked the Sparkle package or instantiated an updater. The
result: every install is permanently frozen at whatever version it
first shipped, silently, with no error and no "Check for Updates" menu
item to surface the problem.

This is why users can stay on known-crashy builds indefinitely: my own
installed copy was v1.4.0 (Jan 2026), three months and one release
behind the fix for the Bonjour-disconnect crash in mattt#166/1.4.1, with no
way to find out short of reading raw Claude Desktop MCP logs.

- Add the Sparkle SPM package to the iMCP app target.
- Construct SPUStandardUpdaterController(startingUpdater: true, ...) in
  App.swift so Sparkle's normal periodic background check actually
  runs, using the existing SUFeedURL/SUPublicEDKey.
- Add a "Check for Updates..." item to the menu bar dropdown, wired to
  updater.checkForUpdates() and disabled while a check is unavailable.

Verified: package graph resolves, `xcodebuild build -scheme iMCP`
succeeds, the built app launches and stays up with Sparkle.framework
loaded, `imcp-serverTests` (incl. ServiceGroupConfigurationTests) still
pass, and `swift format lint --strict --recursive .` is clean.

Note: https://downloads.imcp.app/appcast.xml (the configured SUFeedURL)
currently fails to resolve in DNS (NXDOMAIN), so this alone won't help
until that feed is live — flagging separately in the PR description.
@mattt
mattt merged commit 6588c0c into mattt:main Sep 5, 2026
@mattt

mattt commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Thanks, @Arsey. This went in alongside the new signing key from #203, so the next release will be the first one that installs can pick up on their own. Merged.

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.

Support in-app updating to new versions

2 participants