feat(validator): add bare FastAgent + Pallas validator for Mnemosyne MCP
A self-contained sub-project under validator/ that wraps Mnemosyne's MCP server in a single FastAgent. Use it to confirm — outside of Daedalus — that Mnemosyne's MCP transport works, every tool registers, args/responses round-trip, and an LLM can actually drive the tools. The validator is its own Pallas-consuming project with its own pyproject (pallas-mcp + fast-agent-mcp), agents.yaml, and fastagent.config.yaml — matching the pattern used by Iolaus and other Pallas consumers. It does not import Mnemosyne Python code; it only speaks MCP over HTTP. The agent never sets workspace_id, so all calls run against the global scope (libraries with workspace_id IS NULL). Workspace-scoped validation will come once Daedalus's chat path is wired (Daedalus injects workspace_id server-side, force-overwriting whatever the LLM produces). Default model is openai.Qwen3.5-35B-A3B-UD-Q4_K_XL.gguf served by llama.cpp at nyx.helu.ca:22079/v1. Token provisioning via `python manage.py create_mcp_token --user <u> --name validator`. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
99
validator/README.md
Normal file
99
validator/README.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Mnemosyne Validator
|
||||
|
||||
A bare [FastAgent](https://github.com/evalstate/fast-agent) + [Pallas](https://git.helu.ca/r/pallas) project whose only purpose is to exercise Mnemosyne's MCP server end-to-end. Use it to confirm the transport works, every MCP tool registers, args/responses round-trip, and the local LLM can actually drive the tools.
|
||||
|
||||
This is **not** a production agent. It does not represent the long-term Daedalus integration — when Daedalus ships, it will inject `workspace_id` server-side. The validator never sets `workspace_id`, meaning all calls run against the global scope (libraries with `workspace_id IS NULL`).
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
validator/
|
||||
├── pyproject.toml # pallas-mcp + fast-agent-mcp deps
|
||||
├── agents.yaml # one-agent Pallas topology
|
||||
├── fastagent.config.yaml # default_model + mnemosyne MCP server
|
||||
├── fastagent.secrets.yaml.example # template for the bearer token
|
||||
├── .env.example # OPENAI_BASE_URL etc.
|
||||
└── agents/
|
||||
└── mnemosyne_validator.py # the FastAgent definition
|
||||
```
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
cd validator/
|
||||
uv venv .venv
|
||||
source .venv/bin/activate
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
Copy and fill the secrets/env templates:
|
||||
|
||||
```bash
|
||||
cp fastagent.secrets.yaml.example fastagent.secrets.yaml
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
## Provision an MCP bearer token
|
||||
|
||||
Mnemosyne requires a bearer token when `MCP_REQUIRE_AUTH=True` (the default). Generate one for your user:
|
||||
|
||||
```bash
|
||||
cd ../mnemosyne
|
||||
python manage.py create_mcp_token --user <username> --name validator
|
||||
```
|
||||
|
||||
The command prints the token **once** — paste it into `validator/fastagent.secrets.yaml` under `mcp.servers.mnemosyne.headers.Authorization` (keep the `Bearer ` prefix).
|
||||
|
||||
## Start Mnemosyne's MCP server
|
||||
|
||||
The validator hits the Mnemosyne ASGI endpoint, so Mnemosyne's MCP server must be running. From the Mnemosyne project:
|
||||
|
||||
```bash
|
||||
cd mnemosyne/
|
||||
uvicorn mnemosyne.asgi:app --host 0.0.0.0 --port 22091 --workers 1
|
||||
```
|
||||
|
||||
By default the validator points at `http://localhost:22091/mcp`. If your Mnemosyne is on another host, override `mcp.servers.mnemosyne.url` in `fastagent.secrets.yaml`.
|
||||
|
||||
## Run the validator
|
||||
|
||||
The `mnemosyne-validator` script is a thin alias for `pallas`:
|
||||
|
||||
```bash
|
||||
# Start with the registry (Pallas mode):
|
||||
mnemosyne-validator
|
||||
|
||||
# Or run the agent directly (no registry):
|
||||
mnemosyne-validator --agent mnemosyne_validator
|
||||
```
|
||||
|
||||
To chat with the agent directly without spinning up a Pallas registry, use the `fast-agent` CLI (provided by `fast-agent-mcp`):
|
||||
|
||||
```bash
|
||||
fast-agent go --config-path fastagent.config.yaml --url http://localhost:24301/mcp mnemosyne_validator
|
||||
```
|
||||
|
||||
## What to test
|
||||
|
||||
These prompts exercise every Mnemosyne MCP tool. After each, the agent should call the named tool and surface the result.
|
||||
|
||||
| Prompt | Tool | What to verify |
|
||||
|--------|------|----------------|
|
||||
| "Run a health check on Mnemosyne." | `get_health` | Returns `status: ok` if Neo4j + S3 + embedding model are all reachable. `degraded` if one is down. |
|
||||
| "List all libraries." | `list_libraries` | Returns the libraries seeded by `load_library_types`, each with `library_type` set. |
|
||||
| "List collections in library `<uid>`." | `list_collections` | Returns collections inside the named library. |
|
||||
| "List items in collection `<uid>`." | `list_items` | Returns items with `chunk_count` and `embedding_status`. |
|
||||
| "Search the technical libraries for `<query>`." | `search` | Returns ranked candidates with `chunk_uid`, `score`, `text_preview`, `library_type`. |
|
||||
| "Fetch the full text of chunk `<chunk_uid>`." | `get_chunk` | Returns the full chunk text from S3. |
|
||||
|
||||
If a call errors, the agent surfaces it verbatim — that's the failure mode you want.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Invalid MCP token"** — token wasn't provisioned, was provisioned for a different user, or got mangled when pasted. Re-run `create_mcp_token` and paste again. Tokens are SHA-256 hashed at rest and can't be retrieved later.
|
||||
|
||||
**"Couldn't connect to Mnemosyne"** — the ASGI server isn't running, or it's bound to a different host/port than `mcp.servers.mnemosyne.url` says. Check `curl http://localhost:22091/mcp/health` returns `{"status":"ok"}`.
|
||||
|
||||
**"No system embedding model configured" in `get_health`** — `LLMModel.get_system_embedding_model()` returns nothing. Configure the embedding model via the Mnemosyne admin or `manage.py` before searches will work.
|
||||
|
||||
**Search returns zero candidates with no error** — Mnemosyne is reachable but has no embedded content yet. Upload an item and run `embed_item`, or use the Daedalus ingest endpoint, before re-testing search.
|
||||
Reference in New Issue
Block a user