-
Notifications
You must be signed in to change notification settings - Fork 7
HTTP Transport
HTTP transport configuration and reference for Memory Journal MCP Server.
Memory Journal supports two MCP transport protocols simultaneously when running in HTTP mode:
| Protocol | Spec Version | Endpoints | Session Management |
|---|---|---|---|
| Streamable HTTP | 2025-03-26 | POST/GET/DELETE /mcp |
mcp-session-id header |
| Legacy SSE | 2024-11-05 |
GET /sse, POST /messages
|
sessionId query param |
Why both? Streamable HTTP is the current MCP standard. Legacy SSE ensures backward compatibility with older MCP clients (e.g., MCP Inspector, older SDK versions).
Note
Legacy SSE is only available in stateful mode. Stateless mode only supports Streamable HTTP.
npm:
# Stateful (default) — supports both protocols
memory-journal-mcp --transport http --port 3000
# Bind to all interfaces (required for containers)
memory-journal-mcp --transport http --port 3000 --server-host 0.0.0.0
# Stateless (serverless) — Streamable HTTP only
memory-journal-mcp --transport http --port 3000 --statelessDocker:
# Stateful
docker run --rm -p 3000:3000 \
-v ./data:/app/data \
writenotenow/memory-journal-mcp:latest \
--transport http --port 3000 --server-host 0.0.0.0
# Stateless
docker run --rm -p 3000:3000 \
-v ./data:/app/data \
writenotenow/memory-journal-mcp:latest \
--transport http --port 3000 --server-host 0.0.0.0 --statelessImportant
Docker containers must use --server-host 0.0.0.0 to accept connections from outside the container.
| Endpoint | Description | Mode |
|---|---|---|
GET / |
Server info (name, version, protocols, endpoints) | Both |
POST /mcp |
JSON-RPC requests (initialize, tools/call, etc.) | Both |
GET /mcp |
SSE stream for server-to-client notifications | Stateful |
DELETE /mcp |
Session termination | Stateful |
GET /sse |
Legacy SSE connection (MCP 2024-11-05) | Stateful |
POST /messages |
Legacy SSE message endpoint | Stateful |
GET /health |
Health check ({ status: "ok", timestamp }) |
Both |
Returns server metadata and available endpoints:
{
"name": "memory-journal-mcp",
"version": "4.x.x",
"status": "running",
"protocols": [
"Streamable HTTP (MCP 2025-03-26)",
"Legacy SSE (MCP 2024-11-05)"
],
"endpoints": {
"POST /mcp": "Streamable HTTP endpoint",
"GET /mcp": "SSE stream (stateful)",
"DELETE /mcp": "Session termination",
"GET /sse": "Legacy SSE connection (MCP 2024-11-05)",
"POST /messages": "Legacy SSE message endpoint",
"GET /health": "Health check"
}
}Always public (no authentication, no rate limiting):
{
"status": "healthy",
"timestamp": "2026-03-05T07:00:00.000Z"
}Every HTTP response includes the following security headers:
| Header | Value |
|---|---|
X-Content-Type-Options |
nosniff |
X-Frame-Options |
DENY |
Content-Security-Policy |
default-src 'none'; frame-ancestors 'none' |
Cache-Control |
no-store, no-cache, must-revalidate |
Referrer-Policy |
no-referrer |
Permissions-Policy |
camera=(), microphone=(), geolocation=() |
Optionally, when --enable-hsts is set:
| Header | Value |
|---|---|
Strict-Transport-Security |
max-age=31536000; includeSubDomains |
- 100 requests per minute per IP (sliding window)
- Returns
429 Too Many Requestswhen exceeded - Health check (
GET /health) is exempt
Configurable via CLI or environment variable. Supports comma-separated multiple origins and wildcard subdomains:
# Single origin
memory-journal-mcp --transport http --cors-origin "http://localhost:3000"
# Multiple origins (comma-separated)
memory-journal-mcp --transport http --cors-origin "http://localhost:3000,https://app.example.com"
# Wildcard subdomain
memory-journal-mcp --transport http --cors-origin "*.example.com"
# Environment variable
MCP_CORS_ORIGIN=http://localhost:3000 memory-journal-mcp --transport httpDefault: * (all origins). Use specific origins in production.
Request bodies are limited to 1 MB to prevent memory exhaustion. Requests exceeding this limit receive 413 Payload Too Large.
Unknown paths return a structured JSON response:
{
"error": "Not found"
}Session IDs are protocol-scoped:
- SSE session IDs are rejected on
/mcpendpoints - Streamable HTTP session IDs are rejected on
/messagesendpoint
This prevents session confusion when both protocols are active simultaneously.
- UUID-based session IDs via
crypto.randomUUID() - 30-minute timeout with automatic cleanup
- 5-minute sweep interval for expired sessions
Streamable HTTP sessions:
# 1. Initialize — server returns mcp-session-id header
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
# 2. Subsequent requests — include mcp-session-id
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "mcp-session-id: YOUR_SESSION_ID" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
# 3. Terminate session
curl -X DELETE http://localhost:3000/mcp \
-H "mcp-session-id: YOUR_SESSION_ID"Legacy SSE sessions:
# 1. Open SSE connection — server sends endpoint event with sessionId
curl -N http://localhost:3000/sse
# 2. Send messages to the returned endpoint
curl -X POST "http://localhost:3000/messages?sessionId=YOUR_SSE_SESSION_ID" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'No session tracking. Each request is independent. Best for serverless deployments.
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"test_simple","arguments":{"message":"Hello"}}}'| Feature | Stateful (default) | Stateless (--stateless) |
|---|---|---|
| Progress Notifications | ✅ Yes | ❌ No |
| SSE Streaming | ✅ Yes | ❌ No |
| Legacy SSE Protocol | ✅ Yes | ❌ No |
| Session Management | ✅ Yes | ❌ No |
| Serverless Compatible | ✅ Native | |
| Horizontal Scaling | ✅ Any instance |
Choose Stateful when:
- Running on persistent infrastructure (VMs, containers, dedicated servers)
- Need progress notifications for long-running tools
- Need Legacy SSE for backward compatibility
Choose Stateless when:
- Deploying to serverless (AWS Lambda, Cloudflare Workers, Vercel)
- Horizontal scaling without sticky sessions
- Simple request-response patterns
The HTTP transport is implemented as a modular directory:
src/transports/http/
types.ts — Configuration, constants, rate limiting types
security.ts — CORS, security headers, rate limiting, client IP
handlers.ts — Health check, root info, auth middleware
server.ts — HttpTransport class
index.ts — Barrel re-export
Key design decisions:
-
Extracted from McpServer.ts — HTTP logic lives in its own module, keeping
McpServer.tsfocused on tool/resource/prompt registration -
Dual-protocol — Both
StreamableHTTPServerTransportandSSEServerTransportshare the same Express app - Built-in rate limiting — Zero-dependency sliding window with automatic cleanup
- Server timeouts — Request (120s), keep-alive (65s), and headers (66s) for DoS mitigation
- Session isolation — Each protocol maintains its own session map; cross-protocol access is blocked
| CLI Flag | Env Variable | Default | Description |
|---|---|---|---|
--transport http |
— | stdio |
Enable HTTP transport |
--port <number> |
PORT |
3000 |
HTTP port |
--server-host <host> |
MCP_HOST |
localhost |
Bind address (0.0.0.0 for containers) |
--stateless |
— | false |
Disable session management |
--cors-origin <origins> |
MCP_CORS_ORIGIN |
* |
CORS allowed origins (comma-separated) |
--backup-interval <minutes> |
— | 0 |
Automated backup interval (0 = off) |
--keep-backups <count> |
— | 5 |
Max backups retained during cleanup |
--vacuum-interval <minutes> |
— | 0 |
Database optimize interval (0 = off) |
--rebuild-index-interval <minutes> |
— | 0 |
Vector index rebuild interval (0 = off) |
Next: Learn about Configuration or check Security.