Commit Graph

2 Commits

Author SHA1 Message Date
Reuven 858ce28f7e fix(cli): bin/cli.js MCP-stdio auto-detect overrode explicit -t http
Investigating why the #1874 boot smoke kept failing in CI uncovered
a separate-but-related cli bug:

  v3/@claude-flow/cli/bin/cli.js auto-routes any `mcp start *`
  invocation to stdio mode when stdin isn't a TTY — even when the
  user explicitly passed `-t http`. Result: every smoke / non-TTY
  caller silently got stdio regardless of the transport flag.

  This is the same class as #1874: a "smart default" that overrides
  explicit user intent, with no test catching it. Yet another
  example of self-consistent code where everyone agreed on the
  wrong behaviour.

Fix: the MCP auto-detect now defers when explicit `-t <non-stdio>`,
`--transport <non-stdio>`, or `--transport=<non-stdio>` is in argv.
HTTP transport now starts when requested even from non-TTY contexts
(CI smoke, daemonized callers, etc.).

Verified locally:
  $ node bin/cli.js mcp start -t http -p N
    [OK] MCP Server started — Transport: http (was: stdio)

Smoke test simplified
─────────────────────

The boot-an-actual-server-and-call-initialize approach hit a
secondary issue (in-process HTTP server doesn't keep the process
alive after `await mcpServer.start()` returns; needs separate
plumbing). For #1874's regression coverage, a static dist scan is
sufficient and reliable: assert the protocolVersion assignment is
a YYYY-MM-DD spec string, reject the {major,...} object form.

Combined with witness markers (#1874-mcp, #1874-shared) attesting
the spec strings live in dist, and the corrected unit test in
mcp.test.ts using the spec string form, this is three-way coverage
of the bug class without flaky integration plumbing.

A separate issue tracks the boot-smoke gap (cli's HTTP server
process-lifetime); not blocking #1874 closure.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-09 14:17:40 -04:00
Reuven d065b2d654 fix #1874 + add MCP protocol-compliance smoke layer
The bug
───────

@claude-flow/mcp and @claude-flow/shared returned protocolVersion as
{ major, minor, patch } in the initialize response. The MCP spec
requires a YYYY-MM-DD string. Claude Code's Zod validator rejects
the object form with 'Invalid input: expected string, received
object', so HTTP MCP transport users couldn't connect at all.

Fix
───

  - MCPProtocolVersion type: interface with major/minor/patch →
    type alias for string (both packages).
  - Server constants: '2025-11-25' (mcp) and '2024-11-05' (shared).
  - Existing unit test in mcp.test.ts also corrected — it was
    asserting the wrong shape, so test + prod agreed on a non-spec
    format. This is the most important finding from the
    'why did validation miss this' investigation.
  - README example updated to spec-compliant string.

Why validation missed it (the gap)
──────────────────────────────────

  - Layer 1 (smoke): no smoke test boots the actual HTTP MCP
    server, sends a real initialize request, and validates the
    wire format. The existing tests only exercise tool execution.
  - Layer 2 (witness): tracks fix presence, can't catch
    'always-wrong-from-the-start' bugs that have no good baseline.
  - Layer 3 (history): same — no marker, no signal.
  - The unit test was self-consistent with the buggy production
    code. Both used { major, minor, patch }. Nothing measured
    against the upstream MCP spec or a real client validator.

Closing the gap
───────────────

  plugins/ruflo-core/scripts/test-mcp-protocol.mjs
    Boots the HTTP MCP server, sends initialize, asserts response
    shape against the spec:
      - protocolVersion is a string matching YYYY-MM-DD
      - capabilities is an object
      - serverInfo has { name, version } strings
    Final assertion mirrors what Claude Code's Zod would accept.

  v3-ci.yml: new mcp-protocol-smoke job (Linux + macOS), gated
  before witness-verify. Three layers of regression guard now
  cover this class.

  verification/witness-fixes.json: registers #1874-mcp and
  #1874-shared. Witness now attests the spec strings are present in
  both dist files; future regressions to the object form are caught
  by witness-verify, not just user reports.

Impact
──────

  84/84 fixes verified in the regenerated manifest (was 82).
  Anyone running ruflo mcp start -t http with the new build can now
  connect Claude Code without the Zod rejection.

Closes #1874

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-09 13:17:38 -04:00