Architecture
Streamable HTTP Transport
MCP v1.0 introduced Streamable HTTP as the standard remote transport. This document covers setup, configuration, and usage of the Streamable HTTP listener in loomd.
For current shipped/in-progress status, see docs/IMPLEMENTATION_STATUS.md.
Architecture
Current (local):
IDE -> stdio -> [loom proxy] -> unix socket -> [loomd] -> stdio -> [mcp-server]
With HTTP (remote):
IDE -> stdio -> [loom proxy --remote] -> HTTPS POST -> [loomd /mcp]
^
Web client --------------------------------- HTTPS POST -> [loomd /mcp]
The Unix socket path remains untouched. Streamable HTTP is an additive parallel listener on a separate port.
Quick Start
Local Development (No Auth)
Start the daemon with HTTP on localhost:
loomd --http-addr localhost:8088 --registry /path/to/registry.yaml
Test with curl:
curl -X POST http://localhost:8088/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1.0"}}}'
Expected output includes a JSON-RPC success response and an Mcp-Session-Id header:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "<server-supported-version>",
"capabilities": {},
"serverInfo": {"name": "loom", "version": "<daemon-version>"},
"instructions": "Loom daemon - unified MCP hub management"
}
}
Use that Mcp-Session-Id value on subsequent requests.
Team/Shared Daemon (With Auth)
- Generate a bearer token:
loom auth token-generate
# Token: loom_a1b2c3...
# Stored as: LOOM_HTTP_TOKEN (in macOS Keychain)
- Configure the daemon (
~/.config/loom/config.yaml):
http:
auth:
type: token
token_secret_key: LOOM_HTTP_TOKEN
tls_cert_file: /path/to/cert.pem
tls_key_file: /path/to/key.pem
- Start the daemon:
loomd --http-addr :8088 --registry /path/to/registry.yaml
- Connect from a developer machine:
loom proxy --remote https://shared-server:8088/mcp --remote-token loom_a1b2c3...
Or set the token via environment variable:
export LOOM_REMOTE_TOKEN=loom_a1b2c3...
loom proxy --remote https://shared-server:8088/mcp
Configuration Reference
Daemon Flags
| Flag | Description | Default |
|---|---|---|
--http-addr | Address for Streamable HTTP listener | (disabled) |
File Config (~/.config/loom/config.yaml)
http:
# Session management
session_timeout_minutes: 30 # Idle session expiry
max_sessions: 1000 # Max concurrent sessions
# Origin restriction (DNS rebinding protection)
allowed_origins:
- "https://app.example.com"
# TLS (required for non-localhost)
tls_cert_file: /path/to/cert.pem
tls_key_file: /path/to/key.pem
# Authentication
auth:
type: token # token | oidc | mtls | oauth2
token_secret_key: LOOM_HTTP_TOKEN
# For type: oidc
oidc_issuer: https://auth.example.com
oidc_client_id: loom-daemon
# For type: mtls
tls_client_ca: /path/to/ca.pem
allowed_common_names:
- "developer.example.com"
Authentication Types
| Type | Description | Use Case |
|---|---|---|
token | Static bearer token | Small teams, dev environments |
oidc | JWT via OIDC provider | Enterprise SSO integration |
mtls | Mutual TLS with client certs | Zero-trust infrastructure |
oauth2 | OAuth 2.1 with PKCE | Standards-based access control |
When binding to localhost, auth is optional. When binding to a non-localhost address, auth is required and the daemon refuses to start without it.
OAuth 2.1 (PKCE)
The daemon includes a built-in OAuth 2.1 authorization server. Enable it in the daemon config:
http:
auth:
type: oauth2
oauth:
enabled: true
token_ttl_minutes: 60
allow_dynamic_registration: true
This exposes standard endpoints:
| Path | Description |
|---|---|
/.well-known/oauth-authorization-server | Server metadata (RFC 8414) |
/.well-known/oauth-protected-resource | Protected resource metadata (RFC 9728) |
/oauth2/register | Dynamic client registration (RFC 7591) |
/oauth2/authorize | Authorization endpoint |
/oauth2/token | Token exchange (PKCE S256 required) |
/oauth2/revoke | Token revocation (RFC 7009) |
See docs/ENTERPRISE_SECURITY.md for the full PKCE flow with curl examples.
Security
- Localhost binding: Auth is optional (
http.auth.typemay be omitted). - Non-localhost binding: Auth required. The daemon refuses to start without
http.auth.typeconfigured. - Non-localhost without TLS: The daemon logs a warning. Strongly recommend TLS for any non-localhost deployment.
- Session management: Sessions expire after configurable idle timeout. A background reaper cleans up expired sessions every minute.
Protocol Details
The Streamable HTTP transport follows the MCP Streamable HTTP specification:
- POST /mcp: Send JSON-RPC messages. Returns
application/jsonfor requests,202 Acceptedfor notifications. - GET /mcp: Returns
405 Method Not Allowed(server-initiated messages not yet implemented). - DELETE /mcp: Terminates a session. Requires
Mcp-Session-Idheader. - Mcp-Session-Id: Set by the server on initialize response. Required for all subsequent requests.
Request Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json |
Accept | Recommended | Should include application/json |
Mcp-Session-Id | After init | Session ID from initialize response |
Authorization | If auth enabled | Bearer <token> |
CLI Commands
Token Management
loom auth token-generate # Generate and store a new token
loom auth token-generate --key MY_KEY # Use custom secret key
loom auth token-show # Display current token
loom auth token-revoke # Delete token
Remote Proxy
loom proxy --remote https://host:8088/mcp --remote-token TOKEN
loom proxy --remote https://host:8088/mcp # Uses LOOM_REMOTE_TOKEN env
Endpoints
| Path | Auth | Description |
|---|---|---|
/mcp | Required (if configured) | MCP Streamable HTTP endpoint |
/health | No | Health check for load balancer probes |
/.well-known/oauth-authorization-server | No | OAuth server metadata (when http.oauth.enabled=true) |
/.well-known/oauth-protected-resource | No | OAuth protected resource metadata (when http.oauth.enabled=true) |
/oauth2/register | No | Dynamic client registration (when http.oauth.enabled=true) |
/oauth2/authorize | No | OAuth authorization endpoint (when http.oauth.enabled=true) |
/oauth2/token | No | OAuth token endpoint (when http.oauth.enabled=true) |
/oauth2/revoke | No | OAuth token revocation endpoint (when http.oauth.enabled=true) |