Skip to content

fix: stop idle MCP input on cancellation - #104

Open
DivyamTalwar wants to merge 1 commit into
pgrundev:mainfrom
DivyamTalwar:fix/stop-idle-mcp-on-cancellation
Open

DivyamTalwar wants to merge 1 commit into
pgrundev:mainfrom
DivyamTalwar:fix/stop-idle-mcp-on-cancellation

Conversation

@DivyamTalwar

Copy link
Copy Markdown
Contributor

What and why

Closes #103.

An idle MCP subprocess could ignore SIGINT/SIGTERM while stdin remained open: the signal context canceled, but the protocol loop stayed blocked in its read. Make inherited stdin interruptible on Linux and macOS with a command-owned wake pipe and poll. Preserve borrowed stdin, stop or join cancellation cleanup, and check cancellation before reading or dispatching another request.

The existing response-write failure handling is retained. No per-read goroutine, global stdin replacement, dependency, SQL or JSON change is introduced.

Verification

Verified commit: fb733cd82fdc79ba8bf2b53401ee7eea72986270.

  • Regression against upstream 9e41414abed05f10ad7ff2fbe7662a5172f151f7 runs the actual main/Cobra child, waits for readiness, sends SIGTERM with stdin held open, and fails until cancellation unblocks the input.
  • Repeated process/transport tests and the complete affected command/MCP race suites pass.
  • Controls cover normal EOF, pre-canceled input, cancellation between buffered requests, read errors, successful output, borrowed-input lifetime and joined cancellation cleanup.
  • bash scripts/gate.sh passes on committed HEAD: build, vet, pinned lint, tests and all six release-platform builds.
  • go test -race ./... passes; formatting and git diff --check are clean.

Scope, risk and rollback

Runtime signal coverage is POSIX-specific; Windows compilation passes, but Windows signal behavior is not claimed verified. Generic opaque non-closeable readers must still cooperate to unblock a read. This fixes the actual CLI stdin path and leaves ordinary tool behavior unchanged. The public generic loop documents its cancellation boundary. Revert this commit to restore the previous input lifecycle.

Checklist

  • Committed-HEAD gate and full race suite pass.
  • Read-only, privacy and deterministic-finding invariants preserved.
  • No new model field, schema migration, dependency or finding.

The signal context canceled while an idle inherited stdin read remained blocked. Use a command-owned wake pipe and poll on supported Unix hosts, preserving borrowed stdin and joining cancellation cleanup. Check cancellation before reads and dispatch without reverting response-write error handling.

Verification: actual main regression fails on current upstream; repeated process and transport tests pass under the race detector. Affected package race suites pass. No dependencies, SQL or JSON fields change. Opaque non-closeable readers still require caller cooperation; Windows signal runtime behavior is not claimed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Idle MCP subprocess does not terminate after cancellation

1 participant