PermitQL is a governed database access layer and MCP server for SQL databases. It validates incoming SQL, rewrites queries to enforce rules such as row limits and filters, and exposes both HTTP and stdio transports for tool-based clients.
License: GNU Affero General Public License v3.0 or later. See LICENSE for the repository notice.
The repository contains:
PermitQL/- the core library for parsing, validating, rewriting, and executing governed queriesPermitQL.Server/- the MCP server and HTTP API hostPermitQL.Tests/- xUnit coverage for parsing, validation, rewriting, rules, metadata, and server behaviorRules/example_rules.yaml- a starter rule set for the sample databaseinit/- schema and seed scripts used by the local Postgres container
- Validates SQL before execution
- Rewrites supported queries to enforce governed behavior
- Loads rule sets from YAML
- Discovers database metadata for PostgreSQL and SQLite
- Exposes MCP tools for querying and describing governed databases
- Exposes HTTP endpoints for query execution and database description
- .NET 10 SDK
- Docker and Docker Compose, if you want to run the sample Postgres database
-
Restore and build the solution:
dotnet restore PermitQL.sln dotnet build PermitQL.sln
-
Start the sample Postgres database:
docker compose up
-
Run the server:
dotnet run --project PermitQL.Server
The default configuration in PermitQL.Server/appsettings.json points to the local Postgres instance created by docker compose.
Install the global tool from nuget.org:
dotnet tool install --global permitqlUpdate an existing installation:
dotnet tool update --global permitqlTagged releases also publish standalone server archives for:
linux-x64win-x64osx-arm64
Download those binaries from the repository's GitHub Releases page when you do not want to install through the .NET tool feed.
Server settings are read from the PermitQL configuration section.
Required values:
RulesDirectory- path to the directory containing YAML rule setsConnectionString- database connection stringProvider-postgresqlorsqlite
You can provide configuration through:
PermitQL.Server/appsettings.jsonappsettings.{Environment}.json- environment variables, for example
PermitQL__ConnectionString PermitQL_CONFIG_JSON
Example:
{
"PermitQL": {
"RulesDirectory": ".",
"ConnectionString": "Host=localhost;Database=mydb;Username=myuser;Password=mypassword",
"Provider": "postgresql"
}
}The server supports two modes:
- HTTP transport, which is the default
- stdio transport, which is intended for local MCP client integration
Start the server normally:
dotnet run --project PermitQL.ServerAvailable endpoints:
POST /api/query- execute a governed queryGET /api/databases- list available rule set keysGET /api/databases/{key}- return a governed database description as JSON
Run the server with the serve --stdio arguments:
dotnet run --project PermitQL.Server -- serve --stdioThe server project exposes two verbs:
serve- run the MCP serverdiscover- inspect a database and write discovered schema metadata to a file
Examples:
permitql discover --output discovered_schema.yaml
permitql serve
permitql serve --stdio
dotnet run --project PermitQL.Server -- discover --output discovered_schema.yaml
dotnet run --project PermitQL.Server -- serve
dotnet run --project PermitQL.Server -- serve --stdioThe server registers these MCP tools:
query- execute a governed SQL querylist_databases- list the available rule set keysdescribe_database- describe the governed schema, capabilities, limits, relationships, indexes, and statistics
The bundled sample rule file governs a database named mydb and exposes tables in the public schema.
To try the sample setup:
- Start the Postgres container with
docker compose up - Use the schema and seed scripts in
init/to populate the sample database - Point the server at
Rules/example_rules.yamlor another rules directory
Run the full test suite:
dotnet test PermitQL.slnThe tests cover:
- SQL parsing
- query validation
- query rewriting
- YAML rules loading
- metadata resolution for PostgreSQL and SQLite
- server startup and MCP tool behavior
appsettings*.jsonfiles are intentionally excluded from publish output.- The server uses the configured database provider to select PostgreSQL or SQLite behavior.
- Keep rule-set filenames and schema/table names aligned with the identifiers you expose in YAML.