wetnoodle
This server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
wetnoodle
⚠️ Experimental software — watch the machine it runs on
wetnoodle is a personal project, not a product. It has no support contract, no warranty, and it has already broken a host: on 2026-10-19 a scheduled ingest pinned all 20 threads of a laptop, the WSL VM grew until Windows stopped responding, and the agent gateway on it crashed. Nobody was hurt and nothing was lost, because the owner caught it.
Ingesting is CPU-heavy. One embedding request can saturate every core it can see. So: run the first index with a monitor open (
top, Task Manager), keep it oncron/refresh-with-ollama.sh(pins the embedder to 4 cores at low priority and stops the daemon afterwards), and do not schedule it more often than every two hours. Readdocs/troubleshooting.mdbefore putting it on a laptop you need.
A local memory archive for Hermes Agent. It indexes every
profile's session database — plus every SKILL.md you own — into one small vector store, so an agent can
answer "what did we decide about X three weeks ago" instead of only seeing what is still in its context
window. Everything stays on your machine: a SQLite file and a local Ollama embedding model. No API keys, no
cloud store, nothing to sign up for.
you ──▶ Hermes sessions (per profile, per SQLite db) ──┐
├─▶ wetnoodle ingest ──▶ rag.db (vectors + text)
you ──▶ skills (*/SKILL.md) ───────────────────────────┘ │
▼
agent (MCP tool) / query.py ◀── search ───┘Start here
You need all three. Python 3.11+, a local Ollama daemon, and the nomic-embed-text model.
# 1. Ollama + the one required model (274 MB; the CPU is fine)
curl -fsSL https://ollama.com/install.sh | sh # macOS/Windows: https://ollama.com/download
ollama pull nomic-embed-text# 2. Clone, bootstrap, first index
git clone https://github.com/OleMurpho/wetnoodle.git && cd wetnoodle
./scripts/bootstrap.shbootstrap.sh builds a venv, installs two libraries, checks Ollama, runs doctor.py, then indexes
everything it can see. It needs no root and is safe to re-run. Indexing runs at about 16 passages a second
here, so a few thousand messages take a couple of minutes — seven minutes for 7,000 passages on a
four-year-old graphics card, several times slower on the CPU alone. You should end with a line like
committed N chunk(s) across 4 corpora.
# 3. Prove it works — ask for something you know is in your history
./.venv/bin/python query.py "the hostname of the machine that runs the bot"A good result names the passage, its date, its profile and its score. If it says no hits, the index is
empty — run python doctor.py, which names the exact fix.
# 4. Let the agent use it — this goes in Hermes config.yaml (YAML, no braces)
mcp_servers:
wetnoodle:
command: /absolute/path/to/wetnoodle/.venv/bin/python
args: [/absolute/path/to/wetnoodle/mcp_server.py]Use the absolute interpreter path; a system python has no numpy or mcp. Restart the gateway (or
start a new session) and three tools appear: rag_search, rag_open, rag_audit.
# 5. Keep it current — every two hours, off the hour, silent unless it fails
17 */2 * * * /absolute/path/to/wetnoodle/cron/refresh-with-ollama.shrefresh-with-ollama.sh is the one to schedule: it starts Ollama pinned to four cores at nice 19, runs the
refresh under the same limits, and stops the daemon afterwards. Set WETNOODLE_CPUS if four is wrong for
your machine. In Hermes you can schedule the same script with the cronjob tool instead of crontab.
If something is wrong, ./.venv/bin/python doctor.py preflights every dependency and prints the fix —
including whether this machine is the thread-rich, memory-poor shape that saturates (it will tell you if you
are inside WSL, and whether anything is capping core count).
Less common problems are in docs/troubleshooting.md.
Related MCP server: cyber-brain
How a search actually works
The model that retrieves is the model that judges. There is no reranker and no judge endpoint anywhere — not local, not cloud.
rag_searchreturns a pool of candidates: a dozen passages, each with a ref, a date, a corpus, and the part of the passage where your query's words actually appear.The agent reads them and calls
rag_openon the ones that answer the question.The agent answers from those passages — or says it could not find it.
Vectors propose a neighbourhood; near-misses are chosen between by the model that asked, which is the one thing in the stack already loaded, already holding the conversation, and already paid for. That is why answer quality follows the model you point at it: a strong model reads the pool and picks, a weak one takes the first hit. The tool tells it not to.
What it actually finds
We wrote 46 questions about things that really happened here, each carrying a distinctive detail — a command, a hostname, a number — present in exactly one passage. Nineteen were locked away while the system was built and never used for a decision. Every figure below is on a fixed 2,000-passage set, so changes compare like for like.
Six of nineteen put the right passage first. The grey bar is not a result — it is the ceiling: in seventeen of nineteen, the answer was already among the twenty candidates. Search fails at choosing between near-misses, not at finding. That gap is the design.
On the hardest questions — detail present in three passages or fewer — it is first once in eight, inside
the top three twice in eight. No amount of ranking polish fixes that stratum, which is why rag_search
returns candidates instead of an answer. Exact figures and method: docs/models.md.
The demo, without installing anything
→ https://olemurpho.github.io/wetnoodle/ — a real index of 5,677 PubMed abstracts, searchable in the browser, every hit a real paper with title, journal, year and PMID.
A browser cannot run an embedding model, and the page says so: typed queries are keyword-only (BM25).
The two sections below the search box replay the embedding search this project actually ships, precomputed
locally with nomic-embed-text and quantised to 256 dimensions:
You are the judge. Three questions where the source abstract is in the eight candidates returned, but is not first — it ranks 3rd, 4th and 7th of 5,677. You pick; the page shows where the source really sat. That is the choice the tool hands to a model instead of making itself.
Where it fails. Three questions where the source is not in the top five at all — it sits at 12th, 30th and 100th. Nothing is hidden; the page shows the miss and then reveals the abstract it wanted.
Six questions, each written by hand against an abstract chosen in advance. That is curation, and it means these are illustrations of the two regimes — pool-or-nothing — not a score. The score is six of nineteen on a held-out set, with the answer inside the top twenty seventeen times.
Commands
Command | What it does |
| incremental ingest of every session corpus |
| per-corpus counts and watermarks |
| rebuild available corpora from scratch |
| drop corpora whose source database is gone |
| index every |
| search from the shell |
| retrieval gate: where each known answer comes back |
| is each eval marker actually present? |
| corpus → text (portable, diffable) |
| text → corpus (re-embedded locally) |
| preflight every dependency, and warn about machine shape |
| pinned, low-priority refresh (the one to schedule) |
| smoke test, no Ollama needed ( |
Settings
Defaults are right for almost everyone. These relocate the store; they are not an invitation to experiment.
Variable | Default | Effect |
|
| where |
|
| the Hermes install to index |
|
| pins vector dim; changing it needs |
|
| the local daemon |
| discovered | override skill roots ( |
|
| per-hit cap in tool output |
|
| cap across the whole result set |
|
| threads Ollama may use per embedding request |
|
| passages per request; smaller means shorter load spikes |
The scoring knobs behind these (RAG_HYBRID, RAG_VEC_WEIGHT, per-corpus quotas, model prefixes) are in
docs/models.md with the measurement that settled each. Every one is measured worse or
neutral, so there is no reason to reach for them.
What did not survive being measured
Every row was built, run against the same questions, and dropped:
A context line above every passage. Published advice for exactly this problem, and it made things worse — seven fewer questions answered first. Boilerplate repeated thousands of times competes with the words that matter.
The session's opening topic instead of a context line. Still three fewer.
A gate forcing rare identifier terms to match. One fewer: the questions that need it are the ones where the identifier is the answer, so it is not in the query to gate on.
Removing all 1,570 duplicate passages (20% of the archive). No change at all — duplicates were not stealing rank, just occupying slots nobody wanted.
Keyword boosting across the whole corpus. Two fewer, because a word that appears everywhere outranks the words that appear once.
Two were abandoned unfinished, so they carry no number: ranking fifty candidates cost about three times as much per search and had not cleared ten questions after forty-six minutes, and a 4B embedding model ran at 0.8 passages a second — nearly three hours an index — while the ceiling says a bigger embedder raises a limit that was not the constraint.
Known limits
Paraphrase queries underperform identifier queries. Embeddings drift from literal tokens; the keyword rerank only partly compensates.
Chunks are raw conversation. Half a chunk can be boilerplate. Quality is bounded by what was said.
One embedding model per store. Switching models without
--fullis a dimension mismatch, which reads like corruption —import_store.pyrefuses rather than write it.Not multi-user. It indexes the Hermes install it can see; there is no auth layer.
Other projects, and what we took from them
Marker-based recall scoring, bounded output, text export/rebuild and the job-runtime isolation pattern came from tomRumi/hermes-memory-rag (MIT), which solves the adjacent problem of curated project memory. No code was copied; the mechanisms were reimplemented against this store and independently measured.
Licence
MIT — see LICENSE. Use it, fork it, ship it.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
This server cannot be deployed
Maintenance
Related MCP Connectors
Self-hosted AI workspace: semantic RAG document search, long-term memory, and AI chat via MCP.
Your personal library, readable by AI agents: durable snapshots, hybrid search, 46 MCP tools.
Agentic search over your Dewey document collections from any MCP-compatible client.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables fully local retrieval over a personal document corpus via hybrid search, cross-encoder reranking, RAPTOR summaries, and knowledge graph queries, served to AI agents over MCP.MIT
- AlicenseNot gradedqualityBmaintenanceExposes a local SQLite-based memory and knowledge base as standard MCP tools, enabling AI clients to search content, recall memory fragments, and query entity relationships through natural language.2MIT
- FlicenseNot gradedqualityAmaintenanceEnables AI agents and MCP hosts to query locally indexed notes, docs, chat logs, and other files via hybrid vector/BM25 retrieval with section-level citations. Exposes tools, resources, and prompts for searching and asking over the indexed content.-
- FlicenseNot gradedqualityAmaintenanceEnables AI agents and MCP hosts to search and ask questions across a local hybrid-retrieval index of scattered notes, documents, PDFs, and chat logs, returning section-level citations and agent-usable tools, resources, and prompts.-