A lightweight .NET 10 MCP server that proxies read-only SQL queries to multiple databases. Designed for AI agents in the fuseraft orchestration framework.
Supported databases: SQL Server, PostgreSQL, MySQL, Oracle
- .NET 10 SDK (build) or .NET 10 Runtime (run)
- Access to at least one configured database
git clone <repo>
cd sql-mcp
dotnet restore
# Set password env vars for any databases that need them
export DB_SAMPLESQL_PASSWORD=yourpassword
export DB_SAMPLEPG_PASSWORD=yourpassword
dotnet run
# Listening on http://*:8080All settings live in appsettings.json.
| Key | Default | Description |
|---|---|---|
App:Urls |
http://*:8080 |
Bind address. Override with env var App__Urls. |
App:MaxRows |
1000 |
Maximum rows returned per query. Response includes "truncated": true when the limit is hit. |
App:QueryTimeoutSeconds |
30 |
Per-query timeout in seconds. |
Each entry under Databases has:
| Field | Required | Description |
|---|---|---|
Name |
yes | Identifier used in API calls. |
Provider |
yes | One of SqlServer, Postgres, MySql, Oracle. |
ConnectionString |
yes | Standard ADO.NET connection string. Use {password} as a placeholder if using PasswordEnvVar. |
PasswordEnvVar |
no | Environment variable name whose value is substituted for {password} in the connection string. |
Example:
{
"App": {
"Urls": "http://*:8080",
"MaxRows": 1000,
"QueryTimeoutSeconds": 30
},
"Databases": [
{
"Name": "prod",
"Provider": "Postgres",
"ConnectionString": "Host=db.example.com;Database=myapp;Username=readonly;Password={password};",
"PasswordEnvVar": "DB_PROD_PASSWORD"
}
]
}For local development, put real connection strings in appsettings.Development.json (gitignored).
Any appsettings.json value can be overridden with an environment variable using __ as the section separator:
App__Urls=http://*:9090
App__MaxRows=500GET /tools — list available tools
POST /tools/{toolName}/invoke — invoke a tool
Returns the names of all configured databases.
curl -X POST http://localhost:8080/tools/list_databases/invoke \
-H "Content-Type: application/json" \
-d '{}'{
"content": [{ "type": "text", "text": "[\"prod\",\"reporting\"]" }]
}Executes a SELECT query. Only SELECT and WITH (CTE) statements are accepted.
curl -X POST http://localhost:8080/tools/query_database/invoke \
-H "Content-Type: application/json" \
-d '{"dbName": "prod", "sql": "SELECT id, name FROM users LIMIT 10"}'{
"content": [{
"type": "text",
"text": "{\"columns\":[\"id\",\"name\"],\"rows\":[...],\"truncated\":false}"
}]
}POST /api/query — same as query_database but returns the result directly without MCP envelope.
{ "dbName": "prod", "sql": "SELECT 1 AS test" }GET /health — returns 200 {"status":"healthy"}. Suitable for load balancer and orchestrator probes.
- Only
SELECTandWITH(CTE) queries are executed. All other statements are rejected at the application layer. - Grant database users read-only access. This is the primary enforcement layer — the application-level check is defence in depth.
- Passwords are never stored in the process environment directly; the
{password}substitution pattern keeps connection strings safe to commit while keeping credentials out.
# Linux x64
dotnet publish -p:PublishProfile=linux-x64
# Output: publish/linux-x64/
# Windows x64
dotnet publish -p:PublishProfile=win-x64
# Output: publish/win-x64/No .NET runtime needed on the target machine.
docker build -t sql-mcp .
docker run -p 8080:8080 \
-e DB_PROD_PASSWORD=secret \
-v /path/to/appsettings.json:/app/appsettings.json \
sql-mcpCreate /etc/systemd/system/sql-mcp.service:
[Unit]
Description=sql-mcp
After=network.target
[Service]
ExecStart=/opt/sql-mcp/sql-mcp
WorkingDirectory=/opt/sql-mcp
Restart=always
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DB_PROD_PASSWORD=secret
[Install]
WantedBy=multi-user.targetsystemctl enable --now sql-mcpsc create sql-mcp binPath="C:\sql-mcp\sql-mcp.exe"
sc description sql-mcp "sql-mcp MCP server"
sc start sql-mcpSet passwords via system environment variables or an appsettings.Production.json placed alongside the executable.
sql-mcp/
├── Program.cs # App wiring, endpoints
├── Services/QueryService.cs # Query execution, validation, row limiting
├── Models/
│ ├── DbConfig.cs # Database config model
│ ├── QueryRequest.cs # Request DTO
│ └── QueryResult.cs # Response DTO
├── Properties/PublishProfiles/
│ ├── linux-x64.pubxml
│ └── win-x64.pubxml
├── appsettings.json # Default config
├── appsettings.Production.json # Production log levels
└── Dockerfile