Title: Startup getSnapshot() on the critical path delays the first tools/list ~10s (health-probe clients show 'tools fetch failed') · Issue #461 · getsentry/XcodeBuildMCP · GitHub
Open Graph Title: Startup getSnapshot() on the critical path delays the first tools/list ~10s (health-probe clients show 'tools fetch failed') · Issue #461 · getsentry/XcodeBuildMCP
X Title: Startup getSnapshot() on the critical path delays the first tools/list ~10s (health-probe clients show 'tools fetch failed') · Issue #461 · getsentry/XcodeBuildMCP
Description: Summary On a cold start, the stdio transport comes up fast (initialize responds in well under a second), but the first tools/list response is delayed ~10–17s. During that window the server is up and healthy, but any MCP client that uses ...
Open Graph Description: Summary On a cold start, the stdio transport comes up fast (initialize responds in well under a second), but the first tools/list response is delayed ~10–17s. During that window the server is up an...
X Description: Summary On a cold start, the stdio transport comes up fast (initialize responds in well under a second), but the first tools/list response is delayed ~10–17s. During that window the server is up an...
Opengraph URL: https://github.com/getsentry/XcodeBuildMCP/issues/461
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Startup getSnapshot() on the critical path delays the first tools/list ~10s (health-probe clients show 'tools fetch failed')","articleBody":"## Summary\n\nOn a cold start, the stdio transport comes up fast (`initialize` responds in well under a second), but the **first `tools/list` response is delayed ~10–17s**. During that window the server is up and healthy, but any MCP client that uses a short-timeout health probe for `tools/list` (e.g. Claude Code's `claude mcp list`) reports the server as `Connected · tools fetch failed`, even though in-session tool calls work fine once the client's longer startup timeout has elapsed.\n\nThe delay appears to come from the startup lifecycle snapshot being `await`ed on the critical path *after* the transport is running but *before* the server settles into steady state.\n\n## Environment\n\n- **XcodeBuildMCP**: 2.6.2 (latest published; behaviour re-checked against `main` HEAD — the relevant code is unchanged there)\n- **Transport**: stdio (`xcodebuildmcp mcp`)\n- **Host**: macOS (Apple Silicon), Xcode 27\n- **Client**: Claude Code (short `tools/list` health probe); also reproducible by timing a raw `tools/list` over stdio\n\n## Observed behaviour / timings\n\n- `Server running on stdio` logged at ~385ms\n- `initialize` round-trips in ~0.8s\n- First `tools/list` returns after ~10–17s\n- In-session tool calls (`list_sims`, builds, etc.) all work — this is purely a first-response latency issue, so it presents as **cosmetic** but it makes the server look broken to any health-probe client.\n\n## Where it comes from (from source, `main` HEAD)\n\n`src/server/start-mcp-server.ts` starts the stdio transport, marks the lifecycle `running`, and then **awaits the startup snapshot on the critical path**:\n\n```ts\n// src/server/start-mcp-server.ts (main)\nlifecycle.markPhase('starting-stdio-transport');\nawait startServer(server, { /* ... */ }); // transport is now up\n// ...\nlifecycle.markPhase('running');\nconst startupSnapshot = await lifecycle.getSnapshot(); // \u003c-- awaited before the server settles\nlog('info', `[mcp-lifecycle] start ${JSON.stringify(startupSnapshot)}`);\n// ...\nlifecycle.markPhase('deferred-initialization');\nvoid bootstrap.runDeferredInitialization({ /* ... */ }); // \u003c-- already fire-and-forget\n```\n\n`lifecycle.getSnapshot()` (in `src/server/mcp-lifecycle.ts`) gathers, among other things, the active simulator os_log sessions (`listActiveSimulatorLaunchOsLogSessions()`) and a peer-process sample (`matchingMcpProcessCount`). That snapshot is `await`ed synchronously in the startup sequence, so the server does not become responsive to the first `tools/list` until it resolves.\n\nNotably, a `runDeferredInitialization(...)` fire-and-forget hook already exists immediately below the `getSnapshot()` call — the startup snapshot looks like a natural fit for the same deferred path.\n\n## What I ruled out\n\n- **Peer-count (`matchingMcpProcessCount`) sampling is not the cause.** The `[mcp-lifecycle] startup anomalies: peer-count-high` warning is a red herring: reaping the leaked peer processes down to a normal count did **not** change the ~10s. So the cost is in the snapshot's other work (the simulator os_log session enumeration path), not the peer sample.\n- **Not a client-side timeout knob.** The delay is server-side; raising the client MCP timeout does not make `tools/list` return faster — it only lets the (successful) slow response through.\n\n## Suggested fix\n\nMove the startup `getSnapshot()` (and specifically the simulator os_log session enumeration it performs) **off the startup critical path** so the first `tools/list` is answered immediately — e.g. make the start-time snapshot fire-and-forget (`void lifecycle.getSnapshot().then(...)`) or fold it into the existing `runDeferredInitialization(...)` block just below it. The telemetry/anomaly logging it feeds is not something the first `tools/list` needs to block on.\n\n## Repro sketch\n\n1. `xcodebuildmcp mcp` over stdio.\n2. Send `initialize`, then immediately `tools/list`; time the `tools/list` response.\n3. Observe `initialize` fast, `tools/list` ~10s+ on a cold start.\n\nHappy to test a patch or provide more startup profiling if useful. Thanks for the great tool.\n","author":{"url":"https://github.com/diskude","@type":"Person","name":"diskude"},"datePublished":"2026-07-06T11:29:44.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/461/XcodeBuildMCP/issues/461"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:467447a6-7918-7a5e-ad78-3397cac4dc48 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | 83CC:4D576:1376AB4:1BC701F:6A4CC113 |
| html-safe-nonce | e3a92787137dc25432b85afb65e657ea3064e2ad687e237aa7b3a1d8a06558b3 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI4M0NDOjRENTc2OjEzNzZBQjQ6MUJDNzAxRjo2QTRDQzExMyIsInZpc2l0b3JfaWQiOiI2NzA0NDM0NjgyMjk5OTkwMjkxIiwicmVnaW9uX2VkZ2UiOiJpYWQiLCJyZWdpb25fcmVuZGVyIjoiaWFkIn0= |
| visitor-hmac | d82021d9706b262e90ccf2bb067b85c60bcd9f04e0cf0ac2ebdd79083e3bf4de |
| hovercard-subject-tag | issue:4818672839 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/getsentry/XcodeBuildMCP/461/issue_layout |
| twitter:image | https://opengraph.githubassets.com/78eada12dd911dac2f6321b3d8e8c8dfafc92152374cf64bd6f5a278b679989d/getsentry/XcodeBuildMCP/issues/461 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/78eada12dd911dac2f6321b3d8e8c8dfafc92152374cf64bd6f5a278b679989d/getsentry/XcodeBuildMCP/issues/461 |
| og:image:alt | Summary On a cold start, the stdio transport comes up fast (initialize responds in well under a second), but the first tools/list response is delayed ~10–17s. During that window the server is up an... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | diskude |
| hostname | github.com |
| expected-hostname | github.com |
| None | 3d11bb817438277de2a940854450e83a7d32b6aeb5014e9e6b00a6423900251c |
| turbo-cache-control | no-preview |
| go-import | github.com/getsentry/XcodeBuildMCP git https://github.com/getsentry/XcodeBuildMCP.git |
| octolytics-dimension-user_id | 1396951 |
| octolytics-dimension-user_login | getsentry |
| octolytics-dimension-repository_id | 945551361 |
| octolytics-dimension-repository_nwo | getsentry/XcodeBuildMCP |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 945551361 |
| octolytics-dimension-repository_network_root_nwo | getsentry/XcodeBuildMCP |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | c03e7e569190bc89b638cdd4acb4b6c6b38a170a |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width