schemagate: access-scoped schema selection for text-to-sql
schemagate
A Python library and MCP server that give the model only the tables a question needs and a role may read
- 136 ★ on the repository
- Last commit
Broad access
Why this level
- `run_query` executes reads in your database and returns rows to the model
- Without OAuth the role comes from the client call, and anyone who reaches the server can claim another role
Install
- Works in
In your terminal, with SkillFoxx CLI
npx skillfoxx add mcp/schemagateDetects the agents on your machine, shows the access level and pins the version.
Other ways to install
Access and checks
How we reviewBroad accessThe tool can change data, run commands or handle secrets.
- `run_query` executes reads in your database and returns rows to the model
- Without OAuth the role comes from the client call, and anyone who reaches the server can claim another role
This is third-party code. Review the repository files before installing.
What it does
schemagate stands in front of the model that writes SQL. Instead of the full database schema, the prompt gets the DDL of only those tables that fit the question and are available to the caller by role. A table the caller may not read never enters the prompt, so rewording the question cannot reach it and there is nothing to scrub from the answer. Install with `pip install schemagate`, and a demo with no database or key runs with `schemagate demo "salary by employee"`. It supports PostgreSQL, Oracle, MySQL, SQL Server and SQLite. `schemagate select` prints the chosen tables, with `--answer` it writes SQL straight away, and `schemagate studio` gives the same as a page. The `schemagate-mcp` server gives an agent nine read-only tools: `select_schema`, `list_objects`, `describe_object`, `run_query`, `semantic_query`, `answer`, `deep_answer`, `refresh_catalog` and `health`. Every decision is written to an audit log.
Who it is for. Data engineers and teams building text-to-sql over a database with hundreds of tables and access roles, who want to save tokens and show the model nothing extra.
Good fit when
- A schema of thousands of objects eats almost the whole prompt while a question needs three tables
- A sales analyst must not see the payroll table even when asking for it directly
- Row-level security hides rows and the model answers "no records" instead of "no access"
- An agent in Cursor or Claude Desktop writes queries against your database and you want to limit its view of the schema
Not a fit when
- The database is small and the whole schema fits the prompt with no loss: the gain is about nine percent there
- You need data protection itself: the server trusts the role passed in the call and is a scoping tool, not a lock, until OAuth is on
- You only need text-to-sql with no access separation: any simpler generator will do
Example request
Use schemagate to pick tables for the question "revenue by month" for the finance role and write a query against the app database.MCP
- Transport
- stdio, http
- Authentication
- not required
Environment variables
SCHEMAGATE_DATABASE_URLsecret- Database connection URL, keep the password here, not in arguments.
SCHEMAGATE_MCP_OAUTH_ISSUER- Token issuer for enabling OAuth over HTTP.
Limitations
By default the MCP server trusts the `principal` and `roles` that the client passes, and it is a scoping tool, not protection: over HTTP put it behind authentication or turn on OAuth (variables `SCHEMAGATE_MCP_OAUTH_ISSUER` and `SCHEMAGATE_MCP_OAUTH_AUDIENCE`). The `run_query` tool returns rows, that is, data.
The author says honestly that table selection can miss a needed one: on Spider 2.0 warehouses every needed table was in the selection for 86.7% of questions. Working with a database needs the driver of its dialect, for example `schemagate[mcp,postgres]`.
How to disable. Remove the schemagate server from the client config with `claude mcp remove schemagate` or by editing JSON. Audit and memory files, if you enabled `SCHEMAGATE_AUDIT_LOG` and `SCHEMAGATE_MEMORY`, sit in `~/.schemagate`.
FAQ
How do I connect schemagate to Claude Code?
With `claude mcp add schemagate -- uvx --from "schemagate[mcp]" schemagate-mcp --url demo` for the bundled schema. For your own database add a driver such as `schemagate[mcp,postgres]` and set `SCHEMAGATE_DATABASE_URL` in `env`.
How is it better than row-level security?
Row-level security hides rows, but the model still sees the forbidden table and writes a query against it, and the user gets "no records". schemagate keeps such a table out of the prompt.
Where do I put the database password?
In the `SCHEMAGATE_DATABASE_URL` variable under `env`, not in the `--url` argument: command arguments are visible to every process on the machine.
Can I try it without a database?
Yes: `schemagate demo "salary by employee"` runs on the bundled schema with no database or key, and the project page has an in-browser demo.
Which databases are supported?
PostgreSQL, Oracle, MySQL, SQL Server and SQLite. Each except SQLite needs its driver as a package extra, for example `postgres`, `mysql`, `mssql` or `oracle`.
Discussion
No questions or reviews yet.
Related
MCP serversFalkorDB's Text2SQL server: an agent asks the database in plain language and a schema graph helps build correct SQL
A text-to-SQL MCP server: an agent asks a database in words, gets SQL plus a trace, and a stated refusal when data is missing.
A Python MCP server for MySQL: listing tables, reading data, running SQL and inspecting schema through a controlled interface
A desktop SQL workspace with a built-in MCP server: the agent reads the schema and runs queries in the same client you already use
An MCP server and skills from TigerData that help agents write PostgreSQL schemas and queries from current docs and practices
vi-sql is a terminal SQL client with a built-in MCP server: the agent sees the schema and drafts queries straight in your editor
README in short
The README shows the text-to-sql problem with a full schema, a demo with two roles, token savings measured on public schemas, CLI, Studio and MCP modes, and ends with a warning that the server trusts the passed role without OAuth.