ctxnest
Stop wasting tokens! CtxNest is a local-first context manager that bridges your files and AI agents (Claude, Cursor, Gemini). * 41 MCP Tools: The most advanced toolset for AI history & search. * Token Efficient: Agents fetch only what they need, saving you cost. * Time Travel: Revert any file to a previous version instantly. * Web Clipping: Save any webpage as clean Markdown.
README
<h1 align="center"> <img src="apps/web/public/logo.png" alt="CtxNest Logo" width="180"><br> CtxNest v6.1.0 </h1> <p align="center"><b>The Centralized Context Engine for Agentic Workflows</b></p>
CtxNest is a high-performance markdown context manager that bridges the gap between your local file system and your AI coding assistants. It features a premium "Obsidian-meets-Terminal" UI and a built-in Model Context Protocol (MCP) server to provide seamless, versioned knowledge to tools like Claude Code, Gemini, and Cursor.
[!NOTE] What's New in v6.1.0 — Search, Sync & Speed:
- Search Optimization — Rewrote SQLite FTS5 logic with a precise tokenizer. Correctly handles technical identifiers and complex file paths.
- Unified Distribution — Perfectly synchronized releases across npm (
npx -y ctxnest-mcp) and Docker Hub (safiyu/ctxnest).- Workflow Safety — Added unsaved-edit guards, atomic file moves, and improved concurrency for high-speed agentic sessions.
- Smarter Context — Every tool now reports estimated tokens and size, allowing agents to budget your context window surgically.
<p align="center"> <img src="apps/web/public/screenshot.png" alt="CtxNest UI Screenshot" width="100%"> </p>
Demo
A short walkthrough of knowledge vaulting, surgical section edits, and live MCP integration with Antigravity and Claude.
<p align="center"> <a href="https://www.youtube.com/watch?v=wq8Hz5d7wHI"> <img src="apps/web/public/Snapshot_2.png" alt="CtxNest demo video" width="80%"> </a> </p>
- 0:11 — System audit with Antigravity
- 0:39 — Clipping web documentation into the knowledge base
- 1:08 — Drafting a strategy doc from project context via MCP
- 1:37 — Bundling project context as a single XML block
Demo Server
You can try out the MCP endpoints interactively by visiting the CtxNest page on Glama.
Why CtxNest?
Git is built for code; CtxNest is built for context. It gives you a single global vault for context across every project, two-way sync that pulls and merges collaborator changes via native git, versioned snapshots as a safety net for accidental wipes, and a pay-as-you-go MCP surface so agents fetch only what they need instead of preloading thousands of tokens per turn. Registering a project also makes it part of a global pool — agents can pull standards from any project to help with the current one.
[!TIP] Deleting a project file in CtxNest only un-indexes it from the AI's memory. Your physical source code is never touched.
Why Local-First
CtxNest runs entirely on your machine — no cloud account, no remote inference, no telemetry. That isn't a missing feature, it's the design.
- Privacy & security — your source, notes, and clipped pages never leave your SSD. Nothing to breach, nothing to "train on", no SOC2 box to tick before you can use it.
- Zero latency — disk reads and SQLite FTS5 finish in milliseconds. No upload speeds, no API timeouts, no cold-start round-trips between your editor and a hosted index.
- Zero infrastructure cost — no subscriptions, no per-seat pricing, no server to keep alive. Run it on a laptop or a homelab box; it's the same binary either way.
- Plays nicely with the rest of your stack — the MCP server is a stdio process your agent already knows how to spawn; the web UI is a localhost service you can put behind a Tailscale/Cloudflare tunnel if you want remote access on your terms.
Key Features
- Global vault & two-way sync — single git repo for context across all projects; native pull/merge of remote changes.
- MCP server — every file-returning tool reports
est_tokensandsize_bytes;list_files/search/whats_new/project_mapalso inlinetags, eliminating N+1 round-trips. - Local-first RAG — SQLite FTS5 (deterministic, no hallucinated relevance), git-backed versioning, no third-party vector clouds.
- Web clipping — Readability-extracted Markdown into the knowledge base, deduped by URL. Detects auth walls (
AUTH_REQUIRED) and accepts aheadersparam for cookie/token retry. - Git intelligence — every edit versioned;
get_history+get_difflet agents explain why a decision was made. - Live UX — animated status bar streams git stages over WebSockets, ambient sync feedback, ZIP export of any folder/project.
- Dual-brain architecture — project context separated from your personal knowledge base.
Team Collaboration
Although CtxNest is local-first, it supports team collaboration through its Global Git Vault:
- Distributed Sync: Every developer runs their own local CtxNest instance.
- Git Relay: When you save context, CtxNest commits and pushes to your team's private Git repository.
- Automatic Merging: When teammates click "Sync," CtxNest pulls and merges their changes into your local database and filesystem, just like code.
AI Agent Capabilities
The MCP server exposes 42 tools designed for agents that care about context-window economy. Every file-returning response is annotated with est_tokens and size_bytes; list/search responses also inline tags and match_excerpt so a single call usually replaces 3-5.
Reading
| Tool | What it does | Example prompt |
|---|---|---|
read_file |
Full file contents + token estimate. | "Read CtxNest file 42." |
read_files |
Batch read by id (≤200) — symmetric to create_files / delete_files. |
"Read files 12, 15, and 19 in one call." |
read_file_by_path |
Same as read_file but looked up by absolute path — bridges from your shell's cwd. |
"Read /Users/me/notes/auth.md from CtxNest." |
read_file_outline |
Heading-only outline (level, text, line, byte range) — survey before pulling. | "What sections does the deployment doc have?" |
read_section |
Just one heading's body — the rest of the file stays out of context. | "Read the 'Rotation' section of the auth notes." |
read_file_lines |
Line-range slice (1-indexed, clamps out-of-range). Honors stack-trace-style references. | "Read lines 40-60 of the auth note." |
describe_file |
Everything ABOUT a file without pulling its content: tags, size, history depth, related files, backlinks. Replaces 3-4 chained calls. | "Tell me about file 31 without loading it." |
list_files |
Filter by project / tag / folder / favorite / untagged; results carry tags + tokens inline. | "List untagged KB files." |
Writing
| Tool | What it does | Example prompt |
|---|---|---|
create_file, create_files |
Single or batch (≤200) create. | "Save these three migration plans as separate files." |
update_file |
Replace whole file content; auto-commits to git. | "Update the API contract note with these changes." |
update_file_section |
Surgical: replace one heading's body without touching siblings. Same git/FTS path as update_file. |
"Replace the 'Setup' section of the auth note with this." |
delete_file, delete_files |
Single or batch (≤500) delete. KB files are unlinked from disk; project-reference files are only un-indexed. | "Delete files 12, 15, and 18." |
move_file |
Rename / relocate. Validation refuses cross-project / cross-section moves. | "Rename file 7 to archive/auth-2024.md." |
journal_append |
Append a timestamped ## HH:MM:SS entry to today's knowledge/journal/YYYY-MM-DD.md; creates on first call. |
"Add this thought to today's journal: …" |
Search
| Tool | What it does | Example prompt |
|---|---|---|
search |
FTS5 full-text. Returns match_excerpt (16-token window with <<<…>>> markers) and title_highlight so agents see WHERE the match was without re-reading the file. |
"Search for OAuth across all CtxNest." |
bundle_search |
Search + concatenate matches into one prompt-ready blob (XML or Markdown). Stops at max_tokens budget; overflow lands in skipped[]. |
"Bundle the top 5 deployment notes under 30k tokens." |
find_related |
Files sharing tags with a given file, ranked by overlap. Surfaces context the same query wouldn't find. | "Find files related to the auth note." |
regex_search |
Cross-file regex when FTS5's tokenizer misses (URLs, code identifiers, hyphenated terms). Scope by project; max_files / max_matches_per_file bound the cost. |
"Find every mention of oa-data-rmspcockpit-[a-z]+ in the project." |
grep_in_file |
Within-file regex with line numbers — different from FTS5; catches what tokenizer-based search can't. | "Find every fact_* table reference in file 83." |
Tagging & favorites
| Tool | What it does | Example prompt |
|---|---|---|
add_tags, remove_tags, list_tags, set_favorite |
The basics. | "Tag file 22 with infra and 2024-q4." |
suggest_tags |
Proposes tags from your existing corpus by FTS-matching the file's distinctive terms against tagged neighbors. No LLM. | "Suggest tags for file 31." |
tag_search_results |
Run a search, then bulk-apply tags to every match. | "Tag every file matching 'kubernetes' with infra." |
Folders & projects
| Tool | What it does | Example prompt |
|---|---|---|
list_folders, create_folder, delete_folder |
Folder CRUD. delete_folder refuses project folders (the watcher would re-ingest); KB only. |
"Create a journal folder under the KB." |
register_project, list_projects |
Add an external repo as a project; CtxNest indexes its .md files. Warns when total tokens exceed CTXNEST_PROJECT_TOKEN_WARN. |
"Register ~/code/foo as a project." |
project_map |
Single-call indented outline of folders + file titles + tags + ids — typically 5× denser than list_files. |
"Give me a map of the acme project." |
stats |
Counts: files, untagged, favorites, top tags, by-project breakdown. Optional total token cost. | "How many untagged files are in the KB?" |
Versioning & integrity
| Tool | What it does | Example prompt |
|---|---|---|
get_history, get_diff, restore_file |
Per-file git log, unified diff between commits, restore to any commit. | "Diff the auth note between this week and last." |
commit_backup |
Sync a project's reference files to its global-vault backup tree (push to remote if configured). | "Back up the acme project." |
diff_against_disk |
Reports drift between disk content and the FTS index (after external edits / sync merges). Returns in_sync / diverged / disk_unreadable / no_index_row. |
"Did anything change on disk that I missed?" |
refresh_index |
Re-scan the KB (or one project) and reconcile the FTS index — picks up new files, refreshes drifted hashes, prunes vanished rows. The MCP server has no file watcher (the web app does), so this is the explicit fix-up after editor / sync writes. | "Refresh the KB index." |
Discovery
| Tool | What it does | Example prompt |
|---|---|---|
whats_new |
Files created or modified since a checkpoint ("30m", "7d", ISO timestamp). Each entry tagged created/modified. |
"What changed in CtxNest in the last 24h?" |
clip_url |
Fetch + Readability-extract a web page into the KB. Detects auth walls (Confluence, SSO, login pages) and returns AUTH_REQUIRED with a login_url so the agent can retry with headers: { Cookie: … }. |
"Clip https://wiki/confluence/…; if it's gated, ask me for a cookie." |
Quick Start (Docker)
Requires Docker 24+ with the compose plugin — no Node, pnpm, or git clone needed.
Option A — Docker Hub (recommended, zero build)
Pull and run the pre-built image from Docker Hub in a single command:
curl -fsSL https://raw.githubusercontent.com/safiyu/ctxnest/main/docker-compose.hub.yml \
| docker compose -f - up -d
Or download the compose file first and run it directly:
curl -fsSL https://raw.githubusercontent.com/safiyu/ctxnest/main/docker-compose.hub.yml \
-o docker-compose.hub.yml
docker compose -f docker-compose.hub.yml up -d
To pin a specific release instead of latest:
# Edit docker-compose.hub.yml and change:
# image: safiyu/ctxnest:latest
# to:
# image: safiyu/ctxnest:5.1.0
docker compose -f docker-compose.hub.yml up -d
To update to the newest image:
docker compose -f docker-compose.hub.yml pull
docker compose -f docker-compose.hub.yml up -d
Option B — Official Docker Hub Image
The fastest way to run CtxNest in production is using our official Docker Hub image. This is the same image used by the Glama Registry.
docker run -it -v /path/to/data:/app/data safiyu/ctxnest:latest
To use it as an MCP server in your mcpServers.json:
{
"mcpServers": {
"ctxnest": {
"command": "docker",
"args": ["run", "-i", "--rm", "-v", "/path/to/data:/app/data", "safiyu/ctxnest:latest"]
}
}
}
Option C — Build from source
Clone the repo and build the image locally (useful if you want to modify the source):
git clone <repository-url>
cd ctxnest
docker compose up -d --build
To change the WebSocket port, override at build time so the value is baked into the client bundle:
docker compose build --build-arg WS_PORT=4001
WS_PORT=4001 docker compose up -d
Access the UI at http://localhost:3000. Both compose files publish 3001 for the WebSocket file-watcher channel. Data is persisted in ./ctxnest-data on the host. The container is wired with a healthcheck against /api/health (returns {"status":"ok"} once the SQLite handle is open).
To stop and remove:
docker compose -f docker-compose.hub.yml down # keeps ./ctxnest-data (Hub)
docker compose down # keeps ./ctxnest-data (source build)
docker compose down -v # also removes volumes (does NOT delete bind-mounted data dir)
Local Development Setup
Prerequisites
| Tool | Version | Why |
|---|---|---|
| Node.js | 20.x LTS | Required by Next 15 + React 19 |
| pnpm | 9.15.0 (pinned via packageManager) |
Package manager for the workspace |
| git | 2.20+ | Sync engine shells out via simple-git at runtime |
| C/C++ toolchain | platform-specific (see below) | better-sqlite3 builds a native module on install |
Install pnpm (matches the repo's pinned version):
# Option A: corepack (ships with Node)
corepack enable && corepack prepare pnpm@9.15.0 --activate
# Option B: npm
npm install -g pnpm@9.15.0
Install the C/C++ toolchain (only needed for the better-sqlite3 build during pnpm install):
- Debian/Ubuntu:
sudo apt install build-essential python3 - Fedora/RHEL:
sudo dnf install gcc-c++ make python3 - macOS:
xcode-select --install - Windows: Install Visual Studio Build Tools with the "Desktop development with C++" workload
Repository Layout
CtxNest is a pnpm + turbo monorepo:
ctxnest/
├── apps/
│ ├── web/ # Next.js 15 UI (App Router, React 19, Tailwind)
│ └── mcp/ # MCP stdio server for AI agents
├── packages/
│ └── core/ # SQLite/FTS5, git engine, file watcher (ctxnest-core)
├── data/ # default runtime data (SQLite + global git vault + backups)
├── docker-compose.yml # build from source
├── docker-compose.hub.yml # pull from Docker Hub (no build)
├── Dockerfile
├── pnpm-workspace.yaml
└── turbo.json
apps/web and apps/mcp both depend on ctxnest-core via workspace:*. The core package must be built once before either app can resolve its imports — pnpm build handles this automatically via turbo's dependency graph.
Install & First Build
git clone <repository-url>
cd ctxnest
pnpm install # installs every workspace package, builds better-sqlite3
pnpm build # builds ctxnest-core first, then apps/web and apps/mcp
pnpm install may take a few minutes on first run while better-sqlite3 compiles. If you see a build error here, your toolchain is missing — see Prerequisites.
Run in Development
pnpm dev
This starts:
- Next.js dev server on
http://localhost:3000(with Turbopack hot reload) - WebSocket file-watcher on
127.0.0.1:3001(auto-started byinstrumentation.ts)
The default data directory is <repo>/data. SQLite + WAL files, the global git vault, and per-project backup snapshots all land there. Override with CTXNEST_DATA_DIR=/path/to/wherever pnpm dev.
[!IMPORTANT] If you're modifying
packages/corewhile developing, runpnpm -C packages/core devin a second terminal — it'stsc --watchand rebuildsdist/on every save. Next dev loads core frompackages/core/dist/, not from source, so changes won't appear without that watch process.
Verify the Install
With pnpm dev running:
- UI loads: open
http://localhost:3000— the three-pane layout (folder tree / file list / content) renders. - Health endpoint:
curl http://localhost:3000/api/healthreturns{"status":"ok"}. - WebSocket connected: open browser DevTools → Network → WS — a connection to
ws://localhost:3001is open. Footer status bar shows● synced …or● idle(not red).
Run in Production (Standalone, without Docker)
For most users, Docker is the recommended production path (see Quick Start above). The compose file already wires the healthcheck, port mapping, and data persistence.
If you need to run standalone (e.g. behind a reverse proxy on a bare-metal host):
pnpm build
NODE_ENV=production \
CTXNEST_DATA_DIR=/var/lib/ctxnest \
PORT=3000 \
WS_PORT=3001 \
CTXNEST_WS_HOST=127.0.0.1 \
node apps/web/.next/standalone/apps/web/server.js
You must also place apps/web/.next/static/ and apps/web/public/ adjacent to server.js in the standalone tree (the Dockerfile shows the exact layout). Reverse-proxy / to :3000 and the WebSocket path to :3001 if you want network access — leave both on 127.0.0.1 if the proxy is on the same host.
Tests
pnpm test # runs vitest across the workspace (currently: packages/core only)
pnpm -C packages/core test # same, scoped to core
Tests create temporary git repos under packages/core/tests/test-data/ and never touch your real repo or your global git config.
Updating
git pull
pnpm install # in case dependencies changed
pnpm build # rebuild core + apps
If packages/core/src/db/migrations/ gained new .sql files, they run automatically the next time the app boots and acquires the SQLite handle.
Troubleshooting
better-sqlite3fails to build duringpnpm install— install the C/C++ toolchain (see Prerequisites), thenrm -rf node_modules && pnpm install.Cannot find module 'ctxnest-core'when starting the web app — you skipped the build step. Runpnpm -C packages/core build(orpnpm buildfrom the root) once.database is lockedin dev — usually a leftover dev process holding the WAL handle. Stop allpnpm devprocesses; if it persists, removedata/ctxnest.db-shmanddata/ctxnest.db-waland restart. The DB is cached onglobalThisto survive HMR; first launches after a hard kill are the danger zone.- WebSocket not connecting — check that port 3001 is free (
lsof -i :3001/netstat -ano | findstr 3001). The server binds to127.0.0.1by default. If your browser is on a different host, setCTXNEST_WS_HOST=0.0.0.0AND configureCTXNEST_WS_ORIGINS(origin allowlist) and/orCTXNEST_WS_TOKEN+NEXT_PUBLIC_WS_TOKEN(shared secret) — non-loopback connections are rejected by default to avoid leaking file paths on the LAN. See Operations. - Sync fails with "Configured global remote URL is not a valid git remote" — only
https://,http://,ssh://,git://, and scp-form (user@host:path) URLs are accepted.file://and credential helpers are rejected by design. - MCP server returns "Database not initialized" — ensure
CTXNEST_DATA_DIRpoints to the same directory the web UI uses; the MCP server opens its own SQLite handle and reads from$CTXNEST_DATA_DIR/ctxnest.db. - Build succeeds but
/shows a placeholder asking for a tablet — your viewport is below 768px. CtxNest targets tablet+ on the desktop UI; widen the window or open on a larger screen.
MCP Integration
The MCP server is a stdio transport (StdioServerTransport). The host AI tool spawns it as a child process and communicates over stdin/stdout — no network port, no separate process to keep running.
Path & environment:
- Server entry:
apps/mcp/dist/index.js(built bypnpm build). The package also exposes actxnest-mcpbin if youpnpm linkit globally. CTXNEST_DATA_DIR— always set this explicitly. It must be the same directory the web UI uses, otherwise the MCP server reads from a different SQLite database. The default fallback is<cwd>/data, where "cwd" is wherever your AI client launched the process from — that is rarely what you want.CTXNEST_DB_PATH(optional) — defaults to$CTXNEST_DATA_DIR/ctxnest.db.
The web UI and the MCP server can run against the same database simultaneously. SQLite WAL mode handles the concurrent reads, and the MCP server uses the same migration system, so first launch order doesn't matter.
Install via npm (recommended for MCP-only users)
If you only need the MCP server (no web UI), install via npm — no Docker required:
{
"mcpServers": {
"ctxnest": {
"command": "npx",
"args": ["-y", "ctxnest-mcp"],
"env": {
"CTXNEST_DATA_DIR": "/absolute/path/to/your/data"
}
}
}
}
CTXNEST_DATA_DIR must be an absolute path. The directory is created on first run. npx -y ctxnest-mcp downloads the package on first use and caches it; subsequent invocations are instant.
If you also want the web UI, run the Docker image alongside the npx install — both read the same CTXNEST_DATA_DIR:
docker run -d -p 3000:3000 -v /absolute/path/to/your/data:/app/data safiyu/ctxnest:latest
Claude Code
claude mcp add ctxnest -s user \
-e CTXNEST_DATA_DIR=/absolute/path/to/your/data \
-- node /absolute/path/to/apps/mcp/dist/index.js
Note the order: -s and -e are flags to claude mcp add and must appear before the -- separator. Anything after -- is the command + args that Claude Code will spawn.
Manual configuration (mcpServers.json)
For Claude Desktop, Cursor, Continue, Gemini, Antigravity, and other clients that read a JSON config file:
{
"mcpServers": {
"ctxnest": {
"command": "node",
"args": ["/absolute/path/to/apps/mcp/dist/index.js"],
"env": {
"CTXNEST_DATA_DIR": "/absolute/path/to/your/data"
}
}
}
}
Use absolute paths — most clients launch the process from their own working directory.
Configuration Paths:
- Antigravity & Gemini:
~/.gemini/antigravity/mcp_servers.json - Claude Desktop:
~/Library/Application Support/Claude/claude_desktop_config.json(macOS) or%APPDATA%\Claude\claude_desktop_config.json(Windows) - Codex:
.codex/mcp_servers.json - Cursor:
Settings -> Features -> MCP
Docker-based configuration
If CtxNest is running in Docker, the MCP server lives at /app/apps/mcp/dist/index.js inside the container. No env block is needed — CTXNEST_DATA_DIR=/app/data is already set by the compose file.
Same machine (AI client on the same host as the container)
Use docker exec to spawn the MCP process directly:
{
"mcpServers": {
"ctxnest": {
"command": "docker",
"args": ["exec", "-i", "ctxnest", "node", "/app/apps/mcp/dist/index.js"]
}
}
}
-i keeps stdin open (required for the stdio transport). ctxnest is the container_name from the compose file — change it if you renamed the container.
Same machine (AI client on the same host as the container)
Use docker exec to spawn the MCP process directly:
{
"mcpServers": {
"ctxnest": {
"command": "docker",
"args": ["exec", "-i", "ctxnest", "node", "/app/apps/mcp/dist/index.js"]
}
}
}
-i keeps stdin open (required for the stdio transport). ctxnest is the container_name from the compose file — change it if you renamed the container.
Mounting your projects (Required for indexing)
For the Docker-based MCP server to see your local files, you must mount your projects directory in docker-compose.yml:
volumes:
- ./ctxnest-data:/app/data
- /home/user/Projects:/home/user/Projects # Mount your host path to the same container path
[!TIP] To ensure the AI client (running on your host) and the MCP server (running in the container) agree on file paths, it is recommended to mount your host path to the exact same path inside the container (e.g.,
/home/safiyu/Projects:/home/safiyu/Projects).
Tool response shape
Every file-returning tool annotates its response with size_bytes and est_tokens so agents can budget their context window before pulling content. The estimator samples each file's head and uses bytes/4 for ASCII-heavy content (~10% accurate vs BPE) or bytes/3 for multi-byte (CJK/emoji). List-style tools also carry a total_est_tokens summary.
| Tool | Response shape |
|---|---|
read_file, read_file_by_path, create_file, update_file, update_file_section |
{ ...file, size_bytes, est_tokens } |
list_files |
{ files: [{ ...file, tags, size_bytes, est_tokens }], total_est_tokens } |
search |
{ matches: [{ ...file, tags, size_bytes, est_tokens, match_excerpt, title_highlight }], total_est_tokens } — excerpts wrap hits in <<<…>>> markers |
whats_new |
{ since, until, count, total_est_tokens, files: [{ ...file, change: "created"|"modified", tags, size_bytes, est_tokens }] } |
project_map |
{ stats: { files, folders, roots, truncated }, est_tokens, outline } (outline is an indented text string with [id] Title #tag1 #tag2 per leaf) |
register_project |
{ project, discovered_files_count, total_est_tokens, discovered_files: [...annotated], warnings? } (warnings include scan failures and over-budget hints) |
bundle_search |
{ bundle, meta: { query, format, total_est_tokens, included: [{id, path, est_tokens}], skipped: [{..., reason}] } } |
read_file_outline |
{ file_id, path, title, outline: [{ level, text, line, byteStart, byteEnd }] } |
read_section |
{ file_id, path, heading, level, line, content, size_bytes, est_tokens } |
read_file_lines |
{ file_id, path, from, to, total_lines, content, size_bytes, est_tokens } |
read_files |
{ files: [...annotated], total_est_tokens, error_count, errors: [{ id, error }] } |
describe_file |
{ id, path, title, project_id, project_name, folder, storage_type, tags, favorite, size_bytes, est_tokens, history_count, related: [{id, shared_tag_count}], backlinks: [{id, title, path}] } — no content |
grep_in_file |
{ file_id, path, pattern, match_count, truncated, matches: [{line, text}] } |
regex_search |
{ pattern, files_scanned, files_truncated, file_hit_count, total_match_count, hits: [{file_id, path, title, match_count, matches: [{line, text}]}] } |
create_files, delete_files |
{ created|deleted_count, error_count, created|deleted: [...], errors: [{ index|id, error }] } — per-item failures don't abort the batch |
tag_search_results |
{ matched_count, tagged_count, tags_applied, tagged_ids, errors } |
list_folders |
{ folders: string[], base_path } |
move_file |
{ ...file } (post-move record) |
stats |
{ scope, file_count, untagged_count, favorite_count, top_tags: [{name, count}], by_project?, total_est_tokens? } |
suggest_tags |
{ file_id, path, existing_tags: string[], suggestions: [{ tag, score, sources }] } |
diff_against_disk |
{ status: "in_sync" | "diverged" | "disk_unreadable" | "no_index_row", ...sizes, first_diff_line?, disk_sample?, index_sample? } |
refresh_index |
{ scope, newly_indexed, refreshed, pruned } |
journal_append |
{ file_id, path, date, time, appended_chars, est_tokens } |
clip_url (auth-walled) |
isError: true with { code: "AUTH_REQUIRED", auth_required: true, login_url, signal, www_authenticate?, hint } — retry with headers: {"Cookie": "..."} or {"Authorization": "Bearer ..."} |
[!NOTE]
list_filesandsearchpreviously returned bare arrays. Clients that pre-parsed the array directly need to read.files/.matchesinstead.
bundle_search runs a full-text search and returns the matched files concatenated into a single prompt-ready blob — saves an agent the round-trips of search + N × read_file when it needs several related files for context. Inputs mirror search (query, project_id, tags, favorite) plus format ("xml" for Anthropic-recommended <document> tags, "markdown" for ## headers + fenced blocks; default "xml") and max_tokens (budget cap, default 50000). Files are added in rank order and the bundle stops at the first file that would exceed the budget; remaining hits land in meta.skipped[] with their estimated size so the agent can decide whether to re-call with a larger budget.
Configuration
You can customize CtxNest behavior using the following environment variables:
| Variable | Description | Default |
|---|---|---|
CTXNEST_DATA_DIR |
Primary storage for Knowledge Base and Backups | <repo>/data (web), /app/data (Docker) |
CTXNEST_DB_PATH |
Path to the SQLite database | $CTXNEST_DATA_DIR/ctxnest.db |
PORT |
Web UI Port | 3000 |
WS_PORT |
WebSocket Port (server-side bind) | 3001 |
NEXT_PUBLIC_WS_PORT |
WebSocket Port baked into the client bundle (set at build time) | 3001 |
CTXNEST_WS_HOST |
Host the WebSocket server binds to | 127.0.0.1 (0.0.0.0 in Docker) |
CTXNEST_WS_ORIGINS |
Comma-separated allowed Origin headers for browser WS clients (only enforced when bound non-loopback) |
unset (loopback only) |
CTXNEST_WS_TOKEN |
Shared-secret token required as ?token=… on the WS handshake (only enforced when bound non-loopback) |
unset |
NEXT_PUBLIC_WS_TOKEN |
Same token, baked into the client bundle at build time so the browser can supply it | unset |
CTXNEST_PROJECT_TOKEN_WARN |
Soft cap (in estimated tokens) above which register_project and project_map add a warning to their response. Set to 0 to disable. |
100000 |
The WebSocket server defaults to loopback because file paths flowing over it leak the local filesystem layout. When CTXNEST_WS_HOST is set to anything non-loopback (e.g. 0.0.0.0 in Docker), the server rejects every connection by default until you configure either CTXNEST_WS_ORIGINS (Origin allowlist for browsers) and/or CTXNEST_WS_TOKEN (shared secret, also requires NEXT_PUBLIC_WS_TOKEN build arg). The shipped docker-compose.yml wires CTXNEST_WS_ORIGINS=http://localhost:3000,http://127.0.0.1:3000 so the browser on the host machine works out of the box without exposing file paths to the LAN.
Operations
- Health check:
GET /api/health→200 {"status":"ok"}when SQLite responds,503otherwise. - Global git remote: only
https://,http://,ssh://,git://, and scp-form (user@host:path) URLs are accepted.file://and other helpers are rejected. - WebSocket auth: loopback bind = no auth (trusted local). Non-loopback bind requires
CTXNEST_WS_ORIGINSand/orCTXNEST_WS_TOKEN(see Configuration). Without either, all connections are dropped with a1008close code and a startup warning is logged. - Token estimation: the file list and content header show
~Nk tokper file plus per-folder totals. The heuristic samples each file's first 4 KB and switches betweenbytes/4(ASCII-heavy: ~10% accurate) andbytes/3(multi-byte: CJK/emoji, more conservative). MCP tool responses include the sameest_tokensfield plus atotal_est_tokensfor list-style tools so agents can budget their context window before pulling content. - Minimum viewport: the UI targets ≥768px. Below that, a placeholder is shown.
Built with care for the future of agentic coding. License: Apache-2.0
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.