443 lines
12 KiB
Markdown
443 lines
12 KiB
Markdown
# MCP Database Server
|
||
|
||
WebSocket-based PostgreSQL tooling service for AI clients using the Model Context Protocol (MCP).
|
||
|
||
## Features
|
||
|
||
- **WebSocket Transport**: Long-running daemon accessible by multiple AI clients
|
||
- **Multi-Environment Support**: Connect to multiple PostgreSQL databases with different schemas
|
||
- **Token Authentication**: Secure Bearer token authentication
|
||
- **Session Isolation**: Per-client session management with transaction binding
|
||
- **Audit Logging**: JSON Lines format with SQL sanitization
|
||
- **Health Check**: Built-in `/health` endpoint for monitoring
|
||
- **Docker Ready**: Multi-stage build with minimal image size
|
||
|
||
## Quick Start
|
||
|
||
### 1. Install Dependencies
|
||
|
||
```bash
|
||
npm install
|
||
```
|
||
|
||
### 2. Build
|
||
|
||
```bash
|
||
npm run build
|
||
```
|
||
|
||
### 3. Generate Auth Token
|
||
|
||
```bash
|
||
node scripts/generate-token.js
|
||
```
|
||
|
||
### 4. Create Configuration
|
||
|
||
```bash
|
||
cp config/database.example.json config/database.json
|
||
# Edit config/database.json with your database connections
|
||
```
|
||
|
||
### 5. Start Server
|
||
|
||
```bash
|
||
export MCP_AUTH_TOKEN="your-generated-token"
|
||
export MCP_DRWORKS_PASSWORD="your-db-password"
|
||
node dist/server.js --config config/database.json
|
||
```
|
||
|
||
### 6. Verify
|
||
|
||
```bash
|
||
curl http://localhost:7700/health
|
||
```
|
||
|
||
## Configuration
|
||
|
||
### Configuration File Format
|
||
|
||
```json
|
||
{
|
||
"server": {
|
||
"listen": {
|
||
"host": "0.0.0.0",
|
||
"port": 7700
|
||
},
|
||
"auth": {
|
||
"type": "token",
|
||
"token": "ENV:MCP_AUTH_TOKEN"
|
||
},
|
||
"maxConcurrentClients": 50,
|
||
"logLevel": "info"
|
||
},
|
||
"environments": {
|
||
"mydb": {
|
||
"type": "postgres",
|
||
"connection": {
|
||
"host": "localhost",
|
||
"port": 5432,
|
||
"database": "mydb",
|
||
"user": "postgres",
|
||
"password": "ENV:MCP_MYDB_PASSWORD"
|
||
},
|
||
"defaultSchema": "public",
|
||
"searchPath": ["public", "app"],
|
||
"pool": {
|
||
"max": 10,
|
||
"idleTimeoutMs": 30000
|
||
},
|
||
"statementTimeoutMs": 60000,
|
||
"mode": "readonly"
|
||
}
|
||
},
|
||
"audit": {
|
||
"enabled": true,
|
||
"output": "stdout",
|
||
"redactParams": true,
|
||
"maxSqlLength": 200
|
||
}
|
||
}
|
||
```
|
||
配置结构总览
|
||
|
||
{
|
||
"server": { ... }, // 服务器配置
|
||
"environments": { ... }, // 数据库环境配置(可多个)
|
||
"audit": { ... } // 审计日志配置
|
||
}
|
||
|
||
---
|
||
一、server - 服务器配置
|
||
|
||
"server": {
|
||
"listen": {
|
||
"host": "0.0.0.0", // 监听地址
|
||
// "0.0.0.0" = 所有网卡(外部可访问)
|
||
// "127.0.0.1" = 仅本机
|
||
"port": 7700 // WebSocket 端口
|
||
},
|
||
"auth": {
|
||
"type": "token", // 鉴权类型:token / mtls / none
|
||
"token": "ENV:MCP_AUTH_TOKEN" // Token 值,从环境变量读取
|
||
},
|
||
"maxConcurrentClients": 50, // 最大同时连接的客户端数
|
||
"logLevel": "info" // 日志级别:debug / info / warn / error
|
||
}
|
||
|
||
---
|
||
二、environments - 数据库环境
|
||
|
||
每个环境是一个独立的连接池,可配置多个:
|
||
|
||
"environments": {
|
||
"drworks": { // 环境名(调用工具时指定)
|
||
"type": "postgres", // 数据库类型(目前仅支持 postgres)
|
||
|
||
"connection": { // ═══ 连接参数 ═══
|
||
"host": "47.99.124.43", // 数据库服务器 IP/域名
|
||
"port": 5432, // PostgreSQL 端口
|
||
"database": "shcis_drworks_cpoe_pg", // 数据库名
|
||
"user": "postgres", // 用户名
|
||
"password": "passw0rd!", // 密码(建议用 ENV:)
|
||
"ssl": {
|
||
"require": false // SSL 连接:true=强制,false=不使用
|
||
}
|
||
},
|
||
|
||
"defaultSchema": "dbo", // ═══ 模式配置 ═══
|
||
// 默认模式,工具调用不传 schema 时使用
|
||
|
||
"searchPath": ["dbo", "api", "nurse"],
|
||
// 搜索路径,查询时按顺序在这些模式中查找表
|
||
// 例:SELECT * FROM patient 会先找 dbo.patient
|
||
|
||
"pool": { // ═══ 连接池配置 ═══
|
||
"max": 10, // 最大连接数(并发查询上限)
|
||
"idleTimeoutMs": 30000, // 空闲连接 30 秒后释放
|
||
"connectionTimeoutMs": 10000 // 获取连接超时 10 秒
|
||
},
|
||
|
||
"statementTimeoutMs": 60000, // SQL 执行超时 60 秒(防止卡死)
|
||
"slowQueryMs": 2000, // 超过 2 秒记录慢查询告警
|
||
|
||
"mode": "ddl" // ═══ 权限模式 ═══
|
||
// readonly = 只能 SELECT
|
||
// readwrite = 可 INSERT/UPDATE/DELETE
|
||
// ddl = 可 CREATE/ALTER/DROP(最高权限)
|
||
},
|
||
|
||
"ipworkstation": { ... } // 第二个环境,配置类似
|
||
}
|
||
|
||
---
|
||
三、audit - 审计日志
|
||
|
||
"audit": {
|
||
"enabled": true, // 是否启用审计日志
|
||
"output": "stdout", // 输出位置:
|
||
// "stdout" = 标准输出(容器推荐)
|
||
// "/var/log/mcp/audit.log" = 文件
|
||
"format": "json", // 格式:json(便于日志系统解析)
|
||
"redactParams": true, // 脱敏:SQL 参数值替换为 [REDACTED]
|
||
"maxSqlLength": 200 // SQL 预览最大长度(超出截断)
|
||
}
|
||
|
||
---
|
||
|
||
### Environment Variable Resolution
|
||
|
||
Use `ENV:VAR_NAME` syntax to reference environment variables:
|
||
|
||
```json
|
||
{
|
||
"password": "ENV:MCP_MYDB_PASSWORD"
|
||
}
|
||
```
|
||
|
||
### Configuration Fields
|
||
|
||
#### server
|
||
|
||
| Field | Type | Default | Description |
|
||
|-------|------|---------|-------------|
|
||
| listen.host | string | "0.0.0.0" | Listen address |
|
||
| listen.port | number | 7700 | Listen port |
|
||
| auth.type | string | "token" | Authentication type: token, mtls, none |
|
||
| auth.token | string | - | Bearer token (required if type=token) |
|
||
| maxConcurrentClients | number | 50 | Maximum WebSocket connections |
|
||
| logLevel | string | "info" | Log level: debug, info, warn, error |
|
||
|
||
#### environments
|
||
|
||
| Field | Type | Default | Description |
|
||
|-------|------|---------|-------------|
|
||
| type | string | "postgres" | Database type (only postgres supported) |
|
||
| connection.host | string | - | PostgreSQL host |
|
||
| connection.port | number | 5432 | PostgreSQL port |
|
||
| connection.database | string | - | Database name |
|
||
| connection.user | string | - | Username |
|
||
| connection.password | string | - | Password |
|
||
| connection.ssl | object | - | SSL configuration |
|
||
| defaultSchema | string | "public" | Default schema |
|
||
| searchPath | string[] | - | Schema search path |
|
||
| pool.max | number | 10 | Max pool connections |
|
||
| pool.idleTimeoutMs | number | 30000 | Idle connection timeout |
|
||
| statementTimeoutMs | number | 60000 | Query timeout |
|
||
| mode | string | "readonly" | Permission mode: readonly, readwrite, ddl |
|
||
|
||
#### audit
|
||
|
||
| Field | Type | Default | Description |
|
||
|-------|------|---------|-------------|
|
||
| enabled | boolean | true | Enable audit logging |
|
||
| output | string | "stdout" | Output: stdout or file path |
|
||
| redactParams | boolean | true | Redact SQL parameters |
|
||
| maxSqlLength | number | 200 | Max SQL preview length |
|
||
|
||
## Command Line Options
|
||
|
||
```bash
|
||
node dist/server.js [options]
|
||
|
||
Options:
|
||
--config <path> Configuration file path (default: ./config/database.json)
|
||
--listen <host:port> Listen address (overrides config)
|
||
--auth-token <token> Auth token (overrides config)
|
||
--log-level <level> Log level (overrides config)
|
||
```
|
||
|
||
Environment variables override configuration file:
|
||
|
||
| Variable | Description |
|
||
|----------|-------------|
|
||
| MCP_CONFIG | Configuration file path |
|
||
| MCP_LISTEN | Listen address (host:port) |
|
||
| MCP_AUTH_TOKEN | Authentication token |
|
||
| MCP_LOG_LEVEL | Log level |
|
||
| MCP_<ENV>_PASSWORD | Database password for environment |
|
||
|
||
## Authentication
|
||
|
||
### Token Authentication
|
||
|
||
Clients must provide a Bearer token in the WebSocket handshake:
|
||
|
||
```http
|
||
GET / HTTP/1.1
|
||
Upgrade: websocket
|
||
Authorization: Bearer your-token-here
|
||
```
|
||
|
||
Generate a secure token:
|
||
|
||
```bash
|
||
node scripts/generate-token.js
|
||
# Output: 64-character hex string
|
||
```
|
||
|
||
### Client Configuration (Claude Code)
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"database": {
|
||
"transport": "websocket",
|
||
"endpoint": "ws://localhost:7700",
|
||
"headers": {
|
||
"Authorization": "Bearer your-token-here"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## Available Tools
|
||
|
||
The server exposes 30+ MCP tools for PostgreSQL operations:
|
||
|
||
### Metadata Tools
|
||
- `pg_list_environments` - List configured database environments
|
||
- `pg_list_schemas` - List schemas in an environment
|
||
- `pg_list_tables` - List tables in a schema
|
||
- `pg_describe_table` - Get table structure
|
||
- `pg_list_views` - List views
|
||
- `pg_list_functions` - List functions
|
||
- `pg_list_indexes` - List indexes
|
||
- `pg_list_constraints` - List constraints
|
||
- `pg_list_triggers` - List triggers
|
||
|
||
### Query Tools
|
||
- `pg_query` - Execute read-only SQL query
|
||
- `pg_explain` - Get query execution plan
|
||
|
||
### Data Tools
|
||
- `pg_insert` - Insert rows
|
||
- `pg_update` - Update rows
|
||
- `pg_delete` - Delete rows
|
||
- `pg_upsert` - Insert or update rows
|
||
- `pg_bulk_insert` - Insert multiple rows
|
||
|
||
### Transaction Tools
|
||
- `pg_begin_transaction` - Start transaction
|
||
- `pg_commit_transaction` - Commit transaction
|
||
- `pg_rollback_transaction` - Rollback transaction
|
||
|
||
### Diagnostic Tools
|
||
- `pg_analyze_query` - Analyze query performance
|
||
- `pg_check_connection` - Check database connectivity
|
||
|
||
## Docker Deployment
|
||
|
||
### Build Image
|
||
|
||
```bash
|
||
docker build -t mcp-database-server:1.0.0 .
|
||
docker build -t mcp-database-server:1.0.1.02 .
|
||
docker build -t mcp-database-server:1.0.1.03 .
|
||
docker build -t mcp-database-server:1.0.2 .
|
||
docker compose build --no-cache && docker compose up -d
|
||
```
|
||
|
||
### Run Container
|
||
|
||
```bash
|
||
docker run -d \
|
||
--name mcp-database-server \
|
||
-p 7700:7700 \
|
||
-v $(pwd)/config/database.json:/app/config/database.json:ro \
|
||
-e MCP_AUTH_TOKEN=your-token \
|
||
-e MCP_DRWORKS_PASSWORD=your-password \
|
||
mcp-database-server:1.0.0
|
||
```
|
||
|
||
### Docker Compose
|
||
|
||
```bash
|
||
cp docker-compose.example.yml docker-compose.yml
|
||
cp config/database.example.json config/database.json
|
||
# Edit configuration files
|
||
|
||
# Create .env file
|
||
echo "MCP_AUTH_TOKEN=$(node scripts/generate-token.js | head -2 | tail -1)" > .env
|
||
echo "MCP_DRWORKS_PASSWORD=your-password" >> .env
|
||
|
||
# Start
|
||
docker compose up -d
|
||
```
|
||
|
||
## Health Check
|
||
|
||
The server exposes a health check endpoint:
|
||
|
||
```bash
|
||
curl http://localhost:7700/health
|
||
```
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"uptime": 3600,
|
||
"version": "1.0.0",
|
||
"clients": 5,
|
||
"environments": [
|
||
{
|
||
"name": "drworks",
|
||
"status": "connected",
|
||
"poolSize": 10,
|
||
"activeConnections": 2
|
||
}
|
||
],
|
||
"timestamp": "2025-12-23T10:30:00.000Z"
|
||
}
|
||
```
|
||
|
||
Status values:
|
||
- `ok` - All environments connected
|
||
- `degraded` - Some environments disconnected
|
||
- `error` - Critical failures
|
||
|
||
## Security Recommendations
|
||
|
||
1. **Use Strong Tokens**: Generate 64-character random tokens
|
||
2. **Enable SSL**: Use `wss://` in production with TLS termination
|
||
3. **Restrict Network**: Use firewall rules to limit access
|
||
4. **Read-Only Mode**: Use `mode: "readonly"` for read-only access
|
||
5. **Audit Logging**: Enable audit logging for compliance
|
||
6. **Rotate Tokens**: Periodically rotate authentication tokens
|
||
7. **Non-Root User**: Docker image runs as non-root user (UID 1001)
|
||
|
||
## Graceful Shutdown
|
||
|
||
The server handles SIGTERM and SIGINT signals:
|
||
|
||
1. Stops accepting new connections
|
||
2. Rolls back active transactions
|
||
3. Closes all sessions
|
||
4. Closes database connection pools
|
||
5. Exits cleanly
|
||
|
||
```bash
|
||
# Graceful stop
|
||
docker stop mcp-database-server
|
||
|
||
# Or send signal directly
|
||
kill -TERM $(pgrep -f "node dist/server.js")
|
||
```
|
||
|
||
## Logging
|
||
|
||
Logs are output in JSON format (pino):
|
||
|
||
```json
|
||
{"level":"info","time":"2025-12-23T10:30:00.000Z","msg":"WebSocket server started","host":"0.0.0.0","port":7700}
|
||
```
|
||
|
||
Log levels: `debug`, `info`, `warn`, `error`, `fatal`
|
||
|
||
## License
|
||
|
||
MIT
|