banditdb-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@banditdb-mcpCreate a campaign 'email_offers' with arms 'discount' and 'free_shipping', feature_dim 3"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
BanditDB Python SDK
The official Python client and Model Context Protocol (MCP) server for BanditDB — the ultra-fast, lock-free Contextual Bandit database written in Rust.
BanditDB abstracts away the complex linear algebra of Reinforcement Learning (LinUCB, Thompson Sampling) behind a dead-simple API. Build real-time personalizers, dynamic A/B tests, and give LLM agents mathematically rigorous persistent memory.
Installation
pip install banditdb-pythonRequires the BanditDB Rust server running (default: http://localhost:8080).
Related MCP server: memory-lancedb-mcp
1. Standard SDK Usage
The client features automatic connection pooling, exponential backoff retries, and strict timeouts.
from banditdb import Client, BanditDBError
# Connect to the BanditDB server.
# Pass api_key if BANDITDB_API_KEY is set on the server.
db = Client(
url="http://localhost:8080",
timeout=2.0,
api_key="your-secret-key", # omit if server runs without auth
)
try:
# 1. Create a campaign (run once at startup)
# algorithm defaults to "linucb"; use "thompson_sampling" for Bayesian exploration
db.create_campaign(
campaign_id="checkout_upsell",
arms=["offer_discount", "offer_free_shipping"],
feature_dim=3,
)
# or: db.create_campaign(..., algorithm="thompson_sampling")
# 2. A user arrives — ask the database what to show them
# Context: [is_mobile, cart_value_normalized, is_returning_user]
arm_id, interaction_id = db.predict("checkout_upsell", [1.0, 0.8, 0.0])
print(f"Showing: {arm_id}") # e.g., "offer_free_shipping"
# 3. The user clicked — send the reward
db.reward(interaction_id, reward=1.0)
except BanditDBError as e:
print(f"Database error: {e}")All Client methods
Health
Method | Description |
| Returns |
| Returns the full health dict including per-campaign |
Campaigns
Method | Description |
| Register a new campaign. |
| Returns a list of all campaigns (active and archived) with |
| Returns full per-arm state: |
| Business-level convergence report. |
| Operator diagnostics: per-arm theta norms, A_inv uncertainty bounds, entropy health ( |
| Soft-delete: pauses predictions/rewards but preserves all learned weights. Recoverable with |
| Restore an archived campaign to active status with all weights intact. |
| Permanently delete a campaign. Returns |
Predict & Reward
Method | Description |
| Returns |
| Predict for up to 100 campaign/context pairs in a single round-trip. Each item: |
| Record outcome. |
Data & Export
Method | Description |
| Flush WAL, snapshot models, write Parquet shards, run neural retrain + tournament eval, rotate WAL. Returns a summary string. |
| List Parquet export shards grouped by campaign. Returns |
2. The AI "Hive Mind" (Model Context Protocol)
Standard LLM agents are stateless — if they route a task to the wrong model and fail, they repeat the same mistake tomorrow. BanditDB's built-in MCP server gives the entire agent swarm shared persistent memory.
Starting the MCP server
# Set environment variables before starting
export BANDITDB_URL=http://localhost:8080
export BANDITDB_API_KEY=your-secret-key # omit if server runs without auth
banditdb-mcpConnecting to Claude Desktop
Add to your Claude configuration file:
Mac:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"banditdb": {
"command": "banditdb-mcp",
"args": [],
"env": {
"BANDITDB_URL": "http://localhost:8080",
"BANDITDB_API_KEY": "your-secret-key"
}
}
}
}The agent swarm now has nine tools:
Tool | What it does |
| Create a new decision campaign. Accepts |
| List all active campaigns (shows |
| Inspect per-arm learning state: |
| Business-level convergence report. Tells you whether the campaign has statistically converged and which arm is winning with confidence intervals. |
| Ask BanditDB which arm to pick for a given context. Returns the arm and an |
| Get decisions for multiple campaigns in a single round-trip. Pass a list of |
| Report whether the chosen action succeeded (1.0) or failed (0.0). Updates the shared model. |
| Soft-delete a campaign. Pauses predictions/rewards but preserves all learned weights. |
| Restore an archived campaign to active status with all weights intact. |
Every decision made by any agent in the network improves the routing for all future agents.
3. Data Science & Offline Evaluation
BanditDB event-sources every prediction and reward to a Write-Ahead Log (WAL). Calling checkpoint() compiles completed prediction→reward pairs into Snappy-compressed Parquet files — one per campaign — for offline analysis with Polars or Pandas.
Every prediction is guaranteed to appear in the Parquet file even if its reward arrives hours later: BanditDB re-emits in-flight interactions at each checkpoint so delayed rewards are always captured in a future cycle.
# Checkpoint: snapshot models, write Parquet, rotate the WAL.
# Call this on a schedule or after significant traffic.
summary = db.checkpoint()
print(summary)
# "Checkpoint written and WAL rotated: 2 campaigns, offset 4821 bytes,
# 150 interactions exported, 3 in-flight re-emitted"
# List which Parquet files are available
print(db.export())
# 'Parquet files in /data/exports: ["llm_routing.parquet"]'
# Load directly from the mounted volume into Polars.
# Flat schema: interaction_id | arm_id | reward | predicted_at | rewarded_at | propensity | feature_0 | ...
import polars as pl
df = pl.read_parquet("/data/exports/llm_routing.parquet")
print(df.head())
print(df.columns)Offline Policy Evaluation (OPE)
The SDK ships three OPE estimators in banditdb.eval. They answer the question: "what would my average reward have been under a different policy — without running a live experiment?"
Install the eval dependencies:
pip install "banditdb-python[eval]"Estimator | Function | How it works | When to use |
Replay |
| Accepts each interaction with probability | Sanity check baseline. Low coverage is expected — ~1/K of interactions are used. |
IPS / SNIPS |
| Uses every interaction with importance weight | Primary estimator. Use when you have enough data but want full coverage. |
Doubly Robust |
| Fits a linear reward model, then applies an IPS correction on residuals. Consistent if either the reward model or the propensities are correct. | Best statistical efficiency. Use when comparing multiple policies or sweeping |
All three estimators:
Accept a Polars or pandas DataFrame loaded from a BanditDB Parquet export
Evaluate the uniform random policy as the target (the unbiased baseline to beat)
Raise
ValueErrorfor Thompson Sampling campaigns (propensity column is null — TS does not log propensities)Return an
OPEResultwithestimate,std_error,n_used,n_total, andmethod
import polars as pl
from banditdb.eval import replay, ips, doubly_robust
df = pl.read_parquet("/data/exports/llm_routing.parquet")
# How much reward would a uniform random policy have earned?
print(replay(df))
# OPEResult(method='replay', estimate=0.4821, std_error=0.0312, coverage=22.1% [33/149])
print(ips(df))
# OPEResult(method='ips', estimate=0.5103, std_error=0.0187, coverage=100.0% [149/149])
print(doubly_robust(df))
# OPEResult(method='doubly_robust', estimate=0.5219, std_error=0.0141, coverage=100.0% [149/149])
# Compare against the observed reward of the logging policy:
print("Observed (logging policy):", df["reward"].mean())
# If observed >> estimate, the campaign has learned something real — it outperforms random.Practical use: sweep alpha offline before deploying. Train a campaign on real traffic, checkpoint to Parquet, then replay different alpha values through doubly_robust() to find the best exploration level — no live experiment needed.
Note: OPE requires the
propensitycolumn, which is only written for LinUCB campaigns. Thompson Sampling campaigns lognullpropensities because TS arm selection is stochastic and propensity scoring requires a deterministic logging policy.
Choosing an Algorithm
BanditDB supports four algorithms, selected at campaign creation time.
Algorithm |
| Exploration style | When to use |
LinUCB |
| Deterministic UCB bonus: | Predictable, tunable. Sweep |
Linear Thompson Sampling |
| Samples θ̃ ~ N(θ, α²·A⁻¹), scores by θ̃·x | Bayesian posterior — no alpha-sweep needed. Concurrent users automatically diversify choices. |
NeuralLinUCB |
| Deep MLP embedding + LinUCB in embedding space | Non-linear reward functions. Retrains the MLP every N rewards. |
Progressive |
| Self-tuning tournament: runs base + challenger in parallel, shifts traffic to the winner | Zero-configuration model selection. Picks the best algorithm automatically. |
from banditdb import Client, NeuralLinUCBConfig, ProgressiveConfig
db = Client("http://localhost:8080")
# LinUCB (default)
db.create_campaign("routing", ["fast", "cheap"], feature_dim=4, alpha=1.5)
# Thompson Sampling — natural Bayesian exploration, alpha=1.0 is ideal
db.create_campaign("routing_ts", ["fast", "cheap"], feature_dim=4,
algorithm="thompson_sampling")
# NeuralLinUCB — learns a deep embedding of the context, then applies LinUCB
cfg = NeuralLinUCBConfig(
context_dim=4, # must match feature_dim
embed_dim=32, # arm matrix dimension (default 32)
hidden_dim=128, # MLP hidden layer width (default 128)
retrain_every=200, # retrain the MLP every N cumulative rewards
)
db.create_campaign("routing_neural", ["fast", "cheap"], feature_dim=4, algorithm=cfg)
# Progressive — runs LinUCB vs NeuralLinUCB, shifts traffic to whoever wins SNIPS checkpoints
cfg = ProgressiveConfig(
base="linucb",
challenger=NeuralLinUCBConfig(context_dim=4, embed_dim=32),
min_obs=100, # minimum buffer entries per arm before any traffic shift
required_wins=3, # consecutive checkpoint wins to earn one traffic step
step_bps=1000, # traffic delta per win run, in basis points (1000 = 10%)
)
db.create_campaign("routing_prog", ["fast", "cheap"], feature_dim=4, algorithm=cfg)All four algorithms share the same predict → reward loop.
Error Handling
Exception | When raised |
| Base exception — catch this to handle all SDK errors. |
| Server is offline or unreachable. |
| Request exceeded the configured timeout. |
| Server returned an error (e.g., campaign not found, unauthorized). |
License
Apache-2.0 — Copyright (C) 2026 Simeon Lukov and Dynamic Pricing Ltd. See the main repository for details.
This server cannot be deployed
Maintenance
Related MCP Connectors
Universal memory for AI agents and tools. Save, organize and search context anywhere.
Persistent memory and knowledge management for AI agents with semantic search and 50+ tools.
- EngramOAuthtools.engram
Memory for AI agent teams across tools, sessions, repositories, and teammates.
Hosted AI agent memory that learns from outcomes, with shared rooms, in Claude, Cursor and ChatGPT.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to record and rank learnings, facts, and methods through a collaborative voting framework. It provides tools for agents to surface the most useful information across sessions using persistent memory storage.8MIT
- AlicenseAqualityDmaintenanceEnables AI agents to store and recall persistent long-term memories across sessions using LanceDB, with semantic search, automatic linking, conflict detection, and maintenance tools.769 npmMIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to share persistent, conflict-safe memory by providing tools to recall, learn, reinforce, and retire lessons, using CockroachDB for storage and AWS Bedrock for embeddings.1MIT
- AlicenseBqualityCmaintenanceProvides persistent memory management for AI agents with 14 tools, including semantic search, context synthesis, auto-context middleware, and write-back actions to external services like Slack.1889 npm1MIT