journal-rag
This local MCP server lets you search, browse, read, regex-query, and write team markdown journal entries using hybrid BM25 + vector retrieval with no API keys.
search_journal: hybrid BM25 + vector semantic search over heading-chunked journals, returning ranked hits with file#heading citations; accepts query and optional k (1–50, default 8); falls back to BM25-only if vector index is unavailable.
get_entry: returns the full markdown of one journal file by relative path or filename.
list_entries: lists journal files with title, date, and section headings; optional case-insensitive substring filter on path/title.
search_regex: regex escape hatch for exact symbols, paths, identifiers, or text; accepts pattern and optional k (1–50, default 20).
write_entry: creates a new markdown journal entry from title and content, auto-generates a dated filename slug, returns the file path, and incrementally updates the vector index.
Provides MCP configuration guidance for JetBrains AI Assistant / Junie, allowing the journal search server to be used from JetBrains IDEs at project scope.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@journal-rag search for updates about project Alpha"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
journal-rag
Source-control-friendly hybrid retrieval over team markdown journals. Heading-chunked BM25 + local vector embeddings fused via Reciprocal Rank Fusion (RRF), with regex as an escape hatch. A per-user daemon shares models and workspace indexes across MCP clients.
Embeddings run locally via @huggingface/transformers — no API keys or hosted inference calls.
Each consuming repo commits journal-rag.config.json and markdown under docs/journal/ (or other configured folders). This package is the shared engine.
Per-repo config
Create journal-rag.config.json at the repo root:
{
"sources": ["docs/journal"],
"cachePath": ".journal-rag/index.json"
}Field | Required | Default | Description |
| yes | — | Directories containing markdown journals |
| no |
| BM25 chunk index cache path |
| no | Platform-specific model | Hugging Face model ID for local embeddings. macOS uses the cache-free |
The vector cache (vectors.json) is stored in the same directory as cachePath.
Add to .gitignore:
.journal-rag/Related MCP server: mnemonic
Build & install (once per machine)
cd c:/repos/journal-rag
npm install # runs prepare → build
npm link # puts journal + journal-mcp on your PATHnpm link registers two global commands:
Command | What it runs |
| CLI ( |
| MCP stdio server (for editor config) |
| Shared local daemon (normally started automatically) |
Re-run npm run build (or npm link again) after pulling server changes.
Alternative to link: npm install -g . from this repo (same effect).
CLI (any teammate)
From a repo root with config:
journal search "HttpFacade singleton" # hybrid BM25 + vector (default)
journal search "HttpFacade singleton" --bm25 # BM25-only (no embedding)
journal list --filter dialog
journal get docs/journal/2026-04-21_vapp-http-facade-and-singleton-sweep.md
journal index --rebuildAfter npm link in this repo, journal search "..." works globally.
Set JOURNAL_RAG_WORKSPACE to an absolute repo root only when you must run the CLI from a subdirectory.
The first run downloads a local embedding model (~90 MB on macOS and ~614 MB elsewhere) to the Hugging Face cache directory. Subsequent runs load from cache. Embedding inference uses DirectML on Windows, Core ML on macOS, and CPU elsewhere. macOS uses a cache-free encoder model because Core ML cannot execute the zero-length key/value-cache inputs used by the Qwen ONNX Community export, and cache-free Qwen exports consume several gigabytes when compiled by Core ML. If an accelerated provider fails during model loading or inference, the error is logged and that model is retried on CPU for the lifetime of the daemon. Indexing uses single-document batches to stay within the memory limits of 6 GB GPUs. DirectML sessions disable memory-pattern optimization and use sequential execution as required by ONNX Runtime. Partial vectors are checkpointed every 100 chunks so an interrupted build can resume.
Each editor still launches a small stdio MCP proxy because stdio cannot be shared between clients. The proxy automatically connects to one per-user daemon over a Windows named pipe or Unix socket. The daemon canonicalizes the path to journal-rag.config.json; Cursor, ChatGPT, and other clients using the same config therefore share one workspace runtime, vector build, and model instance. No administrator-level service installation is required.
Optional CUDA on Linux x64
Set JOURNAL_RAG_DEVICE=cuda in the environment before starting the daemon.
Supported overrides are cpu, cuda, dml, and coreml; without an override the
platform defaults above still apply. A running daemon keeps its existing environment.
CUDA uses the Qwen FP16 export (~1.2 GB download), because the q8 export's
MatMulInteger operations execute on CPU even with the CUDA provider selected.
The vector cache records the embedding precision and is rebuilt when precision
changes. CPU fallback retains the selected precision so queries and cached vectors
remain compatible. Custom models must provide the selected export.
The Linux x64 onnxruntime-node package includes the CUDA provider, but it also
needs CUDA 12 and cuDNN 9 runtime libraries visible through LD_LIBRARY_PATH.
A private installation avoids changing system libraries or another project's venv:
uv venv .cuda-venv
uv pip install --python .cuda-venv/bin/python \
nvidia-cublas-cu12==12.8.4.1 nvidia-cuda-runtime-cu12==12.8.90 \
nvidia-cudnn-cu12==9.19.0.56 nvidia-cufft-cu12==11.3.3.83 \
nvidia-curand-cu12==10.3.9.90 nvidia-nvjitlink-cu12==12.8.93Add the .cuda-venv/lib/python*/site-packages/nvidia/*/lib directories to
LD_LIBRARY_PATH when launching Node. Check that ldd on
node_modules/onnxruntime-node/bin/napi-v6/linux/x64/libonnxruntime_providers_cuda.so
reports no missing libraries. Missing native dependencies can terminate the process
before JavaScript can fall back to CPU.
For side-by-side testing, use a separate Git worktree with its own npm ci, a
private workspace/config and cache, and a private TMPDIR directory. TMPDIR
isolates both the daemon socket/startup lock and vector indexing lock on Linux.
Set JOURNAL_RAG_LOG_DIR separately too. Do not relink global binaries or stop the
existing daemon. In that environment, node dist/cli.js search "query" tests the
CLI and node dist/server.js starts the MCP proxy. A first CUDA inference may
spend a minute compiling kernels; use repeated warm queries for comparisons.
Diagnostic logs
The MCP proxy and daemon write daily JSONL logs and retain them for 14 days:
Windows:
%LOCALAPPDATA%\journal-rag\logsmacOS:
~/Library/Logs/journal-ragLinux:
$XDG_STATE_HOME/journal-rag/logsor~/.local/state/journal-rag/logs
Set JOURNAL_RAG_LOG_DIR to override the directory. Logs include process IDs, canonical config paths, daemon startup and request failures, vector-build timing, selected execution device, model-load timing, and process memory after model loading. Query text and journal content are not logged.
MCP tools
Tool | Purpose |
| Hybrid BM25 + vector search with RRF fusion ( |
| Create a new journal entry ( |
| Full file by path or filename |
| Browse metadata ( |
| Exact / path / symbol lookup |
Editor setup
Use stdio — spawn Node with dist/server.js.
Put MCP config in the workspace, not your user profile
The server resolves journal-rag.config.json by walking up from its working directory. That file lives at each consuming repo's root (next to docs/journal/), not in journal-rag itself.
If you add the server to a global / user-level editor profile, the spawn cwd is usually wrong (home dir, editor install dir, last random folder, etc.) and the server cannot find config — even if you hardcode "cwd": "C:/repos/my-repo", that breaks the moment you open a second repo workspace.
Do this instead: commit workspace-level MCP config inside each repo that has journals. Teammates run npm link once (see above) so journal-mcp is on PATH — no machine-specific paths in the committed JSON.
Cursor
.cursor/mcp.json at the repo root (e.g. my-repo/.cursor/mcp.json) — safe to commit:
{
"mcpServers": {
"journal": {
"command": "journal-mcp",
"cwd": "${workspaceFolder}",
"env": {
"JOURNAL_RAG_WORKSPACE": "${workspaceFolder}"
}
}
}
}${workspaceFolder} resolves to the repo you opened. journal-mcp comes from npm link in the journal-rag repo.
VS Code (Copilot agent mode)
Same idea: .vscode/mcp.json in the repo, not User settings:
{
"servers": {
"journal": {
"type": "stdio",
"command": "journal-mcp",
"cwd": "${workspaceFolder}"
}
}
}JetBrains AI Assistant / Junie
Configure MCP at project scope (.idea / project settings), not the IDE default profile. Open the repo as the project root. Command: journal-mcp (after npm link).
If journal-mcp is not found
Ensure npm's global bin dir is on your PATH (npm bin -g). On Windows that is usually %APPDATA%\\npm. Then re-run npm link from journal-rag. Fallback for a single machine only: "command": "node", "args": ["<absolute-path>/journal-rag/dist/server.js"].
Fallback
If an editor cannot set cwd per workspace, set env JOURNAL_RAG_WORKSPACE to the absolute path of the consuming repo root in that workspace's MCP config.
Design notes
Corpus is small (~tens of files); BM25 over heading chunks matches how journals are written.
Vector embeddings (local, via Transformers.js) add semantic recall for paraphrased or conceptual queries.
Reciprocal Rank Fusion (RRF, k=60) merges BM25 and vector rankings without needing score normalization.
Index caches are optional and gitignored; markdown in git is the source of truth.
Vector cache is incremental — only new/changed chunks are re-embedded on rebuild.
Vector index builds take a machine-wide lock, so MCP servers opened for different workspaces do not run expensive embedding jobs concurrently. The lock has a heartbeat and is recovered after a crashed or killed process.
The daemon owns workspace runtimes keyed by canonical config path. MCP stdio processes contain no model or index state and only forward tool calls.
Available Tools
5 toolsget_entryA
Return the full markdown of one journal file by relative path or filename.
Inputs: path (required).
list_entriesA
List journal files with title, date, and section headings. Optional filter substring on path/title.
Inputs: filter.
search_journalA
Hybrid BM25 + vector semantic search over team markdown journals (heading-chunked). Returns ranked hits with file#heading citations.
Inputs: query (required), k.
search_regexA
Regex search across journal chunks (escape hatch for symbols, paths, exact identifiers).
Inputs: pattern (required), k.
write_entryA
Create a new markdown journal entry. Filename is generated from today's date and the title slug. Returns the file path. The vector index is incrementally updated (only new chunks are embedded).
Inputs: title (required), content (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 5 tools
Each tool has a clearly distinct role: semantic/full-text search, regex-based search, listing, full-entry retrieval, and entry creation. Even though search_journal and search_regex can both find text, their purpose and query syntax are clearly separated, so an agent should not confuse them.
All tool names follow a consistent lowercase verb_noun pattern: search_journal, get_entry, list_entries, search_regex, write_entry. The naming is predictable and immediately conveys the action and target.
Five tools is a well-scoped set for a journal RAG server. There is one tool for semantic search, one for regex search, one for listing, one for retrieving full entries, and one for creating new entries—each earns its place without redundancy.
The tool surface covers the core journal workflow: create entries, list them, retrieve them, and search them semantically or by regex. Update and delete capabilities are absent, but for a journal/RAG-oriented server these are often intentionally not needed, so this is a minor gap rather than a significant one.
Maintenance
Related MCP Connectors
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
Your personal library, readable by AI agents: durable snapshots, hybrid search, 46 MCP tools.
Cloud or self-hosted knowledge for AI agents: hybrid search, reranking, GraphRAG, scoped MCP tools.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceHybrid semantic search (dense vector + BM25) over local knowledge bases and codebases, exposed as MCP tools for AI agents to search and list knowledge bases.-
- AlicenseNot gradedqualityDmaintenanceMCP server for on-device hybrid search over markdown knowledge bases, combining BM25, vector embeddings, and LLM reranking with link graph and time decay.23 npmMIT
- AlicenseAqualityDmaintenanceA local MCP server enabling hybrid search over documents, memory, and knowledge graphs for retrieval-augmented generation, with tools for SQLite, semantic memory, and entity-relationship queries.41MIT
- AlicenseNot gradedqualityDmaintenanceAn MCP server that provides a unified hybrid-search interface over Slack, wikis, code, and databases, enabling agents and humans to query scattered knowledge with exact and semantic search.MIT