Skip to content

mcpx: Phase 1 of #1384 — supervised stdio transport behind a flag (supervisor owns the child's pipes) #1385

Closed

Description

@dezren39

Phase 1 of the mcpx supervisor design, #1384 (design doc: files/designs/code-mcpx-stdio-supervisor.md in the keep-the-four-repos-healthy goal workspace). This phase is deliberately the experiment that proves the attach model before any takeover code changes: everything here is additive and flag-gated.

Scope

  1. Hidden mcpx supervise subcommand. Re-exec of the same binary. It spawns exactly one stdio MCP server child with the process semantics NewStdio has today (pkgs/mcpx/internal/mcpclient/stdio.go: own process group via Setpgid, plain os.Pipe()s rather than cmd.Std*Pipe, stderr captured to a ring buffer), owns the child's stdin/stdout/stderr for the child's whole life, and:
    • serves one attached daemon at a time over a unix socket in the mcpx state directory (socket file mode follows the 0600 state-file precedent, internal/daemon/sessions.go);
    • pumps stdin/stdout bytes between socket and child without interpreting MCP frames (framing stays in the daemon's transport reader);
    • buffers child output produced while no daemon is attached, up to a bounded limit; on overflow it keeps the tail and counts dropped bytes, reporting the count to the next daemon that attaches;
    • reports child PID and child exit (with exit error) to the attached daemon;
    • exits when its child has exited and no daemon is attached (no lingering supervisors for dead children).
  2. Supervised transport in internal/mcpclient implementing the same transport interface the pool uses for StdioTransport, connecting to the supervisor socket instead of spawning a child. Detach/adoption semantics of the existing transport are not reused — a supervised transport's Close detaches from the supervisor without signalling the child.
  3. Per-server opt-in config flag selecting the supervised transport for a stdio server. Default off. With the flag off, behaviour is byte-for-byte today's (direct spawn, existing takeover path untouched).

Out of scope: any change to internal/daemon/takeover.go or internal/pool/handoff.go (that is Phase 2); HTTP/SSE upstreams; making supervised the default (Phase 3).

Acceptance criteria

  • With the flag on for a stdio server, the server runs under a supervisor: child PID ≠ daemon-spawned direct child, and the supervisor's parent is not the daemon's serving process (child survives the daemon).
  • Defining test: start daemon + supervised server, make a call, SIGKILL the daemon, start a new daemon — the child's PID is unchanged and a subsequent call on that server succeeds.
  • Child exit while supervised is surfaced to the daemon exactly as a direct child's exit is today (existing pool behaviour/tests apply), and the supervisor process exits afterwards.
  • Unattached-output buffer: a child that writes while no daemon is attached does not block indefinitely or grow memory unboundedly; the dropped-byte count is reported on attach (test covers overflow).
  • With the flag off (default), the full existing mcpx test suite passes unchanged, including internal/e2e/takeover_test.go.
  • go test ./... in pkgs/mcpx passes; new code has tests for the supervisor pump, attach/detach, and buffer overflow.

Evidence / grounding

Activity

  1. added
    kind/featureNew feature or capability request
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/lLarge: multi-day or open-ended; expect staged check-ins
    on Oct 27, 2026
  2. developing-today commented on Oct 27, 2026

    @developing-today
    Contributor
  3. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  4. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · blocked

    • Agent: design architect (repo-design-architect-code job)
    • Session / ID: repo-design-architect-code cron run, 2026-10-27 04:28 CDT
    • Found via: filed this run
    • Task: Queue correction for the note above: the triage packet's first enqueue attempt lost its output to a tool-session failure and landed in the default repo-health-code-shadow queue as task 1354 instead of repo-health-code-pilot. Because queue dedupe is absolute on the dedupe key, re-enqueueing with the correct --queue returned that same row; I cancelled task 1354 (reason recorded on the task) rather than leave live work in the dormant shadow queue. This issue still carries queue/queued with no live task — the fleet monitor's safety-net reconciliation is the route that re-enqueues it into the pilot queue.
    • Expectation: fleet monitor picks this up on its next reconciliation; if it has not within one cycle, re-file the packet under monitor guidance.
    • Links: design design(mcpx): a supervisor that owns each stdio child's pipes — replace the takeover handoff for stdio #1384; cancelled shadow task 1354 (repo-health-code-shadow)
  5. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · blocked

  6. 28 remaining items

  7. added
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    status/parkedDeliberately paused with a recorded resume condition
    on Oct 27, 2026
  8. dezren39 commented on Oct 27, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · parked

  9. added
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 28, 2026
  10. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  11. added a commit that references this issue on Oct 28, 2026
  12. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · done

    • Agent: queue worker (repo-worker-code), Lane D shift
    • Session / ID: queue task 1463
    • Found via: queue claim (resume of parked task)
    • Task: Merged PR mcpx: supervised stdio transport behind a flag (#1385, Phase 1 of #1384) #1495 after CI completed green.
    • Outcome: PR mcpx: supervised stdio transport behind a flag (#1385, Phase 1 of #1384) #1495 merged (merge commit 194e32c). 17 checks: 15 pass, 1 skipped, 1 neutral, 0 fail. Phase 1 delivered as scoped: hidden mcpx supervise subcommand, supervised transport in internal/mcpclient (attach handshake, 1 MiB tail-keep buffer with droppedBytes reporting, detach-only Close), mcpx.supervised per-server flag default off, Pool.dial branch; takeover.go/handoff.go untouched. Closing this issue — all acceptance criteria are Phase 1 scope and are covered by the merged implementation + its tests (supervisor pump, attach/detach, buffer overflow, defining SIGKILL-reattach test in internal/mcpclient/supervised_test.go, full suite green in CI). Cross-repo: dezren39/nix no longer vendors mcpx — it builds from the pinned mcpx-src flake input, so the nix side picks this up on its next pin bump (recorded as SET-REMAINDER in the code backlog; no nix source port owed).
    • Links: PR mcpx: supervised stdio transport behind a flag (#1385, Phase 1 of #1384) #1495
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/lLarge: multi-day or open-ended; expect staged check-inskind/featureNew feature or capability requestpriority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions