@braincode-tech/database-mcp
v2.0.0
Published
MCP Server for multiple databases (ClickHouse, PostgreSQL, MySQL) with SSH Tunnel and Multi-Cluster Support
Downloads
16
Maintainers
Readme
Database MCP Server
A Model Context Protocol (MCP) server that enables AI assistants to securely interact with multiple database types (ClickHouse, PostgreSQL, MySQL) through optional SSH tunneling.
Overview
This MCP server provides a bridge between AI assistants (like Claude, Ollama, Microsoft Copilot) and various databases, allowing natural language queries and database exploration with enterprise-grade security features.
Supported Databases
| Database | Default Port | EXPLAIN Types | Features | |----------|--------------|---------------|----------| | ClickHouse | 8123 | AST, SYNTAX, PLAN, PIPELINE, ESTIMATE | Columnar analytics, high performance | | PostgreSQL | 5432 | ANALYZE, VERBOSE, COSTS, BUFFERS, FORMAT | Full-featured RDBMS, JSON support | | MySQL | 3306 | EXTENDED, PARTITIONS, FORMAT | Wide compatibility, mature ecosystem |
Architecture
flowchart LR
subgraph Clients["AI Clients"]
CC[Claude Code<br/>stdio transport]
OL[Ollama / LLama<br/>HTTP transport]
CP[Microsoft Copilot<br/>HTTP + Auth]
end
subgraph MCP["MCP Server"]
TR[Transport Layer]
TL[8 Tools]
CR[Cluster Registry]
DB[Database Adapters]
end
subgraph Databases["Databases"]
SSH[SSH Tunnel<br/>optional]
CH[(ClickHouse)]
PG[(PostgreSQL)]
MY[(MySQL)]
end
CC -->|JSON-RPC| TR
OL -->|REST API| TR
CP -->|REST API| TR
TR --> TL
TL --> CR
CR --> DB
DB --> SSH
SSH --> CH
SSH --> PG
SSH --> MY
DB -.->|Direct Connection| CH
DB -.->|Direct Connection| PG
DB -.->|Direct Connection| MYDeployment Scenarios
Choose the deployment scenario that matches your environment:
Scenario 1: Development (Local with Internet)
Best for: Local development with Claude Code
flowchart LR
CC[Claude Code] -->|stdio| MCP[MCP Server]
MCP --> CH[(ClickHouse)]
MCP --> PG[(PostgreSQL)]
MCP --> MY[(MySQL)]# Quick start
npm install && npm run build
# Claude Code auto-detects via .mcp.jsonScenario 2: Cloud/Remote with SSH Tunnel
Best for: Accessing databases behind bastion/jump host
flowchart LR
AI[AI Client] --> MCP[MCP Server<br/>localhost]
MCP --> SSH[SSH Bastion]
SSH --> DB[(Databases<br/>Private Network)]
style SSH fill:#f9f,stroke:#333# Uses SSH tunnel configuration in clusters.json
docker compose up -dScenario 3: Internal Network (No SSH)
Best for: MCP Server on same network as databases
flowchart LR
AI[AI Client] --> MCP[MCP Server]
MCP --> DB[(Databases<br/>Same Network)]
style MCP fill:#9f9,stroke:#333# Direct connection - no SSH needed
# Edit config/clusters.internal.json
docker compose -f docker-compose.prod.yml up -dScenario 4: Air-Gapped / Offline Environment
Best for: Internal servers without internet access (e.g., enterprise data centers)
flowchart TB
subgraph Internal["Internal Server (No Internet)"]
OL[Ollama + LLama<br/>:11434]
MCP[MCP Server<br/>:3100]
DB[(Databases<br/>Existing)]
OL -->|HTTP API| MCP
MCP -->|Direct| DB
end
USER[User / Application] --> OL# On internet-connected machine:
./scripts/prepare-offline.sh
# Transfer offline-package/ to internal server
# On internal server:
./install.sh
docker compose -f docker-compose.prod.yml up -dAir-Gapped Deployment Guide - Complete instructions for offline deployment
Scenario 5: Microsoft 365 Copilot Integration
Best for: Enterprise environments using Microsoft Copilot as official AI assistant
flowchart LR
subgraph Microsoft["Microsoft Cloud"]
CS[Copilot Studio<br/>M365 Copilot]
end
subgraph Azure["Azure"]
AR[Azure Relay<br/>Hybrid Connection]
end
subgraph OnPrem["On-Premises"]
MCP[MCP Server<br/>:3100]
DB[(Databases)]
end
CS -->|"MCP Protocol"| AR
AR -->|"Outbound Only"| MCP
MCP --> DBRequirements:
- Azure Relay for secure tunnel (outbound-only)
- API Key authentication enabled
- Security team approval for outbound connection
Copilot Integration Guide - Complete setup guide + security proposal template
Features
- 8 MCP Tools for comprehensive database interaction
- Multi-Database Support - ClickHouse, PostgreSQL, MySQL
- Multi-Cluster Support - Manage multiple database instances
- SSH Tunneling - Secure connections through bastion hosts
- Dual Transport - Support for both stdio (Claude Code) and HTTP (Ollama/Copilot)
- Security First - Read-only queries, SQL injection prevention
- Environment Variable Substitution - Secure credential management
Quick Start
Quick Start by Scenario
Choose your deployment scenario and run the corresponding commands:
Option 1: Development with Claude Code (stdio)
# Use development environment template
cp config/env/.env.development .env
# Install and build
npm install && npm run build
# Claude Code auto-detects via .mcp.jsonOption 2: Air-Gapped with Ollama (HTTP)
# Use Ollama environment template
cp config/env/.env.ollama .env
# Edit .env with your database passwords
# CH_PASSWORD=your_clickhouse_password
# PG_PASSWORD=your_postgres_password
# MYSQL_PASSWORD=your_mysql_password
# Start with Docker
docker compose -f docker-compose.prod.yml up -dOption 3: Microsoft Copilot Integration (HTTP + Auth)
# Use Copilot environment template
cp config/env/.env.copilot .env
# Edit .env with your credentials
# API_KEY=your_secure_api_key (generate: openssl rand -base64 32)
# CH_PASSWORD=your_clickhouse_password
# Start with Docker
docker compose -f docker-compose.prod.yml up -d
# Register MCP URL in Copilot StudioConfiguration Templates: See
config/env/for all available environment templates.
Installation via npm (Recommended for Developers)
Install globally or use via npx for easy integration with Claude Code.
Option A: Using npx (No Installation)
npx @braincode-tech/database-mcpOption B: Global Installation
npm install -g @braincode-tech/database-mcp
database-mcpConfiguration for npm Usage
When using via npm/npx, you need to provide your own configuration:
Step 1: Create Configuration Directory
# Linux/macOS
mkdir -p ~/.database-mcp
# Windows (PowerShell)
New-Item -ItemType Directory -Force -Path "$env:USERPROFILE\.database-mcp"Step 2: Create clusters.json
Create ~/.database-mcp/clusters.json:
Multi-Database Configuration:
{
"clusters": {
"clickhouse-analytics": {
"name": "ClickHouse Analytics",
"ssh": {
"host": "bastion.yourcompany.com",
"port": 22,
"user": "your-username",
"keyPath": "~/.ssh/id_rsa"
},
"connection": {
"type": "clickhouse",
"host": "clickhouse.internal",
"port": 8123,
"database": "analytics",
"user": "readonly",
"password": "${CH_PASSWORD}"
}
},
"postgres-app": {
"name": "PostgreSQL App",
"connection": {
"type": "postgres",
"host": "localhost",
"port": 5432,
"database": "myapp",
"user": "reader",
"password": "${PG_PASSWORD}",
"schema": "public"
}
},
"mysql-legacy": {
"name": "MySQL Legacy",
"connection": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"database": "legacy_db",
"user": "readonly",
"password": "${MYSQL_PASSWORD}"
}
}
},
"defaultCluster": "clickhouse-analytics"
}Direct Connection (Same Network):
{
"clusters": {
"local": {
"name": "Local ClickHouse",
"connection": {
"type": "clickhouse",
"host": "localhost",
"port": 8123,
"database": "default",
"user": "default",
"password": ""
}
}
},
"defaultCluster": "local"
}Step 3: Configure Claude Code (.mcp.json)
Create or edit ~/.mcp.json (global) or .mcp.json (project):
{
"mcpServers": {
"database": {
"command": "npx",
"args": ["@braincode-tech/database-mcp"],
"env": {
"CLUSTERS_CONFIG_PATH": "~/.database-mcp/clusters.json",
"CH_PASSWORD": "your_clickhouse_password",
"PG_PASSWORD": "your_postgres_password",
"MYSQL_PASSWORD": "your_mysql_password",
"MCP_TRANSPORT": "stdio"
}
}
}
}Windows Users
Use full paths in .mcp.json:
{
"mcpServers": {
"database": {
"command": "npx",
"args": ["@braincode-tech/database-mcp"],
"env": {
"CLUSTERS_CONFIG_PATH": "C:\\Users\\YourName\\.database-mcp\\clusters.json",
"CH_PASSWORD": "your_clickhouse_password",
"PG_PASSWORD": "your_postgres_password",
"MYSQL_PASSWORD": "your_mysql_password",
"MCP_TRANSPORT": "stdio"
}
}
}
}Step 4: Test Connection
In Claude Code, try:
"List all database clusters"
"Show tables in the database"
"Run query: SELECT version()"Security Best Practices
| Practice | Description |
|----------|-------------|
| SSH Key Auth | Use keyPath instead of password for SSH |
| Read-only User | Create database users with read-only permissions |
| Environment Variables | Use ${VAR} syntax for sensitive data |
| Local Config | Keep clusters.json outside version control |
Prerequisites
- Node.js >= 20.0.0
- npm or yarn
- SSH access to your database server (if using SSH tunnel)
- Database servers with their respective interfaces enabled
Installation
# Clone the repository
git clone https://github.com/braincode-tech/database-mcp.git
cd database-mcp
# Install dependencies
npm install
# Build the project
npm run buildConfiguration
1. Environment Variables
Create a .env file in the project root:
# Transport mode: stdio (for Claude) or http (for Ollama)
MCP_TRANSPORT=stdio
# HTTP settings (only for http transport)
HTTP_PORT=3100
HTTP_HOST=0.0.0.0
# Logging level: debug, info, warn, error
LOG_LEVEL=info
# Path to cluster configuration
CLUSTERS_CONFIG_PATH=./config/clusters.json
# Database credentials (referenced in clusters.json)
CH_PASSWORD=your_clickhouse_password
PG_PASSWORD=your_postgres_password
MYSQL_PASSWORD=your_mysql_password2. Cluster Configuration
Create config/clusters.json:
Option A: Multi-Database with SSH Tunnel
{
"clusters": {
"clickhouse-analytics": {
"name": "ClickHouse Analytics",
"ssh": {
"host": "bastion.example.com",
"port": 22,
"user": "ssh-user",
"keyPath": "/path/to/key.pem"
},
"connection": {
"type": "clickhouse",
"host": "clickhouse.internal",
"port": 8123,
"database": "analytics",
"user": "readonly",
"password": "${CH_PASSWORD}"
}
},
"postgres-app": {
"name": "PostgreSQL App",
"connection": {
"type": "postgres",
"host": "postgres.internal",
"port": 5432,
"database": "myapp",
"user": "reader",
"password": "${PG_PASSWORD}",
"schema": "public"
}
},
"mysql-legacy": {
"name": "MySQL Legacy",
"connection": {
"type": "mysql",
"host": "mysql.internal",
"port": 3306,
"database": "legacy_db",
"user": "readonly",
"password": "${MYSQL_PASSWORD}"
}
}
},
"defaultCluster": "clickhouse-analytics"
}Option B: Direct Connection (No SSH)
{
"clusters": {
"clickhouse-local": {
"name": "Local ClickHouse",
"connection": {
"type": "clickhouse",
"host": "localhost",
"port": 8123,
"database": "default",
"user": "default",
"password": ""
}
},
"postgres-local": {
"name": "Local PostgreSQL",
"connection": {
"type": "postgres",
"host": "localhost",
"port": 5432,
"database": "postgres",
"user": "postgres",
"password": "${PG_PASSWORD}",
"schema": "public"
}
}
},
"defaultCluster": "clickhouse-local"
}Option C: Legacy ClickHouse Format (Still Supported)
{
"clusters": {
"legacy": {
"name": "Legacy Format",
"clickhouse": {
"host": "localhost",
"port": 8123,
"database": "default",
"user": "default",
"password": ""
}
}
},
"defaultCluster": "legacy"
}Database-Specific Configuration
ClickHouse Options
{
"connection": {
"type": "clickhouse",
"host": "localhost",
"port": 8123,
"database": "default",
"user": "default",
"password": "${CH_PASSWORD}"
}
}PostgreSQL Options
{
"connection": {
"type": "postgres",
"host": "localhost",
"port": 5432,
"database": "mydb",
"user": "myuser",
"password": "${PG_PASSWORD}",
"schema": "public",
"ssl": false
}
}MySQL Options
{
"connection": {
"type": "mysql",
"host": "localhost",
"port": 3306,
"database": "mydb",
"user": "myuser",
"password": "${MYSQL_PASSWORD}"
}
}Usage
With Claude Code
Option A: Project-level configuration (Recommended)
The project includes a .mcp.json file. When you open this project in Claude Code, it will automatically detect and offer to enable the MCP server.
- Open the project directory in Claude Code
- Claude Code will prompt to enable the MCP server
- Approve the MCP server when prompted
Option B: Global configuration
Create or edit ~/.mcp.json to add the server globally:
{
"mcpServers": {
"database": {
"command": "node",
"args": ["D:\\path\\to\\database-mcp\\dist\\index.js"],
"cwd": "D:\\path\\to\\database-mcp"
}
}
}After configuration:
Restart Claude Code
Test the connection:
- "List all database clusters"
- "Show tables in the database"
- "Run query: SELECT version()"
With Ollama (HTTP Transport)
- Set transport mode in
.env:
MCP_TRANSPORT=http
HTTP_PORT=3100- Start the server:
npm start- The server exposes these endpoints:
GET /health- Health checkGET /tools- List available toolsPOST /tools/:name- Call a tool by namePOST /v1/functions/:name- OpenAI-compatible format
With Docker
Docker deployment is ideal for production environments and easy integration with AI models via HTTP.
Docker Compose Files
| File | Use Case |
|------|----------|
| docker-compose.yml | Default - SSH tunnel to remote databases |
| docker-compose.prod.yml | Production - Ollama + MCP for internal/air-gapped servers |
| docker-compose.dev.yml | Development - Includes database servers |
Quick Start
# Development (with local databases)
docker compose -f docker-compose.dev.yml up -d
# Production (connect to existing databases)
docker compose -f docker-compose.prod.yml up -d
# Default (SSH tunnel)
docker compose up -d
# Check logs
docker compose logs -f
# Stop
docker compose downConfiguration
- Create
.envfile (environment variables):
MCP_TRANSPORT=http
HTTP_PORT=3100
LOG_LEVEL=info
CLUSTERS_CONFIG_PATH=./config/clusters.json
CH_PASSWORD=your_clickhouse_password
PG_PASSWORD=your_postgres_password
MYSQL_PASSWORD=your_mysql_password- Create
config/clusters.json(cluster configuration):
{
"clusters": {
"main": {
"name": "Main Database",
"connection": {
"type": "clickhouse",
"host": "clickhouse.internal",
"port": 8123,
"database": "analytics",
"user": "readonly",
"password": "${CH_PASSWORD}"
}
}
},
"defaultCluster": "main"
}- Run Docker Compose:
docker compose up -dVerify Container
# Check health
curl http://localhost:3100/health
# List available tools
curl http://localhost:3100/tools
# List clusters
curl -X POST http://localhost:3100/tools/list_clusters \
-H "Content-Type: application/json" \
-d '{}'HTTP API Endpoints
| Endpoint | Method | Description |
|----------|--------|-------------|
| /health | GET | Health check with cluster status |
| /tools | GET | List all available tools |
| /tools/:name | POST | Call a tool by name |
| /call | POST | Call a tool (name in request body) |
| /v1/functions/:name | POST | OpenAI-compatible function call |
Example API Calls
Execute a Query:
curl -X POST http://localhost:3100/tools/query \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT version()", "limit": 10}'List Tables:
curl -X POST http://localhost:3100/tools/list_tables \
-H "Content-Type: application/json" \
-d '{"database": "default"}'Get Sample Data:
curl -X POST http://localhost:3100/tools/get_sample \
-H "Content-Type: application/json" \
-d '{"table": "events", "rows": 5}'Describe Table Schema:
curl -X POST http://localhost:3100/tools/describe_table \
-H "Content-Type: application/json" \
-d '{"table": "events"}'Integration with AI Models
With Ollama/Open WebUI:
Configure the MCP endpoint as a function/tool provider:
Base URL: http://localhost:3100With LangChain:
import requests
def call_database_tool(tool_name: str, params: dict):
response = requests.post(
f"http://localhost:3100/tools/{tool_name}",
json=params
)
return response.json()
# Example: Execute query
result = call_database_tool("query", {
"sql": "SELECT count() FROM events"
})With Custom Applications:
async function queryDatabase(sql, limit = 100) {
const response = await fetch('http://localhost:3100/tools/query', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sql, limit })
});
return response.json();
}
// Example usage
const result = await queryDatabase('SELECT version()');
console.log(result);Available Tools
Cluster Management
| Tool | Description |
|------|-------------|
| list_clusters | List all configured clusters with connection status |
| switch_cluster | Switch to a different cluster |
| get_active_cluster | Get information about the active cluster |
Query Execution
| Tool | Description |
|------|-------------|
| query | Execute SELECT queries (read-only) with automatic LIMIT |
Table Operations
| Tool | Description |
|------|-------------|
| list_tables | List tables in a database with row counts and sizes |
| get_sample | Get sample rows from a table |
| describe_table | Get detailed table schema (columns, types, keys) |
Query Analysis
| Tool | Description |
|------|-------------|
| explain_query | Get query execution plans (database-specific) |
Tool Reference
query
Execute a SELECT query on the database.
Parameters:
sql(required): The SQL SELECT querylimit(optional): Max rows to return (default: 100, max: 10000)cluster(optional): Target cluster ID
Example:
Run query: SELECT count() FROM events WHERE date = today()list_tables
List all tables in a database.
Parameters:
database(optional): Database name (uses default if not specified)cluster(optional): Target cluster ID
Example:
List tables in the analytics databasedescribe_table
Get detailed table schema.
Parameters:
table(required): Table name (can include database prefix)cluster(optional): Target cluster ID
Example:
Describe the events tableget_sample
Get sample data from a table.
Parameters:
table(required): Table namerows(optional): Number of rows (default: 5, max: 100)cluster(optional): Target cluster ID
Example:
Show 10 sample rows from users tableexplain_query
Analyze query execution plan.
Parameters:
sql(required): The SQL query to analyzetype(optional): Explain type (database-specific, see table below)cluster(optional): Target cluster ID
EXPLAIN Types by Database:
| Database | Available Types | |----------|-----------------| | ClickHouse | AST, SYNTAX, PLAN, PIPELINE, ESTIMATE | | PostgreSQL | ANALYZE, VERBOSE, COSTS, BUFFERS, FORMAT | | MySQL | EXTENDED, PARTITIONS, FORMAT |
Example:
Explain the execution plan for: SELECT * FROM events WHERE user_id = 123Architecture
┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Claude Code │────▶│ MCP Server │────▶│ SSH Tunnel │
│ (stdio) │ │ (Node.js) │ │ (ssh2) │
└─────────────────┘ └──────────────────┘ └────────┬────────┘
│
┌─────────────────┐ ┌──────────────────┐ │
│ Ollama │────▶│ HTTP Transport │ │
│ (HTTP) │ │ (Fastify) │ ▼
└─────────────────┘ └──────────────────┘ ┌─────────────────┐
│ Database │
┌─────────────────┐ ┌──────────────────┐ │ Adapters │
│ Copilot │────▶│ API Key Auth │ ├─────────────────┤
│ (HTTP + Auth) │ │ │ │ ClickHouse │
└─────────────────┘ └──────────────────┘ │ PostgreSQL │
│ MySQL │
└─────────────────┘Project Structure
database-mcp/
├── src/
│ ├── index.ts # Entry point
│ ├── server.ts # MCP Server implementation
│ ├── tools/ # Tool implementations
│ │ ├── clusters.ts # Cluster management tools
│ │ ├── query.ts # Query execution
│ │ ├── tables.ts # Table operations
│ │ ├── schema.ts # Schema inspection
│ │ └── explain.ts # Query analysis
│ ├── databases/ # Database adapters
│ │ ├── database-client.ts # Abstract interface
│ │ ├── database-factory.ts # Adapter factory
│ │ ├── clickhouse-adapter.ts # ClickHouse implementation
│ │ ├── postgres-adapter.ts # PostgreSQL implementation
│ │ └── mysql-adapter.ts # MySQL implementation
│ ├── clusters/
│ │ ├── cluster-config.ts # Type definitions
│ │ └── cluster-registry.ts # Connection management
│ ├── transports/
│ │ ├── http.ts # HTTP transport
│ │ └── stdio.ts # Stdio transport
│ ├── middleware/
│ │ └── auth.ts # API Key authentication
│ ├── tunnel/
│ │ ├── ssh-manager.ts # SSH tunnel manager
│ │ └── connection-pool.ts # Connection pooling
│ └── utils/
│ ├── config.ts # Configuration loader
│ └── logger.ts # Logging
├── config/
│ ├── env/ # Environment templates
│ │ ├── .env.development # Claude Code (stdio)
│ │ ├── .env.ollama # Air-gapped Ollama
│ │ └── .env.copilot # Microsoft Copilot
│ ├── clusters.json # Default cluster config
│ ├── clusters.example.json # Example multi-database config
│ ├── clusters.dev.json # Development config
│ └── clusters.internal.json # Internal network config
├── docs/
│ ├── AIR_GAPPED_DEPLOYMENT.md # Offline deployment guide
│ └── COPILOT_INTEGRATION.md # Copilot Studio guide
├── scripts/
│ └── prepare-offline.sh # Build offline package
├── dist/ # Compiled JavaScript
├── .env # Environment variables (from template)
├── .mcp.json # MCP server configuration
├── docker-compose.yml # Default Docker config
├── docker-compose.dev.yml # Development stack
├── docker-compose.prod.yml # Production stack
└── package.jsonSecurity
Query Safety (Configurable)
The MCP server enforces read-only access by default with multiple layers of protection:
| Protection | Default | Description |
|------------|---------|-------------|
| Allowed Prefixes | SELECT, WITH, SHOW, DESCRIBE, EXPLAIN | Only these query types are allowed |
| Blocked Keywords | INSERT, UPDATE, DELETE, DROP, ... | These keywords are blocked anywhere in query |
| Multiple Statements | Blocked | Queries with ; are rejected |
| SQL Comments | Blocked | -- and /* */ comments are rejected |
| Row Limit | 10,000 max | Prevents large result sets |
Security Configuration
All security settings are configurable in config/clusters.json:
{
"clusters": { ... },
"defaultCluster": "main",
"security": {
"allowedQueryPrefixes": ["select", "with", "show", "describe", "desc", "explain"],
"blockedKeywords": ["insert", "update", "delete", "drop", "truncate", "alter", "create", "grant", "revoke"],
"enableKeywordBlocking": true,
"allowedDatabases": [],
"allowedTables": [],
"maxRowLimit": 10000,
"defaultRowLimit": 100,
"blockMultipleStatements": true,
"blockComments": true
}
}Security Options Reference
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| allowedQueryPrefixes | string[] | ["select", "with", ...] | Query must start with one of these |
| blockedKeywords | string[] | ["insert", "update", ...] | Keywords blocked anywhere in query |
| enableKeywordBlocking | boolean | true | Enable/disable keyword blocking |
| allowedDatabases | string[] | [] (all) | Whitelist of allowed databases |
| allowedTables | string[] | [] (all) | Whitelist of allowed tables |
| maxRowLimit | number | 10000 | Maximum rows returned |
| defaultRowLimit | number | 100 | Default LIMIT if not specified |
| blockMultipleStatements | boolean | true | Block queries with semicolons |
| blockComments | boolean | true | Block SQL comments |
Example: Restrict to Specific Tables
{
"security": {
"allowedDatabases": ["analytics", "reporting"],
"allowedTables": ["analytics.events", "analytics.users", "reporting.summary"]
}
}Example: Minimal Security (Not Recommended)
{
"security": {
"enableKeywordBlocking": false,
"blockMultipleStatements": false,
"blockComments": false
}
}Credential Management
- Environment variable substitution for sensitive data
- SSH key or password authentication support
- Separate credentials per cluster and database type
Network Security
- SSH tunneling for all remote connections
- Local port forwarding for isolation
- Support for bastion/jump hosts
Defense in Depth
For maximum security, combine MCP security settings with:
- Database readonly user - Create users with read-only permissions
- Network isolation - Use SSH tunneling through bastion hosts
- Database permissions - Grant SELECT only on specific tables
Development
Scripts
# Development mode with hot reload
npm run dev
# Build for production
npm run build
# Run production build
npm start
# Lint code
npm run lint
# Clean build directory
npm run cleanAdding New Tools
- Create a new file in
src/tools/ - Define the tool definition and input schema
- Implement the handler function
- Register the tool in
src/server.ts
Adding New Database Support
- Create a new adapter in
src/databases/ - Implement the
DatabaseClientinterface - Register the adapter in
database-factory.ts - Update the configuration schema in
cluster-config.ts
Rebuilding After Configuration Changes
When you update clusters.json, .env, or any source code, you need to rebuild the project.
Local Development (Claude Code / stdio)
# 1. Rebuild the project
npm run build
# 2. Restart Claude Code to reconnect MCP
# In Claude Code, use: /mcp or restart the applicationQuick rebuild command:
npm run clean && npm run buildDocker Deployment
# 1. Rebuild Docker image (required after source code changes)
docker-compose build
# 2. Restart container (picks up volume-mounted config changes)
docker-compose down && docker-compose up -d
# 3. Verify the container is running
docker-compose logs -f database-mcpWhen to rebuild Docker image vs restart container:
| Change Type | Action Required |
|-------------|-----------------|
| clusters.json changes | Restart container only (docker-compose restart) |
| .env changes | Restart container only |
| Source code (src/) changes | Rebuild image (docker-compose build) |
| package.json changes | Rebuild image |
| Dockerfile changes | Rebuild image |
Full rebuild command:
docker-compose down && docker-compose build --no-cache && docker-compose up -dVerify Connection After Rebuild
For Claude Code (stdio):
# Check MCP status in Claude Code
/mcpFor Docker (HTTP):
# Health check
curl http://localhost:3100/health
# Test query
curl -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"query","arguments":{"sql":"SELECT 1"}}}'Troubleshooting
SSH Connection Failed
Error: SSH connection errorSolutions:
- Verify bastion host is reachable:
ssh user@bastion-host - Check SSH credentials (password or key path)
- Ensure port 22 is open in firewall
- Verify SSH user has required permissions
Database Connection Failed
Error: Query error: Connection refusedSolutions:
- Verify database port is accessible from bastion (or directly)
- Check database user credentials
- Ensure database exists
- Verify database service is running
MCP Server Not Responding
Error: MCP server not foundSolutions:
- Ensure project is built:
npm run build - Verify path in Claude settings points to
dist/index.js - Check if
cwdis set correctly in settings - Restart Claude Code after config changes
Debug Mode
Enable debug logging:
LOG_LEVEL=debugCheck logs for detailed error information.
Environment Variables Reference
| Variable | Description | Default |
|----------|-------------|---------|
| MCP_TRANSPORT | Transport type (stdio/http) | stdio |
| HTTP_PORT | HTTP server port | 3100 |
| HTTP_HOST | HTTP server host | 0.0.0.0 |
| LOG_LEVEL | Logging level | info |
| CLUSTERS_CONFIG_PATH | Path to clusters config | ./config/clusters.json |
| API_KEY | API key for authentication (empty = disabled) | |
| `API_KEY_HEADER` | HTTP header name for API key | `X-API-Key` |
| `CH_PASSWORD` | ClickHouse password (referenced in clusters.json) | |
| PG_PASSWORD | PostgreSQL password (referenced in clusters.json) | |
| `MYSQL_PASSWORD` | MySQL password (referenced in clusters.json) | |
Tip: Use environment templates from
config/env/for quick scenario switching.
License
MIT License - see LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
Support
For issues and feature requests, please open an issue on GitHub.
