trackmcp
Back to directory

A secure, read-only MCP server for querying MySQL, PostgreSQL, and Redis datasources

1 stars PythonOthers Updated Aug 5, 2026
mcpmysqlpgsqlredissql

Documentation


Every query passes through a layered safety pipeline before it ever reaches your database — so you can give an AI assistant data-access capabilities without handing it a loaded gun.

Table of Contents

Why use this?

  • Read-only by design. Writes are structurally impossible — there is no `execute` path that ever mutates data.
  • Defense in depth. SQL is validated three ways (SELECT enforcement → injection detection → automatic LIMIT). Redis commands are restricted to an explicit allowlist.
  • Secrets never leave your config. Passwords are loaded from env vars and stripped from logs and error messages.
  • One server, many datasources. Connect to all your databases through a single MCP endpoint.
  • Works with any MCP client — Claude Code, Cursor, Windsurf, and anything else that speaks MCP.

Features

  • Query multiple MySQL, PostgreSQL, and Redis instances through one server
  • Three-layer SQL safety (SELECT enforcement + injection detection + automatic LIMIT)
  • Redis command allowlist (only explicitly safe read-only commands)
  • Markdown output for efficient AI context usage
  • stdio, SSE, and streamable-http transports
  • Docker Compose stack with seed data for local development

Quick Start

Requirements

  • Python 3.10+
  • Docker and Docker Compose (optional, for containerized deployment)

Install and run locally

bash
# Clone
git clone https://github.com/pennxiv/thoth-mcp.git
cd thoth-mcp

# Set up a virtual environment
python -m venv .venv
source .venv/bin/activate  # or .venv\Scripts\activate on Windows

# Install
pip install -e ".[dev]"

# Point at your datasources and run
export THOTH_DATASOURCES_FILE=config/datasources.yaml
python -m thoth_mcp

Run with Docker

bash
# Starts the server in streamable-http mode on port 8080
docker compose up -d --build

# Connect from any machine on your network:
# http://:8080/mcp

Connect your MCP client

Claude Code (`~/.claude.json` or project `.mcp.json`):

json
{
  "mcpServers": {
    "thoth": {
      "url": "http://:8080/mcp",
      "transport": "streamable-http"
    }
  }
}

Cursor / Windsurf (`.cursor/mcp.json`):

json
{
  "mcpServers": {
    "thoth": {
      "url": "http://:8080/mcp",
      "transport": "streamable-http"
    }
  }
}

For local-only use, configure the client to launch the server over stdio instead — no HTTP exposure needed.

Configuration

Create a `datasources.yaml` file (or set `THOTH_DATASOURCES_FILE` to point at one):

yaml
mysql:
  prod_db:
    host: mysql.example.com
    port: 3306
    user: readonly_user
    password: ${MYSQL_PROD_PASSWORD}  # overridden via environment variable
    database: production
    min_pool_size: 1
    max_pool_size: 10

redis:
  cache:
    host: redis.example.com
    port: 6379
    db: 0
    min_pool_size: 1
    max_pool_size: 10

Supplying secrets

Passwords should never live in config files. Override them via environment variables using the pattern `THOTH_____PASSWORD`:

bash
export THOTH_MYSQL__PROD_DB__PASSWORD=secret123
export THOTH_POSTGRES__WAREHOUSE__PASSWORD=another_secret
export THOTH_REDIS__CACHE__PASSWORD=redis_secret

See `config/datasources.yaml` for a full example with all three datasource types.

MCP Tools

ToolDescription
`query_mysql(datasource, sql)`Execute a SELECT query against a MySQL datasource
`list_tables(datasource)`List all tables in a MySQL datasource
`describe_table(datasource, table)`Show column details for a MySQL table
`query_postgres(datasource, sql)`Execute a SELECT query against a PostgreSQL datasource
`list_tables_postgres(datasource)`List all tables in a PostgreSQL datasource (public schema)
`describe_table_postgres(datasource, table)`Show column details for a PostgreSQL table
`query_redis(datasource, command, args?)`Execute a safe read-only Redis command
`list_datasources()`List all configured MySQL, PostgreSQL, and Redis datasources

Security

This server is built around the assumption that anything reaching the database must be read-only and injection-free.

SQL safety (three-layer defense)

1. SELECT-only enforcement — only SELECT statements are permitted.

2. Injection pattern detection — blocks UNION injection, comment obfuscation, and multi-statement attacks.

3. Automatic LIMIT injection — queries without a LIMIT clause receive a default limit (100 rows) to prevent unbounded scans.

Redis safety

Only these read-only commands are permitted: `GET`, `HGET`, `HGETALL`, `LRANGE`, `SMEMBERS`, `TTL`, `TYPE`, `LLEN`, `SCARD`, `EXISTS`, `HEXISTS`, `SRANDMEMBER`, `ZCARD`, `ZSCORE`, `ZRANGE`.

Commands like `SET`, `DEL`, `KEYS`, and `FLUSHALL` are explicitly blocked.

Error sanitization

Error messages never expose hostnames, IPs, connection strings, or credentials. This holds even when connection setup or query execution fails.

Network exposure

When running in `streamable-http` or `sse` mode, the server listens on `0.0.0.0:8080` by default. Place it behind authenticated network boundaries — do not expose it directly to the public internet without additional auth. See SECURITY.md.

Transports

ModeUse caseEnv
`stdio` (default)Client and server on the same machine`MCP_TRANSPORT=stdio`
`streamable-http`Remote clients over HTTP`MCP_TRANSPORT=streamable-http`
`sse`Browser-based / unidirectional streaming`MCP_TRANSPORT=sse`
VariableDefaultDescription
`MCP_TRANSPORT``stdio`Transport mode
`MCP_HOST``0.0.0.0`Listen host (http/sse only)
`MCP_PORT``8080`Listen port (http/sse only)
`THOTH_API_TOKEN`*(unset)*Bearer token required for HTTP clients (http/sse only)

SSE mode exposes `/sse` (client connections) and `/messages/` (POST endpoint).

API Token Authentication

When serving over HTTP transports (`streamable-http` or `sse`) you should

set `THOTH_API_TOKEN` to protect the server. With a token set, every MCP

request must carry an `Authorization: Bearer ` header; requests without

a valid token are rejected with `401 Unauthorized`. The `/health` endpoint is

always open for monitoring probes.

bash
# On the server
export THOTH_API_TOKEN=$(openssl rand -hex 32)   # generate a strong token
export MCP_TRANSPORT=streamable-http
export MCP_PORT=8080
python -m thoth_mcp
bash
# On the client (curl)
curl -H "Authorization: Bearer " http://server:8080/mcp

When `THOTH_API_TOKEN` is unset, authentication is disabled — suitable for

local `stdio` usage, but **never expose an unauthenticated HTTP instance to

the public internet**.

Architecture

code
┌──────────────────────────────────────────────────────────────┐
│                      FastMCP Server                          │
│  ┌─────────────┐ ┌──────────────┐ ┌─────────────┐          │
│  │ MySQL Tools │ │PostgreSQL    │ │ Redis Tools │          │
│  │             │ │Tools         │ │             │          │
│  └──────┬──────┘ └──────┬───────┘ └──────┬──────┘          │
│         │               │                │                  │
│  ┌──────▼──────┐ ┌──────▼───────┐ ┌──────▼──────┐          │
│  │ MySQL Pool  │ │PostgreSQL    │ │ Redis Pool  │          │
│  │   Manager   │ │Pool Manager  │ │   Manager   │          │
│  └──────┬──────┘ └──────┬───────┘ └──────┬──────┘          │
│         │               │                │   ┌──────────┐  │
│  ┌──────▼──────┐ ┌──────▼───────┐ ┌──────▼──────┐          │
│  │  SQL Safety │ │  SQL Safety  │ │Redis Safety │          │
│  └──────┬──────┘ └──────┬───────┘ └──────┬──────┘          │
│         └───────────────┴────────────────┴───│  Config  │  │
│                                              └──────────┘  │
└──────────────────────────────────────────────────────────────┘
          │               │                │
     ┌────▼────┐    ┌────▼─────┐     ┌────▼────┐
     │  MySQL  │    │PostgreSQL│     │  Redis  │
     │   DB    │    │    DB    │     │Instance │
     └─────────┘    └──────────┘     └─────────┘

Development

bash
# Run the test suite
pytest tests/ -v

# Run a single test file
pytest tests/test_mysql_tools.py -v

# Run with coverage
pytest tests/ --cov=src/thoth_mcp --cov-report=html

# Lint
ruff check src/ tests/

See CONTRIBUTING.md for contribution guidelines and CHANGELOG.md for version history.

Project structure

code
thoth-mcp/
├── src/thoth_mcp/
│   ├── config.py          # Configuration loading
│   ├── server.py          # FastMCP server assembly
│   ├── __main__.py        # Entry point
│   ├── db/                # Connection pool managers (mysql, postgresql, redis)
│   ├── tools/             # MCP tools (mysql, postgresql, redis, discovery)
│   └── utils/             # Safety layers, formatters, logging
├── tests/                 # Test suite
├── docker/                # Docker seed data
├── config/                # Example configurations
└── pyproject.toml

License

MIT License — see LICENSE.

Frequently asked questions

What is thoth-mcp?

thoth-mcp is A secure, read-only MCP server for querying MySQL, PostgreSQL, and Redis datasources

How do I install thoth-mcp?

Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.

Is thoth-mcp open source?

Yes — it is hosted on GitHub at https://github.com/pennxiv/thoth-mcp and has 1 stars.

Related MCP tools

Run your own MCP server? See who uses it and what to fix.

Measure it with TrackMCP