Context collection and storage foundation for AI projects (MCP-native)
Project description
Context-Hub
MCP-native context collection and storage for AI-assisted software projects.
Context-Hub collects project context (Slack messages, Backlog/Redmine issues, meeting notes) into a local SQLite or PostgreSQL store and exposes it over MCP (Model Context Protocol) and a REST API. AI agents such as Claude Desktop and Claude Code connect to it to answer questions about your project without sending raw data to third-party services.
What is this?
| Feature | Detail |
|---|---|
| MCP server | stdio transport — plug directly into Claude Desktop or Claude Code |
| REST API | FastAPI — for custom integrations and web UIs |
| Hybrid search | Vector (sqlite-vec / pgvector) + FTS5 keyword search, RRF fusion |
| Meeting → tasks | On-prem LLM extracts action tasks from meeting transcripts at ingest time and persists them; get_meeting returns extractedTasks (stable across reads) |
| Slack scraping ingest | POST /projects/{id}/ingest/slack upserts scraped Slack messages (idempotent on ts) — no Slack API token required |
| camelCase contract | All REST responses are camelCase (consumed by AI-Project-Manager / @yohakuforce/core) |
| Three profiles | quickstart (SQLite + mock), personal (SQLite + BGE-M3), production (PostgreSQL) |
| Zero-dependency start | pipx install then context-hub serve — no Docker, no Postgres, no API keys required |
Looking for the full operator guide? See docs/usage-guide.md — covers profiles, all five ingest paths, querying, ops, and privacy.
Quick Start (60 seconds)
# Install
pipx install yohakuforce-context-hub
# Initialise with the zero-dependency quickstart profile
context-hub init --profile quickstart
# Apply database schema
context-hub migrate
# Start the HTTP REST API server (use --mcp-only for the stdio MCP server)
context-hub serve
Then query it:
# REST
curl http://127.0.0.1:8000/health
# {"status":"ok"}
# MCP version check (used by AI-PM at startup)
curl http://127.0.0.1:8000/mcp/version
# {"mcp_protocol_version":"2024-11-05","server":"context-hub","server_version":"0.3.0"}
Add to Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"context-hub": {
"command": "context-hub",
"args": ["serve", "--mcp-only"],
"env": {
"CONTEXT_HUB_API_KEY": "your-api-key"
}
}
}
}
Profiles
| Profile | Database | Embedding | Scheduler | Use case |
|---|---|---|---|---|
quickstart |
SQLite (file) | mock (hash-based) | in-memory | Zero-dependency local dev |
personal |
SQLite (file) | BGE-M3* | SQLite | Single-user persistent storage |
production |
PostgreSQL | BGE-M3* | PostgreSQL | Production deployment |
*BGE-M3 requires: pip install 'yohakuforce-context-hub[embedding]' (~2.3 GB model download on first run)
Switch profiles:
context-hub init --profile personal # or production
context-hub migrate
context-hub serve
Admin GUI
Prefer clicking to editing .env? Start the server and open the admin console:
context-hub serve # HTTP REST API (the admin UI rides on it)
open http://127.0.0.1:8000/admin
It's a single server-rendered page (no build step), in Japanese, styled to match the yohakuforce docs (paper/crimson theme). Every setting has an inline, collapsible guide — なぜ必要 (why) / 取得手順 (how to obtain) / 設定方法 (how to set) — so you never have to leave the screen to figure out where a token comes from. Three tabs:
- Settings — every connection setting and secret (Slack / Backlog / Redmine /
Gmail / LLM / embedding / DB / inbox …). Secrets are shown masked (last 4 chars);
saving writes
.envand hot-reloads non-restart values. Fields that need a restart are badged. - Sources — create projects and configure each source (enable, sync interval, Slack channel IDs, Backlog/Redmine keys) without touching the database directly. Each source has a Test button (readiness + a live ping for Slack/Redmine).
- Status — profile, ingest mode, scheduler, auto-sync, vector-search vs FTS-only, inbox folder, and per-project enabled sources.
Auth: the page shell loads unauthenticated (bind to 127.0.0.1), but every
data call requires an ADMIN API key you paste once (stored in the browser).
In development (the quickstart / personal profiles) that's the DEV_API_KEY
value — context-hub init generates one for you and prints it (it's also
saved in your .env). Grab it from the init output, or run
grep DEV_API_KEY .env, and paste it when the GUI prompts. In production
(APP_ENV=production) DEV_API_KEY is ignored — mint an ADMIN consumer key
instead (see SECURITY.md). The backing endpoints are
GET/PUT /api/v1/config, POST /api/v1/config/test/{source},
GET /api/v1/status, and the project/source CRUD under /api/v1/projects.
Run the admin UI on localhost only. It reads and writes credentials.
Windows support
Context-Hub runs on Windows. One platform nuance to know:
pip installworks — all dependencies (includingsqlite-vec) ship Windows wheels.- SQLite profiles auto-degrade to FTS-only when needed. The official
python.org Windows build of Python compiles
sqlite3without loadable-extension support, so thesqlite-vecextension can't load there. When that happens, Context-Hub automatically runs in FTS-only mode:migrate, ingestion, and keyword search all work — only semantic (vector) search is disabled. A clear warning is logged at startup. (In thequickstartprofile the default embedding is a meaningless hash, so you lose nothing real there.) - Want full semantic search on Windows? Either:
- Use a Python that has loadable sqlite extensions — conda / miniforge Python does — then the SQLite profiles get full vector search; or
- Use the
productionprofile (PostgreSQL + pgvector), which doesn't usesqlite-vecat all and is fully featured on any Python.
- Scheduling: use Windows Task Scheduler to run
context-hub ingest all, or just keepcontext-hub serverunning (its built-in scheduler auto-syncs). Seeexamples/launchd/README.mdfor the Task Scheduler recipe.
Architecture Overview
┌─────────────────────────────────────────────────────┐
│ Context-Hub Process │
│ │
│ ┌──────────────┐ ┌──────────────────────────┐ │
│ │ MCP Server │ │ FastAPI REST API │ │
│ │ (stdio) │ │ /api/v1/{projects,query} │ │
│ └──────┬───────┘ └───────────┬──────────────┘ │
│ │ │ │
│ └───────────┬────────────┘ │
│ ▼ │
│ QueryService (shared) │
│ VectorStore + FTS + RRF fusion │
│ │ │
│ ┌───────────┴───────────┐ │
│ ▼ ▼ │
│ SQLite (sqlite-vec) PostgreSQL (pgvector) │
│ SchedulerStore SchedulerStore │
└─────────────────────────────────────────────────────┘
Both MCP and HTTP layers are thin adapters over the shared QueryService. Neither layer owns business logic.
Data Sources
Ingestion adapters collect context and write to the store:
- Slack — messages and threads (mock or live via
slack-sdk) - Backlog — issues and wiki (mock or live)
- Redmine — issues and wiki (mock or live)
- Gmail — labelled messages via the Gmail API (mock or live, opt-in extra)
- Manual ingest —
POST /api/v1/documentsfor meeting notes, memos, email bodies, or any text the user wants to inject (see below)
Manual document ingest
There are two ways to feed user-authored context (meeting notes, memos, email bodies, ...) into Context-Hub:
A. Inbox folder watcher (recommended for daily use)
Set CH_INBOX_DIR and drop files into the matching subdirectory. A background job scans every CH_INBOX_POLL_SECONDS (default 60) and upserts each file as a Document. No commands to run, no API to call — just save the file.
# .env (or shell)
CH_INBOX_DIR=~/.context-hub/inbox
CH_INBOX_POLL_SECONDS=60
# CH_PROJECT_ID=... # required only if more than one project exists in the repo
Layout (Context-Hub is 1:1 with a project — no per-project subfolder needed):
~/.context-hub/inbox/
meeting/
2026-05-20-weekly.md
2026/05/20-detail.md # nested subdirs are fine
file/
product-spec.md
email/
saved-thread.txt
Rules:
- Accepted extensions:
.mdand.txtonly. PDF / PowerPoint / docx must be converted to Markdown by the user before being dropped in. - The first Markdown
# H1is used as the title; otherwise the filename stem is used. external_id = "<source_type>/<relative_path>". Editing a file in place upserts the existing document; unchanged files are skipped (no embedding cost).- Hidden files (
.DS_Storeetc.) and unknown subdirectories are ignored. - When
CH_INBOX_DIRis unset, the watcher is disabled.
B. Direct REST call (for integrations and one-offs)
curl -X POST http://127.0.0.1:8000/api/v1/documents \
-H "X-Api-Key: $CONTEXT_HUB_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj-001",
"source_type": "meeting",
"title": "2026-05-20 weekly",
"text": "Decision: ship bundle plan A. Owner: koya. Next: ...",
"external_id": "meeting-2026-05-20",
"author": "koya"
}'
source_type accepts meeting | file | email. Slack/Backlog/Redmine content must go through their dedicated /sources/*/sync endpoints. Re-posting with the same external_id upserts (replaces) the prior document. Omit external_id for a fresh insert each call.
C. File upload (.md / .txt / .pdf / .docx)
For documents that already live as files on disk (contracts, specs, exported meeting notes), POST them as multipart form data:
curl -X POST http://127.0.0.1:8000/api/v1/documents/upload \
-H "X-Api-Key: $CONTEXT_HUB_API_KEY" \
-F "project_id=proj-001" \
-F "source_type=file" \
-F "file=@./specs/project-phase1.pdf"
Accepted extensions: .md, .txt (always), and .pdf, .docx (only when the [documents] extra is installed):
pip install 'yohakuforce-context-hub[documents]'
- Max file size: 10 MiB. Larger files return
413. - Server-side text extraction: pymupdf for PDF, python-docx for DOCX, UTF-8 decode for
.md/.txt. external_iddefaults to the filename, so re-uploading the same file replaces the prior document.- Scanned PDFs without OCR cannot be ingested (no extractable text) — convert to OCR'd PDF first, or paste the text via the
/documentsendpoint.
Check what your install supports:
curl -H "X-Api-Key: $CONTEXT_HUB_API_KEY" \
http://127.0.0.1:8000/api/v1/documents/upload/supported-extensions
Gmail ingest
Pull labelled messages straight from Gmail into Context-Hub via the Gmail API.
Why label-based by default? The default query label:context-hub is explicit opt-in — only emails you tag with the context-hub label are ingested, so private mail stays out of the store. Override with any Gmail search syntax if you need broader coverage.
Setup:
# 1. Install the optional Google dependencies
pip install 'yohakuforce-context-hub[gmail]'
# 2. In Google Cloud Console, create an OAuth 2.0 Desktop client and download
# credentials.json. Enable the Gmail API for the project.
# 3. Save credentials.json somewhere local, e.g. ~/.context-hub/gmail/credentials.json
# 4. Configure .env
GMAIL_CREDENTIALS_FILE=~/.context-hub/gmail/credentials.json
GMAIL_TOKEN_FILE=~/.context-hub/gmail/token.json
GMAIL_QUERY=label:context-hub # override as needed
INGEST_MODE=live # mock by default; flip to live to hit Gmail
# 5. First run opens a browser for consent; the refresh token is then cached in
# GMAIL_TOKEN_FILE and used for subsequent syncs.
context-hub ingest gmail --mode live
Trigger a sync via the API or CLI:
curl -X POST http://127.0.0.1:8000/api/v1/sources/gmail/sync \
-H "X-Api-Key: $CONTEXT_HUB_API_KEY" -H "Content-Type: application/json" \
-d '{"project_id":"proj-001"}'
For scheduled sync, add an EMAIL SourceConfig to the Project (same pattern as Slack/Backlog/Redmine). The watcher uses the cursor mechanism to pull only newer messages on each tick.
Settings Profiles (ADR-003)
Three pydantic-settings profiles inherit from a common base. Override any field with environment variables:
CH_PROFILE=quickstart # default
CH_PROFILE=personal
CH_PROFILE=production
CLI Reference
context-hub init --profile [quickstart|personal|production]
context-hub migrate [--dry-run] [--target HEAD] [--yes]
context-hub serve [--host 127.0.0.1] [--port 8000] [--mcp-only] [--reload]
# default: HTTP REST API. --mcp-only: stdio MCP server instead.
context-hub ingest [slack|backlog|redmine|gmail|inbox|all] [--mode mock|live]
context-hub query "<text>" [--top-k 5] [--json] [--project-id <uuid>]
One-shot full sync — ingest all
context-hub ingest all syncs every enabled source for the project in a
single run (Slack / Backlog / Redmine / Gmail), then scans the inbox folder when
CH_INBOX_DIR is set. A failure in one source is logged and the rest continue,
so one bad credential never blocks the others:
CH_PROFILE=personal INGEST_MODE=live context-hub ingest all
# Ingest-all: project_id='…', 2 enabled source(s), mode=live.
# + slack: status=completed items=12
# + backlog: status=completed items=3
# Ingest-all complete. project_id='…' succeeded=2 failed=0
This is the command to put on a schedule. See
examples/launchd/ for a ready-made launchd agent (macOS)
that runs ingest all every 15 minutes, plus cron / systemd / Windows Task
Scheduler equivalents.
Automatic background sync while serve runs
You don't even need an external scheduler if you keep context-hub serve
running: on startup it registers an interval job for every enabled source of
every project and re-syncs each on its syncInterval (minimum 5 minutes). The
inbox folder watcher runs the same way. This is on by default; disable it with:
CH_SOURCE_SYNC_ENABLED=false # in .env or the environment
Pick one automation strategy: the built-in serve scheduler (simplest if the
server is always up) or an external ingest all job (durable across reboots
without keeping serve running). Running both just syncs twice.
Optional Extras
# BGE-M3 local embedding (personal / production profiles)
pip install 'yohakuforce-context-hub[embedding]'
# PostgreSQL support
pip install 'yohakuforce-context-hub[postgres]'
# Gmail live ingest (OAuth2 + Gmail API)
pip install 'yohakuforce-context-hub[gmail]'
# PDF / DOCX upload extraction (pymupdf + python-docx)
pip install 'yohakuforce-context-hub[documents]'
# All
pip install 'yohakuforce-context-hub[embedding,postgres,gmail,documents]'
Docker
See examples/docker/ for Docker Compose configuration.
Contributing
See CONTRIBUTING.md.
Security
See SECURITY.md for vulnerability reporting.
License
Apache-2.0 — see LICENSE.
日本語セクション
Context-Hub は AI 支援ソフトウェア開発プロジェクト向けの MCP ネイティブなコンテキスト収集・保存基盤です。
Slack / Backlog / Redmine などのプロジェクトデータをローカルの SQLite または PostgreSQL に集約し、MCP (Model Context Protocol) と REST API の両方で公開します。Claude Desktop や Claude Code などの AI エージェントが直接接続し、プロジェクト固有の情報に基づいた回答を生成します。
特徴
- MCP 一級市民: stdio トランスポートで Claude Desktop / Claude Code から直接利用可能
- ハイブリッド検索: ベクトル検索 (sqlite-vec / pgvector) + FTS5 全文検索を RRF でフュージョン
- ゼロ依存スタート:
pipx installのみで動作開始、Docker 不要、Postgres 不要 - 3 プロファイル: quickstart (SQLite + mock)、personal (SQLite + BGE-M3)、production (PostgreSQL)
クイックスタート
pipx install yohakuforce-context-hub
context-hub init --profile quickstart
context-hub migrate
context-hub serve
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file yohakuforce_context_hub-0.3.0.tar.gz.
File metadata
- Download URL: yohakuforce_context_hub-0.3.0.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f26d173706da045bab56b7d320fb095cab2d66f23d403b8bb6b645ea2c85ad44
|
|
| MD5 |
e804e66326a2cadfd76794f6abdda9b8
|
|
| BLAKE2b-256 |
4112901a622b9b2d486626a1b2f86287cd6ab6fc141017646b6a32ce3abb66e2
|
File details
Details for the file yohakuforce_context_hub-0.3.0-py3-none-any.whl.
File metadata
- Download URL: yohakuforce_context_hub-0.3.0-py3-none-any.whl
- Upload date:
- Size: 217.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d90eabe6ccf34e1a97695d9208c912167d00786625f1fc946bcc0085a576240c
|
|
| MD5 |
41c29b92ae80eeeabc80d339f6699096
|
|
| BLAKE2b-256 |
86903ca765ef741f758c1fe356ac3b0c16b169c1b52684039b4355af32cd390a
|