MCP SQLKit is a database access toolbox built on top of the MCP protocol. It exposes a minimal set of tools that allow any MCP-host (CLI, Claude Desktop, etc.) to:
- register database connectors (connection definitions),
- list existing connectors,
- execute SQL queries and obtain the result set as JSON,
- execute SQL DML / DDL statements and obtain execution metadata.
The project is written in Go, released under the Apache 2 licence and
distributed as a single self-contained executable (mcp-sqlkit
).
- Features
- Quick start
- Configuration
- Available tools
- Connector secrets
- Authentication & authorization
- Secure connector-secret flow
- Installation
- Building from source
- Running the unit-tests
- Project structure
- Contributing
- Licence
• Multi-database support – ships with metadata for MySQL, BigQuery and is
easily extensible to other drivers supported by
database/sql
.
• Namespace isolation – requests are scoped to the caller’s namespace so that multiple users (JWT subjects, OAuth2 e-mails, etc.) can share a single toolbox instance without seeing each other’s connectors.
• Zero-copy result streaming – query results are streamed directly from
database/sql
into JSON without intermediate allocations.
• Built-in secret management – credentials are encrypted with
scy (Blowfish-GCM by default) and written
to an abstract secret URL. Out-of-the-box SQLKit supports file://
(local
disk), mem://
(in-memory) and any additional schemes implemented by the
scy project – for example Cloud Secret Manager, HashiCorp Vault, etc. The
default location is file://~/.secret/mcpt
.
• MCP user-interaction flow – if a connector lacks a stored secret SQLKit
uses the MCP CreateUserInteraction
API to instruct the client to open a
browser window. The user types the credentials (or completes an OAuth2
consent screen) directly in that page – the secret never passes through the
MCP client. Once submitted the connector transitions from PENDING_SECRET to
ACTIVE automatically.
The easiest way to try the toolbox is to run the server with both HTTP and STDIO transports enabled:
go run ./cmd/mcp-sqlkit -a :5000
-a :5000
– HTTP listen address (omit to disable HTTP transport).-s
– enable STDIO transport (useful when the toolbox is launched by another process via pipes).
The server will print something similar to:
2025/07/12 mcp-sqlkit server listening on HTTP :5000
2025/07/12 mcp-sqlkit server listening on stdio
At this point you can connect with any MCP client and invoke the tools listed in the next section.
All configuration knobs live under the mcp.Config
structure
(mcp/config.go
). The executable will look for a JSON file specified via the
-c / --config
command-line flag; if not provided sensible defaults are
applied.
In addition to adding connectors at runtime you can pre-load connection
definitions via configuration so that they are available immediately after the
server starts. This is done with the connector.defaultConnectors
array
(see db/connector.Config
). Each entry contains a namespace
and a list of
connectors
.
- Global / shared connectors – set
namespace
to an empty string or"default"
. All callers (even unauthenticated) can use them. - Per-user connectors – set
namespace
to the e-mail / subject expected in the user’s ID-token. Only that principal will see the connector.
Example:
{
"connector": {
"defaultConnectors": [
{
// Shared read-only replica available to everyone.
"namespace": "default",
"connectors": [
{
"name": "analyticsRO",
"driver": "mysql",
"dsn": "analytics-ro:3306/analytics",
// optional inline secret – persisted at first start-up
"secrets": {
"URL": "file://~/.secret/mcpt/mysql/analytics/default",
"Key": "blowfish://default"
}
}
]
},
{
// Private BigQuery connector visible only to [email protected]
"namespace": "[email protected]",
"connectors": [
{
"name": "bqPrivate",
"driver": "bigquery",
"dsn": "bigquery://project/dataset"
}
]
}
]
}
}
On start-up SQLKit persists any provided secrets (if they are not yet stored) and registers the connectors under their respective namespaces.
Configuration can also be built programmatically – see
cmd/mcp-sqlkit/main.go
for a minimal example.
The package db/driver
blank-imports the most common database/sql
drivers
(MySQL, Postgres, SQLite, etc.) and the product-specific metadata
registrations used by github.com/viant/sqlx
. Import it once in your main if
you use the services outside of the toolbox:
import _ "github.com/viant/mcp-sqlkit/db/driver"
Toolbox binaries already import it for you, so no action is required when you
run mcp-sqlkit
.
The toolbox registers the following MCP tools (see mcp/tool.go
).
Tool name | Description | Input struct |
---|---|---|
dbQuery |
Execute a SQL query and return the result set | db/query.Input |
dbExec |
Execute DML/DDL and return rows affected | db/exec.Input |
dbListConnections |
List connectors visible to the caller | db/connector.ListInput |
dbAddConnection |
Register a new connector | db/connector.ConnectionInput |
dbUpdateConnection |
Update an existing connector (upsert) | db/connector.ConnectionInput |
dbListTables |
List tables for a given catalog/schema | db/meta.ListTablesInput |
dbListColumns |
List columns for a given table | db/meta.ListColumnsInput |
- Register a connector (either via
dbAddConnection
or through the browser interaction described later). WithdbAddConnection
you pass only non-secret fields:
{
"name": "mysqlLocal",
"driver": "mysql",
"host": "127.0.0.1",
"port": 3306,
"db": "test",
"options":"parseTime=true"
}
The toolbox expands these into a driver-specific DSN template (e.g.
tcp(127.0.0.1:3306)/test?parseTime=true
) and triggers the user-interaction
flow if credentials are missing.
- Call the
dbQuery
tool with the following payload:
{
"query": "SELECT id, name FROM users WHERE status = ? LIMIT 10",
"connector": "mysqlLocal",
"parameters": ["active"]
}
- The toolbox responds with a JSON array containing the rows.
When you add a connector whose credentials are not yet stored the toolbox
transitions it into a PENDING_SECRET state and – provided the client
supports CreateUserInteraction
– opens a browser page where you can supply
the secret.
• Basic auth drivers (e.g. MySQL, Postgres) prompt for username and password.
• BigQuery driver triggers an OAuth2 authorisation code flow and appends the obtained token URLs to the DSN automatically.
Secrets are encrypted with scy and stored at:
<SecretBaseLocation>/<driver>/<database>/<namespace>
Key points about secret storage:
- Encryption uses Blowfish-GCM with keys managed by scy; SQLKit never stores secrets in plain text.
- The location scheme is pluggable – any URL that scy recognises works
(
file://
,mem://
,gsecret://
,vault://
, …). - Changing
SecretBaseLocation
to an empty string switches tomem://
storage so secrets live only for the lifetime of the process. Great for demos, not recommended for production.
MCP SQLKit can run with or without OAuth 2.0 / OpenID Connect identity
verification. When an OAuth2 configuration is supplied and the flag
requireIdentityToken
is set, every inbound MCP request must carry a valid
JWT ID-token (usually passed as Authorization: Bearer …
). The toolbox
extracts the subject or e-mail claim to derive the request namespace so
that each principal sees only its own connectors.
Minimal JSON snippet enabling token verification (see mcp.Config
):
{
"connector": {
"policy": {
"requireIdentityToken": true,
"oauth2Config": { // Standard golang.org/x/oauth2 cfg
"clientID": "<client_id>",
"clientSecret": "<secret>",
"endpoint": {
"authURL": "https://idp.example.com/auth",
"tokenURL": "https://idp.example.com/token"
},
"redirectURL": "http://localhost:5000/oauth2/callback",
"scopes": ["openid", "email"]
}
}
}
}
When the policy
block is omitted the toolbox falls back to a shared
namespace called default
– useful for local development or CI where no
identity provider is available.
Adding a connector is a two-step operation:
- Persist the connection definition (driver, DSN, etc.).
- Supply the associated secret (basic credentials or OAuth token).
Step 2 is performed via a browser-based user-interaction page served by SQLKit so that credentials never transit through the MCP client. The flow is identical for HTTP and stdio transports and differs only in the type of credential supplied.
The diagrams below use Mermaid (GitHub renders it automatically).
sequenceDiagram
autonumber
participant U as User
participant C as "MCP Client"
participant S as "SQLKit Server"
participant UI as "Browser (UI)"
participant SS as "Secret Store"
U->>C: dbAddConnection (missing secret)
C->>S: rpc dbAddConnection
S-->>C: state = PENDING_SECRET (+callback URL)
note over S: entry stored in-memory
C-->>U: open browser to URL
U->>UI: navigate
UI->>S: GET interaction page
U->>UI: enter user / pass
UI->>S: POST secret (TLS)
S->>SS: encrypt & persist (file:// or mem://)
S-->>UI: 204 No Content
S-->>C: optional MCP notification
note over S: connector state ➜ ACTIVE
sequenceDiagram
autonumber
participant U as User
participant C as "MCP Client"
participant S as "SQLKit Server"
participant UI as Browser
participant OP as "OAuth Provider"
participant SS as "Secret Store"
U->>C: dbAddConnection (BigQuery etc.)
C->>S: rpc dbAddConnection
S-->>C: state = PENDING_SECRET (+callback URL)
C-->>U: open browser to URL
U->>UI: navigate
UI->>S: GET interaction page (OAuth flow)
UI->>OP: redirect (Auth URL)
OP->>UI: login & consent
OP-->>UI: redirect back with code
UI->>S: POST code
S->>OP: exchange code → access/refresh/id tokens
S->>SS: encrypt & persist tokens
S-->>UI: success
S-->>C: optional MCP notification
note over S: connector state ➜ ACTIVE
Security properties:
- Secrets are always submitted over TLS (browser → SQLKit).
- The MCP client never sees the credential – it only carries the callback URL to the user.
- Secrets are encrypted via scy using Blowfish‐GCM; keys reside on the host – no plain-text on disk.
- When
secretBaseLocation
is empty, secrets stay in-memory; perfect for demos but not recommended for production.
If a user invokes a tool that references an unknown connector SQLKit will
activate the MCP Elicit protocol method to collect the missing
definition on the fly. The server sends a JSON-Schema describing the
ConnectionInput
structure; the MCP client renders it as a form, collects the
input and returns it without any secrets. The subsequent secret flow runs the
same way as in Branch A/B.
sequenceDiagram
autonumber
participant U as User
participant C as "MCP Client"
participant S as "SQLKit Server"
participant SS as "Secret Store"
U->>C: dbQuery (connector=unknown)
C->>S: rpc dbQuery
S-->>C: Elicit request (ConnectionInput schema)
C-->>U: render form
U->>C: fill host / port / db …
C->>S: Elicit result (accepted)
S->>S: create connector (may be PENDING_SECRET)
alt secret required
S-->>C: state = PENDING_SECRET (+callback URL)
else no secret
S-->>C: dbQuery result
end
S->>SS: (optional) persist secret when provided
Pre-built binaries are provided on the [releases page]
(https://github.com/viant/mcp-sqlkit/releases). Download the archive that
matches your OS / CPU, unpack it and move the mcp-sqlkit
binary somewhere in
your PATH
, e.g.:
curl -L -o mcp-sqlkit_linux_amd64.tar.gz \
https://github.com/viant/mcp-sqlkit/releases/latest/download/mcp-sqlkit_linux_amd64.tar.gz
tar -xzf mcp-sqlkit_linux_amd64.tar.gz
sudo mv mcp-sqlkit /usr/local/bin/
Alternatively you can build and install directly with the Go tool-chain (Go 1.21+ recommended):
go install github.com/viant/mcp-sqlkit/cmd/mcp-sqlkit@latest
The command places the binary in $(go env GOPATH)/bin
which should already
be on your PATH
if you installed Go using the official instructions.
The project uses the Go tool-chain – clone and build as usual:
git clone https://github.com/viant/mcp-sqlkit.git
cd mcp-sqlkit
go build ./cmd/mcp-sqlkit
This yields a single binary mcp-sqlkit
.
Tests follow a data-driven pattern (see db/query/cache_test.go
for an
example). Run the full suite with:
go test ./...
├── auth/ – Namespace derivation & JWT/OAuth2 helpers
├── cmd/ – CLI entry-points (currently only mcp-sqlkit)
├── db/ – Database-related logic
│ ├── connector/ – connector management, secret handling, UI flow
│ ├── exec/ – DML/DDL execution service
│ └── query/ – Query service with dynamic record type caching
├── mcp/ – Toolbox service, MCP handler & tool registration
└── policy/ – Security policy primitives
Pull requests are welcome – please make sure that:
- Code is formatted (
go fmt ./...
) andgo vet
passes. - New logic is covered by data-driven tests that use
assert.EqualValues()
fromstretchr/testify
. - You do not introduce driver-specific hacks – prefer a generic solution so that other connectors can benefit as well.
This project is released under the Apache Licence, version 2.0 – see the
LICENSE
file for the full text.