Problem
The vendored mcp/server/fastmcp/server.py:180 (in the mcp Python package shipped with zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2) hardcodes enable_dns_rebinding_protection=True whenever host is localhost/127.0.0.1/::1. Combined with the default allowed_hosts=["127.0.0.1:*", "localhost:*", "[::1]:*"], any MCP client connecting from a non-localhost hostname is rejected with HTTP 421 Invalid Host header — even if the deployment is behind LAN-only ingress, behind Authentik/CF Access, or on a private overlay network.
In practice this means:
- Claude Code running on a separate host can't reach Graphiti via
http://homelab-host:8765/mcp
- Cline / Cursor / Continue / etc. running on a dev box can't share the same Graphiti backend that OWU on the homelab itself uses
- The
MCP_SERVER_HOST=0.0.0.0 env var (already supported) implies cross-host intent — but the host-header check makes it cosmetic, not functional
Repro
# from any non-localhost host
curl -X POST http://homelab-host:8765/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"x","version":"1"}}}'
# → HTTP 421 "Invalid Host header"
Workaround shipped downstream
1-line sed patch baked into a thin downstream image (ghcr.io/sgral/graphiti-mcp:1.0.2-host-fix):
FROM zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2
RUN sed -i \
's/enable_dns_rebinding_protection=True/enable_dns_rebinding_protection=False/' \
/app/mcp/.venv/lib/python3.11/site-packages/mcp/server/fastmcp/server.py
This works but is brittle (file path tied to vendored mcp version) and disables protection globally instead of allowing scoped allowlists.
Proposed fix
Expose mcp.server.transport_security.TransportSecuritySettings knobs in Graphiti's config.yaml server: block:
server:
transport: "http"
host: "0.0.0.0"
port: 8000
transport_security:
enable_dns_rebinding_protection: true # default keeps current safety
allowed_hosts:
- "localhost:*"
- "127.0.0.1:*"
- "my-homelab-host:*"
- "memory.example.com"
Graphiti's MCP entrypoint would construct TransportSecuritySettings(...) from config and pass through FastMCP(transport_security=...). Default behavior unchanged — operators who need cross-host access add hostnames explicitly.
Happy to send a PR if there's appetite for this shape.
Environment
- Image:
zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2
- Graphiti version: 0.28.2
- MCP transport: streamable HTTP
- Deployment: Docker on Proxmox LXC, behind Cloudflare Tunnel + Authentik OIDC
Problem
The vendored
mcp/server/fastmcp/server.py:180(in themcpPython package shipped withzepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2) hardcodesenable_dns_rebinding_protection=Truewheneverhostislocalhost/127.0.0.1/::1. Combined with the defaultallowed_hosts=["127.0.0.1:*", "localhost:*", "[::1]:*"], any MCP client connecting from a non-localhost hostname is rejected withHTTP 421 Invalid Host header— even if the deployment is behind LAN-only ingress, behind Authentik/CF Access, or on a private overlay network.In practice this means:
http://homelab-host:8765/mcpMCP_SERVER_HOST=0.0.0.0env var (already supported) implies cross-host intent — but the host-header check makes it cosmetic, not functionalRepro
Workaround shipped downstream
1-line
sedpatch baked into a thin downstream image (ghcr.io/sgral/graphiti-mcp:1.0.2-host-fix):This works but is brittle (file path tied to vendored mcp version) and disables protection globally instead of allowing scoped allowlists.
Proposed fix
Expose
mcp.server.transport_security.TransportSecuritySettingsknobs in Graphiti'sconfig.yamlserver:block:Graphiti's MCP entrypoint would construct
TransportSecuritySettings(...)from config and pass throughFastMCP(transport_security=...). Default behavior unchanged — operators who need cross-host access add hostnames explicitly.Happy to send a PR if there's appetite for this shape.
Environment
zepai/knowledge-graph-mcp:1.0.2-graphiti-0.28.2