Skip to content

eunaverse/MCPContentSearch

Repository files navigation

🔍 ContextWiki

CI

A private knowledge retrieval MCP server for LLM clients. Syncs Notion · Tistory · GitHub · Obsidian into vector + metadata stores and returns citation-backed context.


🏗️ Architecture

[ Sources ]
 Notion / Tistory / GitHub / Obsidian
                |
                v
         [ Ingestion Service ]
             /            \
            v              v
      [ Chroma ]      [ SQLite ]
    semantic search   metadata gate
            \              /
             v            v
         [ Verified Context ]

🛠️ MCP Tools

Tool Description
list_sources() List configured sources
sync_source(source_id) Sync a specific source
sync_all() Sync all sources at once
get_sync_status(source_id="") Get source and sync job status
search_context(query, ...) Semantic search with SQLite validation
search_documents(query, ...) Search results grouped by document
fetch_context(document_id="", chunk_id="") Fetch a specific document or chunk directly

💡 In production, use search_context / search_documents to gather grounded evidence, then let a downstream LLM generate the final answer.


⚡ Quick Start

Prerequisites: Python 3.13, uv

uv sync --locked
cp .env.example .env
uv run --locked python main.py

Docker:

docker build -t contextwiki .
cp .env.example .env
docker run --rm -i \
  --env-file .env \
  -v contextwiki_data:/home/appuser/.mcp_content_search \
  contextwiki

For Obsidian in Docker, add -v "/path/to/vault:/vault:ro" and set CONTEXTWIKI_OBSIDIAN_VAULT_PATH=/vault.


⚙️ Configuration

Source Activation

Source Source ID Env var to enable
Notion source_notion NOTION_API_KEY
Tistory source_tistory TISTORY_BLOG_NAME
GitHub source_github CONTEXTWIKI_GITHUB_REPOSITORIES
Obsidian source_obsidian CONTEXTWIKI_OBSIDIAN_VAULT_PATH

Set only the sources you plan to use. A source stays disabled when its enabling config is missing or empty. Bad credentials can still fail later during refresh or sync. Some invalid target values can fail earlier during startup or source refresh; for example, a malformed CONTEXTWIKI_GITHUB_REPOSITORIES value can prevent the server from starting cleanly.

Source-specific env vars only register and enable each source. With the default embedding setup, successful sync/indexing still also requires OPENAI_API_KEY unless you reconfigure embeddings.

.env Example

OPENAI_API_KEY=...              # required for default embeddings/indexing; also used by optional rewrite

NOTION_API_KEY=...
TISTORY_BLOG_NAME=devlog        # subdomain only, not the full URL

CONTEXTWIKI_GITHUB_REPOSITORIES=eunhwa99/MCPContentSearch@main
GITHUB_TOKEN=...                # needed for private repos or higher rate limits

CONTEXTWIKI_OBSIDIAN_VAULT_PATH=/absolute/path/to/vault

Important GitHub notes:

  • Use owner/repo or owner/repo@ref.
  • Do not wrap CONTEXTWIKI_GITHUB_REPOSITORIES in quotes in .env.
  • GITHUB_TOKEN is optional, but private repositories and higher rate limits usually need it.

Notion example

NOTION_API_KEY=...

Set this only if you want to enable the Notion source.

Tistory example

TISTORY_BLOG_NAME=devlog

Use the blog subdomain only, not the full URL. For example, use devlog, not https://devlog.tistory.com.

Obsidian example

CONTEXTWIKI_OBSIDIAN_VAULT_PATH=/absolute/path/to/your/vault
CONTEXTWIKI_OBSIDIAN_MAX_FILES=2000
CONTEXTWIKI_OBSIDIAN_MAX_FILE_BYTES=512000

Use the vault root path, not an individual .md file path.

Search Query Rewrite (Optional)

CONTEXTWIKI_SEARCH_LLM_ENABLED=true
CONTEXTWIKI_SEARCH_LLM_PROVIDER=openai
CONTEXTWIKI_SEARCH_LLM_MODEL=gpt-4.1-mini

🚀 Usage

Claude Desktop — local uv (Recommended)

This is the easiest setup path on macOS because:

  • Claude Desktop can spawn the server directly.
  • ContextWiki loads the repository-local .env at startup, so Claude Desktop does not need plaintext env entries in claude_desktop_config.json.
  • Obsidian can use your real host vault path directly.
  • You do not need Docker mounts for the vault.

Important:

  • Repository .env values do not override env vars already set by Claude Desktop or your shell.
  • If you previously set OPENAI_API_KEY, NOTION_API_KEY, GITHUB_TOKEN, or other source env vars in claude_desktop_config.json or a parent shell, clear the stale values there too.

Do this in order:

  1. Create .env in your repo root.
  2. Put your real values there.
  3. Add the MCP entry below to Claude Desktop.
  4. Fully restart Claude Desktop.
  5. In a fresh Claude Desktop chat, ask it to call list_sources().

Example .env:

# Required for default sync/indexing because embeddings use OpenAI by default
OPENAI_API_KEY=...

# Optional: enable Notion source
NOTION_API_KEY=...

# Optional: enable Tistory source
TISTORY_BLOG_NAME=devlog

# Optional: enable GitHub source
CONTEXTWIKI_GITHUB_REPOSITORIES=eunhwa99/MCPContentSearch
CONTEXTWIKI_GITHUB_DEFAULT_REF=main

# Optional for private repos or higher GitHub API limits
GITHUB_TOKEN=...

# Optional: enable Obsidian source
CONTEXTWIKI_OBSIDIAN_VAULT_PATH=/absolute/path/to/your/vault

On macOS, add this to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
  "mcpServers": {
    "content-search-server": {
      "command": "/absolute/path/to/uv",
      "args": [
        "--directory", "/absolute/path/to/MCPContentSearch",
        "run", "--python", "3.13", "python", "main.py"
      ]
    }
  }
}

Run which uv to find the path. Fully restart Claude Desktop after any config change.

Claude Desktop — Docker

{
  "mcpServers": {
    "content-search-server": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "--env-file", "/absolute/path/to/MCPContentSearch/.env",
        "-v", "contextwiki_data:/home/appuser/.mcp_content_search",
        "contextwiki:latest"
      ]
    }
  }
}

Cursor

Add the same local uv config above to .cursor/mcp.json.

After Connecting

  1. Call sync_all() or sync_source("source_notion")
  2. Search with search_context() or search_documents()

Example prompt:

find my projects about DynamoDB and organize it with STAR method. Answer in English

Claude Desktop using ContextWiki MCP as a retrieval backend before Claude composes the final STAR-style response


🔧 Troubleshooting

Symptom Fix
MCP server not discovered Recheck config path and fully restart the client
Only works after manual start Run command + args directly in terminal to see errors
Invalid GitHub repository spec Remove quotes from .env; use owner/repo, not a full URL
Obsidian not working in Docker Set both the volume mount and CONTEXTWIKI_OBSIDIAN_VAULT_PATH=/vault
Source still disabled after config change Fully restart the MCP client — a chat refresh is not enough
sync_all() too slow Sync individually: sync_source("source_github"), etc.

✅ Verification

./scripts/demo.sh                           # Quick flow check with sample vault (no credentials needed)
./scripts/verify_all.sh                     # Full verification after code changes
./scripts/demo.sh --query "your question"   # Custom query
  • ./scripts/demo.sh is the default reviewer path. It uses the bundled sample vault, needs no credentials, and keeps retrieval plus helper preview on the same input by default.

📁 Project Structure

main.py          FastMCP server entry point
api/             MCP tool handlers
core/            Shared models, exceptions, utilities
environments/    Env var and secret loading
fetching/        Source connectors (Notion, Tistory, GitHub, Obsidian)
indexing/        Chunking, deduplication, Chroma indexing
search/          Search, ranking, metadata gate, citation answer support
storage/         SQLite lifecycle management
tests/, scripts/ Verification harnesses and utilities

📖 Additional Docs

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages