Content
# Tool List
MCP (Model Context Protocol) tools for providing read-only database access for [Claude Code](https://docs.anthropic.com/claude-code). Based on .NET 8 and the official `ModelContextProtocol` SDK, supporting SQL Server, MySQL, Oracle, with built-in SQL security guard, multi-environment configuration, hot reloading of configuration, audit logs, and native Admin UI configuration maintenance page.
## Features
- **Triple Database Support**: Oracle (compatible with 11g R2+), SQL Server, MySQL
- **Multi-Environment Project Configuration**: Same project can maintain multiple environments such as `dev` / `test` / `prod`, and set default environment
- **SQL Security Guard**: Whitelist (read-only statements) + blacklist (three-layer merged keywords) double verification, intercepting multi-statement injection
- **Hot Reloading Configuration**: Modifying `config.json` takes effect immediately, no need to restart MCP process
- **Audit Logs**: JSONL format records parsed queries, SQL blocking, and execution results after project and environment, supporting switch, rotation by size, and expiration by day
- **AI-Friendly Return**: Columns and rows separated, rows compressed using two-dimensional array to reduce token consumption
- **Native Admin UI**: Maintain `config.json` through browser, support direct editing of connection strings, production environment protection, backup before saving, and atomic writing
## Quick Start
### Build
```bash
git clone <repo>
cd mcp-db-tools
dotnet build
```
### Configure Database
Edit [src/McpDbTools.Server/config.json](src/McpDbTools.Server/config.json), add projects and environments under `databases`:
```jsonc
{
"audit": {
"enabled": true,
"logPath": "logs/audit.log",
"maxFileSizeMB": 10,
"maxRetentionDays": 30
},
"databases": {
"my-project": {
"displayName": "Example Project",
"defaultEnvironment": "test",
"environments": {
"test": {
"displayName": "Test Environment",
"isProduction": false,
"type": "sqlserver",
"connectionString": "Server=.;Database=MyDb;Trusted_Connection=true;TrustServerCertificate=true;",
"maxRows": 1000,
"commandTimeout": 30,
"disabledKeywords": []
},
"prod": {
"displayName": "Production Environment",
"isProduction": true,
"type": "sqlserver",
"connectionString": "Server=prod;Database=MyDb;User Id=readonly;Password=***;TrustServerCertificate=true;",
"maxRows": 500,
"commandTimeout": 30,
"disabledKeywords": []
}
}
}
}
}
```
> By default, the program reads `config.json` under the program directory. Can override the configuration file path with environment variable `ConfigStore__ConfigPath`. If the configuration file does not exist, the service will start with an empty configuration, and can be completed later through Admin UI or creating a configuration file.
### Connect to Claude Code
During development, can directly mount through `dotnet run`:
```json
{
"mcpServers": {
"db-tools": {
"command": "dotnet",
"args": ["run", "--project", "D:/GitHub/mcp-db-tools/src/McpDbTools.Server/McpDbTools.Server.csproj"],
"env": {
"ConfigStore__ConfigPath": "D:/GitHub/mcp-db-tools/src/McpDbTools.Server/config.json"
}
}
}
}
```
After release, recommend running exe directly and placing `config.json` in the same directory:
```json
{
"mcpServers": {
"db-tools": {
"command": "D:/Tools/McpDbTools/McpDbTools.Server.exe",
"args": []
}
}
}
```
Restart Claude Code, can call `db_list` to view available projects and environments, then call `db_query` to execute read-only queries.
## Running Modes
Same program supports MCP and Admin running modes:
| Mode | Parameter | Description |
|------|------|------|
| MCP Mode | No parameter | Default mode. Start MCP stdio server, do not start Admin UI |
| Admin Mode | `--admin-only` | Only start native Admin Web service, do not start MCP stdio server |
| Debug Mixed Mode | `--admin` | Start MCP and Admin UI simultaneously; only recommended for development and debugging |
Admin UI default port is `5123`, can be modified with `--admin-port`. During development, if need to use configuration file under source code directory, also recommend setting `ConfigStore__ConfigPath`:
```bash
ConfigStore__ConfigPath=D:/GitHub/mcp-db-tools/src/McpDbTools.Server/config.json \
dotnet run --project src/McpDbTools.Server -- --admin-only --admin-port 5123
```
After startup, logs will output local access address, for example:
```text
Admin UI: http://127.0.0.1:5123/admin
```
Admin service only listens to `127.0.0.1`. When accessing `/admin` for the first time, the server will automatically set session cookie for `/admin` path only; Admin API verifies this HttpOnly, SameSite=Strict session cookie. Session secret is only saved in current process memory, not written to `config.json`.
## Admin UI
Directly access the address output in startup logs to open configuration page:
```text
http://127.0.0.1:5123/admin
```
Admin UI currently supports:
- Add, edit, delete projects
- Add, edit, delete environments
- Set default environment
- Maintain `displayName`, `isProduction`, database type, connection string, `maxRows`, `commandTimeout`, environment-level `disabledKeywords`
- Maintain global blocking keywords and database type-specific blocking keywords (access `/admin/keywords`)
- Maintain audit log configuration
- Local page directly loads and displays complete connection string for easy copying and maintenance
- Production environment displays risk prompt, saving configuration no longer requires inputting project name confirmation
- Automatically backup current `config.json` before saving
- Use temporary file verification + atomic replacement writing configuration to avoid MCP process reading semi-written file
- Saving will rewrite `config.json` to standard JSON; original file comments and manual formatting will not be retained
Backup files are written to `backups/` under `config.json` directory:
```text
backups/config.20260623-184500-123.json
```
## MCP Tools
### db_list
List all projects and environments in current configuration, recommended to call before querying.
Return JSON example:
```json
{
"projects": [
{
"name": "my-project",
"defaultEnvironment": "test",
"environments": ["test", "prod"]
}
]
}
```
### db_query
Execute read-only SQL query on specified project and environment.
| Parameter | Type | Required | Description |
|------|------|------|------|
| `project` | string | Yes | Project name, corresponds to key of `databases` in `config.json` |
| `sql` | string | Yes | SQL statement, only allows read-only operations |
| `environment` | string | No | Environment name; if not passed, use project's `defaultEnvironment` |
| `limit` | int | No | Temporary limit return rows, must be positive integer; final take `min(limit, maxRows)`, cannot exceed configuration upper limit |
Return JSON example:
```json
{
"success": true,
"project": "my-project",
"environment": "test",
"databaseType": "SqlServer",
"rowCount": 42,
"maxRows": 1000,
"truncated": false,
"executionTimeMs": 125,
"columns": ["Id", "Name", "CreatedAt"],
"rows": [
[1, "张三", "2024-01-15"],
[2, "李四", "2024-03-22"]
]
}
```
Errors returned as structured JSON, not thrown to MCP protocol layer. Common error codes:
| Error Code | Description |
|--------|------|
| `PROJECT_NOT_FOUND` | Project does not exist |
| `ENVIRONMENT_REQUIRED` | Environment not specified, and project has no default environment |
| `ENVIRONMENT_NOT_FOUND` | Environment does not exist |
| `SQL_BLOCKED` | SQL blocked by security guard |
| `SQL_PARSE_ERROR` | SQL empty or cannot identify first keyword |
| `QUERY_TIMEOUT` | Query timeout |
| `QUERY_ERROR` | Database execution error |
## Configuration File Details
Complete configuration see [src/McpDbTools.Server/config.json](src/McpDbTools.Server/config.json). Core structure as follows:
```jsonc
{
"defaultDisabledKeywords": ["DROP", "DELETE", "UPDATE"],
"defaultDisabledKeywordsByType": {
"sqlserver": ["BULK INSERT", "OPENROWSET", "xp_cmdshell"],
"mysql": ["LOAD DATA", "FLUSH"],
"oracle": ["FLASHBACK", "PURGE"]
},
"audit": {
"enabled": true,
"logPath": "logs/audit.log",
"maxFileSizeMB": 10,
"maxRetentionDays": 30
},
"databases": {
"<project>": {
"displayName": "Project Display Name",
"defaultEnvironment": "test",
"environments": {
"<environment>": {
"displayName": "Environment Display Name",
"isProduction": false,
"type": "sqlserver|mysql|oracle",
"connectionString": "...",
"maxRows": 1000,
"commandTimeout": 30,
"disabledKeywords": []
}
}
}
}
}
```
### Three-Layer SQL Blocking Keywords
| Layer | Field | Scope |
|------|------|--------|
| Global | `defaultDisabledKeywords` | All databases, all projects, all environments |
| Type | `defaultDisabledKeywordsByType` | Additional by database type |
| Environment | `databases.<project>.environments.<environment>.disabledKeywords` | Single environment additional |
Final blocking list = Global ∪ By Type ∪ Environment. All converted to uppercase and deduplicated; lower layer can only add, cannot reduce upper layer.
### Audit Log Configuration
```json
"audit": {
"enabled": true,
"logPath": "logs/audit.log",
"maxFileSizeMB": 10,
"maxRetentionDays": 30
}
```
`logPath` supports relative path. Relative path resolved by current process working directory; recommend fixing program directory during release and deployment, or using absolute path.
Audit log records range: project and environment successfully parsed `db_query` will record SQL blocked by security guard, and actual execution result after entering database provider. Early parameter parsing errors such as project does not exist, environment missing will directly return structured JSON, currently not written to audit log.
## SQL Security Policy
**Whitelist (by database type)**:
- Universal allow: `SELECT`, `WITH` (CTE), `EXEC` / `EXECUTE`
- MySQL additional: `CALL`, `SHOW`, `DESCRIBE` / `DESC`, `EXPLAIN`
- Oracle additional: `CALL`, `DESCRIBE` / `DESC`
- SQL Server additional: `sp_help`, `sp_tables`, `sp_columns` and other system stored procedures
**Blacklist**: `DROP`, `DELETE`, `UPDATE`, `INSERT`, `ALTER`, `CREATE`, `TRUNCATE`, `MERGE`, `GRANT`, `REVOKE` and others, plus database type and environment-specific keywords.
Verification process: remove comments → normalize whitespace → first sentence first keyword whitelist judgment → full text blacklist scan. Can intercept `SELECT 1; DROP TABLE x` multi-statement injection.
## Release and Deployment Recommendations
Recommend releasing to fixed program directory, let MCP and Admin UI share same `config.json`:
```text
D:\Tools\McpDbTools\
├── McpDbTools.Server.exe
├── config.json
├── backups\
├── logs\
└── wwwroot\
└── admin\
├── index.html
├── admin.js
└── admin.css
```
Release command:
```bash
dotnet publish src/McpDbTools.Server -c Release
```
Production recommendation:
```text
Admin service: McpDbTools.Server.exe --admin-only --admin-port 5123
MCP mount: McpDbTools.Server.exe
```
MCP client configuration does not need Admin parameter, avoid Claude modifying configuration through MCP.
## Development
### Run Test
```bash
dotnet test
```
MCP mode stdout is protocol channel, new logs or debug output must go through stderr, avoid breaking MCP stdio protocol.
### Common Commands
```bash
dotnet build
dotnet test
dotnet test --filter "FullyQualifiedName~SqlGuardTests"
dotnet test --filter "MultiStatement_Injection_Blocked"
dotnet run --project src/McpDbTools.Server
dotnet run --project src/McpDbTools.Server -- --admin-only --admin-port 5123
dotnet publish src/McpDbTools.Server -c Release
```
### Project Structure
```text
src/McpDbTools.Server/
├── Admin/ # Admin API DTO and configuration read/write service
├── Audit/ # Audit logger
├── Configuration/ # Configuration model, hot reloading, three-layer keyword merging
├── Database/ # Three database providers + factory
├── Security/ # SqlGuard SQL security guard
├── Tools/ # db_query / db_list MCP tools
├── wwwroot/admin/ # Static Admin UI
└── Program.cs # MCP / Admin running mode entry
```
### Technology Stack
- .NET 8
- ASP.NET Core Minimal API (Admin UI)
- Static HTML / CSS / JavaScript (no npm build chain)
- [ModelContextProtocol](https://github.com/modelcontextprotocol/csharp-sdk) 1.4.0 (MCP C# SDK)
- Microsoft.Data.SqlClient 7.0.1 / MySqlConnector 2.6.0 / Oracle.ManagedDataAccess.Core 3.21.210
- xUnit
## Known Limitations
- Do not parse string literals, string keywords may be misjudged (security tool宁可误拒)
- Do not support stored procedure parameter passing (parameters directly spliced in SQL text)
- Do not support cross-environment / multi-connection JOIN query (each environment corresponds to a database connection; same connection database itself supports cross-schema query determined by database)
- Admin UI currently only responsible for configuration maintenance, do not execute test connection or test query
- Admin UI currently only designed for local access; if need remote access, need to design authentication, authorization, TLS and audit separately
- Actual database connection need to be verified in target environment with real database (unit test covers pure logic layer)
## Design Documents
- [doc/design.md](doc/design.md)
- [doc/admin-ui-design.md](doc/admin-ui-design.md)
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available