QueryAPIGate
MCP server tự lưu trữ, biến các truy vấn SQL đã lưu của bạn thành công cụ cho các tác nhân AI, với đầu vào có kiểu dữ liệu. Máy chủ, chứ không phải prompt, kiểm soát quyền truy cập: cấp quyền theo từng khóa, che giấu cột, SQL tùy ý chỉ đọc, yêu cầu con người phê duyệt thao tác ghi, hạn mức và nhật ký kiểm toán chống giả mạo. Hỗ trợ PostgreSQL, MySQL, SQLite, DuckDB, ClickHouse, MongoDB và các tệp trên S3/GCS/R2. Apache-2.0.
Tài liệu
QueryAPIGate
Turn SQL into secure, governed REST APIs - and MCP tools for AI agents.
Every feature, one by one: the full walkthrough (6 minutes, in chapters)
Every front door runs the same checks, so an AI agent's call is governed exactly like an app's. Write the SQL once; it's a REST endpoint, an MCP tool, a live event stream and a scheduled export.
One path for REST, MCP, events and exports. A stage that fails stops the call with a typed error code - except recording, which never blocks the response.
QueryAPIGate is a self-hosted service that runs SQL against your databases - and against Parquet, CSV and JSON files on disk, S3, GCS or the web, through DuckDB - and returns the results as JSON, NDJSON, XML, YAML, CSV, TSV, Excel or Parquet. Save a query once and it becomes a versioned endpoint with typed, injection-safe parameters and run history - without writing a controller, a repository layer, pagination, auth or serialization boilerplate for it.
Write SQL. Configure the query. Apply access controls. Get an API.
$ curl 'http://127.0.0.1:5000/q/example_film_search?text=Harbor&page_size=2' -H 'X-API-Key: demo-key'
[{"film_id":48,"title":"Broken Harbor","category":"Action","rating":"PG-13"},{"film_id":44,"title":"Electric Harbor","category":"Documentary","rating":"G"}]
$ curl 'http://127.0.0.1:5000/q/example_top_films?top_n=2&category=Comedy&format=csv' -H 'X-API-Key: demo-key'
title,category,rating,rentals,rank
Electric Signal,Comedy,PG,977,1
Crimson Garden,Comedy,PG-13,631,2
The built-in Console at /console: write SQL with completion and a schema browser, run it, then save it as an API - no separate tool to install.
More of the Console - Home, connections, keys and roles, history, the audit log, metrics, alerts, the access map - screen by screen: a tour of the Console.
Contents
- Why QueryAPIGate
- Features
- Install · Quick start · Saving a query as an endpoint
- Try it with Docker
- Documentation
- Contributing · Security · License · Contact
Why QueryAPIGate
Valuable SQL sits in reports, dashboards, ETL jobs and application code, with no way to a REST endpoint except a backend service written around each query. QueryAPIGate makes the query itself the API: write the SQL once, and it is a versioned endpoint with typed parameters, governed by who may call it, how often and what they may see - and the same query is an MCP tool for AI agents, a live event stream and a scheduled export.
That MCP surface is a reason in itself: it's how you let an AI agent query production data without handing it a database connection. The agent sees only governed tools, ad-hoc SQL over MCP is always read-only, writes wait for a person's approval, and the same masking, limits and audit apply - the limits live in the gateway, where no prompt can talk its way around them. One governed core, two front doors that matter most: REST for your apps, MCP for your agents.
It doesn't replace an application backend; it removes the boilerplate when the requirement is "expose this query safely". Use cases, how it compares to PostgREST, Hasura and others, and the thinking behind it: why QueryAPIGate.
Features
- Saved, versioned queries as endpoints -
GET /q/<name>, typed and injection-safe parameters, drafts and publishing, run history. - Scoped API keys, roles and collections - per connection, per query or per collection; expiry, IP allow-lists, rate limits, quotas, table allow-lists.
- A governed MCP server for AI agents - saved queries as self-describing tools, read-only ad-hoc SQL, masking-aware schema discovery, OAuth sign-in, and write tools that wait for a person's approval - the same grants, masking and audit as every other caller.
- Named administrators and SSO - admin roles and tokens, Console sign-in through your identity provider, signed-in users' JWTs.
- Workspaces (experimental) - several teams on one server, each running its own connections, queries and keys, and administering nothing of another's.
- Column masking - hash, mask or drop what a caller mustn't see, traced through the SQL to the source column.
- Eight database types, and files - PostgreSQL, MySQL, SQLite, DuckDB, ClickHouse and MongoDB; H2 and JDBC; Parquet, CSV and JSON on S3, GCS, R2 or disk.
- Eight output formats, and streaming - JSON, NDJSON, XML, YAML, CSV, TSV, Excel and Parquet; whole results streamed from the database cursor.
- Exports to object storage - scheduled, incremental, to S3, GCS, R2 or a folder.
- Live events - every run as it happens, per key, with resume.
- A tamper-evident audit log - a signed hash chain, streamed to your SIEM.
- Observability - Prometheus metrics, OpenTelemetry tracing, alerts that clear themselves, a Grafana dashboard.
- Configuration as code and secrets from files and Vault.
- OpenAPI and Postman - every saved query a typed endpoint in
/openapi.jsonand/docs. - Docker, Helm and several instances - one PostgreSQL store, Redis for shared limits; signed releases with SLSA provenance.
Every feature in detail: features. Every setting: configuration.
Install
pip install "queryapigate[postgres]" # pick the drivers you need: mysql, postgres, clickhouse, h2, duckdb
# or everything: pip install "queryapigate[all]"
SQLite needs no extra driver. H2 and generic JDBC connections (queryapigate[h2]) also need a Java runtime; H2's own
driver jar is bundled, a JDBC connection to another vendor brings its own. DuckDB (queryapigate[duckdb]) needs no
external runtime either - it's a native Python extension, same as SQLite. queryapigate[encryption] adds
encryption at rest for connection passwords -
only needed if you set QUERYAPIGATE_SECRET_KEY.
From a clone: pip install -e ".[dev]". Or use Docker - see below.
Quick start
Fastest: queryapigate examples load && queryapigate serve installs four worked example APIs
(reporting, dashboard, export, partner) you can try, and queryapigate examples unload removes them again. Loading
them creates a real API key per scenario, which also means the server now requires a key for every request - set
QUERYAPIGATE_API_KEY yourself first so you have an admin key on hand for ad-hoc SQL too:
QUERYAPIGATE_API_KEY=demo-key queryapigate examples load # also prints one scoped key per scenario - store them now
QUERYAPIGATE_API_KEY=demo-key queryapigate serve # http://127.0.0.1:5000
The examples come with a small generated examples database (films, customers and rentals), so you can also run ad-hoc SQL
straight away:
curl -X POST 'http://127.0.0.1:5000/execute_sql?page_size=3' -H 'X-API-Key: demo-key' -H 'Content-Type: application/json' \
-d '{"sql": "SELECT film_id, title, rating FROM film WHERE film_id > :min", "params": {"min": 10}, "connection_name": "examples"}'
Open http://127.0.0.1:5000/docs for the interactive API reference, or http://127.0.0.1:5000/console for the admin UI to manage connections and saved queries and run ad-hoc SQL without leaving the browser.
For your own databases, run queryapigate init in an empty folder: it creates queryapigate.db with an
inactive template connection for every supported database type. Edit them (admin UI, or PATCH /api/v1/connections/<name>), set "active": true, and start the server there.
Saving a query as an endpoint
This uses the examples connection that queryapigate examples load sets up:
curl -X POST http://127.0.0.1:5000/api/v1/queries -H 'X-API-Key: demo-key' -H 'Content-Type: application/json' -d '{
"name": "film_by_id",
"sql": "SELECT * FROM film WHERE film_id = :id",
"parameters": {"id": {"type": "int", "min": 1, "max": 60, "description": "Film id"}},
"connection_name": "examples",
"author": "me", "description": "Look up a film",
"publish": true
}'
curl 'http://127.0.0.1:5000/q/film_by_id?id=7&format=yaml' -H 'X-API-Key: demo-key'
curl 'http://127.0.0.1:5000/q/film_by_id?id=0' -H 'X-API-Key: demo-key'
# {"error": "Invalid parameters: id must be at least 1", "errors": {"id": "must be at least 1"}}
Rules: type (int, float, str, bool), default, required, enum, min/max, min_length/max_length,
pattern and description - see the API reference.
POST /api/v1/queries/film_by_id/versions adds version 2 - a draft until published ("publish": true, or
POST .../publish); DELETE /api/v1/queries/film_by_id/versions/1 removes one version.
Add "cache_ttl": 60 to cache a response for that many seconds (X-Cache: HIT/MISS, ETag, Cache-Control) -
opt-in, and never used for a query that writes. See
Response caching.
Try it with Docker
Every release is published for linux/amd64 and linux/arm64, signed:
docker run -p 5000:5000 -v queryapigate-data:/data -e QUERYAPIGATE_API_KEY=change-me ghcr.io/anantharajuc/queryapigate:latest
Or start it in front of a PostgreSQL database seeded with sample films, with
docker-compose.yml:
docker compose up --build
curl -H 'X-API-Key: demo-key' 'http://127.0.0.1:5000/q/films_by_rating?rating=PG&max_length=90'
Open http://127.0.0.1:5000/docs, paste demo-key into the box at the top, and both saved queries are there as
endpoints; docker compose down -v cleans up.
The image tags, volumes and a real deployment - TLS, secrets, backups, Prometheus and Grafana, several instances, Kubernetes: deployment.
Documentation
The documentation site has all of it; on GitHub:
| Start | Installation and setup · Configuration · Example APIs · How-to guides |
| Reference | API · MCP server · Database connections · Query metadata · Features |
| Run it | Deployment · Performance · Technology stack · A tour of the Console |
| Security | Security policy · Threat model · Where data goes |
| Project | Why QueryAPIGate · Changelog · Roadmap · Architecture decisions |
Contributing
Contributions are welcome - database drivers, security, performance, the Console, documentation, tests. Please read CONTRIBUTING.md first: the development setup, the tests, and how a change gets in.
Security
Report a vulnerability privately - see SECURITY.md, which also has the hardening checklist for a deployment and how to verify a release.
Third-party components
The wheel bundles the H2 Database JDBC driver (MPL 2.0 / EPL 1.0). The example data is generated
locally by queryapigate examples load; no third-party datasets are included.
License
QueryAPIGate is open source, under the
Apache License, Version 2.0 (Apache-2.0)
© Anantha Raju C - see NOTICE. Use it, modify it and
redistribute it, commercially or not, under that license's terms.
Earlier versions: 0.39.0 onward is Apache-2.0; 0.7.0 to 0.38.0 were released under the Functional Source License,
Version 1.1, MIT Future License (FSL-1.1-MIT), and versions up to 0.6.1 under MIT. A copy you already obtained keeps
the license it came with.
Contact
Anantha Raju C - @anantharajuc - arcswdev@gmail.com
Project link: https://github.com/AnanthaRajuC/QueryAPIGate