polyglot
Polyglot is a uniform interface to 18 databases across 9 categories, usable as a Python/Java library or an MCP server for LLMs, with built-in guardrails.
Documentation
Polyglot
One uniform interface to many databases — usable as a library and as a Model Context Protocol (MCP) server for LLMs, in both Python and Java.
Polyglot gives you a single, consistent set of operations — list_tables,
run_query, explain_query, execute, copy_data, and more — that behave the
same across relational, document, key-value, wide-column, object, graph, vector,
time-series, search, and warehouse engines. One core library backs both the MCP
tools and the importable API, so they never drift.
An independent, community-driven open-source project, released under the Apache 2.0 license.
The problem
Every database speaks its own language. The moment an app — or an LLM agent — needs more than one, you're on the hook for a different driver, query language, auth scheme, result shape, and safety story for each one. That cost multiplies by every database you touch, and again for every language you write in and every LLM tool you expose.
Without Polyglot — every engine is its own bespoke integration:
flowchart LR
App["Your app / LLM agent"]
App -->|"psycopg · SQL"| PG[(PostgreSQL)]
App -->|"pymongo · BSON filters"| MG[(MongoDB)]
App -->|"redis-py · commands"| RD[(Redis)]
App -->|"boto3 · S3 API"| S3[(S3)]
App -->|"bolt · Cypher"| NEO[(Neo4j)]
App -->|"REST · vector search"| QD[(Qdrant)]
App -->|"…a new SDK each time"| ETC[(…9 more)]
Every arrow is separate code to build, secure, and maintain — no shared caps on result size, no consistent read-only/destructive rules, no uniform output.
With Polyglot — one uniform interface (and one set of guardrails) in front of them all:
flowchart LR
App["Your app / LLM agent"] ==>|"one API · 12 MCP tools"| P{{Polyglot}}
P --> PG[(PostgreSQL)]
P --> MG[(MongoDB)]
P --> RD[(Redis)]
P --> S3[(S3)]
P --> NEO[(Neo4j)]
P --> QD[(Qdrant)]
P --> ETC[(…14 engines,<br/>9 categories)]
Highlights
- One interface, 14 engines tested live across 9 categories (18 engines
implemented in all; the warehouse category and a few managed/licensed engines
are implemented but need cloud credentials to test).
list_tables,run_query,explain_query,execute,copy_data, … behave the same everywhere. - Library and MCP server from one core. Call it from code, or let an LLM
drive it — identical behavior, because both wrap the same
DatabaseCore. - Safe by default. Read-only unless a connection opts in; destructive ops need explicit confirmation; results are capped; PII columns are redacted; credentials never reach the model.
- Two languages, one contract. Python and Java expose byte-identical MCP tools — a Java gateway is a drop-in replacement for the Python one.
# the same call, whatever the engine underneath
db.run_query("warehouse", "SELECT ...") # a SQL warehouse
db.run_query("cache", "GET session:42") # Redis
db.copy_data("shop", "orders", "orders_archive") # any engine, same signature
"Which customers churned last month?" — an LLM connected to Polyglot answers that against Postgres, Mongo, or BigQuery without you writing per-database glue.
Get started
| I want to… | Go to |
|---|---|
| Use it from Python (library or MCP server) | python/README.md |
| Use it from Java (library or MCP server) | java/README.md |
| Test it (incl. a natural-language script) | TESTING.md |
| Contribute | CONTRIBUTING.md |
When should I use this?
Pick based on who is driving:
- The library (
polyglot-core) — when code is the consumer: ETL and migrations, a data-access layer spanning several stores, admin/reporting endpoints, batch jobs. Typed, programmatic, no LLM involved. - The MCP server (
polyglot-mcp) — when an LLM or agent is the consumer: conversational data access in Claude Desktop/Code, Cursor, etc.; agentic workflows that inspect, query, and move data; governed access for non-engineers.
Both share the same DatabaseCore, so behavior and guardrails are identical
whether a function call or a language model triggers them.
Architecture
flowchart TD
subgraph Consumers
A[LLM via MCP client]
B[Application code]
end
A -->|MCP tools over stdio/HTTP| G[polyglot-mcp<br/>MCP gateway]
B -->|import| C
G --> C[polyglot-core<br/>DatabaseCore + ConnectionRegistry]
C --> S[Security guardrails<br/>read-only · destructive-confirm · row caps · redaction]
C --> D{DatabaseAdapter<br/>one per engine}
D --> E1[(Relational)]
D --> E2[(Document)]
D --> E3[(Key-value)]
D --> E4[(Wide-column)]
D --> E5[(Object)]
D --> E6[(Graph / Vector)]
D --> E7[(Time-series)]
D --> E8[(Search)]
D --> E9[(Warehouse)]
The gateway is an in-process router: one MCP server that loads adapters as
libraries and dispatches each call to the right backend by a connection name.
The Python and Java gateways expose the same tool contract (identical names,
arguments, and result shapes) and are drop-in replacements for each other.
Supported databases
Universal operations work on every engine. Legend — ✅ tested live in the Docker stack · ⚠️ implemented, not yet tested (needs a licensed q process or cloud credentials) · — not yet implemented in that language (roadmap).
| Category | Engines | Python | Java |
|---|---|---|---|
| Relational | PostgreSQL, MySQL/MariaDB, SQLite | ✅ | ✅ |
| Relational (managed) | GCP Cloud SQL | ⚠️ | ⚠️ |
| Document | MongoDB | ✅ | ✅ |
| Document | CouchDB | ✅ | ✅ |
| Key-value | Redis | ✅ | ✅ |
| Key-value | Amazon DynamoDB | ✅ | ✅ |
| Wide-column | Cassandra / ScyllaDB | ✅ | ✅ |
| Object store | S3 / MinIO | ✅ | ✅ |
| Graph | Neo4j | ✅ | ✅ |
| Vector | Qdrant | ✅ | ✅ |
| Time-series | TimescaleDB, InfluxDB | ✅ | ✅ |
| Time-series | kdb+ / q | ⚠️ | — |
| Search | OpenSearch / Elasticsearch | ✅ | ✅ |
| Warehouse | BigQuery, Snowflake | ⚠️ | — |
Java has full parity on every Docker-testable engine — 14 engines, verified by the Java test suite. kdb+ and the cloud warehouses are the Java roadmap.
Real AWS S3 needs no separate adapter — the tested S3/MinIO adapter talks to AWS directly; just omit
endpoint_urland supply AWS credentials.
Security guardrails
- Read-only by default. Writes require
allow_writeon the connection. - Destructive operations need extra care.
DELETE/DROP/TRUNCATE/UPDATE-without-WHERE(and each engine's equivalents), pluscopy_datawithmode='replace'(which clears the target first), require bothallow_deleteand an explicitconfirm_destructive=true. - Reads stay reads.
run_queryaccepts only reads; the SQL adapters run them inside a rolled-back, server-side read-only transaction, so a data-modifying CTE orEXPLAIN ANALYZE DELETEthat slips past classification still can't write. - Result caps. Reads are clamped to the connection's
max_rows. - PII redaction.
redact_columnsare masked in read output. - No credentials to the model. Connections are pre-registered; the LLM only references them by name.
Guardrails live in the core and apply identically to the library and the MCP server, in both languages.
Repository structure
polyglot/ (monorepo)
├── python/ Python implementation → PyPI
│ ├── polyglot-core/ the library
│ ├── polyglot-mcp/ the MCP server
│ └── tests/
├── java/ Java implementation → Maven Central (dev.polyglot)
│ ├── polyglot-core/ the library
│ └── polyglot-mcp/ the MCP server
├── examples/ SHARED: docker-compose stack, seed data, connection configs
├── README.md (this file)
├── ANALYSIS.md · TESTING.md · PUBLISHING.md
├── CONTRIBUTING.md · CODE_OF_CONDUCT.md · LICENSE
└── .mcp.json attaches the server to Claude Code sessions
The package names are identical across languages: PyPI polyglot-core /
polyglot-mcp, and Maven dev.polyglot:polyglot-core /
dev.polyglot:polyglot-mcp (the reverse-DNS groupId provides uniqueness).
Absolute paths in configs:
.mcp.json,examples/claude_desktop_config.json, and thesqlite_notesentry inexamples/connections.jsonhold machine-specific absolute paths (the interpreter,POLYGLOT_CONFIG, and the SQLite file). If you clone to a different location, update those paths and recreate the.venv.
License
Apache License 2.0 — see LICENSE. Copyright 2026 The Polyglot Authors.