https://db-mcp.tigzig.com/mcpOverview
This MCP server is also listed in the machine-readable MCP directory at /.well-known/mcp/servers.json. Connect a transport below and run read-only SQL as a tool call.
A security-hardened, read-only SQL query API exposing two databases as MCP tools for AI clients - an open endpoint for public use and an Auth0-secured endpoint for gated access. Connect from Claude Code, Claude Desktop, Claude.ai (web connectors), Claude in Excel, or any MCP client. Setup instructions in the README.
Prefer plain HTTP? The two query endpoints below take POST with a JSON body (primary; no URL-length limit). They also accept GET ...?sql=<url-encoded SQL> for fetch-only clients (browsers, no-code HTTP nodes) that cannot send a body.
MCP endpoints
Open MCP endpoint (no auth)
https://db-mcp.tigzig.com/mcp- Streamable HTTP, the recommended transport (MCP spec 2025-03-26). No API key, no login on any open endpoint - safe because of the 23-layer stack below.
Secured MCP endpoint (Auth0 OAuth)
https://db-mcp.tigzig.com/mcp-secure- Streamable HTTP, Auth0-gated (recommended). Requires Auth0 login with an email whitelist - same databases and tools as the open endpoint, with authentication on top.
What's inside
Two databases, ~2 million rows of cricket ball-by-ball data (2013-2025):
- Postgres (Supabase) - ODI cricket, ~1M rows.
- DuckDB (embedded) - T20 cricket, ~1M rows.
- Both read-only at database and application level.
- JSON and TSV output (TSV uses ~70% fewer tokens).
Exact table and column names live in one canonical place, not copied here (so they can never drift): the query endpoint's own description in Swagger / openapi.json - the same text an MCP client hands the model as the tool description. The service root db-mcp.tigzig.com/ lists the tables too, and any query against a wrong table or column returns a 400 that hands back the real tables, all columns, and working calls.
Security hardening
The open endpoint is intentionally public - anyone with the URL can query. This is safe because of a 23-layer defense stack covering:
- Cloudflare WAF + application-level rate limiting.
- Per-IP and global concurrency caps.
- 12-layer SQL validation - prefix allowlist, keyword blocklist, resource-exhaustion blocking, self-join detection, response size limits, comment rejection.
- System-catalog and metadata-function blocking.
- Query timeouts with DuckDB engine interrupt.
- Database-level read-only enforcement (Postgres + DuckDB) and container resource limits.
- Error-message sanitization - no internal details leaked.
- Auth0 OAuth with JWT verification on the secured endpoint.
Full details in the README. For the broader web-app security checklist (120 items across all stacks), see tigzig.com/security.
Deploy your own (open source)
The source is open (Apache 2.0) - the repo runs the read-only SQL MCP server; point it at your own Postgres or DuckDB.
github.com/amararun/shared-fastapi-database-mcp
Built on FastAPI, fastapi-mcp, asyncpg, DuckDB, SlowAPI.
Auth0 OAuth is optional - the repo covers enabling the secured endpoint or running open-only.
Guides
This page is the reference - what the endpoints are and how to call them. The guides below are the long-form versions, with worked examples and the edges you only meet in real use:
- Demystifying the API errors - what each error actually means and what to do about it, instead of guessing from a status code. Covers every TigZig API, not just this one.
- Your agents and scripts have been talking to me - what real callers actually do, read out of the server logs: the common mistakes, what works, and the patterns worth copying.
Each is a plain page with a Markdown twin, so you can hand a URL straight to an agent. Come back to this page when you want parameter-level detail.
Rate limits
Published so a well-behaved client can plan around them. These are per-IP limits:
- Per IP: 30 requests / minute.
- At most 4 concurrent queries per IP.
You get a 429 with Retry-After and a body naming the budget you crossed.
Avoiding 429s: These are ~1M-row tables, so aggregate or LIMIT server-side in the SQL rather than paginating. One GROUP BY costs a single request where pagination costs dozens.
Every successful response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (Unix epoch seconds), read straight from the running limiter, and Retry-After is set on 429. The current numbers are also published as machine-readable JSON at https://db-mcp.tigzig.com/, derived from live config. Read those at runtime rather than hard-coding the figures above - limits change, and these channels change with them.
API Endpoints (REST / HTTP)
https://db-mcp.tigzig.comPrepend this to every path listed below (e.g. /series becomes https://db-mcp.tigzig.com/series). The curl example on each card shows the full URL.Generated from the live OpenAPI spec - always in sync with the API. Try them interactively in Swagger.
/v1/query/duckdb
Run read-only SQL on DuckDB - T20 Cricket ball-by-ball data
Execute a read-only SQL query against the DuckDB database. Contains ~1M rows of T20 (Twenty20) cricket ball-by-ball data from 2013 onwards. Table: ball_by_ball. Columns: match_id, season, start_date, venue, innings, ball, batting_team, bowling_team, striker, non_striker, bowler, runs_off_bat, extras, wides, noballs, byes, legbyes, penalty, wicket_type, player_dismissed, other_wicket_type, other_player_dismissed, match_type. Supports JSON (default) and TSV response formats. TSV uses shortened headers and is ~70% smaller (better for AI context windows).
curl -X POST "https://db-mcp.tigzig.com/v1/query/duckdb" -H 'Content-Type: application/json' -d '{"sql":"SELECT striker, SUM(runs_off_bat) AS runs, COUNT(*) AS balls FROM ball_by_ball WHERE season = '\''2023'\'' GROUP BY striker ORDER BY runs DESC LIMIT 10","format":"json"}'/v1/query/postgres
Run read-only SQL on Postgres (Supabase) - ODI Cricket ball-by-ball data
Execute a read-only SQL query against the Supabase Postgres database. Contains ~1M rows of ODI (One Day International) cricket ball-by-ball data from 2013 onwards. Table: odi_cricket_ball_by_ball. Columns: match_id, season, start_date, venue, innings, ball, batting_team, bowling_team, striker, non_striker, bowler, runs_off_bat, extras, wides, noballs, byes, legbyes, penalty, wicket_type, player_dismissed, other_wicket_type, other_player_dismissed, match_type. Supports JSON (default) and TSV response formats. TSV uses shortened headers and is ~70% smaller (better for AI context windows).
curl -X POST "https://db-mcp.tigzig.com/v1/query/postgres" -H 'Content-Type: application/json' -d '{"sql":"SELECT striker, SUM(runs_off_bat) AS runs, COUNT(*) AS balls FROM odi_cricket_ball_by_ball WHERE season = '\''2023'\'' GROUP BY striker ORDER BY runs DESC LIMIT 10","format":"json"}'