Sql Mcp
API | MCP Server | A2A Agent
Generic SQL database API + MCP Server + A2A Agent for the agent-utilities ecosystem — one connector for PostgreSQL, MySQL/MariaDB, Microsoft SQL Server, Oracle, and SQLite over SQLAlchemy 2.x Core.
Version: 1.0.1
Documentation — Installation, deployment, and usage across the API, CLI, and MCP interfaces are maintained in
docs/.
Table of Contents
- Overview
- What it provides
- MCP tools
- Dialects & extras
- Configuration (environment)
- Installation
- Usage
- MCP config
- Docker deployment
- Safety model
- Tests
Overview
sql-mcp exposes read-only queries, gated DML/DDL, schema reflection, and
connection administration as typed, deterministic MCP tools, and ships an optional
Pydantic-AI agent server. It is read-only by default: every query passes a
statement-type allowlist, every result is bounded by a row cap and a timeout, and
all values travel as bound parameters — never interpolated into SQL strings.
What it provides
SqlApi(sql_mcp.api.api_client_sql) — a SQLAlchemy 2.x Core facade with named multi-connection support, lazy engine creation, the read-only statement gate, row-cap/timeout enforcement, and bounded result envelopes ({columns, rows, row_count, truncated}).- Four MCP tools (
sql-mcpconsole script):sql_query(execute/explain),sql_execute(execute/script — gated bySQL_ALLOW_WRITES),sql_schema(schemas/tables/views/columns/indexes/foreign_keys/ddl/sample), andsql_admin(ping/version/active_connections/connections/dialects). Seedocs/usage.mdfor the full action surface. - A dialect registry (
sql_mcp.dialects) — per-engine driver, URL scheme, pip extra, EXPLAIN prefix, and admin SQL. Core ships SQLite only; the other drivers install via extras. - An A2A agent server (
sql-agentconsole script) — a Pydantic-AI graph agent wired to the MCP server viaMCP_URL.
MCP tools
The table below is auto-generated from the MCP server — do not edit by hand.
Condensed action-routed tools (default — MCP_TOOL_MODE=condensed)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
sql_admin |
SQLTOOL |
Connection health, server version, sessions, and registry info. |
sql_schema |
SQLTOOL |
Inspect schemas, tables, views, columns, indexes, FKs, and DDL. |
Verbose 1:1 API-mapped tools (MCP_TOOL_MODE=verbose or both)
22 per-operation tools — one per public API method (click to expand)
| MCP Tool | Toggle Env Var | Description |
|---|---|---|
sql_active_connections |
SQL_APITOOL |
List active server sessions where the dialect supports it. |
sql_connection_names |
SQL_APITOOL |
Names of all configured connections. |
sql_default_connection |
SQL_APITOOL |
The sole/first configured connection — used when none is named. |
sql_describe_connections |
SQL_APITOOL |
Describe configured connections with passwords redacted. |
sql_dialect_spec |
SQL_APITOOL |
The registered :class:DialectSpec for a connection, if any. |
sql_dispose |
SQL_APITOOL |
Dispose all pooled engines. |
sql_engine |
SQL_APITOOL |
Lazily create (and cache) the Engine for a named connection. |
sql_execute |
SQLTOOL |
Execute one DML/DDL statement in a transaction (writes gate applies). |
sql_execute_script |
SQL_APITOOL |
Run several statements in ONE transaction (all-or-nothing). |
sql_explain |
SQL_APITOOL |
Return the dialect's query plan for a read-only statement. |
sql_list_columns |
SQL_APITOOL |
Describe a table's columns: name, type, nullable, default. |
sql_list_foreign_keys |
SQL_APITOOL |
List a table's foreign keys (columns -> referred table/columns). |
sql_list_indexes |
SQL_APITOOL |
List a table's indexes (name, columns, uniqueness). |
sql_list_schemas |
SQL_APITOOL |
List schema names. |
sql_list_tables |
SQL_APITOOL |
List table names (optionally within a schema). |
sql_list_views |
SQL_APITOOL |
List view names (optionally within a schema). |
sql_ping |
SQL_APITOOL |
Connection test: SELECT 1 round-trip with latency. |
sql_query |
SQLTOOL |
Execute a read-only SELECT/CTE with bound parameters. |
sql_resolve_connection |
SQL_APITOOL |
Map an optional connection name to a configured one (or raise). |
sql_sample_rows |
SQL_APITOOL |
Return up to limit rows from a table (cap still applies). |
sql_server_version |
SQL_APITOOL |
Report the server version (dialect SQL, else SQLAlchemy's probe). |
sql_table_ddl |
SQL_APITOOL |
Reflect a table and render its CREATE TABLE DDL for this dialect. |
2 action-routed tool(s) (default) · 22 verbose 1:1 tool(s). Each is enabled unless its <DOMAIN>TOOL toggle is set false; MCP_TOOL_MODE selects the surface (condensed default · verbose 1:1 · both). Auto-generated — do not edit.
Every tool takes action, params_json, and an optional connection naming one
of the configured connections. The whole set is toggled with SQLTOOL.
Dialects & extras
| Dialect | SQLAlchemy scheme | Driver | Install |
|---|---|---|---|
| SQLite | sqlite+pysqlite |
stdlib | pip install sql-mcp (core) |
| PostgreSQL | postgresql+psycopg |
psycopg 3 | pip install sql-mcp[postgres] |
| MySQL / MariaDB | mysql+pymysql |
PyMySQL | pip install sql-mcp[mysql] |
| SQL Server | mssql+pyodbc |
pyodbc | pip install sql-mcp[mssql] |
| Oracle | oracle+oracledb |
python-oracledb | pip install sql-mcp[oracle] |
pip install sql-mcp[all] pulls every driver plus the MCP and agent extras.
Configuration (environment)
| Var | Default | Meaning |
|---|---|---|
SQL_CONNECTIONS |
(empty) | JSON map of named connections: DSN strings or {dialect, host, port, username, password, database, options} objects |
SQL_URL |
(empty) | Single DSN registered as connection default |
SQL_DIALECT / SQL_HOST / SQL_PORT / SQL_USERNAME / SQL_PASSWORD / SQL_DATABASE / SQL_OPTIONS |
(empty) | Discrete fields for a single default connection |
SQL_ALLOW_WRITES |
False |
Enable sql_execute (DML/DDL). Read-only by default |
SQL_MAX_ROWS |
500 |
Per-call row cap; tool requests are clamped to it |
SQL_TIMEOUT_SECONDS |
30 |
Per-statement timeout |
SQLTOOL |
True |
Register the SQL tool set |
With nothing configured the server registers a zero-infra in-memory SQLite
connection named memory, so it works out of the box. Tools take an optional
connection parameter naming one of the configured connections; it defaults to
the sole/first one. Passwords are parsed into sqlalchemy.URL objects and only
ever rendered redacted. Copy .env.example to .env and
populate only what you use.
Installation
Pick the extra that matches what you want to run. DB-driver extras
(postgres / mysql / mssql / oracle) are additive — combine them with
[mcp] or [agent], e.g. sql-mcp[mcp,postgres] (see Dialects & extras).
| Extra | Installs | Use when |
|---|---|---|
sql-mcp[mcp] |
Slim MCP server only (agent-utilities[mcp] — FastMCP/FastAPI) |
You only run the MCP server (smallest install / image) |
sql-mcp[agent] |
Full agent runtime (agent-utilities[agent,logfire] — Pydantic AI + the epistemic-graph engine) |
You run the integrated agent |
sql-mcp[all] |
Everything (mcp + agent + every DB driver + logfire) |
Development / both surfaces |
pip install sql-mcp # core (SQLite only, MCP server, API)
pip install "sql-mcp[mcp]" # slim MCP server (add drivers: [mcp,postgres])
pip install "sql-mcp[agent]" # full agent runtime (Pydantic AI + engine)
pip install "sql-mcp[all]" # every driver + MCP + agent extras
pip install -e . # from source
Container images (:mcp vs :agent)
One multi-stage docker/Dockerfile builds two right-sized images, selected by --target:
| Image tag | Build target | Contents | Entrypoint |
|---|---|---|---|
knucklessg1/sql-mcp:mcp |
--target mcp |
sql-mcp[mcp] — slim, no engine/pydantic-ai/dspy/llama-index/tree-sitter |
sql-mcp |
knucklessg1/sql-mcp:latest |
--target agent (default) |
sql-mcp[agent] — full agent runtime + epistemic-graph engine |
sql-agent |
docker pull knucklessg1/sql-mcp:mcp # slim MCP server
docker build --target mcp -t knucklessg1/sql-mcp:mcp docker/ # build slim MCP server
docker build --target agent -t knucklessg1/sql-mcp:latest docker/ # build full agent
docker/mcp.compose.yml runs the slim :mcp server; docker/agent.compose.yml runs the
agent (:latest) with a co-located :mcp sidecar.
Knowledge-graph database (epistemic-graph)
The full agent ([agent] / :latest) embeds the epistemic-graph engine (pulled in
transitively via agent-utilities[agent]). For production — or to share one knowledge graph
across multiple agents — run epistemic-graph as its own database container and point the
agent at it instead of embedding it. Deployment recipes (single-node + Raft HA), connection
config, and the full database architecture (with diagrams) are documented in the
epistemic-graph deployment guide.
The slim [mcp] server does not require the database.
Usage
sql-mcp # stdio MCP server (default transport)
sql-mcp --transport streamable-http --host 0.0.0.0 --port 8000
Point it at a database:
export SQL_URL="postgresql+psycopg://svc:****@db.example.com:5432/app"
sql-mcp
Or several:
export SQL_CONNECTIONS='{
"warehouse": "postgresql+psycopg://svc:****@dw.example.com:5432/dw",
"erp": {"dialect": "mysql", "host": "erp.example.com", "username": "svc",
"password": "****", "database": "erp"}
}'
sql-mcp
Run the agent server against a live MCP server:
sql-agent --mcp-url http://localhost:8000/mcp --host 0.0.0.0 --port 8080
MCP config
Install the slim
[mcp]extra. For MCP-server hosting installsql-mcp[mcp](add DB-driver extras as needed, e.g.sql-mcp[mcp,postgres]) — the MCP-server extra pulls only the FastMCP / FastAPI tooling (agent-utilities[mcp]). It deliberately excludes the heavy agent runtime (the epistemic-graph engine,pydantic-ai,dspy,llama-index,tree-sitter), souvx/container installs are dramatically smaller and faster. Use the full[agent]extra only when you need the integrated Pydantic AI agent (see Installation).
{
"mcpServers": {
"sql-mcp": {
"command": "uv",
"args": ["run", "sql-mcp"],
"env": {
"SQL_URL": "postgresql+psycopg://svc:****@db.example.com:5432/app",
"SQL_ALLOW_WRITES": "False"
}
}
}
}
Additional Deployment Options
sql-mcp can also run as a local container (Docker / Podman / uv) or be
consumed from a remote deployment. The
Deployment guide has full, copy-paste
mcp_config.json for all four transports — stdio, streamable-http,
local container / uv, and remote URL:
- Local container / uv — launch the server from
mcp_config.jsonviauvx,docker run, orpodman run, or point at a local streamable-http container byurl. - Remote URL — connect to a server deployed behind Caddy at
http://sql-mcp.arpa/mcpusing the"url"key.
Docker deployment
docker compose -f docker/mcp.compose.yml up -d # MCP server only
docker compose -f docker/agent.compose.yml up -d # MCP + A2A agent
curl -s http://localhost:8000/health # {"status":"OK"}
Both services read configuration from ../.env (copy
.env.example); see docs/deployment.md.
Safety model
- Read-only by default —
sql_executerefuses to run unless the server was started withSQL_ALLOW_WRITES=True; agents cannot flip the flag per call. - Statement allowlist —
sql_queryaccepts onlySELECT/WITH/EXPLAIN/SHOW/DESCRIBE/PRAGMA/VALUES; CTEs are inspected at paren depth zero soWITH ... INSERTcannot smuggle a write,SELECT INTOis rejected, and multi-statement payloads are refused. - Bounded results — per-call row caps clamp to
SQL_MAX_ROWS; statements run underSQL_TIMEOUT_SECONDSon a worker thread. - Parameterized only — values bind via
:nameparameters; identifiers are quoted by SQLAlchemy reflection, never hand-interpolated.
Tests
python -m pytest # full suite against in-memory SQLite (no live DBs)
pre-commit run --all-files
Deploy with agent-os-genesis
This package can be provisioned for you — skill-guided — by the agent-os-genesis
universal skill (its single-package deploy mode): it picks your install method, seeds
secrets to OpenBao/Vault (or .env), trusts your enterprise CA, registers the MCP
server, and verifies it — the same machinery that stands up the whole Agent OS, narrowed
to just this package. Ask your agent to "deploy sql-mcp with agent-os-genesis".
| Install mode | Command |
|---|---|
| Bare-metal, prod (PyPI) | uvx sql-mcp · or uv tool install sql-mcp |
| Bare-metal, dev (editable) | uv pip install -e ".[all]" · or pip install -e ".[all]" |
| Container, prod | deploy knucklessg1/sql-mcp:latest via docker-compose / swarm / podman / podman-compose / kubernetes |
| Container, dev (editable) | deploy docker/compose.dev.yml (source-mounted at /src; edits live on restart) |
Secrets are read-existing + seeded via vault_sync — you are only prompted for what's missing.
Environment Variables
Package environment variables
| Variable | Example | Description |
|---|---|---|
HOST |
0.0.0.0 |
|
PORT |
8000 |
|
TRANSPORT |
stdio |
options: stdio, streamable-http, sse |
ENABLE_OTEL |
True |
|
OTEL_EXPORTER_OTLP_ENDPOINT |
http://localhost:8080/api/public/otel |
|
OTEL_EXPORTER_OTLP_PUBLIC_KEY |
pk-... |
|
OTEL_EXPORTER_OTLP_SECRET_KEY |
sk-... |
|
OTEL_EXPORTER_OTLP_PROTOCOL |
http/protobuf |
|
EUNOMIA_TYPE |
none |
options: none, embedded, remote |
EUNOMIA_POLICY_FILE |
mcp_policies.json |
|
EUNOMIA_REMOTE_URL |
http://eunomia-server:8000 |
|
SQL_CONNECTIONS |
{"warehouse": "postgresql+psycopg://svc:password@db:5432/dw"} |
password, database, options} objects. Takes priority over SQL_URL. |
SQL_URL |
postgresql+psycopg://svc:password@db.example.com:5432/app |
Single connection (registered as "default") |
SQL_DIALECT |
postgres |
... or discrete fields for a single "default" connection |
SQL_HOST |
db.example.com |
|
SQL_PORT |
5432 |
|
SQL_USERNAME |
svc |
|
SQL_PASSWORD |
— | |
SQL_DATABASE |
app |
|
SQL_OPTIONS |
{"sslmode": "require"} |
|
SQL_ALLOW_WRITES |
False |
Policy (read-only by default) |
SQL_MAX_ROWS |
500 |
|
SQL_TIMEOUT_SECONDS |
30 |
|
SQLTOOL |
True |
Inherited agent-utilities variables (apply to every connector)
| Variable | Example | Description |
|---|---|---|
MCP_TOOL_MODE |
condensed |
Tool surface: condensed |
MCP_ENABLED_TOOLS |
— | Comma-separated tool allow-list |
MCP_DISABLED_TOOLS |
— | Comma-separated tool deny-list |
MCP_ENABLED_TAGS |
— | Comma-separated tag allow-list |
MCP_DISABLED_TAGS |
— | Comma-separated tag deny-list |
MCP_CLIENT_AUTH |
— | Outbound MCP auth (oidc-client-credentials for fleet calls) |
OIDC_CLIENT_ID |
— | OIDC client id (service-account auth) |
OIDC_CLIENT_SECRET |
— | OIDC client secret (service-account auth) |
DEBUG |
False |
Verbose logging |
PYTHONUNBUFFERED |
1 |
Unbuffered stdout (recommended in containers) |
MCP_URL |
http://localhost:8000/mcp |
URL of the MCP server the agent connects to |
PROVIDER |
openai |
LLM provider for the agent |
MODEL_ID |
gpt-4o |
Model id for the agent |
ENABLE_WEB_UI |
True |
Serve the AG-UI web interface |
24 package + 14 inherited variable(s). Auto-generated from .env.example + the shared agent-utilities set — do not edit.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sql_mcp-1.0.1.tar.gz.
File metadata
- Download URL: sql_mcp-1.0.1.tar.gz
- Upload date:
- Size: 41.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f373e9939eec7bc7629e9bd2195e5d59df605111f8e57486d06c05a9902cb01
|
|
| MD5 |
1b686ee034f78caea302f9648f3562c7
|
|
| BLAKE2b-256 |
b17260be28d5164c75ef171f49d36437d7fed472bdd2deaeb2dba754d8e3b6df
|
File details
Details for the file sql_mcp-1.0.1-py3-none-any.whl.
File metadata
- Download URL: sql_mcp-1.0.1-py3-none-any.whl
- Upload date:
- Size: 30.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a2057b9010e19dc86859dc2f426275c7f02b85abc90d22c248e48b8d7b5a889
|
|
| MD5 |
b9f011fd41bd3a96b6c83e5d30a0ae08
|
|
| BLAKE2b-256 |
fe4faf0dfa21ae856279259accc103ec6464fa6be9a0707cfa246a7602610797
|