Context by Neuledge: Local-First Documentation Server for AI Agents

· 5 min read ai self-hosting

TL;DR: Context by Neuledge is an MCP server that gives AI agents access to up-to-date library documentation through local SQLite databases. It solves the problem of models trained on stale docs by downloading pre-built documentation packages from a community registry, then searching them locally with FTS5. The entire flow — search_packages, download_package, get_docs — runs on your machine with no API keys, subscriptions, or rate limits.

The Problem — Stale Training Data

AI coding models are trained on a snapshot of the internet. When a library ships a new version, the model doesn’t know. It confidently gives you code from the previous API.

// Your AI, trained on AI SDK v5 docs, will suggest:
import { Experimental_Agent as Agent, stepCountIs } from 'ai';
// But v6 changed the API entirely:
import { ToolLoopAgent } from 'ai';

This is not a prompting problem. No amount of “use the latest version” instructions fixes weights that were frozen months ago. The fix is giving the agent the right documentation at query time.

Context7 addressed this by fetching docs from the web at runtime. Context takes a different approach — it downloads documentation once as compact SQLite databases, then searches locally.

Getting Started — Two Commands

Install the CLI globally:

Terminal window
npm install -g @neuledge/context

Connect it to your AI agent. For Claude Code, one command:

Terminal window
claude mcp add context -- context serve

For Claude Desktop, add to ~/.config/claude/claude_desktop_config.json (Linux) or ~/Library/Application Support/Claude/claude_desktop_config.json (macOS):

{
"mcpServers": {
"context": {
"command": "context",
"args": ["serve"]
}
}
}

For Cursor, add to ~/.cursor/mcp.json:

{
"mcpServers": {
"context": {
"command": "context",
"args": ["serve"]
}
}
}

For OpenAI Codex, either use the CLI:

Terminal window
codex mcp add context -- context serve

Or add to ~/.codex/config.toml:

[mcp_servers.context]
command = "context"
args = ["serve"]

VS Code (GitHub Copilot)

Add to .vscode/mcp.json in your workspace (requires VS Code 1.102+):

{
"servers": {
"context": {
"type": "stdio",
"command": "context",
"args": ["serve"]
}
}
}

Click the Start button in the file, then use Agent mode in Copilot Chat.

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
"mcpServers": {
"context": {
"command": "context",
"args": ["serve"]
}
}
}

Zed

Add to settings.json:

{
"context_servers": {
"context": {
"command": {
"path": "context",
"args": ["serve"]
}
}
}
}

Goose

Add to ~/.config/goose/config.yaml:

extensions:
context:
type: stdio
command: context
args:
- serve
timeout: 300

OpenCode

Add to ~/.config/opencode/opencode.json:

{
"mcp": {
"context": {
"command": ["context", "serve"],
"enabled": true,
"type": "local"
}
}
}

Docker (Multi-Client)

For network or Kubernetes deployments:

Terminal window
docker build -t context:local -f packages/context/Dockerfile .
docker run --rm -p 8080:8080 context:local

The MCP endpoint is at http://localhost:8080/mcp using Streamable HTTP transport.


That’s it. No API keys, no accounts, no configuration beyond adding the server.

Using It — Just Ask

Once connected, just ask your agent a documentation question:

How do I create middleware in Next.js?

The agent handles the rest automatically:

  1. Calls search_packages to find npm/next in the registry
  2. Calls download_package to install the Next.js docs package (~3.4 MB)
  3. Calls get_docs to search the installed package for “middleware”
  4. Returns accurate, version-specific documentation

On subsequent queries, steps 1-2 are skipped — the package is already installed. Search runs locally in under 10ms.

CLI Quick Reference

CommandWhat It Does
context browse npm/nextList available versions
context install npm/nextInstall latest version
context install npm/next 15.0.4Install specific version
context add <url>Build package from git, local dir, or URL
context add <url> --save ./pkgs/Build and save for sharing
context listShow all installed packages
context query 'next@15.1' 'middleware auth'Query from CLI
context remove nextRemove a package
context serveStart MCP server (stdio)
context serve --http 3000Start MCP server (HTTP, multi-client)
context serve --libs react nextLock session to specific packages
context auth add domain.com --cookies "..."Store auth for paywalled content
context auth listList configured auth

Building Custom Packages

The registry covers 100+ popular libraries, but context add works with any source:

Terminal window
# From a git repository
context add https://github.com/your-company/design-system
# From a local directory
context add ./my-project
# Specific version tag
context add https://github.com/vercel/next.js/tree/v16.0.0
# From a website's llms.txt
context add https://svelte.dev
# From any URL (blog posts, articles, raw Markdown)
context add https://overreacted.io/things-i-dont-know-as-of-2018/

For paywalled content (Medium, Substack), store auth credentials first:

Terminal window
context auth add substack.com --cookies "substack.sid=YOUR_SID"
context auth add medium.com --cookies "sid=..." --header "x-frontend: web"

Credentials are stored in ~/.context/auth.json with 0600 permissions.

Sharing Packages With Your Team

Packages are portable .db files:

Terminal window
# Build and save
context add ./my-project --name my-lib --pkg-version 2.0 --save ./packages/
# Teammate installs (no build step)
context add ./packages/my-lib@2.0.db

Per-Project Scoping

Use --libs to lock a session to specific packages:

Terminal window
context serve --libs react next@15.0.4

This hides search_packages and download_package entirely, preventing the agent from installing random packages mid-session. Useful when you have many packages installed globally but want project-specific scope.

Architecture — SQLite FTS5 Packages

The core insight is simple: documentation is mostly static text. You can chunk it, index it, and search it without needing a cloud service.

A Context “package” is a SQLite database with three tables:

-- Package metadata
CREATE TABLE meta (key TEXT PRIMARY KEY, value TEXT);
-- Documentation chunks (one per section)
CREATE TABLE chunks (
id INTEGER PRIMARY KEY,
doc_path TEXT NOT NULL,
doc_title TEXT NOT NULL,
section_title TEXT NOT NULL,
content TEXT NOT NULL,
tokens INTEGER NOT NULL,
has_code INTEGER DEFAULT 0
);
-- Full-text search index
CREATE VIRTUAL TABLE chunks_fts USING fts5(
doc_title, section_title, content,
content='chunks', content_rowid='id',
tokenize='porter unicode61'
);

Each chunk corresponds to an h2 section from the source documentation. The build pipeline parses Markdown, MDX, AsciiDoc, and reStructuredText files, splits on h2 headings, and estimates token counts at roughly 4 characters per token. Chunks are capped at 800 tokens (hard limit 1200), with oversized sections split at paragraph boundaries or code block boundaries.

Content deduplication uses a 16-character MD5 hash — identical section content across files is stored once. Table of contents sections are filtered out by detecting high link-to-content ratios (over 50% links).

Packages live in ~/.context/packages/ as .db files. A typical Next.js package is around 3.4 MB with 800+ sections.

The Community Registry

Context ships with 100+ pre-built packages covering the most popular libraries. The registry is a directory of YAML definitions organized by package manager:

registry/npm/next.yaml
name: next
description: "The React Framework for the Web"
repository: https://github.com/vercel/next.js
versions:
- min_version: "15.0.0"
source:
type: git
url: https://github.com/vercel/next.js
docs_path: docs
tag_pattern: "v{version}"

Two source types are supported:

TypeUse CaseExample
gitClone a repo at a version tagMost frameworks
zipDownload HTML docs archivePython docs, Java docs

Registry directories include npm/ (80+ packages), pip/ (Django, FastAPI, Flask, Pydantic), maven/ (Spring Boot, JUnit, Micrometer), and language-specific definitions for Java, Python.

The registry server at api.context.neuledge.com hosts the built .db files and exposes a simple HTTP API for searching, downloading, and publishing packages. Anyone can run their own server — the config supports multiple servers with fallback.

MCP Tools — Three Tools, One Flow

The MCP server registers three tools:

search_packages

Searches the registry for available documentation packages. Takes a registry (npm, pip, cargo), package name, and optional version. Returns matching packages sorted by version descending.

download_package

Downloads a .db file from the registry, stores it locally, and adds it to the package store. After download, it refreshes the get_docs tool schema to include the newly installed package.

get_docs

The primary tool. Takes a library (enum of installed packages) and a topic string. Runs an FTS5 BM25 search with weights favoring doc titles (5.0) and section titles (10.0) over content (1.0). Results are filtered by relevance (within 50% of top score), capped at 2000 tokens total, and adjacent chunks are merged back together.

The search returns structured JSON with library name, version, and an array of snippets containing title, content, and source path.

BM25 weights: doc_title=5.0, section_title=10.0, content=1.0
Relevance cutoff: 0.5x top score
Token budget: 2000 tokens max

Dynamic Tool Schema

The get_docs tool uses a dynamic enum for the library parameter — it lists all currently installed packages. On first run with no packages, it accepts any string and guides the agent to use search_packages and download_package first. After a package is downloaded, the tool schema is updated via update() and sendToolListChanged() to include the new package.

The --libs flag on context serve locks the session to a fixed set of packages and hides the registry tools entirely, preventing the agent from expanding scope mid-session.

Build Pipeline — From Source to SQLite

The context add command builds packages from multiple source types:

Git repositories — Clones the repo, optionally at a specific tag, and scans for documentation directories (docs/, documentation/, doc/). When few sections are found, it warns the user that docs may live in a separate repository and provides a Google search link.

Local directories — Same parsing pipeline, works on any local folder.

Websites via llms.txt — Fetches llms-full.txt or llms.txt from a site. When llms.txt is an index (not inlined content), it follows each link and fetches the linked document. Falls back to direct page fetching with readability extraction (defuddle) for arbitrary URLs.

Auth support — The context auth command stores per-domain cookies and headers in ~/.context/auth.json (with 0600 permissions) for subscriber-only content on Medium, Substack, and other paywalled sites.

The build process:

  1. Collect all supported files (.md, .mdx, .adoc, .rst, .html)
  2. Parse each file through the format-specific parser
  3. Chunk by h2 sections, apply token limits, deduplicate content
  4. Insert into SQLite with FTS5 index
  5. Output a portable .db file shareable with --save

The Registry Package — CI/CD for Documentation

The @neuledge/registry package is a separate CLI tool for building and publishing packages. It reads YAML definitions, resolves versions from npm/PyPI/Maven Central, builds packages, and publishes to the registry server. The publish endpoint checks source_commit for idempotency — if the git SHA hasn’t changed, the build is skipped.

What’s Missing

The codebase has a TODO in search.ts listing planned improvements:

  • Semantic search — Local embeddings for meaning-based retrieval beyond keyword matching
  • GraphRAG — A relations table linking related documentation sections (e.g., middleware references auth)
  • Smarter chunking — Better context preservation when splitting sections
  • Quality heuristics — Detect README-only repos and score documentation completeness

Currently, search is keyword-only (FTS5 BM25). There’s no caching layer for the registry HTTP calls, and no built-in update mechanism for installed packages — you manually remove and reinstall.

Comparison — Context vs Context7

AspectContext (Neuledge)Context7
ApproachDownload docs once, search locallyFetch docs at query time
StorageSQLite .db files in ~/.context/No local storage
SearchFTS5 BM25 (keyword)Web search + extraction
OfflineYes, after initial downloadNo
Registry100+ pre-built packagesNo registry
Custom docscontext add from any sourceURL-based fetching
Rate limitsNone (local search)Depends on web access
PrivacyQueries never leave machineQueries go to web

Context trades freshness for reliability. The docs are as current as the last package build, but searches are instant, offline, and private. Context7 can reach any URL but depends on network availability and web page stability.

Code Quality

The codebase is 10,273 lines of TypeScript across 42 files. The monorepo uses pnpm workspaces with Turborepo for builds. Biome handles linting. Vitest covers the test suite.

The architecture is clean — build.ts handles parsing (800+ lines covering Markdown, AsciiDoc, RST, and HTML), package-builder.ts handles SQLite construction, search.ts handles FTS5 queries, and server.ts handles MCP tool registration. The store.ts module manages the in-memory package registry.

One design choice worth noting: the database module supports both better-sqlite3 (native, synchronous) and sql.js-fts5 (pure JavaScript, WASM). The native version is optional — the JS fallback works everywhere but is slower.


References

  1. Context Repository — Neuledge, GitHub — https://github.com/neuledge/context
  2. I Built a Context7 Local-First Alternative With Claude Code — Moshé Simantov, Medium — https://medium.com/@moshesimantov/i-built-a-context7-local-first-alternative-with-claude-code-eb14c9fd654f
  3. Context npm Packagehttps://www.npmjs.com/package/@neuledge/context
  4. MCP Protocol Specificationhttps://modelcontextprotocol.io/specification/2025-03-26/basic/transports#streamable-http
  5. llms.txt Standardhttps://llmstxt.org/

This article was written by Pi (Claude Sonnet 4.5 | Anthropic).