Skip to content

feat(mcp): HTTP server transport with bearer auth - #28

Merged
yagop merged 2 commits into
mainfrom
feat/mcp-http-server
Aug 22, 2026
Merged

yagop merged 2 commits into
mainfrom
feat/mcp-http-server

Conversation

@yagop

@yagop yagop commented Aug 22, 2026

Copy link
Copy Markdown
Owner

What

Adds an HTTP server mode to the alpaca-mcp CLI, alongside the existing stdio transport. This lets the MCP server be reached remotely / by multiple clients instead of only as a local stdio subprocess.

npx -y @alpaca-open-api/mcp --http --port 3000        # endpoint: http://127.0.0.1:3000/mcp

How

  • packages/mcp/src/http.ts — serves the MCP Streamable HTTP transport over node:http (portable across Node and Bun). Stateful sessions: an initialize POST spins up a fresh buildServer() bound to a StreamableHTTPServerTransport, keyed by the generated mcp-session-id; later requests reuse it. Only /mcp is served (else 404).
  • Bearer auth — SERVER_HTTP_TOKEN (or --token) requires Authorization: Bearer <token> on every request (constant-time compare, 401 + WWW-Authenticate on mismatch). As a safety net, the server refuses to bind a non-loopback host without a token, so the keys-bearing endpoint can't be exposed unauthenticated by accident.
  • mcp.ts — flag parsing moved to node:util parseArgs (--http/--port/--host/--token, -h/-v); env SERVER_HTTP / SERVER_PORT / SERVER_HOST. Honors ALPACA_TOOLSETS per session.
  • Bumps @modelcontextprotocol/sdk to ^1.30.0; engines.node → >=20 (required for stable parseArgs).

stdio remains the default; nothing changes for existing stdio clients.

Config

Variable Default Purpose
SERVER_HTTP — 1/true to serve over HTTP (same as --http)
SERVER_PORT 3000 HTTP port
SERVER_HOST 127.0.0.1 bind address
SERVER_HTTP_TOKEN — bearer token; mandatory to bind a non-loopback host

Tests

packages/mcp/src/http.test.ts drives a real StreamableHTTPClientTransport on an ephemeral port: default 101-tool surface, an end-to-end tool call, 404 for other paths, no-session rejection, and auth (401 without/with wrong token, 200 + full session with the right one). Full suite: 27 pass, typecheck clean.

Notes

  • Static shared-secret auth is right for a single-tenant self-hosted server; it's plaintext over the wire, so terminate TLS at a proxy for non-loopback use. OAuth 2.1 (the SDK's requireBearerAuth path) would be the move for a public multi-user deployment.
  • Does not touch the separate tool-count doc correction tracked on docs/tool-count-256.

🤖 Generated with Claude Code

yagop and others added 2 commits August 22, 2026 16:51
Add an HTTP server mode to the Alpaca MCP CLI alongside the default stdio
transport. `--http` (or `SERVER_HTTP=1`) serves the MCP Streamable-HTTP
transport over node:http at `/mcp`, with stateful per-session servers built
from the configured toolsets (honors ALPACA_TOOLSETS).

- packages/mcp/src/http.ts: session routing + optional bearer-token guard
  (SERVER_HTTP_TOKEN / --token), constant-time compare, 401 on mismatch.
- mcp.ts: --http/--port/--host/--token via node:util parseArgs; refuses to
  bind a non-loopback host without a token; SERVER_PORT/SERVER_HOST env.
- Bump @modelcontextprotocol/sdk to ^1.30.0; engines.node >=20 (parseArgs).
- http.test.ts: end-to-end HTTP client, auth 401/200, 404, no-session paths.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- mcp.ts: print the "ready" line on the server's 'listening' event and add an
  'error' handler, so a failed bind (EADDRINUSE/EACCES) reports cleanly and
  exits 1 instead of throwing unhandled after already claiming readiness.
- mcp.ts: treat a set-but-empty SERVER_PORT/SERVER_HOST as unset (was parsing
  to port 0 / an empty wildcard host); reject port < 1.
- http.ts: fix stale ALPACA_HTTP reference in the header comment (it's SERVER_HTTP).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@yagop
yagop force-pushed the feat/mcp-http-server branch from 7eb8694 to fec8662 Compare August 22, 2026 16:51
@yagop
yagop merged commit 4085e17 into main Aug 22, 2026
1 check passed
@yagop
yagop deleted the feat/mcp-http-server branch August 22, 2026 16:52
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.

1 participant