- Add a
without_buildingoption totest_macos,test_sim, andtest_devicethat runsxcodebuild test-without-buildingto reuse the test bundle a prior run already compiled into the scoped DerivedData, skipping the build/planning phase on repeated runs;XcodebuildRunner.testgains awithoutBuildingflag (the test-arg assembly extracted into a testable statictestArgs) that preserves the-destinationand-only-testing/-skip-testing/-testPlanselectors into the without-building phase and records the actual action inRawBuildLog; a sharedwithoutBuildingSchemaPropertyis merged into all three tools and threaded throughTestToolHelper.runAndFormat;swift_package_testis intentionally left unchanged since SwiftPM'sswift testhas no build/test split; inspired bygetsentry/XcodeBuildMCP#475(#430)
- Add
extra_argsas a session default and per-call override for passthroughxcodebuildarguments;SessionDefaultsgains anextraArgs: [String]?(persisted, decoded leniently so session files written before the field still load) settable viaset_session_defaults, and a newSessionManager.resolveExtraArgsresolves a per-invocationextra_argsarray — presence of the key, even an empty array, replaces the session default for that one call; otherwise the persisted default is used — threaded (appended last, so it takes precedence) into all 11xcodebuild-invoking tools (build_sim,build_run_sim,test_sim,build_macos,build_run_macos,archive,test_macos,build_device,build_deploy_device,test_device,build_debug_macos), so a flag like-skipPackagePluginValidationcan be set once instead of on every call; inspired bygetsentry/XcodeBuildMCP#463(#426)
- Resolve the simulator build destination from the selected simulator's runtime instead of hardcoding
platform=iOS Simulator;build_sim/build_run_sim/test_simbuilt every simulator against an iOS destination, so an iOS+visionOS (or watchOS/tvOS) app targeting a non-iOS simulator built for the wrong platform and failed — the device build tools already resolved this correctly viaDeviceCtlRunner.lookupDevice;SimctlRunnergains aSimulatorPlatformenum whoseinit?(runtimeIdentifier:)maps a CoreSimulator runtime id to a destination (thexrOStoken becomesvisionOS Simulator) and aresolveForBuild(matching:)that resolves a UDID or name to a concrete device, canonicalizes a name to its UDID so-destination id=is always valid, rejects an unavailable or removed runtime with a clearplatformUndeterminederror rather than silently guessing, and composes the correctplatform=…,id=…destination;PreviewCaptureToolis intentionally left on its own iOS/macOS fallback; mirrorsgetsentry/XcodeBuildMCP#472(#425) - Stop
discover_projsfrom following a symlink out of the sandbox base during its recursive scan;DiscoverProjectsTool.search()validated only the initial search path against the base, then descended into any real subdirectory viaFileManager.fileExists/contentsOfDirectory(both follow symlinks) without re-checking each entry — so a symlink inside the tree pointing outside the base let the walk report.xcodeproj/.xcworkspacebundles from outside the sandbox (read-only, gated behind the default sandbox, but a real boundary gap); a newPathUtility.isWithinSandbox(_:)resolves symlinks on both the candidate and base before reusing the existing separator-awareisPath(_:within:)(returningtruewhen sandboxing is disabled, so--no-sandboxis unchanged), andsearch()now guards every entry with it before reporting or recursing; the exact prefix-match bug this mirrors —getsentry/XcodeBuildMCP46b2cf6— was already not present here sinceisPath(_:within:)anchors on a path separator (#429) - Fix two
WaitForProcessExitTeststhat flaked under a starved cooperative thread pool during the full 1502-test parallel CI run (runs 300, 301, 304); "Detects process killed bySIGKILLmid-wait" fired the kill from a cooperative-poolTaskthat could be starved past the 15s wait timeout — leaving the process alive sowaitForProcessExitcorrectly returnedfalseand the assertion tripped — now killed from a detachedThreadimmune to pool pressure; and "Timeout is bounded" dropped itselapsed < 15supper bound, which measured wall-clock around theawaitand so included unbounded continuation-scheduling latency after thekqueuewait resumes (observed 19.7s), keeping only the correctness and lower-bound checks since a genuine hang blocks the wait forever and is caught by the CI job timeout (#427)
- Add
show_last_build_raw(read-only) toxc-buildand monolithicxc-mcp; it returns the complete, unparsed clang/ld output of the most recent build/test so an agent can recover the verbatim linker diagnostic — the fullUndefined symbols …/duplicate symbol '…' in:block with every colliding source path — when the parsed summary truncates it and Xcode leaves a 0-byte.xcactivitylog;XcodebuildRunner.build/testnow persist the raw combined stdout/stderr of every scheme build/test to a PPID-scoped file (/tmp/xc-mcp-last-build-{ppid}.log,XC_MCP_LAST_BUILDoverride) with a JSON metadata sidecar, capturing on both the BUILD-FAILED nonzero-exit path and the timeout/stuck partial-output path with no build-time flag; the tool defaults toLinkerDiagnostics-extracted error/linker regions (full: truedumps everything,tail: Nthe final lines) and always prints the on-disk path as a last-resort fallback (#414) - Add
analyze_app_bundle(read-only) toxc-buildand monolithicxc-mcp; it inspects a built.app(or the.appinside an.xcarchive) and reports total bundle size with a binary/resource split, the main executable's Mach-O segment breakdown (excluding the__PAGEZERO4GB artifact) and architectures, the_relinkableLibraryClassesmergeable-library merge-marker count,LC_RPATHentries, linked in-project (@rpath) frameworks, per-embedded-framework sizes, and an rpath-aware launchability verdict — resolving each@rpathdependency dyld-style against the binary's actualLC_RPATHset to flag deps that only resolve via an absolute DerivedDataPackageFrameworkspath, making the "a loose build product is not self-contained; only an archive embeds everything" distinction explicit instead of something rediscovered via dyld crash logs; the string parsing (otool/size/nm/lipo) and resolution logic live in a pure, unit-testedCore/MachOInspector, and a single spaceless temp symlink works around cctoolsotool/sizere-tokenizing a bundle path with spaces (e.g.MyApp (debug).app) even when passed as a single argv element (#423)
- Stop injecting
-configuration Debugwhen no configuration is specified, soxcodebuildhonors the scheme's own Build/Run/Test action configuration;SessionManager.resolveConfigurationreturned a hardcoded"Debug"fallback whenever a tool got noconfigurationargument and no session default, andXcodebuildRunner.build/buildTarget/test/clean/showBuildSettingsalways appended the flag — overriding a scheme whose action uses a non-Debug configuration and reporting the wrong build settings (bundle identifier, derived.apppath) frombuild_macos,test_macos,get_mac_app_path,get_app_bundle_id,show_build_settings, and the rest; the configuration is now optional (nil= unspecified) end-to-end — through the runner,resolveConfiguration,validateMacOSSupport,findProjectRoot,TestToolHelper, andShowBuildDependencyGraph— and-configurationis emitted only when a value is actually provided; also removed the duplicated inline"Debug"-defaulting blocks in the bundle-id/app-path tools; mirrors upstreamgetsentry/XcodeBuildMCP623db7a(#424) - Fix three flaky
WaitForProcessExitTests(CI runs 295–297) by replacingProcessResult.waitForProcessExit'sTask.sleeppoll loop with a blocking kqueueEVFILT_PROC/NOTE_EXITwait dispatched to a dedicated thread; polling on the cooperative pool made both exit detection and the timeout unreliable — under a starved pool (full parallel test run) a 100ms sleep could overshoot by ~20s, so the loop either missed a process that had exited (returningfalse) or blew past its wall-clock deadline (elapsed 19.9s vs a 15s bound); the kqueue wait runs off the cooperative pool so exit detection is exact (a kernel event, not sampling) and the timeout is enforced bykevent's owntimespec, with a fast-pathkill(pid, 0)for an already-gone pid and an ESRCH-on-register race treated as an exit; the affected tests now pass in 0.369s (was ~22s and flaky) (#422) - Fix
PathUtility's sandbox containment check rejecting every path when the base directory is the filesystem root; the separator-anchoredisPath(_:within:)added to close the sibling-path escape computedbasePath + "/", which becomes"//"for base/— a prefix no real path matches — so aPathUtility(basePath: "/")threwpathOutsideBasePathfor all inputs and broke 11 CI tests (MoveFileTool,SearchTestPlansTool,AddTargetToTestPlanTool) that use temp paths under/var/folders/…; root is now special-cased to contain any absolute path, preserving the sibling-escape guard for all other bases; also silenced theInteractRunnerbuild warning aboutref as! AXValuenever producingnilby switching theCFTypeID-verified downcast tounsafeDowncast(#421) - Add
add_storekit_configtoxc-project(and monolithicxc-mcp) and harden the file/scheme operations around.storekitfiles; the new tool does the whole coherent job in one call — creates the project file reference (so the config appears in Edit Scheme → Run → Options → StoreKit Configuration), optionally adds it to a named test target's resources forSKTestSession(configurationFileNamed:), and wires the scheme's Run/TestStoreKitConfigurationFileReferencewith the correct scheme-relative path — warning when the target isn't a unit/UI test bundle (and skipping the resource add so a config can't be bundled into a shipping app), when the config is already in an app target's Copy Bundle Resources, or when no scheme is wired;remove_fileon a.storekitnow cleanly unwires every scheme reference that resolved to it and warns about the picker /SKTestSessioncouplings instead of leaving a dangling reference;validate_schemeflags a StoreKit reference whose relative path doesn't resolve and a.storekitshipped in an app target's resources; and the raw-XML scheme editor was extracted into a sharedSetSchemeStoreKitConfigTool.applyStoreKitReference(plus astoreKitIdentifiersreader) that writes each identifier verbatim relative to the scheme file and edits actions independently, so a sibling action's path can never be recomputed to the wrong depth (#408) - Warn from the macOS launch tools (
build_run_macos,build_debug_macos,launch_mac_app) when the launched scheme's Run action references a StoreKit configuration; apps launched directly (not through the Xcode IDE) never receive the scheme'sStoreKitConfigurationFileReference— Xcode injects it over a privatestorekitdXPC hand-off the CLI can't replicate — soProduct.products(for:)silently returns an empty array and StoreKit-gated features stay disabled; rather than expose astorekit_configparameter that couldn't reliably apply it, a new pureStoreKitLaunchAdvisoryreads the Run-action reference (reusingstoreKitIdentifiers), flags when it doesn't resolve to a file, and points at the paths that do work (run from Xcode, or drive it from tests viaSKTestSession);launch_mac_appuses the session's default scheme/project best-effort since it takes no scheme argument (#407) - Fix
find_build_settingsomitting project-levelbuildSettings, which made an audit look complete when it wasn't; the tool scanned only native-targetbuildSettingsdicts and silently ignored thePBXProject-level ones, so a malformed inherited flag (e.g.OTHER_LDFLAGS = "-Wl -no_exported_symbols"on the whole project, stripping every framework's exported symbols) was invisible unless a target happened to override it; it now scans the project-levelbuildSettingsin the same single pass and reports matches under a synthetic[project]label, with thevaluesandconfigurationfilters applied uniformly across the project scope and every target scope via a sharedscanhelper (#410) - Fix the linker-error parser reporting
Undefined symbol '<name>'for ldduplicate symboldiagnostics — opposite root causes, so the label pointed a debugging session 180° the wrong way;LinkerErrornow carries an explicitkind(undefined / duplicate / other) thatBuildResultFormatterlabels from, the parser collects every indented defining-file line under aduplicate symbol 'X' in:header (framework binaries, dylibs, and the literalbundle-file— not just.o/.a, which had dropped them and left the error looking undefined), flushes each pending duplicate on the next header / theld: N duplicate symbolssummary / end-of-parse so multiple duplicates aren't collapsed into one, and foldskindinto the dedup key so an undefined and a duplicate of the same symbol name stay distinct (#411)
- Reorganize the flat
Sources/Coredirectory (59 top-level files, stale-documented as 25) into concern-based subdirectories viagit mv—Runners/,BuildOutput/,ProjectFile/,Interaction/,Locators/,MCP/,Testing/,Session/, andAppBundle/, leaving five genuinely cross-cutting singletons at the root — with noPackage.swiftchange needed since theXCMCPCoretarget globsSources/Corerecursively; updatedCLAUDE.md's Package Structure tree and the two path-specific references to match (#409) - Add
audit_swift_packagestoxc-project(and monolithicxc-mcp); a read-only, offline SwiftPM dependency-health check adapted (reimplemented, not a dependency) fromcrleonard/swift-package-auditthat cross-references a project's declaredXCRemoteSwiftPackageReferencerequirements against itsPackage.resolvedpins and reportsmissingPackageResolved,unresolvedReference(declared but unpinned),stalePin(pinned but no longer declared),branchDependency/revisionDependency/exactVersionstability warnings,duplicateURLForm, andurlFormMismatch; a newCore/PackageResolvedParsernormalizes both the legacy v1 (object.pins) and modern v2/v3 (pins) formats and locates the pins file under the project's embeddedproject.xcworkspace(#406) - Refactor
Sources/Core/BuildOutputfrom a/swiftreview pass; migrateCoverageParserandBuildSettingExtractoroffJSONSerialization+[String: Any]casting toCodablemodels decoding fromData, collapseBuildSettingExtractor's three copies of the settings-JSON parse behind one sharedjsonSettinghelper, extractappendErrorIfNew/appendWarningIfNewinBuildOutputParserand a singleskipCommentOrStringscanner helper inPreviewExtractor(replacing the string/comment-skip triad duplicated at four sites), add apluralizedhelper andreserveCapacityinBuildResultFormatter, makeErrorExtractor'sonly_testingtarget-membership check O(1) via aSet, and drop anewestDateforce-unwrap inCoverageParser— behavior-preserving, 1455 tests green (#412) - Refactor
Sources/Core/AppBundle; parallelize per-frameworkcodesigninspection inCodeSignInspectorvia awithTaskGroup, dedupe the codesign-output parsing, and standardize path handling acrossAppBundlePreparerandIconManifest(#413) - Refactor
Sources/Core/Interactionfrom a/swiftreview pass; extract sharedAppleScript(oneescape— the two prior copies disagreed on escaping\n\r\t) andWindowList(typed wrapper overCGWindowListCopyWindowInfo) helpers plusSimctlRunner.findDevice, collapsing the duplicatedappleScriptEscape/resolveBootedDevice/ window-enumeration / focus-window-osascriptbodies acrossSimulatorUIInput,SimulatorKeyboardHelper, andWindowCapture; replace all six blockingusleepcalls inside theSimulatorUIInputactor withTask.sleepso they suspend instead of pinning a cooperative-pool thread; drop the per-sampled-pixelNSColorallocation inScreenRectDetectorby readingNSBitmapImageRep.bitmapDatabytes directly and cache oneCGEventSourceinstead of one per synthesized event; and renamebundleId/simulatorId/elementIdto…IDat all call sites (#416) - Refactor
Sources/Core/Locatorsfrom a/swiftreview pass; fix a path-prefix sandbox-escape bug where a rawhasPrefixboundary check let/base-evilpass the containment test for base/base(resolvePathURL/makeRelativePathnow go through anisPath(_:within:)that requires the match to land on a path separator), extractfindAncestorEntry(matching:startingFrom:)and anisWorkspaceBundlepredicate to dedupfindProjectPath/findWorkspacePath/findAncestorDirectory, migratePIFCacheReaderoff[String: Any]+JSONSerialization+ ~15as?casts to privateDecodableDTOs decoded through a genericdecodeEach(withthrows(Error)and a hoisted file-scope regex), and dropPIDResolver's redundantMainActor.runwrapper while renamingbundleId→bundleID(#417) - Consolidate
Sources/Core/ProjectFilepbxproj parsing from a/swiftreview pass; extract a sharedPBXProjParsing(oneproject.pbxprojreader,splitLines, and a single 24-char object-identifier test replacing four divergent implementations) reused acrossPBXProjTextEditor/PBXTargetMap/PBXProjReferenceAudit, add a statefulPBXProjEditorthat holds the file as[String]and applies edits in place — migrating the six tools that chain 2+ edits (add_frameworkalone chained 15) off the per-edit split/join so the whole batch splits and re-joins once, with the existing staticString -> Stringmethods kept as thin wrappers so single-edit callers and tests are unchanged — and micro-optimizegenerateUUID(viaString(unsafeUninitializedCapacity:)) andextractLeadingUUID(dropping an O(n) full-linecount); behavior-preserving (#418) - Refactor
Sources/Core/MCPfrom a/swiftreview pass; giveArgumentExtraction'sgetRequiredString/parseBatchTranslationEntriestypedthrows(MCPError)(converting acompactMapto areserveCapacity'd loop so the typed throw propagates) and extract a sharedstringValues(from:)reused bygetStringDictionaryand the batch-translation parser, replaceProgressReporter.ingest'schunk.split(...).reversed()with a backward-scanninglastNonBlankLine(in:)helper (no[Substring]allocation on the streaming hot path) and name the pollTask, cacheNextStepHints'JSONEncoderas astatic letinstead of per-renderedallocation, and renamebundleId→bundleID(#419) - Refactor
Sources/Core/Runnersfrom a/swiftreview pass; add a scopedBuildGuard.withGuardthat releases the cross-process lock fd viadeferon every exit path (replacing the manual acquire / do-catch / release triplets inSwiftRunner.run,XcodebuildRunner.run, and an extractedDetectUnusedCodeTool.runPeriphery), a sharedProcessResult.xcrun(_:arguments:)thatSimctlRunner/DeviceCtlRunner/XctraceRunnernow delegate to plus aProcess.xcrun(_:arguments:)factory for the unstarted-process cases (XctraceRunner.record,SimctlRunner.recordVideo), and anXcodebuildRunner.projectArgs(...)helper for the-workspace/-project+ scoped-derivedDataPathprefix duplicated acrossbuild/buildTarget/test/clean/listSchemes/showBuildSettings; hardenInteractRunnerby collapsing the double AX children fetch per element (getAttributestakes a precomputedchildCount; onechildren(of:)helper reused bytraverse/findChildByTitle/navigateMenu), replacingAXValue/AXUIElementforce casts withCFGetTypeID-guarded casts, and makingnavigateMenuasync viaTask.sleepinstead of blockingThread.sleep; plus lint hygiene — named the previously-unnamedTask/addTaskclosures (xcodebuild readers + watchdog, subprocess run/timeout, lldb command timeout), astaticJSONDecoderinSimctlRunner, and a documented@unchecked SendableonSendableAXUIElement(#420)
- Fix two flaky CI tests that tripped fixed time budgets under heavy parallel load (1422 tests) rather than any product bug;
SubprocessTimeoutGroupKillTestsnow sleeps600(effectively unbounded) inside the subprocess and asserts the kill returns under60sinstead of20s, decoupling the "did not hang" guard from natural command completion so cooperative-pool starvation can't trip it while a true hang still does, andSessionManagerWarmupTestsraises itswaitUntilCompletedpoll budget from15sto60s(a.background-priority warmup that completed in0.08swasn't observed within15son a saturated runner) and fixes the stale "within 2s" failure message (#405) - Stop
remove_targetfrom orphaning a dependent target's own outgoing dependency edge; removing a target (e.g. a unit-test bundle that depends on an app target) deleted the target and its incoming edges but left its outgoingPBXTargetDependency+PBXContainerItemProxyobjects behind, still pointing at the depended-on target — a pure orphan that the safe-write dangling-reference gate then used to refuse removal of that target;TargetGraphCleanup.removeReferencesnow also deletes the target's own outgoing dependencies and proxies and clears itsdependenciesarray (fixing bothremove_targetandremove_app_extension, which share the helper), andrepair_projectgained a garbage-collection pass that dropsPBXTargetDependencyobjects not referenced by any target (or whosetargetis gone) andPBXContainerItemProxyobjects not referenced by any dependency/reference-proxy (or whose remote object is gone), so a project already left in the orphaned state can be recovered without a git restore (#404) - Stop
remove_target(andremove_app_extension/remove_swift_package) from durably writing a project Xcode can't load; the real defect was incomplete cleanup leaving dangling object references —remove_targetleft aPBXFileSystemSynchronizedBuildFileExceptionSetand aTargetAttributesentry pointing at the deleted target, andremove_app_extensionorphanedPBXTargetDependencyobjects — none of which the post-op validator (which only re-scanned.xctestplan/.xcschemefiles) could catch; added a universalPBXProjReferenceAuditwired into theSafeProjectWritechokepoint that refuses any write introducing a dangling reference (delta-checked against the on-disk baseline so pre-existing and cross-projectremoteGlobalIDStringreferences never false-positive), centralized the cross-target teardown (dependencies + proxies, container proxies,TargetAttributes, exception sets) in a sharedTargetGraphCleanuphelper, and made the removers refuse-by-default when another target still references the one being removed (remove_targetgains an explicitcascadeflag;remove_swift_packagewithremove_from_targets=falsenow refuses rather than leaving a product dependency pointing at a deleted package);plutil -linthad passed the corrupt files because they were valid plists with only an internally-inconsistent object graph, and the huge diffs that masked the bug were cosmetic XcodeProj serializer churn, not data loss (#403) - Stop
remove_targetfrom leaving a project that won't load or crashing the server; the tool now cascades the removal to every.xctestplan(entry stripped viaTestPlanFile) and.xcscheme(owning wrapper element removed via newCore/SchemeTargetEditor, raw-XML editing rather than a lossyXCSchememodel round-trip) that still references the target, editing those cross-file references before the project file drops the target so no intermediate on-disk state ever points at a missing target, then re-scans every test plan and scheme as a post-op gate that fails on any surviving dangling reference; it also now removes thePBXBuildFiles that embed/link the target's product from other targets' build phases (and sweeps orphans) before serializing, since a build file left pointing at the deleted product tripped a force-unwrap in XcodeProj's serializer and trapped the process — tearing down the MCP connection (-32000: Connection closed) instead of surfacing as a normal error (#402) - Route every Xcode project mutation through a single durable-write chokepoint so a crash, kill, invalid serialization, or concurrent writer can no longer corrupt or clobber the shared
project.pbxproj; the newSafeProjectWritewrites bytes to a same-directory temp file,fsyncs, andrename(2)s over the original (so a crash leaves it byte-for-byte intact), serializes writers with an advisoryflockon a per-project lock file, validates the candidate withplutil -lintbefore promoting it (an invalid project is rejected and the original left untouched), preserves the original mode bits, and refuses the write with aconcurrentModificationerror when a caller passes the bytes it read and the file changed underneath it; both write paths (PBXProjWriterviaPBXProj.dataRepresentation,PBXProjTextEditor) now funnel through it — making all 49 mutation call sites atomic, validated, and lock-serialized — and the highest-risk tools (remove_target,add_target,remove_swift_package) capture the load-time bytes to refuse a stale-read clobber outright (#401)
- Extend
manage_type_identifierso identifier-less / malformed type declarations are manageable;update/removenow acceptmatch_description(byUTTypeDescription) ormatch_index(1-based, as shown bylist_type_identifiers) in addition toidentifier(precedence index → description → identifier), so a declaration missing itsUTTypeIdentifiercan be located, and passingidentifierwhen located by description/index backfills the key in place instead of orphaning the entry behind a new appended one; a newpruneaction removes every declaration in the chosen list missing a non-emptyUTTypeIdentifier(reporting which, and dropping the plist key when the list empties); and validation now requires a non-emptyidentifieronaddand refuses to leave an entry without aUTTypeIdentifieronupdate(#399) - Add
set_scheme_storekit_configtoxc-project(and monolithicxc-mcp); sets or clears a scheme's StoreKit configuration by writing/removing the<StoreKitConfigurationFileReference>child under a shared.xcscheme'sLaunchAction(Run) and/orTestAction(Test), withactionadd|remove andtarget_actionslaunch|test|both; theidentifieris computed as the.storekitpath relative to the scheme file (a repo-rootThesis.storekitbecomes../../../Thesis.storekit, matching Xcode's serialization) via a newSchemePathResolver.schemeRelativeIdentifier; idempotent (replaces an existing reference rather than duplicating), and it edits the scheme XML directly rather than round-tripping throughXCSchemebecause the XcodeProj model only represents the reference onLaunchAction, so a model round-trip would silently drop an existingTestActionreference (#398)
- Fix the broken simulator UI-automation tools (
tap/long_press/swipe/gesture/type_text/key_press/button); they shelled out tosimctl io <device> <tap|swipe|keyboard|button>, butsimctl iohas no input operations, so every call was a no-op that errored; replaced with a host-sideSimulatorUIInputactor that synthesizesCGEvents on the on-screen Simulator window — locating the device window viaCGWindowList, detecting the device-screen rectangle inside the title bar and bezel via projection profiles, and mapping device-pixel coordinates (thescreenshotimage space) onto global display points; typing connects the hardware keyboard and sends US-layout keycodes (ASCII), hardware buttons drive the SimulatorDevicemenu, and thescreencapture/osascriptsubprocesses run throughProcessResultfor cancellation safety; requires the Simulator window visible plus Screen Recording and Accessibility permissions (#396) - Drop the unsupported
OnFailurevalue fromset_test_plan_options'diagnostic_collection_policyenum; Xcode 26.2 only acceptsAlwaysandNeverforXCTHDiagnosticCollectionPolicy, and writingOnFailuremade the test plan unreadable ("String representation of XCTHDiagnosticCollectionPolicy was not a supported value"); the tool description no longer recommendsOnFailureand now suggestsNeverto cut per-test diagnostic overhead (#395)
- Add
set_test_plan_optionstoxc-project(and monolithicxc-mcp); edits a.xctestplan's per-configurationoptionsblock or plan-leveldefaultOptionsfor the keys the siblingSetTestPlan*Tooltools didn't reach —diagnosticCollectionPolicy(Always / OnFailure / Never),userAttachmentLifetimeanduiTestingScreenshotsLifetime(keepNever / keepAlways / deleteOnSuccess),codeCoverage, andmainThreadCheckerEnabled;configuration_nametargets a namedconfigurations[]entry while omitting it editsdefaultOptions, only the keys you pass are written (others left untouched), enum values are schema- and execute-validated, and acleararray resets keys to the plan default; reusesCore/TestPlanFile.swiftand also backfills the missingset_test_plan_target_parallelizableentry inServerToolDirectory(#394)
- Add
xcstrings_promote_literalstoxc-strings(andServerToolDirectory); promotes hand-typed localizable string literals to reusable manual String Catalog keys by addingextractionState = manualsource-language entries to the.xcstrings, deriving aSCREAMING_SNAKEkey (or accepting an explicit one) and reporting the camelCased Swift symbol Xcode 26 generates (e.g.NONE_SELECTED→.noneSelected) so call sites likeButton("Cancel")can be rewritten toButton(.cancel); reuses an existing key that already holds the same value and reports collisions when a key exists with a different value; parameterized values are supported (pass the format string, e.g."Add %1$(ordinal)@ citation", and the result includes the generated method signatureaddCitationToGroup(ordinal: String)); create-only — it does not scan or rewrite Swift sources (#392)
- Namespace xc-mcp's scoped
-derivedDataPathby platform soxc-build(macOS) andxc-simulator(iOS) builds against the same project no longer shareBuild/Products/Build/Intermediates.noindexand cross-link framework slices (thebuilding for 'macOS', but linking in dylib built for 'iOS-simulator'GRDB cascade);DerivedDataScopernow derives an SDK-style suffix (-macosx,-iphonesimulator, …) from the build destination,XcodebuildRunnerthreadsdestinationthroughbuild/buildTarget/test/showBuildSettings, every macOS read-back tool (GetMacAppPath,BuildRunMacOS,ProfileAppLaunch,DiffBuildSettings, thefindProjectRootdiagnostics, andShowBuildLog— which had been bypassing scoping entirely) passes the matching destination, andclean(derived_data: true)sweeps every per-platform sibling so one clean can't leave the other platform's contaminated cache behind (#391) - Fix four rough edges in the new-framework-module flow across
move_group/create_group/add_target/add_dependency;move_groupnow snapshots where every synchronized folder resolves on disk before a re-path or re-parent and rewrites each affected child'spathso it keeps pointing at the same directory (fixing the cascade that leftSources/Testsred after correcting a parent group's path), reporting how many children it preserved;create_groupappends aWarning:when a suppliedpath(relative to the parent group) resolves to a directory that doesn't exist, catching the doubled-prefix mistake (parent_group=Integrations, path=Integrations/GoogleDocs→Integrations/Integrations/GoogleDocs);add_targetsetsDEFINES_MODULE=YES/SKIP_INSTALL=YESon framework targets and gains acreate_groupboolean (default true) to skip the empty placeholder navigator group;add_dependencygains alink_binaryboolean that also adds the dependency's product to the target's Link Binary With Libraries phase for in-project dependencies (re-running links a dependency previously added without one); shared on-disk-path arithmetic extracted to a newOnDiskPathhelper (#393) - Fix two flaky CI tests;
raceTimeoutinSources/Core/ProcessResult.swiftis now deterministic — the deadline task raises a stickyTimeoutFlag(a copyableSendablebox around aMutex, so it crosses theaddTasksendingboundary) before killing the process group, so a post-killruncompletion can no longer win the task-group race and swallow theProcessError.timeoutunder parallel load;SessionManagerWarmupTestsdrops its explicit 5s poll override for the 15s default so the.background-priority warmup isn't starved on saturated runners (#390)
- Require positive evidence of build success in
BuildOutputParser; a build or test killed before any terminal marker (OOMKilled: 9, truncated stream) now reports a newincompletestatus instead of a false green,statusis reconciled against the aggregate failed-test count so it can never disagree withsummary.failedTests, and** TEST SUCCEEDED **/** TEST EXECUTE SUCCEEDED **/ parenthesizedBuild succeeded (…)/ xcbeautifyBuild Succeededmarkers are now recognized; ported from xcsift #73 (#389)
LLDBCommandTimeoutTestsreader-leak regression test flaked on CI when cooperative-pool starvation under parallel load delayed the nextsendCommand("version")past its tight 3s budget on a 5s-commandTimeout session; widened the sessioncommandTimeoutto 30s and the "reader didn't leak" budget to 15s so the binary leak signal (response silently swallowed → call wedges to the full timeout) still trips while absorbing CI variance (#372)- Add
search_test_planstoxc-project(and monolithicxc-mcp); given a project path and substring, walks every.xctestplanunder the project parent and reports the JSON path + matching value per hit (keys and stringified leaves), with an optionalcase_sensitiveflag — closes the rename-sweep gap where pbxproj/entitlements/Swift sites had bulk tools (find_build_settings, etc.) but test-plan JSON did not, forcing a per-fileReadloop just to confirm no plan still references an old bundle ID, scheme, or target name (#382) remove_targetleaves orphaned references inproject.pbxproj(#347)debug_evaluateuser-cancel on multi-line Swift expression with custom types (#384)mcp__xc-build__archivereported success but produced no.xcarchiveon disk; the no-output watchdog (added in #331) recognised the build-phaseBuild succeeded in …marker as terminal during an archive run and short-circuited a still-running install/codesign phase, returning exit 0 while xcodebuild was SIGKILL'd mid-install;outputShowsBuildFinishednow takes the xcodebuild argv and, whenarchiveis the action, only treats archive-specific markers (** ARCHIVE SUCCEEDED/FAILED **,Archive succeeded in …,Archive failed after …) as terminal;ArchiveToolalso verifies the.xcarchivebundle exists aftercheckBuildSuccessand throws a clear "reported success but no bundle on disk; retry with a larger timeout" error otherwise (#385)
- Add
set_framework_merge_attributetoxc-project(and monolithicxc-mcp); toggles the per-libraryMergePBXBuildFile attribute on entries inside a target'sPBXFrameworksBuildPhase(the flagMERGED_BINARY_TYPE = manualuses to pick which mergeable dependencies actually merge), matching SPMproductName, cross-projectPBXReferenceProxyname/path, or local framework path/last-component; preserves sibling attributes (e.g.Weak), refuses ambiguous matches, no-ops when already in the requested state;list_frameworks_phasenow appendsmerge=trueto entries whose ATTRIBUTES containsMergeso manual-merge setups are auditable without re-parsing pbxproj (#388) - Add
remove_build_settingtoxc-project(and monolithicxc-mcp); deletes a build setting key from a target's (or the project's)XCBuildConfiguration.buildSettingsdict for a given configuration (orAll), with a no-op + clear message when the key isn't present; closes the unset gap where the only options wereset_build_settingto an empty string (semantically different from unset) or hand-editingproject.pbxproj(#387) - Add
list_dependenciesandremove_dependencytools toxc-project; lists eachPBXTargetDependencyedge for a target with uuid,proxyType,remoteGlobalID,remoteInfo, andcontainerPortal, and drops a specific edge plus itsPBXContainerItemProxywithout touching the Frameworks build phase or the dependency target — closing the round-trip with the existingadd_dependency(#371) - Add
list_frameworks_phasetoxc-project; classifies eachPBXFrameworksBuildPhaseentry asfileRef,productRef,crossProject, ordangling, flaggingcrossProjectentries with no matchingPBXTargetDependencyedge as the link-only asymmetry that can produce duplicate build-graph nodes;validate_projectgrows a pairedcheckReferenceProxyWithoutDependencywarning (#373) - Extend
validate_projectwith two structural checks for duplicatePBXTargetDependencyedges and staleremoteInfoacross proxies pointing at the same target; the first groups a target's dependencies by resolved remote identity and warns on collapsed-edge collisions, the second flags rename-without-refresh proxies whose cachedremoteInfostrings disagree — both classes silently produce "Multiple targets in the build graph" failures, often only at archive time (#375) - Add
dump_pifandwhy_target_idtools toxc-projectplus a sharedPIFCacheReaderthat reads Xcode's on-disk PIF (Project Interchange Format) cache;why_target_idresolves a 64-char target hash (raw or from the fulltarget-<Name>-<hash>-SDKROOT:…error string) to the matching PIF target(s), surfacing duplicate-build-graph-node collisions plus the owning project and every consumer;dump_pifreturns a cache summary or scoped raw JSON for workspace/project/target inspection — no hash reproduction needed, the 64-char ID is the top-levelguidfield Xcode already writes to disk after every build (#374) - Teach
xc-project'sadd_dependencyto wire cross-project PBXTargetDependency edges; whendependency_nameisn't a native target of the consumer project, the tool now scansrootObject.projectsfor a referenced sub-.xcodeprojexposing a matchingPBXNativeTargetand synthesizes aPBXContainerItemProxy(containerPortal: .fileReference(<projectRef>), remoteGlobalID: .string(<remoteUUID>), proxyType: .nativeTarget)plus a target-lessPBXTargetDependency, eliminating the hand-edit that was previously required to add ordering edges likeCore → GRDBCustom; optionalcross_project_pathdisambiguates when multiple sub-projects expose the same target name (#376) - Add
export_archivetool toxc-build(and monolithicxc-mcp) that wrapsxcodebuild -exportArchive, synthesizingExportOptions.plistfrommethod/team_id/signing_style/provisioning_profiles/destinationand writing it next to the export output for inspection; rejects the deprecated pre-Xcode-16 method names (app-store,ad-hoc,development) with a hint pointing at the modern spelling, always passes-allowProvisioningUpdatesso missing distribution profiles regenerate on demand, and forwards-authenticationKeyID/-authenticationKeyIssuerID/-authenticationKeyPathwhendestination=uploadto deliver straight to App Store Connect — closes the archive → export → upload loop that previously dead-ended at the.xcarchivebundle (#386) - Add
archivetool toxc-build(and monolithicxc-mcp) wrappingxcodebuild archivewithgeneric/platform=macOSorgeneric/platform=iOS; defaults match Xcode Cloud's pre-archive flags (configuration=Release,code_signing_allowed=falseinjectsCODE_SIGNING_ALLOWED=NO/REQUIRED=NOplus emptyCODE_SIGN_IDENTITY/ENTITLEMENTS, optionalskip_macro_validationandskip_package_plugin_validation, 600s timeout); reuses theXcodebuildRunner.build(action: "archive", …)path so error parsing, partial-diagnostics formatting, and process-group lifecycle matchbuild_macos, unblocking local repro of archive-only failures (mergeable-library duplicate symbols, cross-platform module leakage) thatbuild_macos/build_simcannot reach (#377) - Add
find_build_settingstoxc-project(and monolithicxc-mcp); bulk-queries every native target in a single pbxproj load and returns each (target, configuration, setting) pair matching the requested setting names, with an optionalvaluessubstring filter andconfigurationscope; replaces the per-targetget_build_settingsloop pattern when auditingMERGEABLE_LIBRARY,MERGED_BINARY_TYPE,SUPPORTED_PLATFORMS,DEVELOPMENT_TEAM, orSWIFT_UPCOMING_FEATURE_*across an app and its frameworks (#378) - Add
find_link_flagandlist_run_script_phasestoxc-project(and monolithicxc-mcp);find_link_flagsubstring-searches every target'sOTHER_LDFLAGSand reports each(target, configuration, matching element)hit for diagnostics like stray-merge_frameworkor-Wl,-no_warn_duplicate_librariesinjected by mergeable-library wiring;list_run_script_phaseslists everyPBXShellScriptBuildPhaseacross targets with name, position,shellPath, inputs/outputs, file lists,runOnlyForDeploymentPostprocessing,alwaysOutOfDate,dependencyFile, and the full shell-script body, optionally restricted to a single target or filtered by a substring of the body (#379) - Extend
list_targetswith optional bulk filters (product_type,has_dependency,missing_dependency,has_settingwith optionalvaluesubstring,missing_setting) so a single call can answer audits like "every unit-test target lacking a dependency onThesisApp" or "every framework target whoseSUPPORTED_PLATFORMSis unset"; when any filter is supplied the per-target line upgrades from- name (productType)to- name [id=… productType=… dependencies=[…]]so callers don't need a pairedlist_dependenciesround-trip, while unfiltered output stays byte-compatible with the prior shape (#380) - Add
set_copy_files_phase_subpathtoxc-project(and monolithicxc-mcp); renames aPBXCopyFilesBuildPhase'sdstPathin place, locating the phase byphase_name,dst_path, or as the target's sole Copy Files phase, so a rename likedocx→DefaultStyles(mitigating the case-insensitive APFS collision between a framework binaryDocXand its siblingdocxresource folder during iOS archive) preserves the phase's identity, files, name, destination, and anyPBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSetlinkages instead of forcing a remove + recreate + relink sweep;remove_copy_files_phasegains the samedst_pathalternate identifier andphase_nameis now optional, making unnamed phases (common in auto-generated app-side Copy Files phases) addressable; sharedCopyFilesPhaseLocatorhelper centralizes the lookup (#383) - Add
XC_MCP_HEADLESS_LAUNCHenv var that suppresses focus-stealing GUI launches; when set to1ortrue,launch_mac_appandbuild_run_macospass-gtoopen(background launch, no foreground steal) andopen_simskips launchingSimulator.appentirely sincesimctl bootis sufficient forsimctl-driven automation; newFocusPolicyhelper inXCMCPCorecentralizes the env-var check and arg construction,open_in_xcodedeliberately bypasses the policy since surfacing a window is its purpose; ported from getsentry/XcodeBuildMCP commit59d5ca3e(#381) xc-project:scaffold_moduleshould handle public imports and access control (#196)- Add tool to extract and query Swift module symbol graphs (#218)
- Add macOS window interaction tools; scroll + click/type into a running app window (#349)
scaffold_*_project: use synchronized folder groups soadd_fileisn't needed for new sources (#286)- Port runtime UI-automation snapshot model (rs/1) from XcodeBuildMCP #416 to simulator tools (#332)
xc-project:add_targetgaps andscaffold_modulecomposite tool (#170)
scaffold_modulenow defaults to a nested navigator layout matching Apple's convention; a single modulePBXGroup(withpath = <name>) containsSourcesandTestssynchronized folders instead of two sibling root groups, with a newgroup_layoutparameter (nested|sibling) for opt-out; also adds amove_grouptool that reparents anyPBXGrouporPBXFileSystemSynchronizedRootGroupunder a different parent (optionally rewriting itspathattribute), so navigator hierarchy fixups no longer require hand-editing pbxproj (#361)- Support
PBXFileSystemSynchronizedGroupBuildPhaseMembershipExceptionSetinxc-project; newadd_synchronized_folder_phase_membershiptool opts files from a synchronized root group into a target's Copy Files (or other) build phase, locating the phase byphase_name→dst_path→ the target's sole Copy Files phase, auto-creating the exception set when missing, and surgically inserting/extending the pbxproj section via a newPBXProjTextEditor.insertGroupBuildPhaseMembershipExceptionSetBlockhelper;list_synchronized_folder_exceptionsnow also reports these phase-membership sets with phase name,dstPath,dstSubfolder, member files, andattributesByRelativePathinstead of printing "Unknown exception set type" (#358) - Extend
TestCrashDiagnosticsto recover libdispatch / abort-class crash causes;trapSignaturesandfatalLogPredicatenow also matchBUG IN CLIENT,Abort trap: 6,EXC_CRASH,SIGABRT,Swift runtime failure:, andAddressSanitizer/ThreadSanitizer/UndefinedBehaviorSanitizererrors, so atest_sim/test_macosrun that aborts on adispatch_assert_queueviolation or sanitizer trip surfaces the cause instead of falling back to "no fatal-error message was recovered" (#355) - Surface test-crash cause from
test_macos; when a test process dies with a bare signal trap rather than an assertion failure, a newTestCrashDiagnosticshelper detects the crash, scrapes SwiftFatal error:/Precondition failed:/ Objective-C exception lines from the captured test-host stderr, and queries the unified log (log show) scoped to the run's wall-clock window for fatal/exception messages, appending aCrash diagnosissection to the failure result (and pointing atshow_mac_logwhen nothing is recovered) (#351) - Surface elapsed wall-clock time in MCP build tool results, so a multi-minute build reports how long it actually took instead of leaving the caller to guess (#302)
- Add a
skip_buildparameter tobuild_debug_macosfor no-rebuild relaunch; when set, the tool skipsxcodebuildand goes straight to bundle preparation plus LLDB launch/attach, reusing the existing DYLD_FRAMEWORK_PATH / Launch Services activation so relaunching the same binary with newenv/argsis fast and reliable; errors clearly if no built product exists yet (#337) - Add a
set_test_plan_skipped_teststool that manages a.xctestplan'sskippedTestsexclusion list ("run everything EXCEPT these"), mirroringset_test_plan_skipped_tagsbut catching XCTest classes/methods that have no tags; takestests(a class/suite name orClass/method()), an optionaltarget_name(defaults to the plan'sdefaultOptions), andactionadd|remove, clearing the key when the last entry is removed; registered in bothxc-projectand the monolithicxc-mcp, and bothset_test_plan_skipped_tagsand the new tool were added toServerToolDirectoryso cross-server hints resolve (#354) - Add
set_test_plan_target_parallelizableto write the per-targetparallelizableboolean directly under each.xctestplantestTargetsentry (or onto plan-leveldefaultOptions.parallelizablewhentarget_nameis omitted); the canonical mitigation for Swift Testing's default parallel execution tripping libdispatch'sBUG IN CLIENT OF LIBDISPATCH: Block was expected to execute on queue [com.apple.main-thread]assertion in iOS app-hosted plans where a transitive XPC call (CloudKit,NSUbiquitousKeyValueStore,CoreSymbolication, …) dispatches a completion block to the main queue of a test host that isn't running a main runloop (#357) - Surface dyld load failures and guard against Team-ID signing mismatches; a new
CodeSignInspectorparsescodesign -dvvTeam IDs and flags ad-hoc/mismatched frameworks that dyld library validation will reject in a hardened-runtime app;build_debug_macosnow appends the consistency warning plus parsed crash-report termination reasons on the launch-crash path, so a dyld__abort_with_payloadshows the real "Library not loaded … different Team IDs" cause instead of a generic SIGABRT backtrace;AppBundlePreparerforces adisable-library-validationre-sign when an otherwise-unmodifiedskip_buildbundle has a Team-ID mismatch; anddebug_evaluate/debug_view_hierarchynow return a clear "process is running, interrupt it first" message instead of empty output on a running process (#345)
-
debug_view_hierarchybounded walks atmax_depth > 12produced no output file when the LLDB expression timed out; the in-target traversal expression opened/tmp/xcmcp-vh-<pid>.txtviafopen("w")(fully buffered) and streamed each node throughfputs, so an expression--timeoutabort discarded the stdio buffer beforefclose; now disables_fpbuffering viasetvbuf(_fp, NULL, _IONBF, 0)immediately afterfopenso each line reaches the kernel synchronously, leaving the partial walk on disk for inspection — making deep bounded walks usable on SwiftUI-heavy hierarchies (#369) -
detect_unused_code(Periphery) aborted with "Cannot calculate full path for file element …" on .xcodeproj files containing self-referencingprojectReferences; a new sharedSelfProjectReferencehelper detects entries whoseProjectRefresolves to the containing project and strips the file reference,projectReferencesentry, and empty Products group; wired intorepair_project(honoringdry_run),validate_project(flags each self-reference as an error pointing torepair_project), anddetect_unused_code(intercepts Periphery's raw error to name the offending self-reference and direct callers torepair_project) (#326) -
add_synchronized_folderstored the folder argument verbatim into thePBXFileSystemSynchronizedRootGrouppathwhen XcodeProj'sfullPath(sourceRoot:)silently returned nil (parent reference not wired or non-.groupsourceTreein the chain), doubling the on-disk path (e.g. under aSyncgroup withpath = Sync, a folder atSync/Sourcesgot stored aspath = Sync/Sourcesand resolved to<root>/Sync/Sync/Sources); the tool now walks the group hierarchy manually, accumulatespathattributes of.group-sourceTree ancestors, and trims that prefix so the stored path is relative to its parent group — matching what Xcode emits via the IDE (#360) -
MCP server stdio transport dies after request cancellation due to stale
notifications/progresswrites; oncenotifications/cancelledarrives the server must skip all responses, retire its progress reporters synchronously, ignoreSIGPIPEprocess-wide, and rethrowCancellationErrorunchanged through the catch-all error wrapper so the SDK's cancellation arm fires; subprocesses now spawn in their own process group and are SIGKILLed as a group on cancel so SPM build-plugin grandchildren can't hold the pipes open (#300) -
debug_lldb_command(e.g.thread backtrace) hangs when the process is stopped at a breakpoint; added a timeout so a stopped-process command can no longer wedge the debug session (#333) -
build_debug_macosbuilds successfully but never launches the app; afterxcodebuildprints** BUILD SUCCEEDED **, grandchild daemons (SwiftPM resolver, build-system services) inherit and hold its stdout/stderr pipes open, soXcodebuildRunner's stream readers never finish and the 30s no-output watchdog firedXcodebuildError.stuckProcess, aborting the tool before the launch/attach step; the watchdog now recognizes a finished-build marker in the collected output and recovers it into a normalXcodebuildResult(exit code derived from the output) instead of erroring; also repaired the staletest-debug.shharness to build the multicallxc-mcpproduct and invoke it via anxc-debugsymlink (#331) -
build_debug_macoshangs in LLDB attach/teardown; orphanedlldb-rpc-serverwedges next launch;lldbspawnslldb-rpc-serveras a child that survives a SIGKILL oflldb(reparents to launchd), and several teardown paths leaked it;LLDBSession.terminate()now captureslldb's direct child PIDs viapgrep -Pbefore killing and SIGKILLs survivors;detach(pid:)treats a wedged-target timeout as partial success and always tears the session down; the launch path terminates the session on any error or cancellation mid-attach (#330) -
add_synchronized_folder_exceptiontargeted the wrongPBXFileSystemSynchronizedRootGroupwhen multiple synchronized folders shared the same leafpath(e.g. every module has aSourcesfolder), silently attaching the exception set to the first match instead of the one bound to the named target;SynchronizedFolderUtilitynow records each sync group's full project path and resolves by leaf, full path, or trailing-component suffix, narrows candidates to the target'sfileSystemSynchronizedGroups, and errors on unresolved ambiguity;add_,remove_, andlist_synchronized_folder_exception(s)all route through the resolver so full paths likeCore/Sourcesdisambiguate shared leaf names (#334) -
WaitForProcessExitTestsflaked in CI under parallel load;waitForProcessExitpolls withTask.sleepon the Swift cooperative thread pool, which the full 1166-test parallel run starves via blocking calls in other suites, delaying the poll loop past the tests' tight detection budgets; gave the two exit-detection tests generous 15s timeouts and loosened theTimeout is boundedupper-bound assertion to 15s (it only needs to prove the call doesn't hang indefinitely); test-only change, no behavior change towaitForProcessExit(#336) -
build_debug_macoscold-rebuilt on every call; a relativeproject_path(e.g."Thesis.xcodeproj") was resolved against the server's live cwd lazily at build time, so cwd drift between calls hashed the same project to a different scopedDerivedData/<name>-<hash>root (sometimes a bogusjason-<hash>), defeating cache reuse;SessionManagernow resolves project/workspace/package paths to a stable absolute path at input time insetDefaults,resolveBuildPaths, andresolvePackagePath(idempotent for absolute paths, normalizing any legacy relative values), so the same logical project always hashes to the same scoped root (#338) -
Debug tools hung indefinitely when stopped at a conditional breakpoint on a high-frequency symbol; a breakpoint on a hot symbol (
sqlite3_prepare_v2) with an inferior-function-calling condition floods LLDB's PTY faster than a(lldb)prompt ever returns, so the reader thread spun a CPU core and starved the cooperative pool, leaving the 30s timeoutTaskunscheduled (a >1h wedge);LLDBRunner.readUntilPromptnow stops the reader the instant any path resolves the continuation and enforces a 1 MB output cap that aborts with a structured error and poisons the session, bounding every command that routes through it (debug_process_status,debug_stack,debug_threads,debug_lldb_command); a newBreakpointConditionAdvisorwarnsdebug_breakpoint_add/debug_lldb_commandwhen a breakpoint targets a hot symbol or its condition calls inferior functions (strncmp,strstr); and a newdebug_capture_backtracetool sets an auto-continuing breakpoint that captures stacks non-interactively (bounded by timeout and the output cap) as the safe alternative to hand-rolling a conditional breakpoint on a hot symbol (#339) -
Flaky high-frequency symbol advisor warning due to
Setiteration order;BreakpointConditionAdvisor.matchedHighFrequencySymbolmatched a breakpoint target against thehighFrequencySymbolsSetwithfirst(where: exact || contains), sosqlite3_prepare_v2could resolve to the substring entrysqlite3_prepareinstead, depending on Swift's per-processSethash seed; the matcher now prefers an exact match and only falls back to the longest contained symbol, making the result deterministic regardless of hash seed (#341) -
Debugger (
xc-debug) breakpoints vanished, the run/stop state desynced, andselfwouldn't resolve at a breakpoint on macOS apps; aftercontinue(sent viasendCommandNoWait) a breakpoint hit emitted an async stop notification that nothing drained, so the tracked state stayed.runningandrequireStoppedwrongly rejecteddebug_stack/debug_variables/debug_evaluate— the resulting timeout poisoned and recreated the session, which is what made breakpoints disappear and compound commands hang;LLDBSession.syncedProcessState()now drains the PTY when state is.runningso a process parked at a breakpoint is reported stopped,debug_evaluategained optionalthread/frameparams soself/locals resolve against the breakpoint frame instead of a run-loop frame inmach_msg2_trap, andattach()now detectsalready being debuggedand reports the target is under another debugger (and did not exit) rather than relaying LLDB's misleadingexited with status = -1(#342) -
build_debug_macosmergeable-library debug builds crashed at launch with a dyldSymbol missing; withMERGEABLE_LIBRARY=YESXcode embeds a thin reexport stub (~51 KB, no exported symbols) intoContents/Frameworksthat shadows the full framework (~20 MB), so the app'sLC_REEXPORT_DYLIB @rpath/…lookups resolved against the stub and dyld reported the symbol missing self-referentially;AppBundlePreparernow detects such stubs by binary-size delta and replaces them with a symlink to the full framework fromBUILT_PRODUCTS_DIR, and also symlinks SPM package-product frameworks from thePackageFrameworks/subdirectory (a secondLibrary not loadedfailure that surfaced once the stub was fixed) before re-signing the bundle (#344) -
start_mac_log_cap/show_mac_logcouldn't target a debug build whose process name contains spaces and parentheses (e.g.ThesisApp (debug)frombuild_debug_macos); the strictprocess_namevalidator rejected it outright andbundle_idmatching fell back to the last dot-component (com.thesisapp.debug→debug), silently capturing zero lines; addedPredicateFilterValidator.validateStringLiteral(permits spaces/parens, rejects only empty/newline/control characters) andescapeStringLiteral(escapes\then"so a value stays a single quoted predicate literal and quote-injection is neutralized rather than rejected), and routedprocess_namethrough them in both tools (#335) -
debug_view_hierarchystill timed out and poisoned the LLDB session on a running macOS app (apcm-bwnregression); the interrupt→eval→resume path landed but never bounded the evaluation itself, so an AppKit call like_subtreeDescriptioncould block past the 30s read-level timeout, which then poisoned the whole session and cascaded into every later debug call; tool-built objc expressions now carry LLDB's own--timeout(15s, plus--unwind-on-error/--ignore-breakpoints) via a sharedobjcExprCommandbuilder, so LLDB self-aborts a hung inferior call and returns a clean prompt well before the read timeout fires — a slow dump now fails the single call instead of wedging the session; routedviewHierarchy,toggleViewBorders, andevaluatethrough the bounded builder (#348) -
test_simappeared to hang on long cold iOS rebuilds and had to be cancelled manually;XcodebuildRunner.runProcessspawnedxcodebuildwithout its own process group and, on timeout/stuck, only sentSIGTERMto the parentxcodebuild, which ignores it and leavesswift-frontend/ build-system grandchildren running; those grandchildren hold the stdout/stderr pipes open, so the stream readers never see EOF, the watchdog's timeout throw can't propagate, and the call hangs (a cold build's steady progress output also keeps theoutput_timeoutsilence window from elapsing, leaving the wall-clocktimeoutas the only backstop — and that backstop was the one that wedged);xcodebuildnow runs as a process-group leader and the watchdogSIGKILLs the whole group on timeout, stuck-detection, and external cancellation, andProcessResult.runSubprocessclosed the same latent gap so itstimeoutpathSIGKILLs the group synchronously instead of relying on Subprocess's parent-onlySIGTERMteardown (#350) -
Runtime inspection returned empty output or timed out on a running macOS app;
debug_view_hierarchy,debug_evaluate, and rawexpr/poviadebug_lldb_commandall need a stopped process, but a running target silently yields empty output or blocks until the 30s command timeout; a newLLDBRunner.withProcessStoppedhelper transparently interrupts a running process, evaluates, then resumes it (resuming even on failure so a transient error can't freeze the app), while a process already stopped at a breakpoint is left untouched;debug_evaluateanddebug_view_hierarchyroute through it (appending an auto-resume note when they paused the app),debug_lldb_commanddetects expression-eval commands (expr/po/p/print/call) and does the same, and the macOS view-hierarchy dump now falls backmainWindow→keyWindow→ first window instead of returning nil for a backgrounded app (#346) -
set_test_plan_skipped_tagsdropped"mode": "or"when adding to an existing per-targetskippedTagsblock, so the block silently fell back to AND semantics and the per-target skip list no-opped (no real test carries every listed tag at once); the per-target write path now preserves an existingmodeand defaults to"or"when none is set — matching plan-leveldefaultOptionsand Xcode's own authoring behavior; the prior fix had inverted the rule and a test assertedmode == nil, locking the bug in, so the assertion was corrected and a regression test exercising the exact repro was added (#356) -
test_sim/test_macos/test_devicestreamed no progress, so a long cold rebuild was indistinguishable from a hang and clients cancelled it manually;XcodebuildRunner.test(...)hardcodedonProgress: nil, dropping every output line the stream readers already received; threaded an optionalonProgresscallback throughXcodebuildRunner.test,TestToolHelper.runAndFormat, and the three test tools'execute, and wired each test handler in the monolithicxc-mcpplus thexc-simulator/xc-build/xc-deviceservers to wrap the call in aProgressReporterwhen the client passes aprogressToken(reusing the cancellation/retirement semantics fromswift_package_test), so a cold test run now streams its latest build/test line every ~2s (#353) -
interact_*tools were unreachable from focused-server clients; the eight macOS Accessibility tools (interact_click,interact_set_value,interact_key,interact_focus,interact_menu,interact_get_value,interact_find,interact_ui_tree) were registered only on the monolithicxc-mcpbinary, so any client wired toxc-debug/xc-build/ etc. sawscreenshot_mac_windowbut no input path — forcing agents into anosascriptfallback that's blocked by the accessibility-permission gate; surfaced the eight tools throughxc-debug(alongsidescreenshot_mac_windowand the LLDB view tools, since they share the build → launch → drive → screenshot loop), and added them toServerToolDirectoryso cross-server hints from other focused servers point atxc-debug(#359) -
build_sim/build_run_simlikewise streamed no progress on a cold build; their tools took noonProgressand the server handlers called them bare, so the build phase looked hung;BuildSimTool.execute/BuildRunSimTool.executenow accept an optionalonProgressand forward it toxcodebuildRunner.build(...), and thebuild_sim/build_run_simhandlers inxc-mcpandxc-simulatorwrap the call in aProgressReporterwhen aprogressTokenis supplied (#352) -
debug_view_hierarchy'stimeoutargument only raised the read-side timeout while the embeddedexpr --timeoutstayed pinned at 15s, so atimeout: 120call against a SwiftUI-heavy hierarchy still timed out at 15s and left the targetSIGSTOP'd;ArgumentExtraction.getDoublenow accepts JSON integer values in addition to.double(the client sends120not120.0, so the integer was discarded and the embedded--timeoutfell back to the hardcoded default), andLLDBRunner.withProcessStoppednow sendsSIGCONTunconditionally on the error path in addition to the queuedcontinue(the fire-and-forget poisoning Task races with the catch block, sosendCommandNoWaitcould succeed without actually resuming the inferior) (#363) -
debug_view_hierarchybounded walk still hung against macOS SwiftUI hierarchies even after theeka-s03/h0c-60ytimeout-propagation fix; recent LLDBs silently promoteexpr -l objcto Objective-C++ ("Expression evaluation in pure Objective-C not supported"), and in that mode variadic ObjC selectors likeappendFormat:won't parse beyond a single argument without Foundation in scope, so the bounded-traversal expression was failing at compile time and the "hang" wasxc-debugwaiting for a prompt that never came; the macOS expression now prepends@import Darwin; @import Foundation; @import AppKit;(Darwin brings<stdio.h>), and a parallel file-streaming variant emits per-node lines through libcfputsinto a host-readable/tmp/xcmcp-vh-<pid>.txtso the dump never has to travel back across the LLDB IPC; the same expression is ~2 KB, which silently stalls when stuffed through the PTY in raw mode, so the tool now writes theexprcommand to a temp.lldbscript and runscommand sourcewhenever the command exceeds 512 bytes, keeping only a short line on the PTY (#364) -
debug_view_hierarchy/debug_evaluatefailed withsession is poisoned by a previous timeouton the very first call after a freshbuild_debug_macoslaunch;LLDBSession.readUntilPromptmarked the session poisoned on every failure path (timeout, >1 MB flood), butdrainPendingOutput,checkForEarlyCrash, andinterruptProcess's stop poll all wrapped the read intry?to advertise tolerated failure, so a speculative drain that wedged on unterminated PTY data silently invalidated the freshly-launched session before the caller ever touched it;readUntilPromptnow takestimeout:/poisonOnFailure:parameters and the three tolerant call sites passpoisonOnFailure: falsewith a 2 s bound;markPoisonednow takes areason:and logs at warning level on the first transition so a still-unknown upstream trigger (hot inferior call, async stop without a trailing prompt) surfaces in stderr instead of being swallowed (#366) -
debug_evaluatehung after the auto-interrupt step when the inferior's main thread was parked in an uninterruptable syscall;LLDBSession.interruptProcesssilently fell back to "assume stopped" when the async stop notification didn't arrive in 5 s, so the follow-upexprwas dispatched against a still-running target and wedged LLDB's expression evaluator with no(lldb)prompt produced; added an opt-inrequireExplicitStopparameter that cross-checks viaprocess status(accepting a stopped state even when the notification is delayed) and throws a structured error otherwise, a non-poisoningsendCommandSpeculativehelper, and a JIT/runtime warmup (expression -- (int)0) after auto-interrupt to prime ObjC bridge resolution before the user's AppKit-touching call;withProcessStoppedopts into both; the partial-output timeout inreadUntilPromptnow identifies an echoed-expr-without-prompt as an expression-evaluator hang and points at TCC syscall wedge / JIT bridge resolution; added a self-containedlul-evz-fixturetotest-debug.sh(busy SwiftUI app + main thread parked inThread.sleep→__semwait_signal) that reproduces the failure without depending on an external project, and the harnessEXITtrap now kills the inferior PID before tearing down the server soevaluatemode no longer leaves stray windows on the desktop (#368) -
debug_evaluate/debug_view_hierarchystill timed out with "no output received" on the very first call after a freshbuild_debug_macoslaunch (a regression-shaped repeat ofrgu-xhg);LLDBSession.readUntilPrompt's GCD reader called blockingFileHandle.availableDataand the timeout path resumed the continuation without waiting for the reader to exit, so a tolerated 2 sdrainPendingOutput/checkForEarlyCrashread left the reader thread blocked on the PTY pastreadUntilPrompt's return; the next command's reader then raced the leaked reader for response bytes on the shared fd, and the leaked reader would consume them and discard them on its stalefinishedflag, leaving the next caller blocked until its 30 s window expired and SIGSTOP'd the inferior; the reader now usespoll()+ non-blockingread()with a 50 ms tick so it can noticefinishedpromptly, and the timeout path waits up to 500 ms for the reader'sreaderDoneflag before resuming the continuation, guaranteeing no leaked reader survives pastreadUntilPrompt's return; added aLLDBCommandTimeoutTestsregression test that exercises the tolerated-timeout-then-next-command flow, plus a self-containedevaluatemode intest-debug.sh(with at57-fixturescaffold that builds a tiny SwiftUI app under.build/, so the repro doesn't depend on any external project) (#367) -
debug_view_hierarchypoisoned the LLDB session on macOS apps with SwiftUI hosting views;_subtreeDescriptionon anNSHostingViewtree could overrun the 15s expression timeout or hit the 1 MB flood guard, wedging every subsequent debug call until the app was relaunched; addedmax_depth,class_filter, andtimeoutparameters that route through a new bounded stack-basedNSView/UIViewtraversal (one line per node with class, address, and frame, capped at 20 000 nodes) so SwiftUI-heavy hierarchies finish well under the expression budget;LLDBSession.objcExprCommandnow takes an optional per-calltimeoutMicroseconds, the per-command read timeout is raised to match and restored after the dump, andwithProcessStoppedfalls back toSIGCONTwhen the post-bodycontinuecan't reach a session that was poisoned mid-body, so the user's app no longer staysSIGSTOP'd after a timeout (#362)
- Apply medium-priority
/swiftreview fixes inSources/Core; extendedSimctlRunner.setStatusBarwithcellularMode/wifiModeparameters and deleted the weakly-typedoverrideStatusBar(udid:options: [String: Any])variant soSimStatusBarToolcalls through named arguments instead of a[String: Any]dictionary; modernizedSessionManager's warmup launch fromTask.detachedtoTask.immediateDetachedso the background warmup starts synchronously off the actor without a scheduler hop (same detached.backgroundsemantics); also fixed an emptyswitchcase inPredicateFilterValidatorthatsm formathad introduced by stripping the trailingcontinue(#365) - macOS
interact_*tools now settle the accessibility tree after a mutating action and return the refreshed UI tree inline;interact_click,interact_set_value,interact_focus,interact_menu, andinteract_keypoll viaInteractRunner.settledUITreeuntil two consecutive structural snapshots match (or an 800ms timeout), refresh theInteractSessionManagerelement cache, and append the settled tree so the next step gets stable element IDs without a separateinteract_ui_treecall;interact_menu/interact_keybecameasyncandinteract_keygained optional app-resolution args (only snapshots when a target app is named, sinceCGEvents post globally); simulator UI automation tools are unchanged (no accessibility tree source, coordinate input doesn't go stale); ported fromXcodeBuildMCP#427 (#343)
xcstrings: addxcstrings_check_untranslatedtool with state-aware detection; existingxcstrings_list_untranslatedonly checked presence and silently missed empty values,needs_reviewstate, and partial plural/device variation coverage; new tool returns structuredUntranslatedIssuerows with areasonenum (missing_localization,empty_value,state_not_translated,missing_variation_string_unit,empty_variation_value, etc.) across one file × N languages; ported fromRyu0118/xcstrings-crudPR #33 (#323)- Add a shared
NextStepHintshelper inSources/Core/NextStepHints.swiftthat renders a sortedNext steps:block of suggested follow-up tool calls in MCP'stool({ key: "value", ... })syntax; wired intodebug_attach_sim(suggestsdebug_breakpoint_add/debug_continue/debug_stackkeyed by the resolvedpid),get_coverage_report(suggestsget_file_coveragetargeting the weakest-covered file), andget_file_coverage(suggestsget_coverage_report); usesJSONEncoderwith.withoutEscapingSlashesso file paths render cleanly; ported fromXcodeBuildMCPPR #420 (#325) - Stream
build_debug_macosbuild output to the MCP client vianotifications/progress; the build's progress lines now flow through aProgressReporter(reusing the cancellation/retirement semantics already used byswift_package_build/swift_package_test) when the client passes aprogressToken, so a multi-minute cold build is no longer indistinguishable from a hang (#328)
- Speed up
build_debug_macoslaunch by narrowing the pre-build-showBuildSettingspass; the macOS destination (platform=macOS[,arch=…]) is now passed toshowBuildSettingssoxcodebuildresolves only the macOS platform's settings instead of the entire SPM package graph for every target; falls back to a destination-less pass when an iOS-only scheme yields no settings so the friendly "scheme does not support macOS" error is preserved; also documents theXC_MCP_DISABLE_DERIVED_DATA_SCOPING=1escape hatch in the tool description for the single-agent "just built in Xcode, now run under LLDB" workflow (#329) - Detect and remove self-referencing sub-project entries that block Periphery scans; a
projectReferencesentry whoseProjectRefpoints at the containing.xcodeproj(a project nested inside itself) makesdetect_unused_codeexit withCannot calculate full path for file element; new sharedSelfProjectReferencehelper finds and strips the file reference, theprojectReferencesentry, and the empty Products group;repair_projectremoves them (honoringdry_run),validate_projectflags each as an[error]pointing torepair_project, anddetect_unused_codenow intercepts Periphery's raw error to name the offending self-reference and direct the caller torepair_project(#327)
detect_unused_code: add passthroughretain_equatable_properties/retain_hashable_propertiesboolean params for periphery's newEquatableHashablePropertyRetainermutator; suppresses false positives on stored properties of value types (struct/enum) where compiler-synthesized==/hash(into:)don't emit index references; defaults tofalse(matching periphery defaults); requires periphery with PR #1126 (post-3.7.4) (#324)
- Validate
bundle_id,subsystem, andprocess_nameagainst a strict allowlist (A-Z,a-z,0-9,.,-,_) before interpolating intoNSPredicatestrings passed tolog stream/log show; coversstart_sim_log_cap,start_mac_log_cap,show_mac_log, andlaunch_app_logs_sim; prevents predicate injection (CWE-78) where abundle_idcontaining"could leak logs from unrelated subsystems or break the predicate parser; the explicitpredicateparameter remains as the escape hatch for callers that need raw NSPredicate syntax; ported fromXcodeBuildMCPPR #407 (#322) - Audit
debug_attach_simforbundle_idvspidmutual-exclusion bug from session defaults; ported fromXcodeBuildMCPPR #411; confirmed not applicable to xc-mcp (SessionManagerdoesn't storebundle_idas a default andDebugAttachSimToolhas no mutual-exclusion validation that could falsely reject); addedDebugAttachSimToolTestswith aMirror-based contract test that will fail if a future change adds abundleId-like session field (#321)
- Auto-create workspace-scoped
.xcresultbundles for test tools; auto bundles now live under~/Library/Caches/xc-mcp/TestResults/<Project>-<hash>/<UUID>.xcresultand persist across runs (opportunistic 7-day prune); replaces the previous$TMPDIR+ immediate-defer-delete behavior so callers can open the bundle in Xcode or feed it to coverage / attachment tools; opt-out viaXC_MCP_DISABLE_TEST_RESULTS_SCOPING; ported fromXcodeBuildMCPPR #401 (#312) - Surface the
.xcresultbundle path in test tool output;formatTestToolResultnow appendsResult bundle: <path>to both the success text and the failure error message when the bundle exists on disk; ported fromXcodeBuildMCPPR #397 (#313) xcstrings: surface NFKC-equivalent key suggestions on lookup failure;XCStringsError.keyNotFoundnow carriessuggestions: [String]andxcstrings_check_keyreturnsfalse (key not found; did you mean: '…'?)so APOSTROPHE U+0027 vs RIGHT SINGLE QUOTATION MARK U+2019 substitutions are no longer silent; uses NFKC plus an explicit curly-quote fold since pure NFKC does not unify those codepoints; ported fromRyu0118/xcstrings-crudPR #29 (#315)
SwiftSymbolsTool: cache decodedSymbolGraphin a private actor keyed by(module, platform, sdkPath, triple); three parallelSwiftSymbolsToolTestswere racing three concurrentswift-symbolgraph-extractinvocations on the GitHub Actions runner and all blew past the tool's 60s subprocess timeout; with cache + inflightTaskdedup, only one extraction runs per key and concurrent callers await the sameTask; also benefits production sessions that query the same module twice (#310)SessionManagerWarmupTests: replace fixedsleep(500ms)with a poll-for-.completedloop (5s cap) plus a 100ms grace window; fixes a CI flake where the warmup ran at.backgroundpriority and was deferred under runner starvation, leavingrunCount == 0when the assertion fired; production dedup needs no change sinceSessionManageris apublic actorandtriggerWarmupIfNeededis already atomic (#311)xcstrings: respectshouldTranslate: falseentries; non-translatable keys no longer count againstlistUntranslated,checkCoverage, orgetStatscoverage totals; ported fromRyu0118/xcstrings-crud@9803d77(#308)xcstrings: preserveisCommentAutoGeneratedmetadata across save/load; previously dropped on write, causing Xcode to re-evaluate auto comments (#307)xcstrings: sort keys withlocalizedStandardCompareand write in Xcode's on-disk format ("key" : value, sorted nested keys, top-levelsourceLanguage/strings/versionorder) so round-trip diffs against Xcode-saved catalogs are clean (#306)SwiftSymbolsTool: bumpswift-symbolgraph-extractsubprocess timeout60s→180sand raise the threeSwiftSymbolsToolTestsintegration tests'.timeLimit2min→5min; theSymbolGraphCachededup landed in #310 was working (single shared inflight task) but cold-cache extraction of theTestingmodule on the GitHub Actions runner still exceeded 60s (#314)xcstrings: stop escaping forward slashes in encoder output;XCStringsFileEncodernow configuresJSONEncoderwith.withoutEscapingSlashesso catalogs containing strings like"Domestic / Foreign"round-trip without\/noise; ported fromRyu0118/xcstrings-crudPR #30 (#316)clean(derived_data: true)now wipes xc-mcp's scoped DerivedData (the path actually passed to-derivedDataPath) in addition to matching entries in Xcode's standard DerivedData; previously it cleared only~/Library/Developer/Xcode/DerivedData/while builds kept reading stale macro-expansion artifacts from~/Library/Caches/xc-mcp/DerivedData/<Project>-<hash>/(#320)
- Migrate
swift_lint/swift_formatMCP tools and theswift_diagnostics/diagnosticslint step fromswiftlint/swiftformat(Lockwood) tosm(swiftiomatic); consume the newsm lint --reporter jsonandsm format --reporter jsonenvelopes so xc-mcp parses structured{file, line, column, severity, rule, message}violations and{changed, unchanged, skipped}format summaries instead of regex-matching plain stdout; tool namesswift_lint/swift_formatkept stable, diagnostics param renamedinclude_lint→run_lint; drops Lockwood-vs-Apple discrimination fromBinaryLocatorand removes legacy.swiftlint.yml/.swiftformatdiscovery (smfinds its own configuration) (#318) - Bump
tuist/xcodeproj9.10.1→9.12.0; pulls in additiveXCBuildConfigurationsupport for xcconfigs insidePBXFileSystemSynchronizedRootGroup(Xcode 16+); auditedXcodeBuildMCPPR #390 shell-injection sites and confirmed xc-mcp reads Info.plist via in-processPropertyListSerializationso the analogous surface doesn't exist here (#309) - Audit launch-arg vs
xcodebuildextra-args separation againstXcodeBuildMCPPR #403; confirmed ourargsparameter is consistently routed to launch-time use across all 7 build/run/launch tools andxcodebuildadditional arguments come from narrowly-scoped session helpers; no conflation, no breaking change needed (#317)
- Auto-scope
xcodebuild-derivedDataPathto~/Library/Caches/xc-mcp/DerivedData/<Project>-<hash>; prevents concurrent build collisions when multiple xc-mcp sessions target the same clone; opt-out viaXC_MCP_DISABLE_DERIVED_DATA_SCOPING(#289) - Add
toggle_software_keyboard/toggle_hardware_keyboardsimulator tools; toggle the simulator's on-screen keyboard via Cmd+K / Cmd+Shift+K through AppleScript (#293) - Surface slowest passing tests in test output via
XC_MCP_SHOW_TEST_TIMING; previously hidden when total > 50 with failures (#291) - Pre-warm SwiftPM cache on
set_session_defaults; spawn a backgroundswift build --build-testswhen the cache is cold; auto-cancel when the user runsswift_package_*; opt-out viaXC_MCP_DISABLE_WARMUP; status visible inshow_session_defaults(#296) - Stream
swift_package_buildandswift_package_testprogress to MCP clients vianotifications/progress; throttled last-line snapshots so long swift-syntax compiles no longer look like hangs; activated when the client passes aprogressToken(#298)
- Expand leading
~in user-supplied paths;set_session_defaultsand per-callproject_path/workspace_path/package_patharguments now resolve~/Developer/foo.xcodeprojcorrectly (#292) - Prevent MCP server disconnect when cancelling a long-running build/test; spawn child processes in their own process group and
SIGKILLthe whole group on cancel so SPM build plugins and grandchildren release the stdout/stderr pipes (#294) swift_package_test/swift_package_buildno longer abort after 5min on a cold cache; auto-extend timeout to 15min when.build/checkoutsis empty; timeout errors now include the package path and a cold-cache hint (#295)- Stop MCP stdio transport from dying on user-cancel during long builds;
ProgressReporternow retires synchronously viawithTaskCancellationHandlerso the unstructured poller can no longer emit a stalenotifications/progressafter the request is cancelled (#300) - Keep the xc-swift (and every focused) MCP server alive when the client half-closes the stdio pipe after a user-cancel; install
signal(SIGPIPE, SIG_IGN)in the multicall entry point so a stale write returns EPIPE instead of terminating the process; also cancelProgressReporter's poll task synchronously fromonCancel(#303) - Preserve full multi-line
Comment(rawValue:)bodies inswift_package_testfailures; the parser now keeps consuming bare indented continuation lines after the first/↳detail marker soassertStringsEqualWithDiff-style diffs reach the agent intact (#304) - Stop xc-swift MCP server from disconnecting after a user-cancelled
swift_package_build/swift_package_test;Swift.Error.asMCPError()nowthrowsand rethrowsCancellationErrorunchanged so the SDK skips the response per the MCP cancellation spec, instead of emitting anMCPError.internalErrorthat Claude Code treated as a protocol violation and tore the stdio pipe down for (#305)
- Review XcodeBuildMCP commits for features to incorporate (#290)
- Investigate
-experimental-skip-non-inlinable-function-bodiesfor swift-syntax compile speedups; benchmarked at 2% on swiftiomatic; not adopted by default; addedXC_MCP_SWIFT_EXTRA_ARGSenv var for opt-in experimentation (#299)
- Surface verbose compiler output on signal crashes;
swift_package_buildandswift_diagnosticsauto-retry with-vto identify the crashing file and compiler backtrace (#283) - Add
remove_run_script_phasetool; removePBXShellScriptBuildPhasebuild phases from a target by name; refuses to remove ambiguous matches; cleans up orphaned build files (#284)
add_package_product: detect SPM plugin products from localPackage.swiftand skip the Frameworks build phase; addkindparameter (auto|library|plugin) for explicit override (#287)add_package_product: wire thepackagefield onXCSwiftPackageProductDependencyfor products not yet linked to any target; addpackage_url/package_pathparameters; discover owning package via localPackage.swiftcheckouts (#288)
- Add
swiftiomatic-pluginsbuild-tool plugin for self-hosted lint-on-build; apply toXCMCPCore,XCMCPTools, and thexc-mcpexecutable (#285)
- Add 9 Icon Composer tools (
create_icon,export_icon,read_icon,add_icon_layer,remove_icon_layer,set_icon_fill,set_icon_effects,set_icon_layer_position,set_icon_appearances); full.iconbundle creation and editing withIconManifestCodable model (#278) - Handle Xcode 26 objectVersion 100 project format; update default from 56 to 77 with configurable
object_versionparameter; add post-migration validation checks tovalidate_project; addrepair_projecttool for fixing null build files and orphaned entries (#282)
- Fix
screenshot_mac_windowhanging for 20+ seconds; replace ScreenCaptureKit withCGWindowListCopyWindowInfo+screencapture -l(#275) - Fix
PreviewCaptureToolcaptureMacOSWindowsame ScreenCaptureKit hang; extract sharedWindowCapturehelper to Core (#274) - Fix
add_filemissinglastKnownFileTypefor.xcassets; fix scaffold tools not wiring source files or asset catalog into Xcode project build phases; fix AppIconContents.jsonmissingscalefield (#276) - Fix
add_filesilently droppingPBXBuildFilewhen build phasefilesis nil; affects resources, sources, and headers phases in real Xcode projects (#277) - Fix
add_filemissinglastKnownFileTypefor.iconfiles; fix path resolution for files above.xcodeprojbut within repo root (#278) - Fix scaffold
AppIcon.appiconset/Contents.jsonusing invalid"platform": "macos"value;actoolsilently skips the icon (#279)
- Bump XcodeProj to 9.11.0; add
debug_as_which_userparameter tocreate_schemefordebugAsWhichUseronLaunchAction export_iconnow returns inline base64 PNG image so the LLM client can see the rendered icon
- Add ReportCrash throttle detection to
search_crash_reports; warn when macOS stops generating.ipsfiles after ~25 reports per process and list other processes with reports in the time window (#259) - Add memory diagnostic tools (
memory_leaks,memory_heap,memory_vmmap,memory_stringdups,memory_malloc_history); wrap Xcode's hidden CLI tools for process memory analysis (#265) - Add
symbolicate_addresstool; batch crash address symbolication viaatos(#266) - Add
version_managementtool; read/set marketing version and build numbers viaagvtool(#262) - Add
notarizetool; full macOS notarization workflow vianotarytoolandstapler(#263) - Add
validate_asset_catalogtool; pre-build.xcassetsvalidation viaactool(#264) - Add
open_in_xcodetool; open files at specific lines, projects, or workspaces viaxed(#267) - Add 6 build diagnostics tools (
check_output_file_map,extract_crash_traces,list_build_phase_status,read_serialized_diagnostics,diff_build_settings,show_build_dependency_graph); debug silent compilation failures by inspecting OutputFileMap entries, compiler crash traces, build phase status,.diafiles, build setting diffs, and dependency graphs (#268)
- Fix
swift_package_buildcrashing on large projects; stream subprocess output with tail-truncation instead of throwing on overflow; reduce default output limit from 10MB to 2MB (#272) - Fix multi-suite test count bug in
BuildOutputParser; accumulate XCTest bundle counts, Swift Testing run counts, and parallel scheduling totals instead of overwriting (#261) - Fix
add_frameworksilently ignoringembed: truefor developer frameworks (XcodeKit, XCTest); fixadd_to_copy_files_phasenot auto-defaultingCodeSignOnCopy/RemoveHeadersOnCopyfor phases withdstSubfolderSpec == .frameworks(#270) - Fix
add_app_extensionusing wrong product type for Xcode extensions; addsource_editorextension type mapping tocom.apple.product-type.xcode-extension; add.xcodeExtensiontoremove_app_extensionvalid types (#271) - Fix
swift_package_testtruncating failure messages; capture all↳continuation lines instead of only the first; preserve parameterized test argument values (→ value) in test name (#273)
- Fix
BuildOutputParserSwift Testing edge cases; handle(aka '...')verbose suffix,with N test casesparameterized results, andrecorded an issue with N argument valuesparameterized issues; add 7 golden-file snapshot tests forBuildResultFormatter(#269)
- Add
remove_package_productandlist_package_productstools; remove individual SPM product dependencies from targets and inspect per-target product linkage (#247) add_target_to_test_plan: supportselectedTestsfiltering withxctest_classesandsuitesparameters; restrict test plan entries to specific classes, methods, or Swift Testing functions (#252)move_filenow updates synchronized folder exception sets; renaming a file that appears inmembershipExceptionsno longer requires manual remove/add workaround (#254)
- Fix
remove_package_productcorrupting pbxproj; clean upPBXTargetDependencyentries withproductRefcreated by Xcode GUI (#248) - Fix
add_frameworkcreating bogus.frameworkfile reference for static libraries (.a); reuse existing product reference or create properarchive.arentry inBUILT_PRODUCTS_DIR(#250) - Fix
test_macosonly_testingfilter failing for Swift Testing backtick-escaped single-word method names; auto-wrap Swift keywords likeclassandimportin backticks (#251) - Fix
build_macossuppressing all compiler warnings; addshow_warningsparameter to list project-local warnings on successful builds (#238) - Fix synchronized folder exception tools corrupting pbxproj; use text-based
PBXProjTextEditorinstead of XcodeProj round-trip serializer (#256) - Fix
add_frameworksilently failing to add local product frameworks; detect existingBUILT_PRODUCTS_DIRreferences before classifying bare names as system frameworks - Fix
add_frameworkcreating stalePBXFileReferencefor cross-project framework products; reuse existingPBXReferenceProxyentries instead of creating unresolvable group-relative references
- Remove unnecessary
@unchecked SendablefromBuildOutputParser; replace[String: Any]JSON parsing withDecodablemodels inXCResultParserandCrashReportParser; fix 21 swiftlint warnings
- Support project-level build settings in
set_build_setting; omittarget_nameto apply settings at the project level instead of a specific target - Add
build_settingsparameter to all build/test tools; pass xcodebuild build setting overrides (e.g.SWIFT_ENABLE_EXPLICIT_MODULES=NO) as highest-precedence positional arguments (#243) - Add MCP tool annotations to all 197 tools; explicit
readOnlyHint/destructiveHint/openWorldHintso clients can auto-approve safe operations (#244) - Add
timeoutparameter tobuild_macosandbuild_run_macostools; return partial diagnostics on timeout instead of an empty error (#245)
- Fix
add_swift_packagecrashing with SIGTRAP on projects with sub-project references; work around XcodeProjsortProjectReferencesforce-unwrap of nilPBXFileElement.nameby backfilling frompath - Fix
remove_targetleaving orphanedPBXContainerItemProxyandPBXTargetDependencyentries in pbxproj; also search all target types instead of only native targets (#237) - Fix
PluralVariationandDeviceVariationfield types to match xcstrings JSON format; addVariationValuewrapper for correct decoding of plural/device variations (#239) - Fix device log capture requiring sudo; switch from
log collect --device-udidtolog streambackground process (#233) - Fix
list_filesmisleadingmembershipExceptionslabel; fixremove_synchronized_folder_exceptionnot finding auto-created exception sets; addadd_package_producttool for linking existing SPM products to targets (#227) - Fix
start_device_log_capunable to capture device logs; switch toidevicesyslogfrom libimobiledevice with CoreDevice-to-hardware UDID resolution (#235) - Fix
stop_device_log_capfailing to collect logs from physical devices; correctlog collect --startdate format from ISO8601 toyyyy-MM-dd HH:mm:ss(#232) - Fix
remove_swift_packageleaving stalePBXBuildFileandPBXSwiftPackageProductDependencyentries in pbxproj (#234)
- Extract
TestToolHelperto deduplicate test tool validation/bundle/formatting logic acrossTestSimTool,TestMacOSTool,TestDeviceTool; replace[String: Any]withDecodabletypes inDeviceCtlRunner; fix lint warnings inBuildResultFormatter,StartDeviceLogCapTool,ScaffoldModuleTool - Upgrade to Swift 6.3, macOS 26, MCP SDK 0.12.0,
swift-subprocess0.4.0; migrateTerminationStatus.unhandledExceptionto.signaled,.combineWithOutputto.combinedWithOutput,.textpattern matching to 3-element tuple - Swift review fixes from 2026-03-21 changes (#236)
- Add
show_mac_logtool to query historical macOS unified logs vialog show; filter by bundle ID, process name, subsystem, or custom predicate with configurable time range and tail lines (#216) - Add
swift_symbolstool to extract and query public APIs of Swift modules viaswift-symbolgraph-extract; filter by name, symbol kind, and platform (#217) - Investigate dead code detection tooling; evaluated Periphery alternatives and confirmed it as the best option (#171)
- Share session defaults across all focused MCP servers;
set_session_defaultsin one server applies everywhere (#208) - Add
get_performance_metrics,set_performance_baseline, andshow_performance_baselinestools; extractmeasure(metrics:)results from xcresult bundles and create/update.xcbaselineplists for automatic regression detection (#205) - Add
set_test_plan_skipped_tagstool; add or removeskippedTagsat plan-level or per-target in.xctestplanfiles (#225) build_macos: truncate cascade errors when root cause is aPhaseScriptExecutionfailure; collapse "Unable to find module dependency" noise into a single summary line (#230)BuildGuard: wait for build lock with 5-minute timeout instead of failing immediately; concurrent agents now queue instead of erroring (#231)
- Fix
build_run_simfalse "build appears stuck" error; increase no-output timeout from 30s to 120s for simulator builds where linking/signing produces long output gaps; auto-boot shutdown simulators before install/launch (#223, #222) - Fix
build_devicefailing to find connected device by UDID; improve device lookup to match partial UDIDs (#212) - Wait for process exit after SIGTERM in
swift_package_stop,LogCapture.stopCapture, andLLDBRunner.terminate(); poll withkill -0and escalate to SIGKILL (#221) - Fix
debug_evaluateanddebug_lldb_commandreturning empty output at breakpoints; drain stale PTY output before sending commands (#226) - Fix
stop_mac_appfailing to kill debugger-attached processes in TX state; detach LLDB before sending SIGTERM/SIGKILL (#224) - Fix
list_filesmisleadingmembershipExceptionslabel; fixremove_synchronized_folder_exceptionnot finding auto-created exception sets; addadd_package_producttool for linking existing SPM products to targets (#227) - Fix
test_macosfailing entire run when oneonly_testingtarget is invalid; pre-validate entries against available test targets and filter out invalid ones with a warning (#229) - Fix
stop_device_log_capfailing to collect logs from physical devices; correctlog collect --startdate format from ISO8601 toyyyy-MM-dd HH:mm:ss; surface error details whenlog collectwrites diagnostics to stdout - Fix device log capture requiring sudo; switch from
log collect --device-udidtolog streambackground process (#233) - Fix
remove_swift_packageleaving stalePBXBuildFileandPBXSwiftPackageProductDependencyentries in pbxproj (#234) - Fix
start_device_log_capunable to capture device logs;log streamhas no device flags; switch toidevicesyslogfrom libimobiledevice with CoreDevice-to-hardware UDID resolution (#235)
- Review XcodeBuildMCP v2.3.0 changes for applicability; no gaps in list-schemes or simulator init, confirmed SIGTERM fix needed (#220)
- Upgrade MCP Swift SDK from 0.10.2 to 0.11.0; adds 2025-11-25 spec coverage, icons/metadata, elicitation, HTTP transport (#219)
- Add
show_performance_baselinestool to xc-build; read and display existing.xcbaselineplists with human-readable metric names, filtering by target, test class, and metric type - Add
get_performance_metricsandset_performance_baselinetools to xc-build; extractmeasure(metrics:)results from xcresult bundles and create/update.xcbaselineplists for automatic regression detection build_macos/test_macos: adderrors_onlyparameter to suppress warnings from output; show only compiler errors, linker errors, and build summary (#195)- Add
sample_mac_appandprofile_app_launchprofiling tools; extractPIDResolverto Core; parse sample output into agent-friendly summaries - Integrate Swift Backtrace API (SE-0419); attach symbolicated backtraces to unexpected
MCPError.internalErroron macOS 26+ - Add
scaffold_modulecomposite tool; create a framework module with test target, sync folders, dependencies, embedding, and test plan entry in one call (#177) create_scheme: acceptbuild_targetsarray for multiple build action entries; first target is primary for launch/testdetect_unused_code: filter out Periphery'ssuperfluousIgnoreCommentwarnings; these are an unresolvable cycle on assign-only properties with// periphery:ignorecomments (#198)build_macos: addfor_testingparameter to runbuild-for-testing; compiles test targets without executing them.test_macos/test_sim/test_device: addtest_planparameter to target non-default test plans.list_test_plan_targets: addtest_planandall_plansparameters to query plans not attached to a schemebuild_devicenow returns the built.apppath in its output; enables seamlessbuild_device→install_app_device→launch_app_devicepipeline- Add
deploy_deviceandbuild_deploy_devicecomposite tools; stop → install → launch (or build → stop → install → launch) in a single call (bpv-4ka)
- Fix
build_devicefalse "build appears stuck" error; increase no-output timeout from 30s to 120s for device builds where code signing produces long output gaps - Fix
list_devicesshowing "Type: Unknown" for iPad Mini; readmarketingNamefromhardwarePropertiesinstead ofdeviceProperties build_macos/build_run_macos/test_macos/build_debug_macosnow reject iOS-only projects with a clear error instead of silently building; checksSUPPORTED_PLATFORMSand suggests xc-simulator tools- Fix
add_synchronized_folder_exceptioncreating duplicate exception sets; append to existing set for the same target instead of creating a second one. Fixremove_synchronized_folder_exceptiononly checking the first exception set for a target - Fix
sample_mac_appbundle ID lookup and output capture; useNSRunningApplicationinstead ofpgrepand-fileflag for reliablesampleoutput - Fix
detect_unused_coderesult_filereturning stale entries from prior scans - Fix
test_macosonly_testingfailing to match Swift Testing functions with backtick-escaped names containing spaces; auto-normalize identifiers by wrapping in backticks and appending() - Fix
stop_app_devicefailing with "Missing expected argument--pid"; resolve bundle identifier to PID viadevicectl device info processesbefore terminating (cfo-jj0) - Fix
start_device_log_capproducing empty log files; replace nonexistentdevicectl device info syslogwithlog collect --device-udid+log showcollection-based approach (m5k-jma)
- Add
detect_unused_codetool wrapping Periphery CLI; finds unused declarations, redundant imports, assign-only properties, and redundant public accessibility in Swift projects (#171) test_macosnow returns XCTestmeasure()timing data in results; average, relative standard deviation, and individual values (#169)test_macosnow surfaces per-test results with skip reasons and performance metrics; no more "1 passed" when 2 tests were silently skipped (#180)test_macoserror output now lists failed test names prominently; no more scanning 3600+ lines to find 4 failures (#185)test_macosoutput now always includes both passed and failed counts in the summary line; grep-friendly even with-quietbuildssearch_crash_reportsnow supportsreport_pathfor reading a specific crash report directly; agents can search → get path → read full report without re-searching (#186)search_crash_reportsnow shows symbolicated crashing thread stack trace; top 15 frames with image names, symbols, and source locations (#182)- Add JSON output mode (
format: "json") and field selection (fields) to discovery tools;show_build_settings,list_schemes,list_test_plan_targets,discover_projs(#163) - Add
get_coverage_reportandget_file_coveragetools; per-target and function-level coverage from xcresult bundles - Add
validate_projecttool; catches dangling copy-files refs, orphaned build files, unreferenced phases, and inconsistent embedding (#134) - Add
remove_frameworktool; remove framework dependencies from one or all targets, cleaning up link phases, embed phases, and orphaned file references (#158) detect_unused_code: addgroup_byparameter for per-target, per-kind, and per-directory summaries (#188)- Add
sample_mac_app,profile_app_launch, andSampleOutputParser; profiling and performance capture tools for xc-build with parsed call-stack summaries sample_mac_appparses rawsampleoutput into agent-friendly summaries; heaviest functions table, call paths, idle thread filtering- Integrate Swift Backtrace API (SE-0419); attach symbolicated backtraces to unexpected
MCPError.internalErroron macOS 26+ (#184)
- Fix
detect_unused_codechecklist format exceeding MCP token limit on large projects; replace separate checklist mode with always-on disk checklist and compact summary output (#183) - Fix
test_macosfalse-positive stuck timeout on XCUI performance tests; increase default no-output timeout from 30s to 120s for test commands (#178) - Fix
list_test_plan_targetsreturning "no test plans found" for schemes with inline test targets; falls back to scheme<TestAction>testable references (#179) - Document
only_testingmethod-level filter limitation for XCUI test targets; xcodebuild silently runs 0 tests; suggest class-level filtering in error message (#181) - Fix subprocess orphan processes on MCP abort/timeout; configure
teardownSequence(SIGTERM → 5s → SIGKILL) so cancelled builds/tests don't hold the SPM lock (#171) - Fix
validate_projectcrash fromPBXBuildFileHashable violation; useObjectIdentifierinstead ofSet<PBXBuildFile> - Fix
formatTestToolResultexit-code override suppressing failures when no tests ran; guard withtotalTestCount > 0(#166) - Fix
swift_package_testreporting passing tests as MCP error -32603; override non-zero exit code when parsed output confirms all tests passed (#160) - Fix
add_filecreating duplicatePBXFileReferenceentries and miscomputing paths for groups with apathproperty; usessourceRootwhen file is outside the group's resolved path, deduplicates existing refs (#159) - Fix
remove_fileremoving files from all targets when multiple targets have files with the same name; now matches by full path viafullPath(sourceRoot:)instead of filename (#156) - Fix
add_swift_packagereturning "already exists" instead of linking product to a new target; now links the product and detects duplicates (#154) - Fix
start_mac_log_capprocess name derivation; resolve actual executable name from app bundleInfo.plistinstead of lowercased bundle ID suffix; case-insensitive fallback when bundle not found (#186) - Fix
detect_unused_coderesult_filereturning stale entries from prior scans; delete old checklist when a new scan overwrites the cache file - Fix
detect_unused_codechecklist not reconciling with already-removed code; strengthen agent instructions to mark items done immediately after each resolution (#187) - Fix
add_filepath doubling when adding files to groups with a filesystempath; file reference now computed relative to the group location (#155) - Default
ONLY_ACTIVE_ARCH=YESfor Debug in all target-creation tools; prevents cross-compilation failures with SPM dependencies (#151) - Fix
add_target,add_app_extension,add_swift_package,add_framework, andcreate_xcodeprojissues found during extension setup; orphan targets, missing framework linking, wrongsourceTreefor developer frameworks, macOSTARGETED_DEVICE_FAMILY,ALWAYS_SEARCH_USER_PATHS(#150) - Fix
add_targetonly creating Debug/Release configs; now matches all project-level build configurations (#176) - Fix
add_targetcreating groups at project root; addparent_groupparameter for nesting under existing groups (#174) - Fix
add_targetadding extraneous build settings; minimize toPRODUCT_BUNDLE_IDENTIFIER,PRODUCT_NAME,GENERATE_INFOPLIST_FILE(#173) - Fix
add_to_copy_files_phasemissingCodeSignOnCopy/RemoveHeadersOnCopyattributes; addattributesparameter with auto-defaults for Embed Frameworks (#175) - Fix
add_filerejecting slash-separated group paths likeComponents/TableView; unify group path resolution across all tools (#172) - Fix
sample_mac_appfailing for apps with spaces/parens in name; useNSRunningApplicationfor bundle ID lookup and-fileflag for reliablesampleoutput capture
- Isolate session defaults by PPID so parallel MCP clients don't clobber each other
- Enhance test plan error hints with scheme awareness; suggests the correct scheme when a test target isn't in the specified scheme
- Trim verbose tool descriptions; reduce token overhead for 7 tools (#163)
- Evaluate MCP vs CLI architecture; concluded MCP should be kept with incremental improvements (#161)
- Investigate XcodeBuildMCP coverage tools; no new tools needed; our
get_coverage_reportandget_file_coveragealready cover the use cases (#168) - Investigate XcodeBuildMCP xcresult/stderr output fixes; no action needed; our combined-stream approach avoids the issues by design
- Review XcodeBuildMCP v2.1.0 changes; no actionable items for xc-mcp (#164)
- Review Sentry XcodeBuildMCP session defaults hardening; our Swift actor approach already covers the key patterns (#94)
- Review tuist/xcodeproj 9.10.0–9.10.1 changes (#162)
- Port crash-to-test association from xcsift;
BuildOutputParsernow tracks which test was running when a crash occurs and reports it in failed test diagnostics (#153) - Bump XcodeProj dependency to 9.10.1 (#152)
- Migrate from Foundation
Processtoswift-subprocess; safer process I/O; no more pipe deadlocks by design (#101) - Add
validate_projecttool; catches stale embeds, missing links, and orphaned build phases before they bite you (#135) - Add project configuration generation tools; create and modify test plans and schemes programmatically (#102)
- Add crash report search/inspect tool; dig through
~/Library/Logs/DiagnosticReportswithout opening Console.app (#127) - Add
check_buildtool for single-target compilation; type-check one target without rebuilding the world (#126) - Debug tools now check process state before sending commands; no more mysterious hangs on crashed processes (#133)
build_debug_macosdetects early process crashes (dyld,SIGABRT) instead of silently hanging (#132)test_macossurfaces crash diagnostics when the test host fails to bootstrap (#100)- Add test plan management tools to
xc-project; create, query, and modify.xctestplanfiles (#122) - Improve UI test and test plan ergonomics; less boilerplate, more doing (#121)
- Validate
only_testingidentifiers before runningxcodebuild; catch typos before a 2-minute build (#118) - Suppress non-project warnings in build output; see your warnings, not Apple's (#98)
- Add in-place target renaming with cross-reference updates (#117)
xc-swiftauto-detectspackage_pathfrom working directory; one less thing to specify (#99)- Add
--build-testsflag toswift_package_build(#113) - Add environment variable and skip filter support to
swift_package_test(#112) - Add
swift_formatandswift_linttools toxc-swiftserver (#95) - Register
test_simin the Build server so you don't need a separate simulator server (#97) - Support
XCLocalSwiftPackageReferencedeletion via XcodeProj 9.9.0 (#108) launch_mac_app/build_run_macosreturn PID and detect early exit (#139)debug_attach_simsupports macOS apps bybundle_idwithout requiring a simulator (#140)- Add
get_test_attachmentstool; extract screenshots and data files from.xcresultbundles with test ID and failure filtering (#144) - Add persistent custom env vars to session defaults;
set_session_defaults(env: {...})deep-merges and applies to all build/test/run commands (#148) - Suggest correct scheme when test target isn't in the specified scheme; no more guessing which scheme has your tests (#145)
start_mac_log_capfixesbundle_idpredicate reliability; addslevelparameter and stream health checks (#147)
- Fix pipe deadlock; drain stdout/stderr before
waitUntilExit; was causing intermittent server hangs (#119) - Fix
xcodebuildprocess not killed on MCP cancellation; orphaned builds no more (#104) - Fix
build_debug_macosfalsely reporting crash on successful launch (#137) - Fix process interrupt via
debug_lldb_commandracing with async stop notification (#136) - Reload shared session file on access so focused servers stay in sync (#138)
- Fix
debug_stackthread backtrace syntax (#131) - Fix
stop_mac_apphanging when process is crashed or under LLDB (#130) test_macosno longer reports success whenonly_testingfilter matches zero tests (#129)- Use parsed build output status instead of exit code alone; catches builds that "succeed" with errors (#115)
- Fix
list_filesmissing files from synchronized folder targets (#106) - Fix
list_test_plan_targetsfailing on relative project paths (#120) - Fix
search_crash_reportsrequiringprocess_nameorbundle_idwhen neither should be mandatory (#123) - Add timeout support to
SwiftRunner; prevents runaway swift commands (#125) - Fix
build_run_macos/launch_mac_appcrashing on non-embedded frameworks; symlink fromBUILT_PRODUCTS_DIRinstead of relying onDYLD_FRAMEWORK_PATH(#141) - Fix
build_debug_macostimeout withstop_at_entry; resolve actual executable name instead of.appfolder name (#142) - Fix
debug_detachrejecting valid PID parameter;getIntnow handles JSON numbers decoded as doubles (#143) - Fix
get_test_attachmentsparsing manifest with wrong keys; returnsUnnamed/unknownfor all attachments (#146) - Fix
create_xcodeprojcreating orphan default target;add_swift_packagenot linking to Frameworks build phase;add_frameworkusing wrongsourceTreefor developer frameworks;add_targetsettingTARGETED_DEVICE_FAMILYfor macOS; missingALWAYS_SEARCH_USER_PATHS = NO
- Redesign integration tests for speed; split slow tests behind
RUN_SLOW_TESTSflag (#96) - Bump XcodeProj to 9.10.1; picks up Xcode 26
dstSubfoldersupport andCommentedStringperf fix (#149)
- Add
build_debug_macos; launch macOS apps under LLDB, the way Xcode's Run button does (#4) - Add 8 new LLDB debug tools; watchpoints, memory reads, symbol lookup, view hierarchy dumps, and more (#1)
- Add
interact_tools for macOS app UI interaction via Accessibility API; click, type, inspect UI trees (#60) - Add
screenshot_mac_windowtool; capture any window via ScreenCaptureKit without needing a simulator (#58) - SwiftUI preview capture tool; render
#Previewmacros to images on a simulator (#59) - Add macOS log capture tools; stream and filter unified logs per-app (#8)
- Share session defaults across MCP servers; set once, use everywhere (#32)
- Add
rename_targettool with cross-reference updates across schemes, dependencies, and build phases (#111) - Add
remove_group,remove_target_from_synchronized_folder, and exception set tools (#103, #128, #107) - Add tool to share existing synchronized folder with another target (#72)
- Improve
test_macosergonomics; timeout parameter, better error surfacing from xcresults (#109) - Doctor, gesture presets, Xcode state sync, next-step hints, and workflow management; a batch of quality-of-life tools (#81)
- Fix LLDB sessions hanging; switch from pipes to PTY for stdin, matching how real terminals work (#33)
- Fix debug tools hanging due to ephemeral LLDB sessions that vanish mid-command (#11)
- Fix
build_debug_macosSIGABRTcrash; launch via Launch Services instead of direct LLDB process launch (#9) - Fix
build_debug_macosproducing no useful error on failure (#38) - Fix
debug_attach_simanddebug_breakpoint_addhanging on macOS native apps (#27) - Fix
preview_capturecompiler crash from#Previewin additional source files (#63) - Fix
preview_capturebuild config to avoidASTManglercrash and launch failure (#62) - Fix
preview_capturefor local Swift packages missing deployment target (#71) - Fix
add_targetsetting wrong bundle identifier key (#79) - Fix
add_targetmissingproductReferenceand Products group entry (#80) - Fix
add_frameworkcreating duplicate file references instead of reusingBUILT_PRODUCTS_DIR(#73, #74) - Fix
list_filesto include synchronized folder contributions (#105) - Fix
rename_targetgaps found during real-world module rename (#110) - Fix
test_macoserror output truncation (#78) - Surface warning when
testmanagerdcrashes during test run (#77) - Fix
swift-frontendSILGen crash when building IceCubesApp fixture (#65, #64) - Fix IceCubesApp full build crash with Xcode 26 (#70)
- Fix Alamofire fixture build with Xcode 26 (#69)
- Fix
buildRunScreenshotinstalling wrong platform build (#68) - Fix integration test failures for
preview_captureand IceCubesApp (#67, #66, #91) - Fix reading test stdout from XCUI tests (#76)
- Extract
ProcessRunner,ProcessKiller,LogCaptureBuilder, andBuildSettingExtractorutilities; less duplication, cleaner tool code (#88, #84, #82) - Migrate manual argument extraction to
ArgumentExtractionhelpers (#89) - Replace
DispatchQueueusage with structured concurrency (#83) - Replace
Date()timing withContinuousClock(#86) - Add typed throws to
XCStringsParsermutation methods (#90) - Deduplicate batch
parseEntriesin XCStrings tools (#85) - Add
reserveCapacityto batch array loops (#87) - Extract shared
findSyncGroupand clean up sync folder tools (#116) - Expose 6 implemented-but-unregistered project tools (#124)
- Fix
preview_captureend-to-end rendering (#61) - Fix
PreviewCaptureToolswiftlint warnings (#92)
- Review xcsift coverage scanner optimization (#2)
- Review xcsift Swift Testing PR (#14)
- Review xcsift issue-52 fix (#34)
- Review xcstrings-crud
BatchWriteResultfix (#39)
- Integrate xcsift build output parsing; structured errors, warnings, and notes instead of raw
xcodebuildnoise (#17) - Add granular test selection to test tools; run specific test classes or methods (#30)
- Add code coverage collection to test tools (#44)
- Add Copy Files build phase management; embed frameworks, copy resources, all the fun stuff (#23)
- Add
remove_synchronized_foldertool (#12)
- Fix MCP tools corrupting unrelated
PBXCopyFilesBuildPhasesections; the worst kind of silent data loss (#29) - Fix
set_build_settingdroppingdstSubfolderfields fromPBXCopyFilesBuildPhase(#31) - Fix
add_synchronized_folderdeleting scheme files on save (#24) - Fix synchronized folder path handling for nested groups (#6)
- Fix scheme deletion; use
writePBXProjinstead ofwriteto preserve.xcschemefiles (#40)
- Eliminate ~100 duplicate files across focused servers (#25)
- Implement review consolidation changes (#20)
- Implement Homebrew package;
brew install toba/tap/xc-mcpand you're off (#42) - Add
--no-sandboxflag toxc-project,xc-build, andxc-stringsservers (#13) - Integrate xcstrings-crud as the
xc-stringsMCP server; full localization string catalog management (#43) - Improve MCP tool timeout handling with streaming progress; no more silent hangs on long builds (#16)
- Error handling improvements across all tools (#37)
- Split
xc-mcpinto 7 focused MCP servers; smaller token footprint, faster client setup (#5) - Complete all 11 implementation phases: Foundation, Simulator, Device, macOS Build, Discovery, Log Capture, Simulator Extended, LLDB Debugging, UI Automation, Swift Package Manager, Utilities (#52 through 50)
- Migrate tests to Swift Testing framework with parameterized test cases (#10)
- Add typed throws to select methods (#7)
- Refactor
NSStringpath manipulation toURL(#3) - Add DocC documentation (#41)
- Add XCStrings test coverage (#36)
- Clean up unused files and update README (#28)
- Create Swift code review skill (#26)
- Code optimization pass (#45)
- Fix swiftlint warnings (#22)
- Document unexposed capabilities (#15)
- Unified Xcode MCP Server milestone completed (#19)