Summary
memory.Client.Call() in internal/memory/proxy.go sends a bare http.Post() to the Dewey MCP endpoint (http://localhost:3333/mcp/). The MCP Streamable HTTP transport requires two things that Call() does not provide:
- An
Accept header containing both application/json and text/event-stream
- A proper MCP session lifecycle:
initialize handshake before tools/call invocations
Without these, Dewey returns HTTP 400 (Accept must contain both '"'"'application/json'"'"' and '"'"'text/event-stream'"'"'). This causes all memory proxy tools - hivemind_store, hivemind_find, and the deprecated hivemind_* stubs - to fail with DEWEY_UNAVAILABLE even when Dewey is healthy and running.
To Reproduce
- Start Dewey with HTTP transport:
dewey --http :3333
- Verify Dewey is healthy:
curl -s -X POST http://localhost:3333/mcp/ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '"'"'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}},"id":1}'"'"' - should return a success response
- Test
memory.Client directly against the running Dewey:
client := memory.NewClient("http://localhost:3333/mcp/")
err := client.Health()
// Returns: dewey unavailable: HTTP 400: Accept must contain both
// '"'"'application/json'"'"' and '"'"'text/event-stream'"'"'
- All three methods fail the same way:
client.Health() - DEWEY_UNAVAILABLE
client.Find("test", "", 5) - DEWEY_UNAVAILABLE
client.Store("test", "tag") - DEWEY_UNAVAILABLE
Expected behavior
When Dewey is running and healthy, hivemind_store and hivemind_find should successfully proxy requests to Dewey and return results.
Root Cause
memory.Client.Call() (internal/memory/proxy.go:60-100) uses c.http.Post(c.url, "application/json", ...) which:
- Does not set the
Accept: application/json, text/event-stream header required by the MCP Streamable HTTP transport
- Does not handle SSE-formatted responses (
event: message\ndata: {json}\n\n)
- Sends bare JSON-RPC method names like
store_learning and semantic_search directly, but MCP requires wrapping these in tools/call with a prior initialize handshake
- Does not manage MCP session state (session ID from
Mcp-Session-Id response header)
The same root cause was partially addressed for the doctor health check in #16, where checkDewey() was fixed to use a standalone MCP initialize probe. However, the underlying memory.Client was not fixed, leaving all tool proxy operations broken.
Affected Consumers
| Consumer |
File |
Impact |
hivemind_store tool |
internal/tools/memory/tools.go:52 |
Calls client.Store() - Call("store_learning", ...) - fails with HTTP 400 |
hivemind_find tool |
internal/tools/memory/tools.go:90 |
Calls client.Find() - Call("semantic_search", ...) - fails with HTTP 400 |
Health() method |
internal/memory/proxy.go:104 |
Calls Call("dewey_health", ...) - fails with HTTP 400 |
| MCP server startup |
cmd/replicator/serve.go:45 |
Creates memClient used by all memory tools |
Suggested Fix
Update memory.Client.Call() to speak proper MCP Streamable HTTP:
- Use
http.NewRequest instead of http.Post to set the required Accept: application/json, text/event-stream header
- Manage MCP session lifecycle: send
initialize on first call, cache the Mcp-Session-Id for subsequent calls
- Wrap tool method names in the MCP
tools/call envelope (e.g., store_learning becomes {"method": "tools/call", "params": {"name": "store_learning", ...}})
- Parse SSE-formatted responses to extract JSON-RPC data from
data: lines
- Update tests in
internal/memory/proxy_test.go to use MCP-compatible mock handlers
Location
- Client implementation:
internal/memory/proxy.go:58-100
- Tool registrations:
internal/tools/memory/tools.go
- MCP server wiring:
cmd/replicator/serve.go:45-46
- Tests:
internal/memory/proxy_test.go'
Summary
memory.Client.Call()ininternal/memory/proxy.gosends a barehttp.Post()to the Dewey MCP endpoint (http://localhost:3333/mcp/). The MCP Streamable HTTP transport requires two things thatCall()does not provide:Acceptheader containing bothapplication/jsonandtext/event-streaminitializehandshake beforetools/callinvocationsWithout these, Dewey returns HTTP 400 (
Accept must contain both '"'"'application/json'"'"' and '"'"'text/event-stream'"'"'). This causes all memory proxy tools -hivemind_store,hivemind_find, and the deprecatedhivemind_*stubs - to fail withDEWEY_UNAVAILABLEeven when Dewey is healthy and running.To Reproduce
dewey --http :3333curl -s -X POST http://localhost:3333/mcp/ -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '"'"'{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}},"id":1}'"'"'- should return a success responsememory.Clientdirectly against the running Dewey:client.Health()-DEWEY_UNAVAILABLEclient.Find("test", "", 5)-DEWEY_UNAVAILABLEclient.Store("test", "tag")-DEWEY_UNAVAILABLEExpected behavior
When Dewey is running and healthy,
hivemind_storeandhivemind_findshould successfully proxy requests to Dewey and return results.Root Cause
memory.Client.Call()(internal/memory/proxy.go:60-100) usesc.http.Post(c.url, "application/json", ...)which:Accept: application/json, text/event-streamheader required by the MCP Streamable HTTP transportevent: message\ndata: {json}\n\n)store_learningandsemantic_searchdirectly, but MCP requires wrapping these intools/callwith a priorinitializehandshakeMcp-Session-Idresponse header)The same root cause was partially addressed for the doctor health check in #16, where
checkDewey()was fixed to use a standalone MCP initialize probe. However, the underlyingmemory.Clientwas not fixed, leaving all tool proxy operations broken.Affected Consumers
hivemind_storetoolinternal/tools/memory/tools.go:52client.Store()-Call("store_learning", ...)- fails with HTTP 400hivemind_findtoolinternal/tools/memory/tools.go:90client.Find()-Call("semantic_search", ...)- fails with HTTP 400Health()methodinternal/memory/proxy.go:104Call("dewey_health", ...)- fails with HTTP 400cmd/replicator/serve.go:45memClientused by all memory toolsSuggested Fix
Update
memory.Client.Call()to speak proper MCP Streamable HTTP:http.NewRequestinstead ofhttp.Postto set the requiredAccept: application/json, text/event-streamheaderinitializeon first call, cache theMcp-Session-Idfor subsequent callstools/callenvelope (e.g.,store_learningbecomes{"method": "tools/call", "params": {"name": "store_learning", ...}})data:linesinternal/memory/proxy_test.goto use MCP-compatible mock handlersLocation
internal/memory/proxy.go:58-100internal/tools/memory/tools.gocmd/replicator/serve.go:45-46internal/memory/proxy_test.go'