Skip to main content

Poison Vectors

A vector-store MCP server with built-in negative-feedback learning. Index documents, search semantically — and when a result is a false match, flag it so that searches similar to the one that found it also exclude it, without harming queries where that document is genuinely relevant. Backed by your choice of store: in-memory, flat-file, SQLite (sqlite-vec), or Qdrant.

"Poison" here is benign — a stored negative-feedback signal, not the adversarial data-poisoning attacks the term usually means in ML.

This repository is the full arc: a validated research result, a packaged Python library, a numerically-certified C# port, and a published MCP server an agent can call over dnx.

The result, in one table

The headline metric is collateral damage — does suppressing a false match here harm the queries where that document is relevant? Measured on real homonym data (CoarseWSD-20, held-out nDCG@10 delta; positive = net benefit, worst = the collateral floor):

Mechanism λ=1 mean / worst λ=5 mean / worst
naive (global suppression) −0.115 / −0.83 −0.648 / −1.00
query-conditional +0.001 / −0.31 −0.027 / −1.00
contrastive (separating-direction) +0.003 / −0.23 +0.004 / −0.26

Verdict: GO. Query-conditional poisoning controls the collateral damage that naive global suppression inflicts; the contrastive (separating-direction) mechanism is the standout — the only one that stays net-positive with a bounded worst-case (never the −1.0 wipeout), robust to its strength parameter. Validated on a falsifiable synthetic corpus and confirmed on real data (SciFact + homonyms).

Full numbers and methodology: Research & Results.

Seeing it work (live, through the MCP server)

A word-sense example — "python" the language vs. the snake. Six docs indexed; the query "best way to learn python programming for data analysis" initially ranks two snake docs above a genuinely-relevant programming doc. After one record_false_match on the top snake doc (anchored to a good doc):

Doc Before After feedback A dissimilar query
("care for a pet snake")
prog-1 (language) 0.67 (#1) 0.67 (#1) ✓ 0.11
prog-2 (language) 0.27 (#4) 0.16 (#2) ↑ 0.16
snake-2 (flagged) 0.35 (#2) −2.49 (last) ↓ 0.51 (#1) ✓
snake-1 (not flagged) 0.32 (#3) −1.31 ↓ (generalized) 0.50 (#2) ✓
monty-1 (not flagged) 0.19 −0.59 ↓ (generalized) 0.15

Feedback on one doc generalizes to the whole wrong sense and to similar future queries, while the same docs stay top-ranked for a dissimilar query where they are correct — query-conditional suppression, zero collateral.

How it works (the short version)

Each mechanism subtracts a non-negative penalty from the base cosine score. The winning mechanism penalizes a candidate's lean along the separating direction between the flagged false match and an anchor (the query, or a known good doc), gated by how similar the new query is to the one that flagged it:

score(d) = sim(q, d) − λ · maxₚ [ gate(sim(q, q_trigₚ)) · max(0, sim(d, sₚ)) ]
           where sₚ = normalize(bad_p − anchor)

So suppression radiates outward from the original query and fades for unrelated queries — and only along the axis that made the match wrong, leaving relevant neighbours intact. Two empirical corrections are load-bearing in every mechanism: penalties are clipped at 0 (never boost a doc) and poisons aggregate by max (not sum). Details: Design & Implementation.

What's in this repo

Component What it is Where
poison-vectors (Python, 0.2.0) The research testbed and the packaged library: PoisonStore overlay, mechanisms, JSON persistence. NumPy-only core. poison_vectors/, pyproject.toml
PoisonVectors (C#, net10.0) A numerically-certified port of the scoring engine — VecMath, the three mechanisms, PoisonStore, the JSON persistence envelope. csharp/PoisonVectors/
PoisonVectors MCP server The agent-facing vector store: an ONNX MiniLM embedder + a pluggable datastore (in-memory, flat-file, SqliteVec, or Qdrant) exposed over MCP (stdio), published to NuGet and runnable via dnx. Semantic search with a negative-feedback (poison) overlay. csharp/PoisonVectors.Cli/

The Python and C# implementations are kept equivalent by golden cross-checks: the C# rerank reproduces Python's scores to ~1e-9, the persistence envelope round-trips both directions (Python↔C#), and the C# ONNX embedder matches Python sentence-transformers/all-MiniLM-L6-v2 to ~6 decimals.

Quickstart

Python — research & library

pip install -e ".[dev]"
python -m pytest -q                                   # 77 tests
python -m poison_vectors.experiments.milestone_a      # synthetic go/no-go
python examples/ann_overlay.py                        # worked ANN-overlay example

pip install -e ".[real]"                              # for real-data runs
python -m poison_vectors.experiments.coarsewsd_run    # real homonyms (CoarseWSD-20)
from poison_vectors import PoisonStore, Mechanism

store = PoisonStore(mechanism=Mechanism.CONTRASTIVE, lam=5.0)
store.add_feedback(query_vec, bad_doc_vec, good_doc_vec)      # vectors in
reranked = store.rerank(query_vec, candidates=[(doc_id, vec), ...], k=10)

C# — library & tests

cd csharp
dotnet test PoisonVectors.sln          # 104 tests (net10.0)

MCP server — run via dnx (needs the .NET 10 SDK)

The server is published to NuGet as an mcpserver tool:

dnx PoisonVectors --yes -- serve        # MCP server over stdio (what a client launches)
dnx PoisonVectors -- embed "some text"  # quick embed check
dnx PoisonVectors -- demo               # before/after rerank demo

First run downloads the all-MiniLM-L6-v2 ONNX model (~90 MB) to a local cache (%LOCALAPPDATA%/poison-vectors/models/all-MiniLM-L6-v2, overridable via POISON_VECTORS_MODEL_DIR).

Register it in a client with the built-in setup command (interactive by default; flags for automation):

dnx PoisonVectors -- setup --client claude --scope project-local --yes

This writes/merges a project-scoped .mcp.json so Claude Code can launch the server. MCP tools exposed: index_document, search, remove_document, record_false_match (optional good-doc anchor; returns a record id), list_poisons, get_poison, search_poisons, remove_poison, remove_poisons_for_doc, clear_poisons, save_store/load_store (full corpus+poison snapshot export/import).

Full guides: Usage (Python + C#/MCP).

Storage providers & configuration

The MCP server persists both the corpus and the poison-record set to a pluggable datastore. Select it with an environment variable, overridable by a serve flag (precedence: flag > env var > default).

Setting Env var serve flag Default
Provider POISON_VECTORS_STORE --store flatfile
Flat-file directory POISON_VECTORS_STORE_DIR --store-dir ~/.poison-vectors
SqliteVec file POISON_VECTORS_STORE_FILE --store-file ~/.poison-vectors/poison-vectors.db
Qdrant host POISON_VECTORS_QDRANT_HOST --qdrant-host localhost
Qdrant port (gRPC) POISON_VECTORS_QDRANT_PORT --qdrant-port 6334
Qdrant API key POISON_VECTORS_QDRANT_API_KEY --qdrant-api-key (none)

Valid providers: memory, flatfile, sqlitevec, qdrant. The default, flatfile, persists both the corpus and the poison records under ~/.poison-vectors — state is durable and shared across launches. sqlitevec is now available — ANN-backed via the sqlite-vec extension; select it with --store sqlitevec (db file at POISON_VECTORS_STORE_FILE, default ~/.poison-vectors/poison-vectors.db). Selecting sqlitevec downloads the sqlite-vec v0.1.9 native extension on first use to ~/.poison-vectors/native/ (cache dir overridable via POISON_VECTORS_VEC0_DIR; point at a prebuilt extension with POISON_VECTORS_VEC0_PATH). qdrant is available — ANN-backed via the official Qdrant.Client (gRPC); select it with --store qdrant. The qdrant provider expects a reachable Qdrant server (e.g. docker run -p 6334:6334 qdrant/qdrant).

Documentation

  • Research & Results — concept, research question, prior art, methodology, all milestone results, references.
  • Design & Implementation — architecture, mechanism math, metrics, the falsifiable synthetic corpus, module map, how to extend.
  • Usage — install, run experiments, use as a library, the C# port, and the MCP server / dnx / setup.
  • Roadmap — the productization plan and its delivery status.
  • Process artifacts (specs, plans, milestone findings): docs/superpowers/.

Status

All three roadmap phases are shipped: the Python module, the C# port (certified equivalent), and the MCP server (published, dnx-distributed, exercised live in Claude Code). The server is now being expanded into a pluggable vector store: the IVectorStore abstraction, addressable poison records (per-id and per-doc removal, get/search), remove_document, and env+CLI store configuration are in place; the flat-file provider is now durable (v2 snapshot: corpus + poison records persist under ~/.poison-vectors); the SqliteVec provider is now available (ANN via sqlite-vec; --store sqlitevec); the Qdrant provider is now available (ANN via Qdrant.Client; --store qdrant). All four providers ship. Licensed under PolyForm Noncommercial 1.0.0 (see LICENSE).

Data & licensing

The synthetic corpus is generated in-process. Real-data loaders download on demand: SciFact (BEIR) and CoarseWSD-20 (homonyms, CC BY-NC 4.0, NonCommercial — research only; downloaded to a gitignored cache, never committed). The repository is licensed under the PolyForm Noncommercial 1.0.0 license — noncommercial use and modification are permitted; no warranty is provided. Future versions may be released under different terms.

Metadata

Release files for poison-vectors 0.2.0

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

Source distribution (sdist)

Source distribution for poison-vectors 0.2.0
File Size Uploaded Provenance
poison_vectors-0.2.0.tar.gz 42.8 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for poison-vectors 0.2.0
File Interpreter ABI Platform
poison_vectors-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 79.2 kB

Release files / poison_vectors-0.2.0.tar.gz

Download URL poison_vectors-0.2.0.tar.gz
Size 42.8 kB
Tags Source
SHA-256 checksum
How to use checksums
be423b3013d3c09f134361a1772088e7a0d4344ffaf0b5ae1767ec9d7da0c3bf
BLAKE2b-256 checksum
How to use checksums
011e6faf769ed28edb0eb3a7ae6ef5c0cb678fbcabaacc925fd39e8ab93cf1c2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.

Transparency log

Release files / poison_vectors-0.2.0-py3-none-any.whl

Download URL poison_vectors-0.2.0-py3-none-any.whl
Size 36.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e5ac11a49e2c43425df01d5f7b94415be2721ddb5f3d4310bc3c3764ffa6cb96
BLAKE2b-256 checksum
How to use checksums
92699684a79a0d115bef2eea763719bd832dcec973e96e86ba384d31652feefd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.

Transparency log

Security for poison-vectors 0.2.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for poison_vectors-0.2.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 30, 2026.

Transparency log

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files Full provenance

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