Skip to content

mcpdo: run the daemon test suites on Windows over named pipes - #2977

Merged
cliffhall merged 6 commits into
v2/mainfrom
v2/chore/2922-mcpdo-windows-named-pipe-tests
Nov 12, 2026
Merged

cliffhall merged 6 commits into
v2/mainfrom
v2/chore/2922-mcpdo-windows-named-pipe-tests

Conversation

@cliffhall

@cliffhall cliffhall commented Nov 12, 2026 •

Copy link
Copy Markdown
Member

Closes #2922

Summary

mcpdo's daemon test suites now run on the windows CI job against the daemon's real named pipe, and mcpdo's per-file 90% coverage gate is enforced on Windows again.

Windows CI proof

windows job on the PR head (2090e96): https://github.com/modelcontextprotocol/inspector/actions/runs/43178529126/job/131048543890 (11m24s, green; the same counts as the earlier run at f9dcfc9, https://github.com/modelcontextprotocol/inspector/actions/runs/43175250060/job/131037805564)

coverage:mcpdo on Windows Before (#2906) After
Tests 563: 436 pass, 127 skipped 681: 674 pass, 7 skipped, 0 fail
Per-file 90% thresholds dropped on win32 enforced, pass (all files 98.1 / 94.44 / 97.35 / 98.35)

The 7 remaining skips are all POSIX-only behaviour, each with its reason at the site: 3 pre-existing exec-bit cases in resolve-command, plus 4 from the old daemon skip set that test something Windows does not have — a stale socket file (daemon-stream, daemon-coverage), the sun_path limit through the CLI (mcp-coverage), and 0700 mode tightening (daemon-paths).

What changed

  • __tests__/helpers/daemon-endpoint.ts (new). The harness derives the endpoint from getDaemonSocketPath(dir) instead of a hard-coded <dir>/mcpdod.sock. stopDaemonIn(dir) stops a spawned daemon and waits for its token/lock (present on every platform, unlike a socket file) and for the pid it reports in ping to exit. removeDaemonDir(dir) retries the removal on EBUSY/EPERM/ENOTEMPTY with a bounded budget. Two Windows findings drove those two waits, both from CI runs on this branch:
    • The daemon chdir()s into its directory and exits only once its event loop drains, after removing its token and lock. Windows refuses to remove a directory that is a live process's cwd, so waiting for the files alone was not enough.
    • A daemon that stopped on its own (idle reap after disconnect, or a test's own daemon stop) leaves no token to ask for its pid, so the removal itself retries while that process drains.
  • publishFakeDaemonToken(dir) is keyed by the daemon directory rather than the endpoint, and every callDaemon / streamDaemon in the fakes passes dir alongside socketPath — a pipe has no directory, so the client cannot find the token from it (daemonTokenDir).
  • helpers/platform.ts: unixDaemonOnly is gone; isWindows names the remaining POSIX-only skips.
  • daemon-paths: the POSIX arms of paths.ts (socket-file path, both sun_path limits, assertTrustedPrivateRoot's checks) are reached on every host by faking process.platform (and standing in getuid where Windows has none) rather than skipping, since the gate now runs there. The sun_path case is no longer skipped anywhere. createPrivateDaemonDir's layout case sets TEMP/TMP too, which is what os.tmpdir() reads on Windows.
  • clients/mcpdo/vitest.config.ts: the win32 threshold carve-out is removed.
  • docs/quality-gate.md: the windows job paragraph no longer says mcpdo's daemon suites and gate are off there.

No production code changed; macOS/Linux keep the Unix-socket path unchanged (npm run local:gate green on macOS).

Follow-up filed

🤖 Generated with Claude Code

cliffhall and others added 5 commits November 12, 2026 00:08
…2922)

The daemon test harness derives the endpoint from getDaemonSocketPath
instead of a hard-coded <dir>/mcpdod.sock, keys fake-daemon tokens by
directory, passes dir alongside a pipe endpoint, and tears a spawned
daemon down by its token/lock (present on every platform) with an
EBUSY-tolerant rmSync. unixDaemonOnly is gone; the few remaining win32
skips are POSIX-only behaviour (socket files, sun_path, mode bits), each
with its reason at the site. mcpdo's per-file coverage threshold is
enforced on Windows again.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…ing its dir (#2922)

The daemon chdir()s into its directory and exits only once its event loop
drains, after it has already removed its token and lock. Windows refuses
to remove a directory that is a live process's cwd (EBUSY), so teardown
now waits on the pid the daemon reports in ping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
…drains (#2922)

A daemon that stopped on its own (idle reap after disconnect, or a test's
daemon stop) has already removed its token, so teardown has no pid to wait
on while the process still has the directory as its cwd. Retry the removal
on EBUSY/EPERM/ENOTEMPTY for a bounded time instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
With mcpdo's per-file gate enforced on Windows, the POSIX arms of
paths.ts (socket-file path, sun_path limits, assertTrustedPrivateRoot's
checks) need covering there too. Fake the platform (and stand in getuid
where Windows has none) instead of skipping; the sun_path case now runs
on every host.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall cliffhall added the v2 Issues and PRs for v2 label Nov 12, 2026
@cliffhall
cliffhall requested a balanced review from Copilot November 12, 2026 07:42

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Closed fake servers leave mcpdod.token behind, causing teardown to wait the full eight seconds even when nothing is listening; fake-server cleanup should remove the token while preserving real-daemon waits.

1 open issue
What changed in this PR

Ports mcpdo’s daemon test harness to Windows named pipes, addressing #2922 without changing production code. The daemon suites now run on Windows, and mcpdo’s per-file 90% coverage gate is restored there.

Changes:

  • Adds shared endpoint and teardown helpers for Unix sockets and Windows named pipes.
  • Removes broad Windows skips, retaining only cases that require POSIX behavior.
  • Updates fake-daemon token handling, path tests, and quality-gate documentation.
File Description
docs/​quality-gate.md Documents Windows daemon tests and restored coverage enforcement.
clients/​mcpdo/​vitest.config.ts Enforces coverage thresholds on every platform.
clients/​mcpdo/​__tests__/​skills-budget-hint.test.ts Enables Windows execution with shared teardown.
clients/​mcpdo/​__tests__/​rate-limit-envelope.test.ts Uses portable endpoints and token lookup.
clients/​mcpdo/​__tests__/​oauth-error-envelope.test.ts Enables Windows tests and shared directory cleanup.
clients/​mcpdo/​__tests__/​mcp-elicitation.test.ts Enables Windows elicitation tests with shared teardown.
clients/​mcpdo/​__tests__/​mcp-coverage.test.ts Enables daemon cases and platform-neutral liveness checks.
clients/​mcpdo/​__tests__/​mcp-connection.test.ts Enables Windows connection tests with shared teardown.
clients/​mcpdo/​__tests__/​load.test.ts Enables daemon-backed load tests on Windows.
clients/​mcpdo/​__tests__/​helpers/​platform.ts Replaces the broad skip flag with isWindows.
clients/​mcpdo/​__tests__/​helpers/​fake-daemon.ts Publishes fake tokens by daemon directory.
clients/​mcpdo/​__tests__/​helpers/​daemon-endpoint.ts Adds portable endpoint, shutdown, and cleanup helpers.
clients/​mcpdo/​__tests__/​elicitation-client.test.ts Uses portable endpoints and explicit token directories.
clients/​mcpdo/​__tests__/​directory-read.test.ts Enables Windows directory-read tests with shared teardown.
clients/​mcpdo/​__tests__/​daemon-stream.test.ts Ports streaming tests and isolates stale-file coverage.
clients/​mcpdo/​__tests__/​daemon-private.test.ts Enables private-daemon tests with explicit directories.
clients/​mcpdo/​__tests__/​daemon-paths.test.ts Exercises platform branches and Windows temporary-directory handling.
clients/​mcpdo/​__tests__/​daemon-handshake.test.ts Runs handshake tests over platform-native endpoints.
clients/​mcpdo/​__tests__/​daemon-coverage.test.ts Ports daemon coverage cases and adopts shared teardown.

Review effort: Balanced

A closed fake server leaves its published token behind, so stopDaemonIn
waited out its full budget in every fake-server teardown. A daemon
answers ping even while stopping, so an unanswered ping means there is no
shutdown to wait for; a process still draining is removeDaemonDir's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: cliffhall <cliff@futurescale.com>
@cliffhall

Copy link
Copy Markdown
Member Author

Copilot round 1 — 1 finding, fixed in 2090e96: stopDaemonIn no longer waits out its budget when nothing answers ping (a closed fake's leftover token), so fake-server teardowns are fast again; real-daemon waits are unchanged. Nothing in the suppressed block.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

No active review issues remain for the Windows daemon test-harness portability and coverage-enforcement changes.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@cliffhall

Copy link
Copy Markdown
Member Author

Copilot review loop closed: round 2 was clean (no inline comments, no suppressed findings, approval recommended). 2 rounds total.

@cliffhall
cliffhall merged commit c5ec0de into v2/main Nov 12, 2026
14 checks passed
@cliffhall
cliffhall deleted the v2/chore/2922-mcpdo-windows-named-pipe-tests branch November 12, 2026 08:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v2 Issues and PRs for v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

mcpdo: run the daemon test suites on Windows by porting the harness to named pipes

2 participants