ContextWiki
MCP Retrieval Server
A private knowledge retrieval server built on the MCP protocol. Syncs Notion, Tistory, GitHub, and Obsidian into a dual-store index — ChromaDB for semantic search, SQLite as a metadata gate — and returns citation-backed context for LLM clients like Claude Desktop.
Architecture
Ingestion → Dual Store → Verified Context
Each source connector fetches raw content, which is chunked and deduplicated before being written to two stores simultaneously. ChromaDB handles semantic similarity via OpenAI embeddings; SQLite acts as a metadata gate that validates chunk provenance before results reach the caller.
│
▼
[ Ingestion Service ] fetch → chunk → deduplicate
╱ ╲
▼ ▼
[ ChromaDB ] [ SQLite ]
semantic search metadata gate
╲ ╱
▼ ▼
[ Verified Context ] → MCP client
Tech Stack
Core
Vector & Storage
Infra & Tooling
MCP Tools
7 tools registered on the FastMCP server
| Tool | Description |
|---|---|
| list_sources() | List all configured source connectors and their status |
| sync_source(source_id) | Trigger incremental sync for a specific source |
| sync_all() | Sync all active sources in one call |
| get_sync_status() | Return current source health and sync job state |
| search_context(query, ...) | Semantic search with SQLite metadata validation — primary retrieval path |
| search_documents(query, ...) | Same retrieval grouped by source document |
| fetch_context(document_id, ...) | Direct chunk or document fetch by ID |
Design Decisions
What I built
- Source connectors for Notion API, Tistory RSS, GitHub REST, and Obsidian vault
- Chunking pipeline with deduplication before indexing
- Dual-store write path: Chroma for embedding, SQLite for metadata gating
- Search & ranking layer with optional LLM query rewrite (GPT-4.1-mini)
- FastMCP server entry point wiring all services together
- Docker image + GitHub Actions CI (lint, type check, security scan, 70%+ coverage)
Evidence gathering vs. answer generation
In production, search_context and search_documents
return grounded evidence chunks, and the downstream LLM — Claude Desktop, Cursor —
composes the final answer.
Keeping the retrieval layer and the answer layer separate means the search results stay inspectable, the MCP server stays stateless, and swapping the LLM client requires zero changes to the server.