mcp-fts5-starter-gemini
Gemini embedder for
mcp-fts5-starter— drop-in hybrid BM25 + dense retrieval via Google's Gemini Embeddings API.
What this is
The parent project ships with an Embedder Protocol and stops short of any actual provider — by design. This repo is the canonical example of that Protocol implemented against a real backend, so you can graduate from BM25-only to hybrid retrieval (BM25 + dense vectors fused with RRF) by changing one line:
from mcp_fts5_starter.search import SearchDB
from mcp_fts5_starter_gemini import GeminiEmbedder
db = SearchDB("data/index.db", embedder=GeminiEmbedder()) # GOOGLE_API_KEY in env
Use this as a working reference. To wire OpenAI, Ollama, sentence-transformers, or anything else, copy the ~150 lines in src/mcp_fts5_starter_gemini/embedder.py and swap the API call.
Quick demo (no API key needed)
The repo ships with five sample notes and a JSON cache of their pre-computed embeddings. The demo runs the same four paraphrased queries against two indexes — BM25 only and BM25 + Gemini — to show what hybrid retrieval actually buys you:
git clone https://github.com/zx22413/mcp-fts5-starter-gemini
cd mcp-fts5-starter-gemini
uv sync
uv run python scripts/demo.py
Real output:
Query: 'speeding up code with memoization'
BM25 only :
(no hits)
BM25 + Gemini :
[ +0.016] Caching strategies (notes/caching.md)
Query: 'managing many simultaneous database connections'
BM25 only :
(no hits)
BM25 + Gemini :
[ +0.016] Database connection pooling (notes/connection-pooling.md)
Query: 'throttling clients that send too many requests'
BM25 only :
(no hits)
BM25 + Gemini :
[ +0.016] API rate limits (notes/rate-limits.md)
...
Query: 'deferring slow work outside the request'
BM25 only :
(no hits)
BM25 + Gemini :
[ +0.016] Background job queues (notes/job-queues.md)
...
The queries are intentionally written without any of the keywords the documents actually use. BM25 has zero recall on all four. Gemini bridges the semantic gap and the right document surfaces every time.
Real usage
import os
from mcp_fts5_starter.search import SearchDB
from mcp_fts5_starter.ingest import sync
from mcp_fts5_starter_gemini import GeminiEmbedder
embedder = GeminiEmbedder(api_key=os.environ["GOOGLE_API_KEY"])
db = SearchDB("data/index.db", embedder=embedder)
sync(db, "data/my-notes") # embeds each doc once during ingest
results = db.search("how do I cache?") # query-time embedding + RRF fusion
The Embedder Protocol is just embed(texts: list[str]) -> list[list[float]] — GeminiEmbedder adds:
- API-key resolution (
GOOGLE_API_KEY→GEMINI_API_KEY→ constructor arg) - Batching to Gemini's 100-input cap
- Exponential-backoff retries on
429 Too Many Requests - A defensive raise when Gemini's response is missing the expected shape
Configuration
| Env var | Purpose |
|---|---|
GOOGLE_API_KEY |
Primary Gemini API key |
GEMINI_API_KEY |
Fallback — checked if the above is unset |
| Constructor arg | Default | Notes |
|---|---|---|
model |
"gemini-embedding-001" |
Pin to a specific model so dimensions are stable |
output_dim |
1536 |
Supported: 128 / 256 / 512 / 768 / 1536 / 3072 |
task_type |
None (symmetric SEMANTIC_SIMILARITY) |
Set "RETRIEVAL_DOCUMENT" / "RETRIEVAL_QUERY" for asymmetric retrieval |
batch_size |
100 |
Gemini's per-call cap |
Task type and the symmetry trade-off
The parent's Embedder Protocol takes a flat list[str] — there's no in-band signal for "is this a document or a query." GeminiEmbedder defaults to SEMANTIC_SIMILARITY, which is symmetric — cosine similarity stays meaningful in both directions.
Gemini's docs claim a small recall improvement from using RETRIEVAL_DOCUMENT for ingest and RETRIEVAL_QUERY for search. To get that, instantiate two embedders and wire them at different points in your stack. For most personal-corpus workloads, the symmetric default is good enough.
Refreshing the embedding cache
The committed data/sample/embeddings.json was generated by:
GEMINI_API_KEY=... uv run python scripts/precompute-embeddings.py
Re-run that script if you change the sample corpus, the demo queries, or the embedding model/dimension. The keys in the JSON are SHA-256 hashes of normalized text — ChangeLog records every refresh.
Status
🚧 Alpha — pre-PyPI. Install from source: pip install git+https://github.com/zx22413/mcp-fts5-starter-gemini. v0.1.0 ships to PyPI once the Trusted Publisher is configured.
Companion repos
| Repo | Role |
|---|---|
mcp-fts5-starter |
The MCP server template + FTS5 index this plugs into |
forget-rag |
Memory-decay layer for FTS5 — different problem, same backend |
License
MIT — see LICENSE.
Metadata
Release files for mcp-fts5-starter-gemini 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mcp_fts5_starter_gemini-0.1.0.tar.gz | 148.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mcp_fts5_starter_gemini-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 157.9 kB
Release files / mcp_fts5_starter_gemini-0.1.0.tar.gz
| Download URL | mcp_fts5_starter_gemini-0.1.0.tar.gz |
|---|---|
| Size | 148.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1ec7f1d23b7461522c182f19c45137c64f31e40fe0d66e5e228ce3e0167e50f7
|
|
BLAKE2b-256 checksum How to use checksums |
3f29dbdb21e62c8f474bc03d8ec04ae78d02f4a615903c0f08f575210ddc2686
|
| 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 May 7, 2026.
Transparency logRelease files / mcp_fts5_starter_gemini-0.1.0-py3-none-any.whl
| Download URL | mcp_fts5_starter_gemini-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
f5b263ecefe520a114fb6edb920b67644e51adf3d2518d8a87c9950d5e78cf8d
|
|
BLAKE2b-256 checksum How to use checksums |
0aed557b99cce6b665e0dea0642ad0092749c82b83d8ed317e14b9adb1bd5ed1
|
| 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 May 7, 2026.
Transparency logSecurity for mcp-fts5-starter-gemini 0.1.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.
Attestation for mcp_fts5_starter_gemini-0.1.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 May 7, 2026.
Transparency logA 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.