Skip to content

feat(mcp): add --host support for HTTP mode and harden daemon startup#232

Open
kleddbot wants to merge 1 commit intotobi:mainfrom
kleddbot:fix/mcp-http-host-flag
Open

feat(mcp): add --host support for HTTP mode and harden daemon startup#232
kleddbot wants to merge 1 commit intotobi:mainfrom
kleddbot:fix/mcp-http-host-flag

Conversation

@kleddbot
Copy link

@kleddbot kleddbot commented Feb 20, 2026

PR #232 Draft — Updated 2026-03-11

Title

feat(mcp): add --host support for HTTP mode and harden daemon startup

Body

Summary

Refreshes PR #232 on top of current upstream main (post-v2.0.1).

The original PR targeted the pre-v2 layout (src/qmd.ts, src/mcp.ts).
Since v2.0.0 moved the relevant code into src/cli/qmd.ts and src/mcp/ server.ts, this update ports the same feature to the current code shape
and includes additional hardening around validation and daemon startup.

Fixes #227.

Problem

Current main still starts MCP HTTP with a hardcoded localhost bind and
no explicit host override. That is unreliable for VM/container host-access paths where the client reaches the host over IPv4 but the server binds to IPv6 loopback.

I re-verified the original Colima reachability issue against current
upstream on March 11, 2026 in an isolated Colima environment:

  • the current QMD MCP HTTP server bound to ::1
  • localhost and [::1] worked on the host
  • 127.0.0.1 did not
  • a Colima container could not reach the server via host.docker.internal

A control test in the same environment confirmed the network behavior
behind the issue:

  • a service bound to 127.0.0.1 was reachable from the Colima container
  • a service bound to ::1 was not

Current main also still has a separate daemon startup bug: qmd mcp --http --daemon reports success before the child has actually bound the
requested port. With a deterministic port-collision repro, the parent
exited successfully, printed Started on ..., and wrote mcp.pid even
though the child had already failed with EADDRINUSE.

What This Change Adds

  • qmd mcp --http --host <ADDR>
  • qmd mcp --http --daemon --host <ADDR>
  • host threading through the v2 CLI and MCP HTTP server
  • IPv6 host normalization/display handling
  • clearer bind-specific EADDRINUSE reporting
  • daemon IPC readiness signaling so the parent only:
    • writes mcp.pid after successful bind
    • prints Started on ... after successful bind

Hardening Included

This version also rejects malformed --host input early, including:

  • empty or blank values
  • URL-like and path-like values
  • flag-like values
  • host:port passed to --host
  • bracketed non-IPv6 values such as [localhost]
  • whitespace-bearing host values

Validation

Validated against current upstream main (post-v2.0.1):

  • the original Colima reachability issue still reproduces on current
    upstream
  • the daemon false-success/stale-PID behavior still reproduces on current
    upstream with a deterministic port collision

Local verification on the refreshed v2 port:

  • pnpm -s tsc -p tsconfig.build.json
  • pnpm vitest run test/mcp-host.test.ts30/30
  • pnpm vitest run test/mcp.test.ts74/74
  • pnpm vitest run test/cli.test.ts112/112
  • pnpm vitest run test/773/773

Examples

qmd mcp --http --host 127.0.0.1
qmd mcp --http --host 0.0.0.0 --port 8181
qmd mcp --http --host ::1
qmd mcp --http --daemon --host 127.0.0.1 --port 8181

@kleddbot kleddbot changed the title Add --host flag to MCP HTTP server feat(mcp): add --host flag to HTTP server bind address Feb 21, 2026
@kleddbot kleddbot changed the title feat(mcp): add --host flag to HTTP server bind address fix(mcp): add --host flag to HTTP server bind address Feb 22, 2026
@kleddbot kleddbot force-pushed the fix/mcp-http-host-flag branch from 8738690 to 330452d Compare February 25, 2026 06:30
@kleddbot
Copy link
Author

Added follow-up hardening in 6ba8786; PR body updated with details.

Add explicit bind-host control for `qmd mcp --http` and fix the daemon
false-success startup bug.

- New `--host <ADDR>` flag for foreground and daemon HTTP modes
- Host validation: rejects URLs, flags, host:port, bracketed non-IPv6,
  whitespace, and empty values via src/mcp-host.ts
- Host normalization: handles [::1] → bind ::1 / display [::1], defaults
  to localhost
- Daemon IPC readiness: parent waits for child bind confirmation before
  writing mcp.pid and reporting success; port collisions now exit 1 with
  no stale PID file
- Settled guard prevents double-resolution from message+exit races
- EADDRINUSE errors now include the bind host

Ported from the v1.1.x PR tobi#232 branch to the v2.0.x source layout
(src/cli/qmd.ts, src/mcp/server.ts).

Fixes tobi#227.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@kleddbot kleddbot force-pushed the fix/mcp-http-host-flag branch from 6ba8786 to 2fa5726 Compare March 11, 2026 17:29
@kleddbot kleddbot changed the title fix(mcp): add --host flag to HTTP server bind address feat(mcp): add --host support for HTTP mode and harden daemon startup Mar 11, 2026
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.

[mcp --http] macOS: server binds IPv6-only via "localhost", unreachable from IPv4 clients (Docker/Colima)

1 participant