Skip to content

MCP Server

The server exposes nine tools for disposable two-database experiments. Track A runs the installed dbwarden CLI; Track B builds a SQLAlchemy reference schema. Their schema dumps are compared, and failing workspaces can be frozen with proof bundles.

Start

uv run python -m mcp_server

Transport is MCP over standard input/output, with no HTTP listener. Configure this command in an MCP client. Model files contain executable Python and must come from trusted callers.

SQLite needs no Docker. For SQLite-only use:

$env:MCP_WARM_POOL_ENABLED = '0'
uv run python -m mcp_server

Importing mcp_server.server registers tools without starting containers. run_server() starts the warm pool and shuts it down on exit.

Tools

Tools return JSON encoded as text. Invalid input raises a tool error.

Tool Arguments Behavior
initialize_workspace backend, optional db_version, name_prefix Creates Track A/B providers; returns ID, backend/version, directory and URLs. Backends: sqlite, postgresql (postgres alias), mysql, mariadb, clickhouse. Prefix accepts 1–64 letters, digits, underscores or hyphens.
destroy_workspace workspace_id Releases providers and active registration. Unknown ID returns removed: false. Files remain on disk.
list_workspaces None Returns IDs, backend/version, paths, creation times and frozen status.
write_model_file workspace_id, relative_path, content Writes within workspace and returns byte count. app/models.py updates initial/current source. Rejects absolute paths, resolved escapes and frozen-workspace writes.
apply_mutation workspace_id, mutation Edits current model source and records mutation; returns source and applied mutations. Frozen workspaces reject changes.
run_two_track_test workspace_id, reference_mode="nuclear" Returns track stages, errors, plan, schema differences, classification and optional bundle path. Mode must be nuclear or incremental.
read_file workspace_id, relative_path Reads UTF-8 text inside workspace, including frozen workspaces.
inspect_schema workspace_id Returns native dumps for both databases. Individual failures appear as ERROR: ... strings.
query_database workspace_id, sql, read_only=true Queries Track A and returns row objects. Writes require false and commit on success. Statements without rows return an empty list. Frozen workspaces allow only reads.

Read-only SQL must parse as one query without DDL, DML, INTO, or row locks. Connections also enable backend read-only mode. This protects database state; it does not sandbox model Python or guarantee database functions have no external effects. SQLite guards have local coverage; server guards require backend integration runs.

Mutations

Helpers edit annotated Mapped[...] = mapped_column(...) declarations through Python's AST. Rendering changes formatting and removes comments. Type changes require the first positional argument to be a SQLAlchemy type. Missing type imports are added. Unsupported source shapes raise MutationError; use write_model_file to preserve formatting or supply arbitrary code.

type Required fields Optional fields
add_column table, column, column_type nullable (true), default
change_type table, column, new_type None
add_index table, columns unique (false); adds a SQLAlchemy Index with all listed columns, preserving literal table options
drop_column table, column None
set_not_null, drop_not_null table, column None
set_default table, column, default None
drop_default table, column None

Reference modes and limits

set_default and drop_default edit the SQLAlchemy client-side default argument. They do not edit server_default. Dropping a column does not rewrite constraints or indexes that reference it.

nuclear recreates reference schema from current SQLAlchemy metadata. incremental compiles recorded add-column mutations from mutated metadata with the backend dialect; other mutations and an empty list fall back to recreation. These paths compare structure, not data preservation or dbwarden metadata that SQLAlchemy does not emit.

SQLite dumps use Python's standard library. PostgreSQL requires pg_dump on PATH; MySQL and MariaDB require mysqldump. ClickHouse uses its client. The comparator parses SQL and retains literals, qualified identifiers, constraint names and table options. It ignores dbwarden bookkeeping tables, sorts statements and table constraints, and canonicalizes simple primary keys. Unsupported SQL raises an error. Equivalent but differently named constraints still differ; use matching naming conventions in both models.

Classification values 95 and 5 label standard versus unsupported/exotic paths. They are not measured success rates or confidence scores. Bundles retain models, migration artifacts, dumps, differences and reproduction material. Bundle files are read-only with a hash manifest, not immutable storage. Frozen workspaces remain readable.

Track A reads plans beside SQL in migrations/primary/. Errors retain stdout and stderr. Pool claims match requested provider version.

Configuration

Variable Default Effect
DBWARDEN_HARNESS_ROOT /tmp/dbwarden-mcp-workspaces Workspace directory; override on Windows if needed.
DBWARDEN_HARNESS_BUG_REPORTS_DIR bug-reports Proof bundle directory.
MCP_MAX_WORKSPACES 20 Active workspace limit.
MCP_WARM_POOL_ENABLED 1 Starts pool when equal to 1.
MCP_WARM_POOL_POSTGRES 5 PostgreSQL container target.
MCP_WARM_POOL_MYSQL 3 MySQL container target.
MCP_WARM_POOL_MARIADB 3 MariaDB container target.
MCP_WARM_POOL_CLICKHOUSE 3 ClickHouse container target.
MCP_POSTGRES_VERSION 16 PostgreSQL image tag.
MCP_MYSQL_VERSION 8.0 MySQL image tag.
MCP_MARIADB_VERSION 11.4 MariaDB image tag.
MCP_CLICKHOUSE_VERSION 24.3 ClickHouse image tag.

See Python API for signatures and fields, and Environment Variables for suite settings.