Skip to main content

context-server

context-server

CI PyPI

Semantic search over a folder of markdown, served as an MCP server for coding agents.

Index once into a SQLite DB (embeddings + BM25). Point Claude Code, Cursor, or any MCP client at serve, and the agent can search that corpus instead of guessing from memory.

One Rust binary. ONNX Runtime is linked in via ort / fastembed — no separate libonnxruntime to ship. SQLite is bundled.

Quick start

pip install context-server
# or: uvx context-server@latest …

context-server index --input ./docs --db context.db
context-server search --db context.db "how do we handle backports"
context-server serve --db context.db

Wheels: Linux x86_64/aarch64 (manylinux_2_39 / glibc 2.39+, e.g. Ubuntu 24.04+) and macOS Apple Silicon.

The first embedding run downloads BGE-small-en-v1.5 into $XDG_CACHE_HOME/context-server/fastembed/ (or ~/.cache/...; once, tens of MB). Override with FASTEMBED_CACHE_DIR or HF_HOME.

Optional: tell the agent when to use this corpus

context-server index --input ./docs --db context.db \
  --instructions-file ./mcp-instructions.txt
# or: --instructions 'Use semantic_search for questions about …'

That text is stored in the DB and exposed as MCP ServerInfo.instructions when you serve.

Claude Code

claude mcp add --transport stdio --scope user context-server \
  -- uvx --refresh context-server@latest \
  serve --db /absolute/path/to/context.db

--refresh + @latest rechecks PyPI on each start. If Claude rarely surfaces the tools, set "alwaysLoad": true on the server entry in your Claude MCP config.

Cursor

~/.cursor/mcp.json (or project .cursor/mcp.json):

{
  "mcpServers": {
    "context-server": {
      "command": "uvx",
      "args": [
        "--refresh",
        "context-server@latest",
        "serve",
        "--db",
        "/absolute/path/to/context.db"
      ]
    }
  }
}

Reload MCP after editing. Re-index when content changes, then restart the MCP session so serve reloads the DB.

What it indexes

Only .md / .markdown. Chunks on # / ## / ###, keeps the heading path on each chunk, and splits long sections with overlap.

Convert structured sources (YAML, etc.) to prose before indexing. Fenced YAML searches poorly; a short paragraph that keeps names, roles, and relationships together works much better.

Try the sample set:

cargo build --release
./target/release/context-server index --input examples/sample-docs --dry-run
./target/release/context-server index --input examples/sample-docs --db /tmp/sample.db
./target/release/context-server search --db /tmp/sample.db "password reset"

Default mode is hybrid: dense cosine (BGE-small-en-v1.5) plus BM25, fused with reciprocal rank fusion. Dense catches paraphrase; BM25 catches exact tokens (usernames, acronyms, IDs).

context-server search --db context.db --mode hybrid "query"   # default
context-server search --db context.db --mode dense "query"
context-server search --db context.db --mode lexical "query"

# Scope to a subtree / heading / metadata tag
context-server search --db context.db --path-prefix teams/ "who owns storage"
context-server search --db context.db --heading Backport "z-stream"
context-server get --db context.db --path teams/storage.md --chunk 0

MCP tools

Tool Role
semantic_search Ranked passages + scores; optional path_prefix / heading / tag filters
list_documents Indexed chunks; optional path_prefix
get_document Full chunk by citation (source_path + chunk_index), or all chunks for a path

Search hits cite chunks as source_path#chunk_index. Call get_document to pull the full text for quoting.

Remote database (GCS)

serve and search accept a gs:// URI. The object is cached under $XDG_CACHE_HOME/context-server/dbs/ (or ~/.cache/...). index still writes a local path only.

context-server serve --db 'gs://my-bucket/latest/context.db'

# Project-qualified form also works (gs:// required; stripped for the Storage API)
context-server serve --db \
  'gs://projects/my-gcp-project/buckets/my-bucket/objects/latest/context.db'

Uses Application Default Credentials. If a sibling {object}.sha256 exists (sha256sum format), a matching local cache is reused; otherwise the DB is re-fetched and verified.

CLI

context-server index  --input <path> [--db FILE] [--dry-run] [--batch N]
                      [--full] [--sync]
                      [--instructions TEXT | --instructions-file FILE]
context-server serve  --db <local path | gs://…>
context-server search --db <local path | gs://…> [--limit N] [--mode hybrid|dense|lexical]
                      [--path-prefix P] [--heading H] [--tag T] <query>
context-server get    --db <local path | gs://…> --path FILE [--chunk N]
context-server embed  <query>         # smoke-test query embedding (BGE instruction)

index is upsert-only by default. Use --sync only when the database should exactly mirror the current input: it deletes indexed paths missing from that input, and an empty input removes every indexed document. The former --update behavior is now the default; replace previous prune-by-default commands with an explicit --sync.

Build from source

cargo build --release
cargo test

Rust 1.90+, Linux x86_64 is the primary target. You need a C++ stdlib for the linker (libstdc++) and whatever OpenSSL/native-tls needs on your platform.

On Fedora/RHEL, if the linker wants -lstdc++ but only libstdc++.so.6 exists:

mkdir -p .linker && ln -sfn /usr/lib64/libstdc++.so.6 .linker/libstdc++.so
export RUSTFLAGS="-L native=$(pwd)/.linker"

Linux wheels (same image CI uses — Ubuntu 24.04 / glibc 2.39):

./scripts/build-wheel.sh
VERSION=2026.716.1 ./scripts/build-wheel.sh   # optional override

Releasing

CalVer YYYY.MMDD.N (e.g. 2026.716.1) so versions work for both Cargo and PyPI. Run the Release workflow on main (Actions UI or CLI); it picks the next version, builds wheels, publishes to PyPI, then creates the matching git tag and GitHub Release (with wheels attached).

gh workflow run release.yml --repo context-server/context-server

Design notes

Under the hood: fastembed BGE-small-en-v1.5 (384-d, L2-normalized; query instruction applied at search time), rusqlite with float32 blobs, rmcp over stdio. index is incremental by file: unchanged files (same post-chunk content hash) are skipped, so the embedding model is not loaded. Indexing safely upserts by default. Pass --sync to also remove database paths missing from --input, or --full to re-embed everything collected. A model or chunker migration requires a complete-corpus --sync run.

More detail and roadmap: PLAN.md.

Supported scale

The primary target is up to 10,000 chunks; 50,000 chunks is the regularly benchmarked upper range for the exact in-memory implementation. Re-evaluate storage/index architecture around 100,000 chunks or 500 MiB resident memory. Run scripts/benchmark-scale.py --source-db context.db to reproduce structural latency and database-size measurements.

License

MIT — see LICENSE.

Metadata

Release files for context-server 2026.915.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for context-server 2026.915.1
File Size Uploaded Provenance
context_server-2026.915.1.tar.gz 295.8 kB Without provenance Details

Built distributions (wheels)

Table of built distributions (wheels) for context-server 2026.915.1
File Interpreter ABI Platform
context_server-2026.915.1-py3-none-manylinux_2_39_x86_64.whl Python 3 none Linux glibc 2.39+ x86-64 Details
context_server-2026.915.1-py3-none-manylinux_2_39_aarch64.whl Python 3 none Linux glibc 2.39+ ARM64 Details
context_server-2026.915.1-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details

Total release size: 48.0 MB

Release files / context_server-2026.915.1.tar.gz

Download URL context_server-2026.915.1.tar.gz
Size 295.8 kB
Tags Source
SHA-256 checksum
How to use checksums
adac04062e9f172033f1a260e98fba0542c22ee1cbf70f78a849804ad0e481f7
BLAKE2b-256 checksum
How to use checksums
1aa0e2836744241a3165e237e1bae3f683d137c7d5f384b9a8459e967b26459a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / context_server-2026.915.1-py3-none-manylinux_2_39_x86_64.whl

Download URL context_server-2026.915.1-py3-none-manylinux_2_39_x86_64.whl
Size 16.5 MB
Tags Linux glibc 2.39+ x86-64 Python 3
SHA-256 checksum
How to use checksums
8f1926a32e383ede2d3e0f74575d26a1e38f26c40ce4af8be3724ca7a4795349
BLAKE2b-256 checksum
How to use checksums
15d56fa5c427dcacccd3fbca5abe780b3fa59d055e99cd1188bf452cb633bb4a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / context_server-2026.915.1-py3-none-manylinux_2_39_aarch64.whl

Download URL context_server-2026.915.1-py3-none-manylinux_2_39_aarch64.whl
Size 16.8 MB
Tags Linux glibc 2.39+ ARM64 Python 3
SHA-256 checksum
How to use checksums
b7660b8b93d903cdc9589d466d36f2d67cc3327f39f7a1aeafa20826d7d93280
BLAKE2b-256 checksum
How to use checksums
443bb8f373599caaf189835c422d806d2b5e5ecabb5f087efc8b85ae376575a0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / context_server-2026.915.1-py3-none-macosx_11_0_arm64.whl

Download URL context_server-2026.915.1-py3-none-macosx_11_0_arm64.whl
Size 14.3 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
4aa6712f730a508528bbc4f8f8392ca5adcdf11c5dd19198024be58c80ef8958
BLAKE2b-256 checksum
How to use checksums
148c8c3c93dcb8d2d09f77f276145a779ce634b205c42c9fdd25299228d21132
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.15 {"installer":{"name":"uv","version":"0.12.15","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for context-server 2026.915.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page