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:
|
||||
logger.exception("Task %s crashed: %s", task_id, e)
|
||||
registry.fail(task_id, str(e))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
mcp.run(transport="stdio")
|
||||
|
||||
Reference in New Issue
Block a user