Skip to main content

ruvector — Python SDK, CLI, and MCP server

Ultra-low-latency vector similarity search, backed by a Rust RaBitQ 1-bit quantization core (ruvector_rabitq::RabitqPlusIndex) with native NumPy interop — zero-copy reads, GIL released on every heavy call. Ships three things from one pip install ruvector:

  • ruvector — the Python library (Collection, RabitqIndex).
  • ruvector console script — a CLI for scripting/ops (create/insert-batch/search/delete/export/import/info/ benchmark/serve), installed with the base package.
  • ruvector serve — an MCP server (stdio or streamable-HTTP) exposing the same surface as tools, plus a ChatGPT Apps SDK ui:// widget for visual search exploration, install with the mcp extra.

This crate is the Python half of the ruvector workspace; the underlying algorithm lives in crates/ruvector-rabitq/ and is unchanged by this binding. Scope, benchmarks, and the milestone roadmap (M1 here → M2 ruLake/ HNSW → M3 embeddings → M4 A2A client) are in docs/adr/ADR-352-ruvector-python-sdk-cli-mcp.md and docs/sdk/.

Install

pip install ruvector            # library + the `ruvector` console script (numpy, click, rich)
pip install ruvector[mcp]       # + `ruvector serve` (MCP server)
pip install ruvector[all]       # everything

For local development from a checkout:

cd crates/ruvector-py
maturin develop --release   # builds the Rust cdylib in-place, links as ruvector._native
pip install -e '.[all]'     # pulls click/rich/mcp for the cli/mcp extras
pytest tests/

The --release flag matters: a debug build is dramatically slower on the search loop and will fail the latency acceptance tests.

30-second example (library)

import numpy as np
from ruvector import Collection

vectors = np.random.default_rng(42).standard_normal((100_000, 128)).astype(np.float32)
coll = Collection.from_vectors(vectors, rerank_factor=20)

hits = coll.search(vectors[0], k=10)
for h in hits:
    print(h.id, h.score)          # ascending squared-L2 distance

coll.save("my.rbpx")              # writes my.rbpx + my.rbpx.meta.json
coll2 = Collection.load("my.rbpx")

Collection adds ids, per-vector metadata, soft delete, and filtering on top of the lower-level RabitqIndex (which is still available directly for the ~50 lines/row case where you don't need any of that):

coll = Collection.create(dim=128)
coll.insert(vectors[0], metadata={"category": "news"})
coll.insert_batch(vectors[1:100], metadatas=[{"category": "sports"}] * 99)

hits = coll.search(vectors[0], k=5, filter={"category": "news"})  # client-side filter
coll.delete(hits[0].id)           # soft delete (tombstone)
coll.vacuum()                     # physically rebuild without tombstoned rows

Filtering is applied client-side (the Rust scan has no filter pushdown in M1.5) — documented in Collection.search's docstring, not hidden.

CLI

ruvector create --path my.rbpx --dim 128
ruvector insert-batch --path my.rbpx --vectors vecs.npy --metadata meta.json
ruvector search --path my.rbpx --query q.npy -k 10 --json
ruvector delete --path my.rbpx --id 42 --vacuum
ruvector export --path my.rbpx --out snapshot
ruvector import --path new.rbpx --vectors vecs.npy
ruvector info --path my.rbpx
ruvector benchmark -n 100000 --dim 128     # in-process latency/QPS, no external comparator
ruvector serve                             # MCP server over stdio
ruvector serve --http --port 8420          # MCP server over streamable-HTTP (loopback)
ruvector serve --read-only                 # no create/insert/delete tools
ruvector serve --max-vectors 50000         # cap vectors per collection (default 1,000,000)

serve --http on a non-loopback --host refuses to start unless RUVECTOR_MCP_TOKEN is set to a non-empty secret (bearer auth); an empty or whitespace-only value counts as unset.

ruvector --help starts in ~20ms — every subcommand lazily imports numpy/ click/rich inside its own function body (see ruvector/cli.py's module docstring), so nothing pays for them until it actually runs.

MCP server

ruvector serve exposes: vector_create_collection, vector_insert, vector_insert_batch, vector_search, vector_delete, vector_stats, vector_list_collections, and vector_explore — a widget-backed tool that renders results in an HTML table (ui://ruvector/explore.html), following the ChatGPT Apps SDK convention (_meta["openai/outputTemplate"]).

Tool arguments name a collection by name, never by filesystem path — names are restricted to [A-Za-z0-9_-] and resolved under RUVECTOR_MCP_DATA_DIR (default ~/.ruvector/collections), so there is no directory-traversal surface regardless of what a remote MCP client sends. See ruvector/mcp_server.py's module docstring for the full security model.

Write size is capped. Per call: 10,000 rows, 2,000,000 floats in total, and 64 KiB of serialized metadata per row. Per collection: 1,000,000 vectors by default, counting deleted-but-not-vacuumed rows; vector_insert and vector_insert_batch fail with a ToolError that names the limit once it would be exceeded. Change it with ruvector serve --max-vectors N or RUVECTOR_MCP_MAX_VECTORS=N (the option wins; a non-positive or non-integer value stops the server at startup). The server re-saves the whole collection on every write, so keep this cap well below what your disk and latency budget can take.

# point an MCP client at: ruvector serve   (stdio)
# or:                      ruvector serve --http --port 8420

API summary (library)

Call Returns Notes
Collection.create(dim, *, rerank_factor=20, seed=42) Collection empty; lazily builds on first insert
Collection.from_vectors(vectors, *, ids=None, metadatas=None, ...) Collection bulk build, parallel rotate+pack
coll.insert(vector, *, metadata=None) / coll.insert_batch(vectors, *, metadatas=None) int / list[int] true incremental add, no rebuild
coll.search(query, k, *, filter=None, rerank_factor=None) list[SearchHit] filter: exact-match dict or predicate callable
coll.delete(id) / coll.vacuum() None / int soft delete / physical rebuild
coll.save(path) / Collection.load(path) — .rbpx + .rbpx.meta.json sidecar
coll.stats() CollectionStats count, dim, rerank_factor, memory_bytes, tombstoned
RabitqIndex.build(vectors, *, ids=None, rerank_factor=20, seed=42) RabitqIndex lower-level index, no metadata/filter/delete
idx.search(query, k, *, rerank_factor=None) list[(int, float)] (id, score²) ascending
idx.save(path) / RabitqIndex.load(path) — .rbpx v1 format
ruvector.RuVectorError / ruvector.CollectionError exceptions base / Collection-level

Non-contiguous or wrong-dtype inputs raise TypeError at the boundary rather than silently copying — predictable beats fast. Ids must fit in u32 (the index's storage width); a larger id raises CollectionError (library) or ValueError (RabitqIndex directly) rather than silently truncating.

Benchmark

Real numbers (this host, random-Gaussian data — adversarial for ANN in general, see the caveat in ADR-352) are in docs/adr/ADR-352-ruvector-python-sdk-cli-mcp.md. ruvector benchmark runs an in-process build+search latency check with no external comparator.

License

MIT, matching the rest of the ruvector workspace (see LICENSE).

Python capability packages

Python portfolio

The Python portfolio maps the ten most downloaded RuVector npm distributions to scoped Python APIs. Version 0.1.3 adds native KVCache (full precision cache attention, no text generation) and RvfStore (trusted local RVF vector storage). Existing vector, graph, GNN, attention and SONA APIs remain available.

from ruvector import KVCache
cache = KVCache(2, max_tokens=8)
cache.append([1.0, 0.0], [0.25, 0.75])
assert cache.attend([1.0, 0.0]) == [0.25, 0.75]

Native version changes merged into main automatically build, audit, test and publish all supported wheel platforms. A failed gate blocks upload.

Metadata

Release files for ruvector 0.1.4

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

Source distribution (sdist)

Source distribution for ruvector 0.1.4
File Size Uploaded
ruvector-0.1.4.tar.gz 2.9 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for ruvector 0.1.4
File
ruvector-0.1.4-cp39-abi3-win_amd64.whl CPython 3.9 abi3 Windows x86-64 Details
ruvector-0.1.4-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
ruvector-0.1.4-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
ruvector-0.1.4-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details
ruvector-0.1.4-cp39-abi3-macosx_10_12_x86_64.whl CPython 3.9 abi3 macOS 10.12+ x86-64 Details

Total release size: 16.8 MB

Release files / ruvector-0.1.4.tar.gz

Download URL ruvector-0.1.4.tar.gz
Size 2.9 MB
Tags Source
SHA-256 checksum
How to use checksums
614697f60b038486372fdd7f6feef819f89938b955b38e7fe5fb608d14406e5f
BLAKE2b-256 checksum
How to use checksums
e07ef317ae2ec6a164de0326dde8e14ab32efa13cf4583b13215133465494075
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / ruvector-0.1.4-cp39-abi3-win_amd64.whl

Download URL ruvector-0.1.4-cp39-abi3-win_amd64.whl
Size 3.0 MB
Tags CPython 3.9 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
6032dd22b1f74d0d4fa8c23142f88ca9275bcb5f31cd114c3e875e164356d5ee
BLAKE2b-256 checksum
How to use checksums
4b08fa9b09d984afc968514a93d02d4d51211df1a5ae56ff8f9a30949eb5d7dc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / ruvector-0.1.4-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL ruvector-0.1.4-cp39-abi3-manylinux_2_28_x86_64.whl
Size 2.9 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
2189bf262fab1533f40ac654afa4bcb580b87ad2e33eee1decd0b7a42f469ebe
BLAKE2b-256 checksum
How to use checksums
5b33b6b42573b552e0f88feefa85a5c8f6db084816ab2037ccdb7079607ae434
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / ruvector-0.1.4-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL ruvector-0.1.4-cp39-abi3-manylinux_2_28_aarch64.whl
Size 2.7 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
d6dabb8f3d5add92e8721adcfc28dcaaaadb70e62ac7e729c625ed3870497a7c
BLAKE2b-256 checksum
How to use checksums
c91712c36f3c768cb05b518365af3b7a15e359e94f6ac8df54658e269b4189cc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / ruvector-0.1.4-cp39-abi3-macosx_11_0_arm64.whl

Download URL ruvector-0.1.4-cp39-abi3-macosx_11_0_arm64.whl
Size 2.6 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
28aeac25bb3151b4afb0b06bc07ec259137432387c7c2cb3316842bc55e82006
BLAKE2b-256 checksum
How to use checksums
af5d3bf35e6d8a1936068de281b2840b46c69b614b372370cb60f81793c3ea16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release files / ruvector-0.1.4-cp39-abi3-macosx_10_12_x86_64.whl

Download URL ruvector-0.1.4-cp39-abi3-macosx_10_12_x86_64.whl
Size 2.8 MB
Tags CPython 3.9 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
3da743e96235ef90d2b95e10f13b42da81374f1844daf3d1fabb9ab011b8670d
BLAKE2b-256 checksum
How to use checksums
f0681514bad3289938903d405d746883feb6ae4a127070563b6f47080f4943ff
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.12.3

Release history Release notifications | RSS feed

This release

0.1.4 This release

6 release files

0.1.3

6 release files

0.1.2

6 release files

0.1.1

6 release files

0.1.0

6 release files

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