Hosted HTTP deployment¶
A hosted edi-mcp lets many users connect with
claude mcp add --transport http edi https://edi-mcp.example.org/mcp. The HTTP
transport is stateless Streamable HTTP1 at /mcp: no session
header, no server-initiated stream, so any instance can answer any request and
instances can sit behind a plain load balancer.
POST /mcp takes JSON-RPC requests; GET and DELETE on /mcp return 405
with Allow: POST. /mcp/ is served directly rather than redirected. Every
response carries an x-request-id header (the caller's own value when it is a
short safe token, otherwise a generated one) that also appears in the JSON logs.
Configuration essentials¶
EDI_MCP_SERVER__TRANSPORT=http
EDI_MCP_SERVER__BIND_ADDRESS=127.0.0.1 # the proxy connects locally
EDI_MCP_SERVER__BIND_PORT=8080
EDI_MCP_SERVER__PUBLIC_BASE_URL=https://edi-mcp.example.org
public_base_url does two things:
- its host and origin join the
HostandOriginallow-lists (server.allowed_hosts,server.allowed_origins) used for DNS-rebinding protection. Add any other names the service answers on to those lists;server.dns_rebinding_protectionforces the check on or off (unset leaves the SDK default, which is on for loopback binds or when allow-lists are set); - when it starts with
https://, it opens the TLS gate for per-caller keys (below).
Other HTTP settings: server.json_response answers POST /mcp with
application/json instead of a single SSE frame, and
server.max_request_body_size (default 1 MiB) caps request bodies. All settings
are listed on the Configuration page.
EDI API keys over HTTP¶
Each caller brings their own EDI API key in the X-EDI-Key header (the name is
server.request_key_header). The header is honoured only when
public_base_url is https://; otherwise the middleware strips it before any
handler sees it and logs one warning. server.allow_insecure_header_key
overrides the gate for local development only.
A call with a key is served by PASTA; a call without one is served anonymously
from DataONE, as on stdio (see Backends). The
operator's own key (EDI_API_KEY in the server's environment) is not lent
to HTTP callers unless server.share_config_key_over_http is true; enable that
only on a private deployment where every caller may act as the operator. The
MCP-level Authorization header is never forwarded to EDI. See
Security for the full key-handling rules.
Behind a reverse proxy¶
Terminate TLS at the proxy (the key is a bearer secret), forward Host
unchanged, and pass X-EDI-Key through. uvicorn runs with proxy headers
enabled2. Caddy3:
nginx:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_buffering off; # single SSE frame per response
}
systemd¶
[Unit]
Description=edi-mcp (Streamable HTTP)
After=network-online.target
[Service]
User=edi
EnvironmentFile=/etc/edi-mcp.env
ExecStart=/opt/edi-mcp/.venv/bin/edi-mcp --transport http
Restart=on-failure
NoNewPrivileges=true
ProtectSystem=strict
[Install]
WantedBy=multi-user.target
Keep /etc/edi-mcp.env readable by the service user only if it holds an
operator key.
Container image¶
A Dockerfile (Python slim base, non-root user, health check on /healthz) is
planned for the v0.1.0 release and is not in the repository yet. Until then,
install the package into a virtual environment as above.
Health and readiness¶
GET /healthzis liveness only: always 200 withstatus,version,protocolVersionandtransport; it contacts nothing upstream.GET /readyzreturns 503 withstatus: warmingwhile startup work runs, then 200 withstatus: ready,degradedandkeyConfigured(whether an operator key is set; the key itself is never shown).
Not available over HTTP¶
Downloads exist only on stdio, confined to downloads.directory: the
download tools (planned for build step 6) are never listed over HTTP. Each instance keeps its own
in-memory response cache (cache.* settings), so instances do not share state.
-
MCP 2026-07-28 — Transports. https://modelcontextprotocol.io/specification/2026-07-28/basic/transports ↩
-
Uvicorn — Deployment. https://www.uvicorn.org/deployment/ ↩
-
Caddy — reverse_proxy. https://caddyserver.com/docs/caddyfile/directives/reverse_proxy ↩