Step 1 — send unauthenticated initialize: server returns HTTP 200 and a live mcp-session-id — proves no credentials are required to establish a session.
Step 2 — send unauthenticated tools/list on the obtained session: server returns the full tool surface (deepseek_chat, deepseek_sessions) — proves tool discovery is reachable without credentials.
RESULT: PASS — tools/list returned deepseek_chat and deepseek_sessions with no credentials supplied.
Step 3 — send unauthenticated tools/call for the local deepseek_sessions tool on the obtained session: server executes the tool and returns its result with no credentials supplied.
HTTP/1.1 200 OK
content-type: text/event-stream
event: message
data: {"result":{"content":[{"type":"text","text":"No active sessions."}]},"jsonrpc":"2.0","id":2}
Impact
In self-hosted HTTP deployments, any host with network access to port 3000 can establish an authenticated-equivalent MCP session and invoke built-in MCP tools without supplying credentials. This was verified end-to-end for session establishment, tool enumeration, and execution of the local deepseek_sessions tool.
deepseek_chat is exposed through the same unauthenticated MCP session, and its handler routes requests through the server-side DeepSeek client. That means a deployment using a valid server-side DEEPSEEK_API_KEY places billable DeepSeek operations behind an unauthenticated endpoint. However, this report's reproduced PoC used a dummy API key and did not directly validate successful upstream DeepSeek billing or quota consumption.
Remediation
Require authentication in self-hosted HTTP mode before MCP session creation. At minimum, pass an authProvider to createMcpExpressApp at transport-http.ts:17 or place equivalent authentication middleware / a reverse proxy in front of /mcp so unauthenticated clients never reach the initialize branch:
For deployments that only need local access, bind to 127.0.0.1 instead of 0.0.0.0 in both createMcpExpressApp and app.listen (transport-http.ts:17 and :107) as a defence-in-depth measure. Upstream docker-compose.yml currently publishes 3000:3000; changing that to 127.0.0.1:3000:3000 would reduce inadvertent exposure on multi-user or server hosts.