ContextPull

io.github.mi2arunPublished by GitHub account mi2arunv0.2.1Updated Nov 3, 2026

Exact document sections on demand for LLM agents: index in context, search, read, grep, neighbours.

VerifiedSTDIODesktop onlyFiles & StorageKnowledge & Memory

Overview

AI-generated overview

Turns a folder of documents into a local SQLite index with five tools so an assistant can pull exact sections on demand instead of receiving pushed context.

What you can do
  • Show a token-budgeted table of contents of the corpus, hierarchical when it is large
  • Search sections and get ids and snippets, never full bodies
  • Read a section verbatim by its stable id such as path.md#3
  • Grep for exact matches, keeping identifiers whole
  • Fetch neighbouring sections, such as a table header row or the next clause
  • Ingest Markdown, text, docx, xlsx, pptx and optionally PDF into heading-aware sections
When to use it
Useful when an assistant needs to answer questions over a local folder of documents and you want it to read only the sections it asks for, with citations, rather than loading whole files. It suits offline, single-machine setups and read-only shared deployments.
Requirements
Runs as a local stdio process, installed from PyPI with uvx or pip, or from npm with npx for the TypeScript reader. Documents must first be ingested into a SQLite store file. Optional extras: a PDF extra for PDFs, an embedding model for hybrid search, and a summarizer model for one-line index summaries. No authentication is declared.
Before you install
The server writes a store file inside the ingested folder. Optional summarizer and embedding options send document content to an external model provider. Pull-style retrieval can cost tens of thousands of tokens per query, and the README reports weaker results for small models without reasoning.

Installation

In SourceWeft

  1. Open ContextPull in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

ContextPull

Website: https://mi2arun.github.io/contextpull/ · demo · docs · MCP Registry io.github.mi2arun/contextpull

Pull, don't push. ContextPull turns a folder of documents into something an LLM agent can pull from the way Claude Code pulls from a codebase: a small index that is always in context, and five tools that return exact sections on demand. The model never receives content it did not ask for.

Zero runtime dependencies. One SQLite file. Works offline.

ContextPull ships with a companion, ragbisect (formerly stagewise): a neutral benchmark harness that builds an eval set from your corpus and scores ContextPull next to bm25, dense and hybrid pipelines. Two names, one project, kept apart so the measurement stays independent of the thing it measures.

Status

M1 to M3 are built: store, ingest, the five operations, CLI, conformance suite, MCP server, Claude Code integration, LLM summaries, protocol client examples, ragbisect adapters, and a TypeScript reader and server. See the roadmap.

Measured

uv documentation, 603 sections, 221 self-generated questions, recall@5, from docs/testing.md:

configrecall@5ms/qmodel tokens/q
hybrid push (dense + bm25)0.964690
bm25 push0.92350
pull, Claude Code (10-question sample)1.00026,56586,656
pull, gpt-5.4-mini with reasoning off0.61516,02310,891

A strong agent reads the right section every time; a small no-reasoning model reads the right section when it reads (NDCG 0.96 given a hit) but misses the gold section on 38% of questions. Push retrieval is nearly free per query; pull costs tens of thousands of tokens. Both facts are in the table on purpose. The model's own searches surfaced the gold section on 88% of a sample, so most of the gap is snippets being answered from rather than read; a stricter prompt did not change that. An earlier version of this table showed 0.045 for the small model; that number came from a threading bug in the benchmark adapter and is retracted in docs/testing.md.

Try it

Fastest: ./scripts/demo.sh ingests the bundled fixture corpus and walks through index, search, read and grep, then prints the exact claude mcp add line. ./scripts/demo.sh ./your-docs does the same on your own folder.

sh
uv tool install contextpull            # or: pip install contextpull   (PyPI: contextpull 0.2.0)contextpull ingest ./docs              # writes .contextpull/store.sqlitecontextpull index                      # the always-in-context table of contentscontextpull search "refund window" --in policy-2025.mdcontextpull read policy-2025.md#3 --context 1contextpull grep TX-4419contextpull neighbours specs.md#1contextpull export-chunks > chunks.jsonl   # ragbisect-compatible sections

In Claude Code

sh
claude mcp add contextpull -- uvx --from "contextpull[mcp]" contextpull serve ./docs

The server ingests ./docs into ./docs/.contextpull/store.sqlite, puts the index into its instructions so it is always in context, and exposes the five tools. Ask a question; the trace shows search, then read, then an answer with [path.md#3] citations. contextpull claude-md prints a CLAUDE.md snippet if you want to tell the model about it explicitly. Add --summarizer openai:gpt-5.4-mini for model-written one-line summaries in the index (cached by document hash).

Any other MCP host works the same way; see examples/clients/ for TypeScript, Go and Java protocol clients and examples/direct_api_loop.py for using the tools straight from a model API with no server.

More

sh
uv sync --extra pdf                                             # PDFs: headings inferred from font sizeuv run contextpull ingest ./docs --embed-model openai:text-embedding-3-small   # enables: search --mode hybriduv run contextpull serve ./docs --transport http --port 8765    # streamable HTTP at /mcp for a shared read-only server

As a library

Embedding it in your own product, with access control and air-gap notes: docs/embedding.md and examples/embed_with_acl.py.

python
from contextpull import Store, Ops
with Store.open(".contextpull/store.sqlite") as store:    ops = Ops(store)    print(ops.index())    hits = ops.search("refund window", in_=["policy-2024.md", "policy-2025.md"]).hits    for h in hits:        print(h.id, h.heading_path, h.snippet)    section = ops.read(hits[0].id).section

Tool definitions for any model API are in contextpull.tools.TOOLS (Anthropic shape) and openai_tools(); tools.json at the repo root is the same thing for other languages.

How it works

  1. Ingest parses Markdown, text, docx, xlsx, pptx and (with the pdf extra) PDF into headings, paragraphs, tables and code, and cuts heading-aware sections with stable ids like policy-2025.md#3. Tables and code are never split mid-block; long tables are split by rows and every part carries the header. Unchanged files are skipped on re-ingest.
  2. Store is one SQLite file with an FTS5 index whose tokenizer keeps identifiers whole (--no-cache, UV_CACHE_DIR, TX-4419, 3.12).
  3. Index is a token-budgeted table of contents, one line per document, delivered into the model's context. It goes hierarchical when a corpus is too large for the budget.
  4. Tools: index, search (ids and snippets, never bodies), read (verbatim), grep (exact matches), neighbours (the header row, the next clause).

Node

sdk/typescript/ is a store-native reader and MCP server in TypeScript over better-sqlite3: open the same store file, no Python at query time. Published to npm as contextpull.

sh
npx contextpull serve /path/store.sqlite                   # npm: contextpull 0.1.0claude mcp add contextpull -- npx -y contextpull serve /path/store.sqlite

It passes the same conformance suite as the Python reference and returns identical results over MCP. Ingest stays in Python (npx contextpull ingest delegates to uvx contextpull ingest).

Go

sdk/go/ is a store-native reader and a single static binary server, pure Go, no cgo: the shape for a shared read-only deployment.

sh
cd sdk/go && go build -o contextpull-server ./cmd/contextpull-server./contextpull-server serve /data/store.sqlite --http 0.0.0.0:8765    # or without --http for stdio

Same conformance suite, identical results to Python over MCP.

Other languages

The store file is the contract. docs/store-format.md says what a reader must do; conformance/ holds a fixture corpus, its store and expected results. An SDK in any language is done when check passes. See the SDK plan.

Docs

Start at docs/README.md: architecture, design, system design, tool reference, evaluation, roadmap, decision records.

Measured with ragbisect, which lives next door.

Source: README.md at commit d544b83

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v0.2.1LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts