fix: dispatch_mcp.py missing mcp.run() entry point
The FastMCP server never started listening on stdio because the file was missing 'if __name__ == "__main__": mcp.run(transport="stdio")'. The LiveKit agent's MCP client got 'Connection closed' during initialize, which killed the entire toolset setup — ALL tools (weather, memory, skills, dispatch) were unavailable. This is why Hope could hear you but never called any tools.
This commit is contained in:
@@ -0,0 +1,152 @@
|
|||||||
|
# Memory Server (Cognee MCP)
|
||||||
|
|
||||||
|
A persistent, centralized **AI memory** service you can attach to any agentic
|
||||||
|
harness (OpenCode, Hermes, Claude Desktop, custom agents). It runs on the Unraid
|
||||||
|
box at `192.168.86.2` as two Docker containers managed by a single compose file
|
||||||
|
(`/mnt/user/appdata/cognee/docker-compose.yml`):
|
||||||
|
|
||||||
|
| Container | Purpose | Port (host) |
|
||||||
|
|----------------------|-------------------------------------------|-------------|
|
||||||
|
| `shane-cognee` | Cognee API + graph/vector store | `8002` (REST) |
|
||||||
|
| `shane-cognee-mcp` | MCP frontend — **Streamable HTTP** | `8003` (`/mcp`) |
|
||||||
|
| `shane-cognee-mcp-sse` | MCP frontend — **SSE** (for clients that can't do Streamable HTTP) | `8004` (`/sse`) |
|
||||||
|
|
||||||
|
Both MCP frontends bridge to the same Cognee API; all memory state lives in the
|
||||||
|
API container, so the two frontends are interchangeable.
|
||||||
|
|
||||||
|
## Endpoints
|
||||||
|
|
||||||
|
- **Streamable HTTP (preferred for most clients):** `http://192.168.86.2:8003/mcp`
|
||||||
|
- **SSE (for OpenCode 1.18.21, Claude Desktop, etc.):** `http://192.168.86.2:8004/sse`
|
||||||
|
- **REST API (custom apps):** `http://192.168.86.2:8002` (docs at `/docs`)
|
||||||
|
|
||||||
|
## Connecting an agentic harness
|
||||||
|
|
||||||
|
Pick the transport your client supports. Use **SSE (8004)** if the client only
|
||||||
|
does SSE, otherwise **Streamable HTTP (8003)**.
|
||||||
|
|
||||||
|
### OpenCode
|
||||||
|
|
||||||
|
OpenCode 1.18.21 only supports SSE (`type: "remote"`). Already configured in
|
||||||
|
`~/.config/opencode/opencode.jsonc`:
|
||||||
|
|
||||||
|
```jsonc
|
||||||
|
"mcp": {
|
||||||
|
"cognee": {
|
||||||
|
"type": "remote",
|
||||||
|
"url": "http://192.168.86.2:8004/sse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify with `opencode mcp list` — it should show `✓ cognee connected`.
|
||||||
|
|
||||||
|
### Hermes
|
||||||
|
|
||||||
|
Hermes speaks Streamable HTTP natively. Already configured in
|
||||||
|
`~/.hermes/config.yaml` under `mcp_servers`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
mcp_servers:
|
||||||
|
cognee:
|
||||||
|
url: http://192.168.86.2:8003/mcp
|
||||||
|
transport: http
|
||||||
|
enabled: true
|
||||||
|
```
|
||||||
|
|
||||||
|
### Claude Desktop / other MCP-aware clients
|
||||||
|
|
||||||
|
Use the SSE endpoint. Example `claude_desktop_config.json`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cognee": {
|
||||||
|
"url": "http://192.168.86.2:8004/sse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
For clients that support Streamable HTTP, point them at
|
||||||
|
`http://192.168.86.2:8003/mcp` instead.
|
||||||
|
|
||||||
|
### Stdio bridge (legacy clients only)
|
||||||
|
|
||||||
|
If a client can only spawn a stdio MCP server, bridge with `mcp-remote`
|
||||||
|
(pointed at the **SSE** endpoint — this `mcp-remote` build is SSE-only):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"cognee": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": ["-y", "mcp-remote", "http://192.168.86.2:8004/sse"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom applications (REST)
|
||||||
|
|
||||||
|
Call the Cognee REST API directly at `http://192.168.86.2:8002`. See
|
||||||
|
`/docs` for the OpenAPI schema. The MCP tools below are thin wrappers over
|
||||||
|
these endpoints.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
The current deployment has no API token (`ENABLE_BACKEND_ACCESS_CONTROL:
|
||||||
|
"false"`). If you later enable auth on the Cognee API, pass the token to the
|
||||||
|
MCP frontend via the `API_TOKEN` env var in the compose file and restart the
|
||||||
|
containers.
|
||||||
|
|
||||||
|
## LAN access / Host guard
|
||||||
|
|
||||||
|
`cognee-mcp` enforces a DNS-rebinding Host/Origin guard. The container is
|
||||||
|
configured to accept the Unraid LAN IP via the env var
|
||||||
|
`MCP_ALLOWED_HOSTS: "192.168.86.2:*"` (comma-separated, requires the `:*` glob).
|
||||||
|
|
||||||
|
If you connect from a client that reaches the server by a **different hostname
|
||||||
|
or IP** (e.g. a DNS name, or a different interface), add that pattern to
|
||||||
|
`MCP_ALLOWED_HOSTS` in `docker-compose.yml` and `docker compose up -d`, or you
|
||||||
|
will get `421 Misdirected Request`. Example for two hosts:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
MCP_ALLOWED_HOSTS: "192.168.86.2:*,cognee.lan:*"
|
||||||
|
```
|
||||||
|
|
||||||
|
To disable the guard entirely (LAN-only, not exposed to the internet), set
|
||||||
|
`MCP_DISABLE_DNS_REBINDING_PROTECTION: "true"`.
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
The server exposes 5 MCP tools:
|
||||||
|
|
||||||
|
| Tool | Description |
|
||||||
|
|----------------|-------------|
|
||||||
|
| `remember` | Store data in memory. Without `session_id` → permanent memory (runs the full add + `cognify` pipeline: ingest, entity extraction, graph build). With `session_id` → fast session-cache memory only (no graph). |
|
||||||
|
| `recall` | Search memory with auto-routing and session awareness. Use this for "what do I know about X". |
|
||||||
|
| `forget` | Delete data from memory (by dataset/id). |
|
||||||
|
| `search_tools` | Find a tool by natural-language description (meta-tool for the agent). |
|
||||||
|
| `call_tool` | Invoke a tool by name with arguments (meta-tool). |
|
||||||
|
|
||||||
|
## Usage patterns
|
||||||
|
|
||||||
|
- **Persist something for good:** `remember` without `session_id`. This triggers
|
||||||
|
`cognify`, which can take a while (ingest + embed + graph). Don't call it in a
|
||||||
|
tight loop; batch related content into one call.
|
||||||
|
- **Scratch / per-conversation notes:** `remember` with a `session_id` for fast,
|
||||||
|
non-graph storage you don't need long-term.
|
||||||
|
- **Retrieve:** `recall` with a natural-language query. It auto-routes between
|
||||||
|
graph and vector search and is session-aware.
|
||||||
|
- **Remove:** `forget` when memory is stale.
|
||||||
|
- Keep payloads reasonable; the MCP frontend rejects uploads over 10 MB.
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
- `421 Misdirected Request` → Host header not in `MCP_ALLOWED_HOSTS`. Add the
|
||||||
|
client's target hostname/IP (with `:*` glob) and recreate the container.
|
||||||
|
- Connection refused on `8003`/`8004` → container not healthy yet; check
|
||||||
|
`docker ps` on Unraid and the API container's health (`/health` on `8002`).
|
||||||
|
- `opencode mcp list` shows the server but not `connected` → check the URL uses
|
||||||
|
the SSE endpoint (`/sse`) for OpenCode, and that the Host pattern is allowed.
|
||||||
@@ -56,3 +56,7 @@ async def _run_worker(worker: "TaskWorker", task_id: str):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception("Task %s crashed: %s", task_id, e)
|
logger.exception("Task %s crashed: %s", task_id, e)
|
||||||
registry.fail(task_id, str(e))
|
registry.fail(task_id, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
mcp.run(transport="stdio")
|
||||||
|
|||||||
Reference in New Issue
Block a user