moor's MCP server (@moor-sh/mcp) currently only supports StdioServerTransport. Operators install it via bunx @moor-sh/mcp, the shim runs locally on their laptop, and it proxies to moor's HTTP API. For a remote moor with private admin, that also means an SSH tunnel.
A native HTTP MCP endpoint on moor itself would let clients (Claude Code, Cursor, anything else MCP-compatible) connect directly to https://moor.example.com/mcp. No local stdio shim, no tunnel, no Bun-on-laptop dependency.
What this does NOT solve
(Corrected from the original framing: HTTP MCP with static bearer auth does not eliminate per-client credentials. The bearer token still has to live in each client's MCP config. "Rotate in one place" would require OAuth, SSO, or per-client minted tokens — separate work.)
What HTTP MCP does remove:
- The local stdio shim (
bunx @moor-sh/mcp process on the laptop).
- The SSH tunnel for remote moor with private admin.
- The Bun-on-laptop install dependency.
That's still meaningful, but the framing should be "remove infrastructure dependencies on the operator's laptop," not "centralized credential management."
Design defaults (locked before implementation)
These were nailed down in design discussion to avoid scope drift during the coding pass:
- Off by default. Enable via
MOOR_MCP_HTTP=1 env var on the moor service. Conservative posture preserved.
- Bearer auth on every request, including
tools/list. No unauthenticated discovery. The cost of gating discovery is approximately zero; the upside of allowing it on a control plane is approximately zero.
- Origin/CORS: deny browser origins by default. Add
MOOR_MCP_ALLOWED_ORIGINS=https://... only when needed. The MCP Streamable HTTP spec explicitly requires servers to validate Origin.
- Stdio path stays permanently supported.
@moor-sh/mcp (the npm package) remains the recommended path for local-only setups. HTTP is for operators who want browser-resident clients or who don't want a local shim.
- First verified client target: Claude Code. End-to-end test against a real client before merging; document compatibility with any other client only after testing.
Implementation notes (open questions for the coding pass)
- SDK adapter vs hand-rolled transport. Current dep
@modelcontextprotocol/server@2.0.0-alpha.2 is alpha. Streamable HTTP requires session-ID handling, protocol-version headers, POST + GET-or-405, SSE responses for streaming, and Origin validation. This is real protocol work. Prefer an HTTP adapter from the SDK over hand-rolling these on the existing Bun route, but verify the adapter exists in the alpha and produces output Claude Code accepts.
- Endpoint shape: the spec uses a single MCP endpoint for both POST (client → server) and GET (server → client SSE). Need to wire both into moor's Bun server.
- Coexistence with
/api/*: same bearer-auth check as the existing API, mounted at a separate path (/mcp). Should reuse the auth middleware, not duplicate.
Not in scope
- OAuth / SSO / per-client tokens. Separate auth track, not blocking HTTP MCP.
@moor-sh/mcp stdio replacement. Stdio path stays.
- Multi-tenancy or RBAC. moor is single-operator by design.
Related work (now complete)
#17 is the last remaining piece of the original MCP onboarding track.
moor's MCP server (
@moor-sh/mcp) currently only supportsStdioServerTransport. Operators install it viabunx @moor-sh/mcp, the shim runs locally on their laptop, and it proxies to moor's HTTP API. For a remote moor with private admin, that also means an SSH tunnel.A native HTTP MCP endpoint on moor itself would let clients (Claude Code, Cursor, anything else MCP-compatible) connect directly to
https://moor.example.com/mcp. No local stdio shim, no tunnel, no Bun-on-laptop dependency.What this does NOT solve
(Corrected from the original framing: HTTP MCP with static bearer auth does not eliminate per-client credentials. The bearer token still has to live in each client's MCP config. "Rotate in one place" would require OAuth, SSO, or per-client minted tokens — separate work.)
What HTTP MCP does remove:
bunx @moor-sh/mcpprocess on the laptop).That's still meaningful, but the framing should be "remove infrastructure dependencies on the operator's laptop," not "centralized credential management."
Design defaults (locked before implementation)
These were nailed down in design discussion to avoid scope drift during the coding pass:
MOOR_MCP_HTTP=1env var on the moor service. Conservative posture preserved.tools/list. No unauthenticated discovery. The cost of gating discovery is approximately zero; the upside of allowing it on a control plane is approximately zero.MOOR_MCP_ALLOWED_ORIGINS=https://...only when needed. The MCP Streamable HTTP spec explicitly requires servers to validateOrigin.@moor-sh/mcp(the npm package) remains the recommended path for local-only setups. HTTP is for operators who want browser-resident clients or who don't want a local shim.Implementation notes (open questions for the coding pass)
@modelcontextprotocol/server@2.0.0-alpha.2is alpha. Streamable HTTP requires session-ID handling, protocol-version headers, POST + GET-or-405, SSE responses for streaming, and Origin validation. This is real protocol work. Prefer an HTTP adapter from the SDK over hand-rolling these on the existing Bun route, but verify the adapter exists in the alpha and produces output Claude Code accepts./api/*: same bearer-auth check as the existing API, mounted at a separate path (/mcp). Should reuse the auth middleware, not duplicate.Not in scope
@moor-sh/mcpstdio replacement. Stdio path stays.Related work (now complete)
@moor-sh/mcppackaging@moor-sh/clipackaging +moor mcp configsubcommand#17 is the last remaining piece of the original MCP onboarding track.