Skip to main content

Lightweight MCP server for semantic search over organizational markdown

Project description

context-server

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 All-MiniLM-L6-v2 into the local Hugging Face / fastembed cache (once, tens of MB).

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"

Search

Default mode is hybrid: dense cosine (MiniLM) 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
answer_question Best matching passage(s) — retrieval only; same filters as search
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]
                      [--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  <text>          # smoke-test embeddings

Build from source

cargo build --release
cargo test

Rust 1.75+, 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. pyproject.toml reads the version from Cargo.toml; release CI rewrites that from the git tag.

tag="$(./scripts/next-calver.sh)"
git tag -a "$tag" -m "$tag"
git push origin "$tag"    # Release workflow → PyPI

Design notes

Under the hood: fastembed All-MiniLM-L6-v2 (384-d, L2-normalized), rusqlite with float32 blobs, rmcp over stdio. Each index run replaces the DB contents.

More detail and roadmap: PLAN.md.

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

context_server-2026.717.2.tar.gz (61.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

context_server-2026.717.2-py3-none-manylinux_2_39_x86_64.whl (17.4 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ x86-64

context_server-2026.717.2-py3-none-manylinux_2_39_aarch64.whl (17.8 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ ARM64

context_server-2026.717.2-py3-none-macosx_11_0_arm64.whl (13.4 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file context_server-2026.717.2.tar.gz.

File metadata

  • Download URL: context_server-2026.717.2.tar.gz
  • Upload date:
  • Size: 61.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}

File hashes

Hashes for context_server-2026.717.2.tar.gz
Algorithm Hash digest
SHA256 1809ff2d2f38fe4a7aa3c00ca6d71098703fb35134e4d692da10e401c8ed168b
MD5 de699abd7114ac822a82fd0ec221f991
BLAKE2b-256 ef4047da75244535c3cf427a2f7728379737459799f2b9afc10248aaadfd5410

See more details on using hashes here.

File details

Details for the file context_server-2026.717.2-py3-none-manylinux_2_39_x86_64.whl.

File metadata

  • Download URL: context_server-2026.717.2-py3-none-manylinux_2_39_x86_64.whl
  • Upload date:
  • Size: 17.4 MB
  • Tags: Python 3, manylinux: glibc 2.39+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}

File hashes

Hashes for context_server-2026.717.2-py3-none-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 43c4d806c3ce910afde3111de56abc865b53a571e05b0853d7bb6483923d1aa9
MD5 65bb44b5207f42005c3eeab2895e412a
BLAKE2b-256 3823d5f8217eaa3cfe86611382ec267ad1bba0a81d42bfcf5fce6363b55975ea

See more details on using hashes here.

File details

Details for the file context_server-2026.717.2-py3-none-manylinux_2_39_aarch64.whl.

File metadata

  • Download URL: context_server-2026.717.2-py3-none-manylinux_2_39_aarch64.whl
  • Upload date:
  • Size: 17.8 MB
  • Tags: Python 3, manylinux: glibc 2.39+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}

File hashes

Hashes for context_server-2026.717.2-py3-none-manylinux_2_39_aarch64.whl
Algorithm Hash digest
SHA256 c93589b8379a41caaa2ec09a2ffd9d83007c33382730f83e7f3c8284fea3e39e
MD5 ddcea094cd258913f03cee0da15a5296
BLAKE2b-256 dfe42276d93ad359f56b414d67d898a1f83bd42809c5dbd6d77bb19bf7db3be6

See more details on using hashes here.

File details

Details for the file context_server-2026.717.2-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: context_server-2026.717.2-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 13.4 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.11.29 {"installer":{"name":"uv","version":"0.11.29","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}

File hashes

Hashes for context_server-2026.717.2-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c67d4b3d0c90a310a04dc39f780821dcf133118c634ee8f4108b95301f5ee7e0
MD5 f34f6925e5b3b30128c75f4d3aa58d29
BLAKE2b-256 8289345945eea6e8406e64c56db2e52d883f481fe7b64626ab01197323609ed2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page