Docs: Mnemosyne MCP
This commit is contained in:
240
docs/mnemosyne_mcp.md
Normal file
240
docs/mnemosyne_mcp.md
Normal file
@@ -0,0 +1,240 @@
|
|||||||
|
# Mnemosyne MCP Server Tools
|
||||||
|
|
||||||
|
Mnemosyne exposes a retrieval surface via the [Model Context Protocol](https://modelcontextprotocol.io/) using [FastMCP](https://github.com/jlowin/fastmcp). The server is a **retrieval surface, not a RAG pipeline**: it returns ranked evidence and the calling LLM is responsible for synthesis and citation.
|
||||||
|
|
||||||
|
## Concepts
|
||||||
|
|
||||||
|
**Library** — the top-level container. Each library has a `library_type` that drives chunking, embedding, and re-ranking strategy:
|
||||||
|
|
||||||
|
| `library_type` | Content |
|
||||||
|
|---|---|
|
||||||
|
| `fiction` | Novels, short stories. Cover art available. |
|
||||||
|
| `nonfiction` | General non-fiction prose. |
|
||||||
|
| `technical` | Manuals, textbooks, docs. Diagrams and code-like content. |
|
||||||
|
| `music` | Lyrics, liner notes, album artwork. |
|
||||||
|
| `film` | Scripts, synopses, stills. |
|
||||||
|
| `art` | Catalogs, descriptions, artwork itself. |
|
||||||
|
| `journal` | Personal entries; temporal/reflective. |
|
||||||
|
| `business` | Proposals, marketing, sales, strategy. Commercial context. |
|
||||||
|
| `finance` | Statements, tax, market commentary. Quote figures exactly. |
|
||||||
|
|
||||||
|
**Collection** — a named group of items inside a library (e.g. a novel series, a multi-volume manual).
|
||||||
|
|
||||||
|
**Item** — an indexed document or file. Only items with `embedding_status = "completed"` appear in search results.
|
||||||
|
|
||||||
|
**Chunk** — a text segment of an item, stored in S3. Search returns a `text_preview` (~500 chars); use `get_chunk` to fetch the full text.
|
||||||
|
|
||||||
|
## Recommended Workflow
|
||||||
|
|
||||||
|
```
|
||||||
|
list_libraries
|
||||||
|
→ search(query, library_type=..., library_uid=...)
|
||||||
|
→ get_chunk(chunk_uid) # only when text_preview is insufficient
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tools
|
||||||
|
|
||||||
|
### `search`
|
||||||
|
|
||||||
|
Hybrid retrieval: vector + full-text + concept-graph candidates fused by RRF (Reciprocal Rank Fusion), with optional Synesis re-ranking.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `query` | `str` | required | The search query. |
|
||||||
|
| `library_uid` | `str \| None` | `None` | Restrict to one library by UID. |
|
||||||
|
| `library_type` | `str \| None` | `None` | Restrict by library type (see table above). |
|
||||||
|
| `collection_uid` | `str \| None` | `None` | Restrict to one collection by UID. |
|
||||||
|
| `limit` | `int` | `20` | Maximum candidates to return. |
|
||||||
|
| `rerank` | `bool` | `True` | Apply Synesis re-ranking. Set `False` to skip. |
|
||||||
|
| `include_images` | `bool` | `True` | Include matching images in the response. |
|
||||||
|
| `search_types` | `list[str] \| None` | `["vector", "fulltext", "graph"]` | Which retrieval strategies to run. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"query": "...",
|
||||||
|
"candidates": [
|
||||||
|
{
|
||||||
|
"chunk_uid": "...",
|
||||||
|
"item_uid": "...",
|
||||||
|
"item_title": "...",
|
||||||
|
"library_type": "...",
|
||||||
|
"text_preview": "... (~500 chars) ...",
|
||||||
|
"score": 0.92,
|
||||||
|
"source": "vector|fulltext|graph"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"images": [...],
|
||||||
|
"total_candidates": 42,
|
||||||
|
"search_time_ms": 85,
|
||||||
|
"reranker_used": true,
|
||||||
|
"reranker_model": "...",
|
||||||
|
"search_types_used": ["vector", "fulltext", "graph"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_chunk`
|
||||||
|
|
||||||
|
Fetch the full text of a single chunk by its UID. Use this when the `text_preview` returned by `search` is not enough.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `chunk_uid` | `str` | The chunk UID from a `search` result. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"chunk_uid": "...",
|
||||||
|
"chunk_index": 3,
|
||||||
|
"item_uid": "...",
|
||||||
|
"item_title": "...",
|
||||||
|
"library_type": "...",
|
||||||
|
"text": "Full chunk text..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `list_libraries`
|
||||||
|
|
||||||
|
Enumerate libraries the caller is authorized to read. Use the returned `uid` or `library_type` to scope a subsequent `search`.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `limit` | `int` | `50` | Max libraries to return (capped at 200). |
|
||||||
|
| `offset` | `int` | `0` | Pagination offset. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"libraries": [
|
||||||
|
{
|
||||||
|
"uid": "...",
|
||||||
|
"name": "...",
|
||||||
|
"library_type": "fiction",
|
||||||
|
"description": "..."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limit": 50,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `list_collections`
|
||||||
|
|
||||||
|
Enumerate collections, optionally filtered to a single library. Use the returned `uid` to scope `search` or `list_items` to one collection.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `library_uid` | `str \| None` | `None` | Filter to one parent library. |
|
||||||
|
| `limit` | `int` | `50` | Max collections to return (capped at 200). |
|
||||||
|
| `offset` | `int` | `0` | Pagination offset. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"collections": [
|
||||||
|
{
|
||||||
|
"uid": "...",
|
||||||
|
"name": "...",
|
||||||
|
"description": "...",
|
||||||
|
"library_uid": "...",
|
||||||
|
"library_name": "..."
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limit": 50,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `list_items`
|
||||||
|
|
||||||
|
Enumerate indexed documents/files, optionally filtered by library or collection. Check `embedding_status` before searching — only `"completed"` items appear in search results. Use `chunk_count` to gauge document size.
|
||||||
|
|
||||||
|
**Parameters**
|
||||||
|
|
||||||
|
| Name | Type | Default | Description |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `collection_uid` | `str \| None` | `None` | Filter to one collection. |
|
||||||
|
| `library_uid` | `str \| None` | `None` | Filter to one library. |
|
||||||
|
| `limit` | `int` | `50` | Max items to return (capped at 200). |
|
||||||
|
| `offset` | `int` | `0` | Pagination offset. |
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"uid": "...",
|
||||||
|
"title": "...",
|
||||||
|
"item_type": "...",
|
||||||
|
"file_type": "...",
|
||||||
|
"chunk_count": 120,
|
||||||
|
"image_count": 4,
|
||||||
|
"embedding_status": "completed"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"limit": 50,
|
||||||
|
"offset": 0
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### `get_health`
|
||||||
|
|
||||||
|
Health check for infrastructure pollers (Pallas, Daedalus). Does not require authentication.
|
||||||
|
|
||||||
|
Returns a Pallas-compatible status object. `neo4j` and `s3` failures result in `"error"` (critical). A missing or unconfigured embedding model results in `"degraded"` (non-critical).
|
||||||
|
|
||||||
|
**Parameters:** none
|
||||||
|
|
||||||
|
**Response**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"status": "ok | degraded | error",
|
||||||
|
"checks": {
|
||||||
|
"neo4j": { "status": "ok", "duration_ms": 2.1 },
|
||||||
|
"s3": { "status": "ok", "duration_ms": 8.4 },
|
||||||
|
"embedding": { "status": "ok", "model": "...", "duration_ms": 0.3 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
All tools except `get_health` require a `Bearer` token in the `Authorization` header. Three credential types are accepted:
|
||||||
|
|
||||||
|
| Type | Issued by | Lifetime | Scope |
|
||||||
|
|---|---|---|---|
|
||||||
|
| **Opaque `MCPToken`** | Mnemosyne admin | Long-lived (optional expiry) | `allowed_libraries` list on the token row. Per-tool ACL available. |
|
||||||
|
| **Per-turn JWT** (`iss=daedalus`) | Daedalus chat | ≤10 minutes | `libs` claim (list of Library UIDs). |
|
||||||
|
| **Team JWT** (`iss=mnemosyne`, `typ=team`) | Mnemosyne | 10-year lifetime | Resolved live from `TeamWorkspaceAssignment` → Neo4j `Library.workspace_id`. Revoked via `active_jti` rotation. |
|
||||||
|
|
||||||
|
Every authenticated request resolves to a `resolved_libraries` list — the set of Library UIDs the caller may read. Tools enforce this list at the query layer; an empty list means the caller is authenticated but sees nothing (fail-closed). `None` (no auth) is also fail-closed.
|
||||||
|
|
||||||
|
The `MCP_REQUIRE_AUTH` Django setting (default `True`) controls whether unauthenticated requests are rejected.
|
||||||
Reference in New Issue
Block a user