Claude Context Hub
Provides GitHub OAuth sign-in for the MCP server, restricted to allowlisted numeric GitHub user IDs, with allowlist enforcement at the OAuth callback, token verification, and per-request layers.
Integrates with Syncthing to monitor synced Claude Code project folders, attribute files to machines via the Syncthing REST API, detect offline sync devices and conflict files, and recover deleted sessions from Syncthing's versions folder.
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., "@Claude Context HubGive me a brief on the website project"
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.
Claude Context Hub
A self-hosted remote MCP server that gives every Claude surface — claude.ai, Claude Desktop, Cowork, mobile, the Office add-ins and Claude Code — read and write access to the memories, transcripts and notes produced by every Claude Code instance on every machine you use.
Claude Code keeps its history as files under ~/.claude/projects. If you sync that folder between your
machines (for example with Syncthing), this hub indexes the shared folder and serves it as a custom connector:
"Give me a brief on the website project" in claude.ai returns the project's memory index, recent sessions from all machines, and notes left by other Claude surfaces.
"Find where we discussed the retry logic" runs a hybrid keyword + semantic search over all transcripts.
A conversation in PowerPoint or on your phone can leave a note, or save a memory that the next Claude Code session on any machine loads automatically.
It is built for one person, low maintenance, and strict lockdown: GitHub sign-in restricted to an allowlist of numeric user ids, secrets redacted before anything is indexed, thinking blocks never stored.
Claude (cloud) ──HTTPS──► reverse tunnel ──► 127.0.0.1:8790 claude-context serve
FastMCP (Streamable HTTP, stateless) + GitHub OAuth proxy
reads index.db · writes memory/note files · audit.db
claude-context index --watch ── watches the synced folder, Syncthing events and an import drop folder
writes index.db (SQLite FTS5 + sqlite-vec), embeds locally on CPU (fastembed)
claude-context maintenance (daily) ── archive, recovery of deleted sessions, retention, backupsTools
Tool | Purpose |
| The main entry point: memory index, recent memory changes, latest sessions, notes, warnings. |
| Cross-project timeline of sessions, memory changes and notes. |
| Hybrid search (FTS5 bm25 + local embeddings, fused with RRF and a recency factor). |
| Browse and read transcripts, paged. |
| Read memories and notes. |
| Write memories in Claude Code's own format (optimistic concurrency by sha256). |
| Leave an append-only note from any surface. |
| Index freshness, counts, sync state, warnings. |
Prompts: catch_up(project) and wrap_up(project).
Related MCP server: claude-memory
How it works
Sources. One or more roots, each a ~/.claude/projects-style tree:
<project-key>/<session-id>.jsonl transcripts, <session-id>/subagents/… subagent transcripts,
memory/MEMORY.md + one memory per file, and remote-notes/*.md (written by log_note). An optional root of
kind stversions recovers sessions that were deleted upstream from Syncthing's versions folder. claude.ai
conversations come from data-export zips dropped into a watched folder.
Indexing. Transcripts are append-only, so the indexer keeps a byte offset per file and parses only new,
complete lines. Every message becomes a row in an FTS5 table; interactive sessions, memories and notes are
also chunked and embedded (BAAI/bge-small-en-v1.5, 384-d, CPU). Automated (SDK-driven) sessions get keyword
search only and are hidden from listings unless asked for. Each file is attributed to the machine that last
modified it via Syncthing's REST API.
Safety properties.
Authentication is never optional. The only exception is
serve --insecure-local-test, which refuses to start unless bound to loopback with no tunnel running, and refuses any request that came through a proxy.The GitHub allowlist is enforced in three independent layers: at the OAuth callback, in token verification, and per MCP request. See
docs/AUTH-NOTES.md.Secrets (API keys, tokens, private keys, passwords, high-entropy values) are redacted at ingest, so they never reach the index or the embeddings, and again on output.
thinkingblocks are skipped by the parsers and never stored.The server writes only memory and note files, atomically, and never deletes:
archive_memorymoves a file intomemory/.archived/.Every tool call and auth event is recorded in
audit.db.Transcript text is labeled as untrusted historical data in the server instructions and tool descriptions.
Requirements
Linux with systemd, Python 3.12+,
uv, SQLite ≥ 3.45 with loadable extensions.A folder of Claude Code sessions (ideally synced from all your machines; Syncthing is supported natively).
A public HTTPS hostname that forwards to
127.0.0.1:8790without opening inbound ports — for example a Cloudflare Tunnel. Claude's servers must be able to reach it; an authenticating proxy in front will not work.A GitHub OAuth App (not a GitHub App) with callback URL
https://<your-host>/auth/callback.
Install
git clone https://github.com/<you>/claude-context-mcp.git && cd claude-context-mcp
uv venv --python /usr/bin/python3.12 && uv sync
mkdir -p ~/.config/claude-context && chmod 700 ~/.config/claude-context
cp config.example.toml ~/.config/claude-context/config.toml && chmod 600 ~/.config/claude-context/config.toml
$EDITOR ~/.config/claude-context/config.toml # base_url, allowed_github_ids, roots, projectsCreate the secrets file in your own terminal (never paste secrets into a Claude session — transcripts are exactly what this tool indexes):
umask 077
read -rp "GitHub Client ID: " GCID
read -rsp "GitHub Client secret: " GCS; echo
cat > ~/.config/claude-context/secrets.env <<EOF
GITHUB_CLIENT_ID=$GCID
GITHUB_CLIENT_SECRET=$GCS
JWT_SIGNING_KEY=$(python3 -c 'import secrets;print(secrets.token_urlsafe(64))')
STORAGE_ENCRYPTION_KEY=$(python3 -c 'import base64,os;print(base64.urlsafe_b64encode(os.urandom(32)).decode())')
EOF
chmod 600 ~/.config/claude-context/secrets.env; unset GCID GCSBuild the index once, then install the services:
uv run claude-context index # first run downloads the embedding model (~70 MB)
uv run claude-context doctor
deploy/install-units.sh # renders units into deploy/rendered/ for review
deploy/install-units.sh --install # copies them to /etc/systemd/system (sudo)
sudo systemctl enable --now claude-context-indexer claude-context-server claude-context-maintenance.timerdeploy/systemd/cloudflared-claude-context.service is a dedicated tunnel unit that reads its token from
/etc/cloudflared/claude-context.token (root, mode 600). It is separate from any other cloudflared service.
Finally add the connector in claude.ai (Customize → Connectors → Add custom connector) with URL
https://<your-host>/mcp, and sign in with the allowlisted GitHub account. Suggested permissions: always allow
the read tools and log_note; require approval for save_memory and archive_memory.
Operations
claude-context serve [--insecure-local-test]
claude-context index [--watch | --full | --rebuild-embeddings | --no-embed]
claude-context import-claudeai <zip>
claude-context recover-stversions [--dry-run]
claude-context prune [--dry-run]
claude-context merge-conflicts [--dry-run]
claude-context maintenance
claude-context status
claude-context search "<query>" [--mode hybrid|keyword|semantic] [--project <alias>]
claude-context doctorHealth. There is no separate alerting stack. The indexer writes a heartbeat (status.json) every minute;
when something is wrong (stale heartbeat, sync device offline for a day, conflict files, low disk, embedding
backlog, unknown transcript record types…) project_brief and recent_activity prepend a "⚠ Hub health" block,
so the problem surfaces the next time any Claude uses the hub. claude-context status and doctor show the
same from the shell; logs go to the journal (journalctl -u claude-context-server -u claude-context-indexer).
Data locations (default ~/.local/share/claude-context/): index.db (rebuildable at any time with
index --full), audit.db, oauth/ (encrypted OAuth store), archive/ (copies of transcripts, kept after
the originals are deleted upstream, until retention), models/, imports/processed/, backups/ (14 nightly
copies of audit.db and the config).
Retention. Sessions older than retention_days are pruned daily from the index and the archive. Live
files are never deleted by the hub (set Claude Code's own cleanupPeriodDays to match). Memories and notes are
never pruned.
Conflicts. If two machines edit a MEMORY.md at once, Syncthing creates a MEMORY.sync-conflict-*.md.
The maintenance job merges these automatically (union of lines, newest wins per memory) and archives the
conflict copy. Conflicts in other files are only reported.
Key rotation.
JWT_SIGNING_KEY: rotating it invalidates every issued token; each connector must sign in again.STORAGE_ENCRYPTION_KEY: rotating it makes the stored OAuth clients and tokens unreadable; deleteoauth/and sign in again.GitHub client secret: generate a new one in the OAuth App, update
secrets.env, restart the server.To revoke access for a GitHub account, remove its id from
allowed_github_idsand restart the server; previously issued tokens for that id stop working immediately.
Upgrading. Dependencies are pinned in uv.lock; nothing upgrades automatically.
uv lock --upgrade-package <name> && uv sync && uv run pytest && uv run claude-context doctor, then restart
the services. When upgrading fastmcp, re-read docs/AUTH-NOTES.md: the allowlist
tests are designed to fail loudly if its OAuth internals change.
Format drift. Claude Code's transcript format changes over time. The parser ignores unknown fields and
counts unknown record types; hub_status reports them so drift is visible instead of silently losing data.
Verified build facts
Checked while building (October 2026); re-check when upgrading.
Item | Outcome |
FastMCP API | Built on fastmcp 4.0.11 (mcp 2.3.0). |
OAuth storage |
|
Allowlist hook | FastMCP has no user allowlist; it is added by subclassing the provider (see the notes for the exact hooks and the private internals they depend on). |
Browser-facing paths |
|
GitHub scope | None: |
Token lifetime | With a GitHub OAuth App there are no refresh tokens and an issued access token lives up to a year; revoke by editing the allowlist or rotating |
Policy denials | The per-message guard answers with a JSON-RPC error (FastMCP middleware cannot set an HTTP status); the source-CIDR check additionally returns a real HTTP 403 before token verification. |
sqlite-vec | 0.1.9 supports vec0 metadata columns with filters; |
FTS5 | SQLite 3.45: a regular (content-storing) FTS5 table is the single text store, so |
Embedding model |
|
claude.ai export schema | Not yet verified against a real export; the parser is defensive and reports what it skipped. |
Troubleshooting
Symptom | Check |
Connector says "couldn't connect" |
|
Sign-in loops or fails | The OAuth App callback URL must be |
Results are stale |
|
Semantic search finds nothing | Embedding backlog in |
A memory edit was rejected | Another machine changed it first: |
Development
uv sync && uv run pytestTests are fully offline and use synthetic fixtures; nothing in this repository is derived from real transcripts.
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
Persistent AI memory shared across Claude, ChatGPT, coding agents, and compatible MCP clients.
Private persistent memory for Claude, ChatGPT & Gemini via MCP - semantic search, zero-code setup.
- mcpOAuthai.butlerbrain
Persistent memory for AI assistants. Save once; recall from Claude, ChatGPT, or any MCP client.
- TaprootOAuthcom.taproothq
Persistent memory layer for AI tools. Save and recall notes across Claude and other MCP clients.
Related MCP Servers
- AlicenseAqualityCmaintenancePersistent memory for Claude Code. Automatically indexes every conversation and provides production-grade hybrid search (BM25 + vectors + reranker) via MCP tools. 100% local, zero config, zero API keys, zero invoice.1653 npm7MIT
- AlicenseNot gradedqualityDmaintenanceCross-machine memory system for Claude Code that records sessions as searchable markdown, syncs across machines via Git, and exposes full-text search, semantic search, session summarization, and a knowledge graph through an MCP server.9 npmMIT
- AlicenseNot gradedqualityCmaintenanceA persistent memory MCP server for Claude Code that enables long-term recall across sessions via hybrid search, code intelligence, and tools for reading/writing memory.9 npm5MIT
- AlicenseAqualityDmaintenanceA zero-dependency MCP server for cross-session memory recall in Claude Code. Provides lexical search, listing, and retrieval of past session memories to avoid re-explaining context.39 npmMIT