A small, self-hosted tool that helps you build up a library of reusable context — and feed exactly the right slice of it to your AI assistants whenever you start a new task.
You write a context once (your coding conventions, your business background, notes on a tricky API). You attach it to as many projects as you like. Claude — or any MCP-aware tool — reads a lightweight manifest, asks for the contexts it needs, and gets to work already up to speed.
There's a CLI, a web UI (with a usage dashboard), and a built-in MCP server that plugs into Claude Code, Claude Desktop, and anything else that speaks the Model Context Protocol.
Every time you start a new AI conversation, you tell the model the same things: who you are, how you work, what this project is about, which APIs you care about. That's wasted effort, and it scales poorly the moment you have more than one project.
context-window gives you one place to:
- Capture durable knowledge as named, described, tagged contexts (Markdown).
- Curate which contexts apply to which project — without copy-pasting.
- Expose a single, lightweight manifest to LLMs so they can self-serve the bodies they actually need.
- See which contexts and tools are actually being used, by which client.
Everything runs locally on your machine. Your knowledge stays yours.
The web dashboard shows every MCP, CLI, and web call recorded over a configurable window — broken down by tool, project, context, and the actual LLM client (Claude, GPT, browser, CLI) that made the call.
- Two clean entities. Contexts are standalone, reusable, versioned bodies of knowledge. Projects are ordered references to contexts plus a manifest file LLMs can read.
- Local-first. SQLite + FTS5 search. No accounts, no cloud, no API keys, no network calls (unless you wire your own MCP client to it).
- MCP server. 16 tools:
get_project_summary,get_context,search_contexts,create_context,attach_context,get_context_budget,get_usage_stats, and more. - CLI. Manage contexts and projects from your shell. Idempotent project init that scaffolds a
CLAUDE.mddirective so Claude actually uses the tools. - Web UI. Browse, search, create, edit, archive, and attach contexts. Reorder attached contexts on a project. View a live usage dashboard.
- Usage analytics. Every MCP / CLI / web call is recorded with the calling client's name + version. Time-series, top tools, top contexts, error rates.
- Auto-maintained manifests. Update a context that's attached to three projects — all three manifests rewrite themselves.
- Token budgeting. Ask for the highest-priority subset of contexts that fits a given token budget; everything excluded is reported with a reason.
You need Node ≥ 20.
git clone https://github.com/prodevuk/context-window.git
cd context-window
npm install
npm run build
npm install -g . # puts `context` and `context-mcp` on your PATHcd /path/to/any/project
context project init -n my-project # creates the project + a CLAUDE.md directive
context new \
-n "Rust Conventions" \
-d "How we write Rust in this codebase" \
--content-file ./RUST_STYLE.md \
--category conventions \
--tags rust,backend \
--priority important
context project attach <context-id> # link it to the current projectThat's it. The project's .context/manifest.json is now up to date, and any MCP client pointed at the server will see your context.
context web --port 5173
# → http://127.0.0.1:5173claude mcp add context-window --scope user context-mcpNo --project-id is needed — the server auto-detects the active project from the nearest .context/manifest.json walking up from your working directory.
Restart Claude Code, and the tools light up.
id uuid
name "Rust Conventions"
description "How we write Rust in this codebase" ← what LLMs read first
category "conventions"
content "# Rust Conventions\n..." ← the actual body, in Markdown
tags ["rust", "backend"]
priority "important" ← critical / important / reference / archived
visibility "private" ← private / shared / public
version 3 ← bumped on every update
token_count 1240 ← pre-computed; trust it for budgeting
A context exists on its own. It is not owned by any project. You can attach the same context to many projects.
A project has a name, a description, an optional root directory, and an ordered list of context references. Each reference can override the context's default priority for that project specifically.
Each project owns a .context/manifest.json that contains:
- the project's name and description,
- how to talk to the MCP server,
- one entry per attached context (id, name, description, category, priority, token count — not the content),
- the total token count of everything attached,
- a short instruction block telling the LLM how to use the available tools.
It's deliberately small so the LLM can read it on every session start without burning a serious slice of its context window.
The body of each context is fetched on demand via get_context.
| Command | What it does |
|---|---|
context init |
Create / upgrade the local database |
context new |
Create a new context (-n, -d, --content or --content-file, plus optional --category, --tags, --priority, --visibility) |
context list |
List contexts with filters |
context search <query> |
Full-text search (FTS5) |
context show <id|prefix> |
Display a context's full content |
context edit <id|prefix> |
Edit content in $EDITOR |
context archive <id|prefix> |
Hide a context from manifests + search |
context delete <id|prefix> --yes |
Permanently delete (rare; prefer archive) |
context export / context import |
Bulk JSON in/out |
context stats |
Usage stats with --scope, --tool, --context, --days |
context web |
Start the web UI |
context serve |
Run the stdio MCP server for the current project |
context setup |
Add a global Claude directive to ~/.claude/CLAUDE.md |
| Command | What it does |
|---|---|
context project init |
Create a project for the current directory, write the manifest, scaffold a CLAUDE.md directive |
context project list |
List all projects |
context project attach <ctx-id> |
Attach a context (idempotent upsert, optional --position, --priority) |
context project detach <ctx-id> |
Detach (the context itself is preserved) |
context project contexts |
List contexts attached to the current project |
context project manifest |
Regenerate the manifest |
context project budget --budget N |
Show which contexts fit a token budget |
context project reorder --ids id1,id2,id3 |
Re-order attached contexts |
The active project is resolved as: --project <id> flag → CONTEXT_PROJECT_ID env → nearest .context/manifest.json walking up from your cwd.
context web (default port 5173) serves an Express app over HTTP on 127.0.0.1. No login, single user, single machine.
You can:
- Browse, search, view, create, edit, archive, and delete contexts.
- Create and view projects, attach / detach / reorder contexts, override priorities per project.
- See usage stats per context and per project (panel at the bottom of each detail page).
- See the /dashboard — five summary cards, an activity-over-time area chart, and bar charts for top tools, top contexts, top projects, and top clients (i.e. which LLM made the call).
The UI is server-rendered HTML with no client-side JavaScript framework. Charts are inline SVG / CSS.
The MCP server is a stdio binary, context-mcp, that any MCP-aware client can talk to. It exposes 16 tools:
Reading the project
get_project_summary— the manifest, freshly built. Call this first.get_context— full content for one context id.get_contexts_by_category— filter the attached set by category.list_all_contexts— every context in the library, regardless of project.search_contexts— FTS5 search;scope: "project"(default) or"all".get_context_budget— highest-priority subset that fits a given token budget.
Writing
create_context,update_context(with optionalexpected_versionfor optimistic locking)archive_context,delete_context(requiresconfirm: true)attach_context,detach_context,reorder_contextscreate_category
Maintenance
regenerate_manifestget_usage_stats(scope: project / context / tool / overview)
Project resolution order:
--project-id <uuid>flagCONTEXT_PROJECT_IDenv varproject_idof the nearest.context/manifest.jsonwalking up from the working directory
Without an active project, only the library-wide tools work (list_all_contexts, get_context, create_context, search_contexts with scope: "all").
Claude Code — registers globally so it auto-detects the right project per repo:
claude mcp add context-window --scope user context-mcpClaude Desktop (claude_desktop_config.json) — Desktop doesn't inherit your shell PATH, so use the absolute path that which context-mcp prints:
{
"mcpServers": {
"context-window": {
"command": "/Users/you/.nvm/versions/node/v22.7.0/bin/context-mcp"
}
}
}By default Claude reads tool descriptions but doesn't proactively call tools. context project init writes (or appends to) a CLAUDE.md file in the project root that tells Claude to call get_project_summary at the start of every task. There's also a context setup command that adds a one-liner to ~/.claude/CLAUDE.md so Claude picks up the tool whenever it sees a .context/manifest.json in any project.
src/
├── core/ Business logic, storage-agnostic
├── storage/ Repository interface + SQLite implementation
├── mcp/ Stdio MCP server
├── cli/ commander-based CLI
├── web/ Express HTTP UI + dashboard
└── config/ Path resolution
Key invariants (these are what the test suite enforces):
- The manifest on disk is derived state — regenerated automatically on every mutation to attached contexts or attachments.
- Contexts with
status !== "active"are excluded from manifests, budgets, and search. - Positions in
project_contextsare normalised to0..n-1after any mutation. - Token counts are computed on write, never on read.
- Storage is transport-agnostic; core is UI-agnostic. Throw
DomainErrorsubclasses; transport layers format them.
A cloud mode (Postgres backend + HTTP transport + multi-tenant auth) is intentionally not implemented. The Repository interface is the seam if you want to add one.
npm run typecheck # strict tsc, no emit
npm run build
node --test tests/services.test.mjs \
tests/usage.test.mjs # 10 unit tests over the service layer
node tests/smoke.mjs # 27 end-to-end checks spawning the built CLI + stdio MCP
node tests/web-smoke.mjs # 30 HTTP checks against every web routeAll three suites must pass in CI before any change is merged.
| Variable | Default | Effect |
|---|---|---|
CONTEXT_DB_PATH |
~/.context-db/context.db |
SQLite file location |
CONTEXT_PROJECT_ID |
(none) | Pin a specific project for the MCP server |
CONTEXT_WEB_DEBUG |
(unset) | Log full stack traces from the web UI |
If you're an LLM working with the context-window MCP server, here's how to use it well.
- Start with
get_project_summary. It returns enough metadata to decide what to load. - Stay under your budget.
get_context_budgetreturns the highest-priority subset that fits. - Search before asking.
search_contextswithscope: "all"will tell you whether something is already captured before you re-ask the user. - Capture what you learn. When the user explains something the next session will need, call
create_contextwith a clear name + description andcreated_by: "llm:<model>".attach_contextif it's project-specific. - Be conservative with destructive ops. Prefer
archive_contextoverdelete_context. Useexpected_versiononupdate_contextto detect conflicts.
The tool descriptions are intentionally specific. Read them.
Contributions are welcome. The project is small enough that a typical change touches one or two files plus a test.
git clone https://github.com/prodevuk/context-window.git
cd context-window
npm install
npm run build
npm run typecheck
node --test tests/services.test.mjs tests/usage.test.mjs
node tests/smoke.mjs
node tests/web-smoke.mjsUse npm link from the project root if you want the global context / context-mcp binaries to follow your local dist/ (avoids re-installing after every build).
| You want to… | Open |
|---|---|
| Add an MCP tool | src/mcp/tools.ts — the tool is auto-listed via ListToolsRequestSchema, no extra wiring |
| Add a CLI command | src/cli/context-commands.ts or src/cli/project-commands.ts |
| Add a web route | src/web/server.ts (and src/web/views.ts for HTML) |
| Add a field to Context / Project | src/core/types.ts → src/storage/sqlite/schema.ts → row mapping in src/storage/sqlite/sqlite-repository.ts |
| Change manifest shape | src/core/manifest-service.ts#build and the Manifest schema in types.ts |
npm run typecheckis clean.- All three test suites pass (
services+usageunit,smoke,web-smoke). - A new tool, CLI command, web route, or invariant has at least one matching assertion in
tests/. - User-facing strings (CLI output, MCP tool descriptions, web UI labels, error messages) are in British English.
- No new layer / abstraction unless an existing service genuinely cannot accommodate the change.
- Commits are scoped and tell the why, not just the what.
- Use GitHub Issues for bug reports and feature ideas.
- For larger proposals (new transports, new entity types, schema migrations), open a discussion first so we can agree on the shape before code lands.
Be kind. Be specific. Assume good faith. We'll add a formal CoC if the project grows beyond a handful of contributors.
MIT © 2026 Prodevel Ltd.

