@adevguide/mcp-database-server 1.0.2 β†’ 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,1050 +1,1181 @@
1
- # MCP Database Server
2
-
3
- > **Enterprise-grade Model Context Protocol server for unified SQL database access**
4
-
5
- A production-ready MCP server that provides seamless, intelligent access to multiple SQL databases with automatic schema discovery, relationship mapping, and built-in security controls.
6
-
7
- ## Features
8
-
9
- - πŸ—„οΈ **Multi-Database Support** - PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle
10
- - πŸ” **Automatic Schema Discovery** - Tables, columns, indexes, foreign keys, and relationships
11
- - πŸ’Ύ **Intelligent Caching** - Persistent schema cache with TTL and version management
12
- - πŸ”— **Relationship Inference** - Automatic foreign key detection plus heuristic pattern matching
13
- - πŸ“Š **Query Intelligence** - Execution tracking, statistics, and performance insights
14
- - 🎯 **Join Assistance** - Smart join path recommendations based on relationship graphs
15
- - πŸ”’ **Enterprise Security** - Read-only mode, operation controls, dangerous operation protection, secret redaction
16
- - ⚑ **High Performance** - Connection pooling, query timeouts, concurrent operation protection
17
- - 🌐 **Environment Flexibility** - Environment variable interpolation for secure configuration
18
-
19
- ## Architecture
20
-
21
- ```
22
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
23
- β”‚ MCP Client β”‚
24
- β”‚ (Claude Desktop, IDEs, etc.) β”‚
25
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
26
- β”‚ JSON-RPC over stdio
27
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
28
- β”‚ MCP Database Server β”‚
29
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
30
- β”‚ β”‚ Schema Cache (TTL + Versioning) β”‚ β”‚
31
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
32
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
33
- β”‚ β”‚ Query Tracker (History + Statistics) β”‚ β”‚
34
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
35
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
36
- β”‚ β”‚ Security Layer (Read-only, Operation Controls) β”‚ β”‚
37
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
38
- β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
39
- β”‚ β”‚ β”‚ β”‚ β”‚
40
- β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
41
- β”‚Postgresβ”‚ β”‚ MySQL β”‚ β”‚ SQLite β”‚ β”‚ MSSQL β”‚ β”‚ Oracle β”‚
42
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
43
- ```
44
-
45
- ## Supported Databases
46
-
47
- | Database | Driver | Status | Notes |
48
- |----------|--------|--------|-------|
49
- | PostgreSQL | `pg` | βœ… Full Support | Includes CockroachDB compatibility |
50
- | MySQL/MariaDB | `mysql2` | βœ… Full Support | Includes Amazon Aurora MySQL compatibility |
51
- | SQLite | `better-sqlite3` | βœ… Full Support | File-based databases |
52
- | SQL Server | `tedious` | βœ… Full Support | Microsoft SQL Server / Azure SQL |
53
- | Oracle | `oracledb` | ⚠️ Stub | Requires Oracle Instant Client |
54
-
55
- ## Installation
56
-
57
- ### Method 1: Install from npm (Recommended)
58
-
59
- If this package is published to npm:
60
-
61
- ```bash
62
- npm install -g @adevguide/mcp-database-server
63
- ```
64
-
65
- Then you can run it directly:
66
-
67
- ```bash
68
- mcp-database-server --config /path/to/your/config.json
69
- ```
70
-
71
- ### Method 2: Install from source
72
-
73
- Clone and build the project:
74
-
75
- ```bash
76
- git clone https://github.com/iPraBhu/mcp-database-server.git
77
- cd mcp-database-server
78
- npm install
79
- npm run build
80
- ```
81
-
82
- Then run it:
83
-
84
- ```bash
85
- node dist/index.js --config ./.mcp-database-server.config
86
- ```
87
-
88
- ## Configuration
89
-
90
- Create a `.mcp-database-server.config` file in your project root:
91
-
92
- > **Note:** The config file is automatically discovered! If you don't specify `--config`, the tool searches for `.mcp-database-server.config` starting in the current directory and traversing up parent directories until found. This means you can run the tool from any subdirectory of your project.
93
-
94
- ```json
95
- {
96
- "databases": [
97
- {
98
- "id": "postgres-main",
99
- "type": "postgres",
100
- "url": "${DB_URL_POSTGRES}",
101
- "readOnly": false,
102
- "pool": {
103
- "min": 2,
104
- "max": 10,
105
- "idleTimeoutMillis": 30000
106
- },
107
- "introspection": {
108
- "includeViews": true,
109
- "excludeSchemas": ["pg_catalog"]
110
- }
111
- },
112
- {
113
- "id": "sqlite-local",
114
- "type": "sqlite",
115
- "path": "./data/app.db"
116
- }
117
- ],
118
- "cache": {
119
- "directory": ".sql-mcp-cache",
120
- "ttlMinutes": 10
121
- },
122
- "security": {
123
- "allowWrite": false,
124
- "allowedWriteOperations": ["INSERT", "UPDATE"],
125
- "disableDangerousOperations": true,
126
- "redactSecrets": true
127
- },
128
- "logging": {
129
- "level": "info",
130
- "pretty": false
131
- }
132
- }
133
- ```
134
-
135
- ### Configuration Reference
136
-
137
- #### Database Configuration
138
-
139
- Each database in the `databases` array represents a connection to a SQL database.
140
-
141
- ##### Core Properties
142
-
143
- | Property | Type | Required | Default | Description |
144
- |----------|------|----------|---------|-------------|
145
- | `id` | string | βœ… Yes | - | Unique identifier for this database connection. Used in all MCP tool calls. Must be unique across all databases. |
146
- | `type` | enum | βœ… Yes | - | Database system type. Valid values: `postgres`, `mysql`, `sqlite`, `mssql`, `oracle` |
147
- | `url` | string | Conditional* | - | Database connection string. Required for all databases except SQLite. Supports environment variable interpolation: `${DB_URL}` |
148
- | `path` | string | Conditional** | - | Filesystem path to SQLite database file. Required only for `type: sqlite`. Can be relative or absolute. |
149
- | `readOnly` | boolean | No | `true` | When `true`, blocks all write operations (INSERT, UPDATE, DELETE, etc.). Recommended for production safety. |
150
- | `eagerConnect` | boolean | No | `false` | When `true`, connects to database immediately at startup (fail-fast). When `false`, connects on first query (lazy loading). |
151
-
152
- <sub>* Required for postgres, mysql, mssql, oracle</sub>
153
- <sub>** Required for sqlite only</sub>
154
-
155
- **Connection String Formats:**
156
- ```
157
- PostgreSQL: postgresql://username:password@host:5432/database
158
- MySQL: mysql://username:password@host:3306/database
159
- SQL Server: Server=host,1433;Database=dbname;User Id=user;Password=pass
160
- SQLite: (use path property instead)
161
- Oracle: username/password@host:1521/servicename
162
- ```
163
-
164
- ##### Connection Pool Configuration
165
-
166
- The `pool` object controls connection pooling behavior. Improves performance by reusing database connections.
167
-
168
- | Property | Type | Required | Default | Description |
169
- |----------|------|----------|---------|-------------|
170
- | `min` | number | No | `2` | Minimum number of connections to maintain in the pool. Kept alive even when idle. |
171
- | `max` | number | No | `10` | Maximum number of concurrent connections. Do not exceed your database's connection limit. |
172
- | `idleTimeoutMillis` | number | No | `30000` | Time (ms) to keep idle connections alive before closing. Example: `60000` = 1 minute. |
173
- | `connectionTimeoutMillis` | number | No | `10000` | Time (ms) to wait when establishing a connection before timing out. Fail-fast if database is unreachable. |
174
-
175
- **Recommendations:**
176
- - **Development:** `min: 1`, `max: 5`
177
- - **Production (Low Traffic):** `min: 2`, `max: 10`
178
- - **Production (High Traffic):** `min: 5`, `max: 20`
179
-
180
- ##### Introspection Configuration
181
-
182
- The `introspection` object controls schema discovery behavior. Determines what database objects are analyzed.
183
-
184
- | Property | Type | Required | Default | Description |
185
- |----------|------|----------|---------|-------------|
186
- | `includeViews` | boolean | No | `true` | Include database views in schema discovery. Set to `false` if views cause performance issues. |
187
- | `includeRoutines` | boolean | No | `false` | Include stored procedures and functions. (Not fully implemented - planned feature) |
188
- | `maxTables` | number | No | unlimited | Limit introspection to first N tables. Useful for databases with 1000+ tables. May result in incomplete relationship discovery. |
189
- | `includeSchemas` | string[] | No | all | Whitelist of schemas to introspect. Only applicable to PostgreSQL and SQL Server. Example: `["public", "app"]` |
190
- | `excludeSchemas` | string[] | No | none | Blacklist of schemas to skip. Common values: `["pg_catalog", "information_schema", "sys"]` |
191
-
192
- **Schema vs Database:**
193
- - **PostgreSQL/SQL Server:** Support multiple schemas per database. Use `includeSchemas`/`excludeSchemas`.
194
- - **MySQL/MariaDB:** Schema = database. Use database name in connection string.
195
- - **SQLite:** Single-file database, no schema concept.
196
-
197
- #### Cache Configuration
198
-
199
- Controls schema metadata caching to improve startup performance and reduce database load.
200
-
201
- | Property | Type | Required | Default | Description |
202
- |----------|------|----------|---------|-------------|
203
- | `directory` | string | No | `.sql-mcp-cache` | Directory path where cached schema files are stored. One JSON file per database. |
204
- | `ttlMinutes` | number | No | `10` | Time-To-Live in minutes. How long cached schema is considered valid before automatic refresh. |
205
-
206
- **Cache Behavior:**
207
- - **On Startup:** Loads schema from cache if available and not expired
208
- - **After TTL Expiry:** Next query triggers automatic re-introspection
209
- - **Manual Refresh:** Use `clear_cache` tool or `introspect_schema` with `forceRefresh: true`
210
- - **Cache Files:** Stored as `{database-id}.json` (e.g., `postgres-main.json`)
211
-
212
- **Recommended TTL Values:**
213
- - **Development:** `5` minutes (schema changes frequently)
214
- - **Staging:** `30-60` minutes
215
- - **Production (Static):** `1440` minutes (24 hours)
216
- - **Production (Active):** `60-240` minutes (1-4 hours)
217
-
218
- #### Security Configuration
219
-
220
- Comprehensive security controls to protect your databases from unauthorized or dangerous operations.
221
-
222
- | Property | Type | Required | Default | Description |
223
- |----------|------|----------|---------|-------------|
224
- | `allowWrite` | boolean | No | `false` | Master switch for write operations. When `false`, all writes are blocked across all databases. |
225
- | `allowedWriteOperations` | string[] | No | all | Whitelist of allowed SQL operations when `allowWrite: true`. Valid values: `INSERT`, `UPDATE`, `DELETE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `REPLACE`, `MERGE` |
226
- | `disableDangerousOperations` | boolean | No | `true` | **Extra safety layer.** When `true`, blocks `DELETE`, `TRUNCATE`, and `DROP` operations even if writes are allowed. Prevents accidental data loss. |
227
- | `redactSecrets` | boolean | No | `true` | Automatically redact passwords and credentials in logs and error messages. |
228
-
229
- **Security Layers (Evaluated in Order):**
230
-
231
- 1. **Database-level `readOnly`** β†’ Blocks all writes for specific database
232
- 2. **Global `allowWrite`** β†’ Master switch for all databases
233
- 3. **`disableDangerousOperations`** β†’ Blocks DELETE/TRUNCATE/DROP specifically
234
- 4. **`allowedWriteOperations`** β†’ Whitelist of permitted operations
235
-
236
- **Example Configurations:**
237
-
238
- ```json
239
- // Read-only access (default - safest)
240
- {
241
- "allowWrite": false
242
- }
243
-
244
- // Allow INSERT and UPDATE only (no deletes)
245
- {
246
- "allowWrite": true,
247
- "allowedWriteOperations": ["INSERT", "UPDATE"],
248
- "disableDangerousOperations": true
249
- }
250
-
251
- // Full write access (development only - dangerous!)
252
- {
253
- "allowWrite": true,
254
- "disableDangerousOperations": false
255
- }
256
- ```
257
-
258
- #### Logging Configuration
259
-
260
- Controls log output verbosity and formatting.
261
-
262
- | Property | Type | Required | Default | Description |
263
- |----------|------|----------|---------|-------------|
264
- | `level` | enum | No | `info` | Log level. Valid values: `trace`, `debug`, `info`, `warn`, `error`. Lower levels include higher levels. |
265
- | `pretty` | boolean | No | `false` | When `true`, formats logs as human-readable text. When `false`, outputs structured JSON (better for production log aggregation). |
266
-
267
- **Log Levels:**
268
- - **`trace`:** Everything (extremely verbose - use for debugging only)
269
- - **`debug`:** Detailed diagnostic information
270
- - **`info`:** General informational messages (recommended for production)
271
- - **`warn`:** Warning messages that don't prevent operation
272
- - **`error`:** Error messages only
273
-
274
- **Recommendations:**
275
- - **Development:** `level: "debug"`, `pretty: true`
276
- - **Production:** `level: "info"`, `pretty: false`
277
- - **Troubleshooting:** `level: "trace"`, `pretty: true`
278
-
279
- ---
280
-
281
- ### Complete Configuration Example
282
-
283
- ```json
284
- {
285
- "databases": [
286
- {
287
- "id": "postgres-production",
288
- "type": "postgres",
289
- "url": "${DATABASE_URL}",
290
- "readOnly": true,
291
- "pool": {
292
- "min": 5,
293
- "max": 20,
294
- "idleTimeoutMillis": 60000,
295
- "connectionTimeoutMillis": 5000
296
- },
297
- "introspection": {
298
- "includeViews": true,
299
- "includeRoutines": false,
300
- "excludeSchemas": ["pg_catalog", "information_schema"]
301
- },
302
- "eagerConnect": true
303
- },
304
- {
305
- "id": "mysql-analytics",
306
- "type": "mysql",
307
- "url": "${MYSQL_URL}",
308
- "readOnly": true,
309
- "pool": {
310
- "min": 2,
311
- "max": 10
312
- },
313
- "introspection": {
314
- "includeViews": true,
315
- "maxTables": 100
316
- }
317
- },
318
- {
319
- "id": "sqlite-local",
320
- "type": "sqlite",
321
- "path": "./data/app.db",
322
- "readOnly": false
323
- }
324
- ],
325
- "cache": {
326
- "directory": ".sql-mcp-cache",
327
- "ttlMinutes": 60
328
- },
329
- "security": {
330
- "allowWrite": false,
331
- "allowedWriteOperations": ["INSERT", "UPDATE"],
332
- "disableDangerousOperations": true,
333
- "redactSecrets": true
334
- },
335
- "logging": {
336
- "level": "info",
337
- "pretty": false
338
- }
339
- }
340
- ```
341
-
342
- ---
343
-
344
- ### Environment Variables
345
-
346
- **Secure Configuration with Environment Variables:**
347
-
348
- The server supports environment variable interpolation using `${VARIABLE_NAME}` syntax. This is the recommended approach for managing sensitive credentials.
349
-
350
- **Example Configuration:**
351
- ```json
352
- {
353
- "databases": [
354
- {
355
- "id": "production-db",
356
- "type": "postgres",
357
- "url": "${DATABASE_URL}"
358
- }
359
- ]
360
- }
361
- ```
362
-
363
- **Environment File (`.env`):**
364
- ```env
365
- DATABASE_URL=postgresql://user:password@localhost:5432/dbname
366
- DB_URL_MYSQL=mysql://user:password@localhost:3306/dbname
367
- DB_URL_MSSQL=Server=host,1433;Database=db;User Id=sa;Password=pass
368
- ```
369
-
370
- **Best Practices:**
371
- - βœ… Store `.env` file outside version control (add to `.gitignore`)
372
- - βœ… Use different `.env` files for each environment (dev, staging, prod)
373
- - βœ… Never commit credentials to git repositories
374
- - βœ… Use secret management services (AWS Secrets Manager, HashiCorp Vault) in production
375
-
376
- ---
377
-
378
- ### Connection String Reference
379
-
380
- | Database | Format | Example |
381
- |----------|--------|---------|
382
- | **PostgreSQL** | `postgresql://user:pass@host:port/db` | `postgresql://admin:secret@localhost:5432/myapp` |
383
- | **MySQL** | `mysql://user:pass@host:port/db` | `mysql://root:password@localhost:3306/myapp` |
384
- | **SQL Server** | `Server=host,port;Database=db;User Id=user;Password=pass` | `Server=localhost,1433;Database=myapp;User Id=sa;Password=secret` |
385
- | **SQLite** | Use `path` property | `"path": "./data/app.db"` or `"path": "/var/db/app.sqlite"` |
386
- | **Oracle** | `user/pass@host:port/service` | `admin/secret@localhost:1521/XEPDB1` |
387
-
388
- **Additional Parameters:**
389
-
390
- **PostgreSQL:**
391
- ```
392
- postgresql://user:pass@host:5432/db?sslmode=require&connect_timeout=10
393
- ```
394
-
395
- **MySQL:**
396
- ```
397
- mysql://user:pass@host:3306/db?charset=utf8mb4&timezone=Z
398
- ```
399
-
400
- **SQL Server:**
401
- ```
402
- Server=host;Database=db;User Id=user;Password=pass;Encrypt=true;TrustServerCertificate=false
403
- ```
404
-
405
- ---
406
-
407
- ## MCP Client Integration
408
-
409
- ### Configuration File Locations
410
-
411
- | MCP Client | Configuration File Path |
412
- |------------|------------------------|
413
- | **Claude Desktop** (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
414
- | **Claude Desktop** (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
415
- | **Cline** (VS Code) | VS Code settings β†’ MCP Servers |
416
- | **Other Clients** | Refer to client-specific documentation |
417
-
418
- ### Setup Methods
419
-
420
- #### Method 1: Global npm Installation
421
-
422
- **Configuration:**
423
- ```json
424
- {
425
- "mcpServers": {
426
- "database": {
427
- "command": "mcp-database-server",
428
- "args": ["--config", "/absolute/path/to/.mcp-database-server.config"],
429
- "env": {
430
- "DATABASE_URL": "postgresql://user:pass@localhost:5432/db"
431
- }
432
- }
433
- }
434
- }
435
- ```
436
-
437
- #### Method 2: Source Installation
438
-
439
- **Configuration:**
440
- ```json
441
- {
442
- "mcpServers": {
443
- "database": {
444
- "command": "node",
445
- "args": [
446
- "/absolute/path/to/mcp-database-server/dist/index.js",
447
- "--config",
448
- "/absolute/path/to/.mcp-database-server.config"
449
- ],
450
- "env": {
451
- "DATABASE_URL": "postgresql://user:pass@localhost:5432/db"
452
- }
453
- }
454
- }
455
- }
456
- ```
457
-
458
- ### Configuration Properties
459
-
460
- | Property | Description | Example |
461
- |----------|-------------|---------|
462
- | `command` | Executable to run. Use `mcp-database-server` for npm install, `node` for source install. | `"mcp-database-server"` |
463
- | `args` | Array of command-line arguments. First arg is usually `--config` followed by config file path. | `["--config", "/path/to/config"]` |
464
- | `env` | Environment variables passed to the server. Used for secure credential management. | `{"DATABASE_URL": "..."}` |
465
-
466
- **Finding Absolute Paths:**
467
- ```bash
468
- # macOS/Linux
469
- cd /path/to/mcp-database-server
470
- pwd # prints: /Users/username/projects/mcp-database-server
471
-
472
- # Windows (PowerShell)
473
- cd C:\path\to\mcp-database-server
474
- $PWD.Path # prints: C:\Users\username\projects\mcp-database-server
475
- ```
476
-
477
- ---
478
-
479
- ## Available MCP Tools
480
-
481
- This server provides 9 tools for comprehensive database interaction.
482
-
483
- ### Tool Reference
484
-
485
- | Tool | Purpose | Write Access | Cached Data |
486
- |------|---------|--------------|-------------|
487
- | `list_databases` | List all configured databases with status | No | Uses cache |
488
- | `introspect_schema` | Discover and cache database schema | No | Writes cache |
489
- | `get_schema` | Retrieve cached schema metadata | No | Reads cache |
490
- | `run_query` | Execute SQL queries with safety controls | Conditional* | Updates stats |
491
- | `explain_query` | Analyze query execution plans | No | No cache |
492
- | `suggest_joins` | Get intelligent join path recommendations | No | Uses cache |
493
- | `clear_cache` | Clear schema cache and statistics | No | Clears cache |
494
- | `cache_status` | View cache health and statistics | No | Reads cache |
495
- | `health_check` | Test database connectivity | No | No cache |
496
-
497
- <sub>* Requires `allowWrite: true` and respects security settings</sub>
498
-
499
- ---
500
-
501
- ### 1. list_databases
502
-
503
- Lists all configured databases with their connection status and cache information.
504
-
505
- **Input Parameters:**
506
-
507
- None required.
508
-
509
- **Response:**
510
- ```json
511
- [
512
- {
513
- "id": "postgres-main",
514
- "type": "postgres",
515
- "connected": true,
516
- "cached": true,
517
- "cacheAge": 45000,
518
- "version": "abc123"
519
- }
520
- ]
521
- ```
522
-
523
- **Response Fields:**
524
-
525
- | Field | Type | Description |
526
- |-------|------|-------------|
527
- | `id` | string | Database identifier from configuration |
528
- | `type` | string | Database type (postgres, mysql, sqlite, mssql, oracle) |
529
- | `connected` | boolean | Whether database connection is active |
530
- | `cached` | boolean | Whether schema is currently cached |
531
- | `cacheAge` | number | Age of cached schema in milliseconds (if cached) |
532
- | `version` | string | Cache version hash (if cached) |
533
-
534
- ---
535
-
536
- ### 2. introspect_schema
537
-
538
- Discovers and caches complete database schema including tables, columns, indexes, foreign keys, and relationships.
539
-
540
- **Input Parameters:**
541
-
542
- | Parameter | Type | Required | Description |
543
- |-----------|------|----------|-------------|
544
- | `dbId` | string | Yes | Database identifier to introspect |
545
- | `forceRefresh` | boolean | No | Force re-introspection even if cache is valid (default: `false`) |
546
- | `schemaFilter` | object | No | Filter which objects to introspect |
547
- | `schemaFilter.includeSchemas` | string[] | No | Only introspect these schemas (PostgreSQL/SQL Server) |
548
- | `schemaFilter.excludeSchemas` | string[] | No | Skip these schemas during introspection |
549
- | `schemaFilter.includeViews` | boolean | No | Include database views (default: `true`) |
550
- | `schemaFilter.maxTables` | number | No | Limit to first N tables |
551
-
552
- **Example Request:**
553
- ```json
554
- {
555
- "dbId": "postgres-main",
556
- "forceRefresh": false,
557
- "schemaFilter": {
558
- "includeSchemas": ["public"],
559
- "excludeSchemas": ["temp"],
560
- "includeViews": true,
561
- "maxTables": 100
562
- }
563
- }
564
- ```
565
-
566
- **Response:**
567
- ```json
568
- {
569
- "dbId": "postgres-main",
570
- "version": "a1b2c3d4",
571
- "introspectedAt": "2026-01-26T10:00:00.000Z",
572
- "schemas": [
573
- {
574
- "name": "public",
575
- "tableCount": 15,
576
- "viewCount": 3
577
- }
578
- ],
579
- "totalTables": 15,
580
- "totalRelationships": 12
581
- }
582
- ```
583
-
584
- ---
585
-
586
- ### 3. get_schema
587
-
588
- Retrieves detailed schema metadata from cache without querying the database.
589
-
590
- **Input Parameters:**
591
-
592
- | Parameter | Type | Required | Description |
593
- |-----------|------|----------|-------------|
594
- | `dbId` | string | Yes | Database identifier |
595
- | `schema` | string | No | Filter to specific schema name |
596
- | `table` | string | No | Filter to specific table name |
597
-
598
- **Example Request:**
599
- ```json
600
- {
601
- "dbId": "postgres-main",
602
- "schema": "public",
603
- "table": "users"
604
- }
605
- ```
606
-
607
- **Response:** Complete schema metadata including tables, columns, data types, indexes, foreign keys, and inferred relationships.
608
-
609
- ---
610
-
611
- ### 4. run_query
612
-
613
- Executes SQL queries with automatic schema caching, relationship annotation, and comprehensive security controls.
614
-
615
- **Input Parameters:**
616
-
617
- | Parameter | Type | Required | Description |
618
- |-----------|------|----------|-------------|
619
- | `dbId` | string | Yes | Database identifier to query |
620
- | `sql` | string | Yes | SQL query to execute |
621
- | `params` | array | No | Parameterized query values (prevents SQL injection) |
622
- | `limit` | number | No | Maximum number of rows to return |
623
- | `timeoutMs` | number | No | Query timeout in milliseconds |
624
-
625
- **Example Request:**
626
- ```json
627
- {
628
- "dbId": "postgres-main",
629
- "sql": "SELECT * FROM users WHERE active = $1 LIMIT $2",
630
- "params": [true, 10],
631
- "timeoutMs": 5000
632
- }
633
- ```
634
-
635
- **Response:**
636
- ```json
637
- {
638
- "rows": [
639
- {"id": 1, "name": "Alice", "email": "alice@example.com", "active": true},
640
- {"id": 2, "name": "Bob", "email": "bob@example.com", "active": true}
641
- ],
642
- "columns": ["id", "name", "email", "active"],
643
- "rowCount": 2,
644
- "executionTimeMs": 15,
645
- "metadata": {
646
- "relationships": [...],
647
- "queryStats": {
648
- "totalQueries": 10,
649
- "avgExecutionTime": 20,
650
- "errorCount": 0
651
- }
652
- }
653
- }
654
- ```
655
-
656
- **Security Controls:**
657
- - βœ… Write operations blocked by default (`allowWrite: false`)
658
- - βœ… Dangerous operations (DELETE, TRUNCATE, DROP) disabled by default
659
- - βœ… Specific operations can be whitelisted via `allowedWriteOperations`
660
- - βœ… Per-database `readOnly` mode
661
-
662
- ---
663
-
664
- ### 5. explain_query
665
-
666
- Retrieves database query execution plan without executing the query.
667
-
668
- **Input Parameters:**
669
-
670
- | Parameter | Type | Required | Description |
671
- |-----------|------|----------|-------------|
672
- | `dbId` | string | Yes | Database identifier |
673
- | `sql` | string | Yes | SQL query to analyze |
674
- | `params` | array | No | Query parameters (for parameterized queries) |
675
-
676
- **Example Request:**
677
- ```json
678
- {
679
- "dbId": "postgres-main",
680
- "sql": "SELECT * FROM users JOIN orders ON users.id = orders.user_id WHERE users.active = $1",
681
- "params": [true]
682
- }
683
- ```
684
-
685
- **Response:** Database-native execution plan (format varies by database type).
686
-
687
- ---
688
-
689
- ### 6. suggest_joins
690
-
691
- Analyzes relationship graph to recommend optimal join paths between multiple tables.
692
-
693
- **Input Parameters:**
694
-
695
- | Parameter | Type | Required | Description |
696
- |-----------|------|----------|-------------|
697
- | `dbId` | string | Yes | Database identifier |
698
- | `tables` | string[] | Yes | Array of table names to join (2-10 tables) |
699
-
700
- **Example Request:**
701
- ```json
702
- {
703
- "dbId": "postgres-main",
704
- "tables": ["users", "orders", "products"]
705
- }
706
- ```
707
-
708
- **Response:**
709
- ```json
710
- [
711
- {
712
- "tables": ["users", "orders", "products"],
713
- "joins": [
714
- {
715
- "fromTable": "users",
716
- "toTable": "orders",
717
- "relationship": {
718
- "type": "one-to-many",
719
- "confidence": 1.0
720
- },
721
- "joinCondition": "users.id = orders.user_id"
722
- },
723
- {
724
- "fromTable": "orders",
725
- "toTable": "products",
726
- "relationship": {
727
- "type": "many-to-one",
728
- "confidence": 1.0
729
- },
730
- "joinCondition": "orders.product_id = products.id"
731
- }
732
- ],
733
- "sql": "FROM users JOIN orders ON users.id = orders.user_id JOIN products ON orders.product_id = products.id"
734
- }
735
- ]
736
- ```
737
-
738
- ---
739
-
740
- ### 7. clear_cache
741
-
742
- Clears schema cache and query statistics for one or all databases.
743
-
744
- **Input Parameters:**
745
-
746
- | Parameter | Type | Required | Description |
747
- |-----------|------|----------|-------------|
748
- | `dbId` | string | No | Database to clear (omit to clear all) |
749
-
750
- **Example Request:**
751
- ```json
752
- {
753
- "dbId": "postgres-main"
754
- }
755
- ```
756
-
757
- **Response:** Confirmation message.
758
-
759
- ---
760
-
761
- ### 8. cache_status
762
-
763
- Retrieves detailed cache statistics and health information.
764
-
765
- **Input Parameters:**
766
-
767
- None required.
768
-
769
- **Response:**
770
- ```json
771
- {
772
- "directory": ".sql-mcp-cache",
773
- "ttlMinutes": 10,
774
- "databases": [
775
- {
776
- "dbId": "postgres-main",
777
- "cached": true,
778
- "version": "abc123",
779
- "age": 120000,
780
- "expired": false,
781
- "tableCount": 15,
782
- "sizeBytes": 45678
783
- }
784
- ]
785
- }
786
- ```
787
-
788
- ---
789
-
790
- ### 9. health_check
791
-
792
- Tests database connectivity and returns status information.
793
-
794
- **Input Parameters:**
795
-
796
- | Parameter | Type | Required | Description |
797
- |-----------|------|----------|-------------|
798
- | `dbId` | string | No | Database to check (omit to check all) |
799
-
800
- **Response:**
801
- ```json
802
- {
803
- "databases": [
804
- {
805
- "dbId": "postgres-main",
806
- "healthy": true,
807
- "connected": true,
808
- "version": "PostgreSQL 15.3",
809
- "responseTimeMs": 12
810
- }
811
- ]
812
- }
813
- ```
814
-
815
- ---
816
-
817
- ### `cache_status`
818
-
819
- Get cache status and statistics.
820
-
821
- **Input:**
822
- ```json
823
- {
824
- "dbId": "postgres-main"
825
- }
826
- ```
827
-
828
- **Output:**
829
- ```json
830
- [
831
- {
832
- "dbId": "postgres-main",
833
- "exists": true,
834
- "age": 45000,
835
- "ttlMinutes": 10,
836
- "expired": false,
837
- "version": "abc123",
838
- "tableCount": 15,
839
- "relationshipCount": 12
840
- }
841
- ]
842
- ```
843
-
844
- ### `health_check`
845
-
846
- Check database connectivity and version information.
847
-
848
- **Input:**
849
- ```json
850
- {
851
- "dbId": "postgres-main"
852
- }
853
- ```
854
-
855
- **Output:**
856
- ```json
857
- [
858
- {
859
- "dbId": "postgres-main",
860
- "healthy": true,
861
- "version": "PostgreSQL 15.3"
862
- }
863
- ]
864
- ```
865
-
866
- ## Resources
867
-
868
- The server exposes cached schemas as MCP resources:
869
-
870
- - **URI:** `schema://{dbId}`
871
- - **MIME Type:** `application/json`
872
- - **Content:** Complete cached schema metadata
873
-
874
- ## Schema Introspection
875
-
876
- ### Automatic Discovery
877
-
878
- The server automatically discovers:
879
-
880
- 1. **Tables and Views**: All user tables and optionally views
881
- 2. **Columns**: Name, data type, nullability, defaults, auto-increment
882
- 3. **Indexes**: Including primary keys and unique constraints
883
- 4. **Foreign Keys**: Explicit relationship metadata
884
- 5. **Relationships**: Both explicit and inferred
885
-
886
- ### Relationship Inference
887
-
888
- When foreign keys are not defined, the server infers relationships using heuristics:
889
-
890
- - Column names matching `{table}_id` or `{table}Id`
891
- - Data type compatibility with target primary key
892
- - Confidence scoring for inferred relationships
893
-
894
- ### Caching Strategy
895
-
896
- - **Memory + Disk**: Dual-layer caching for performance
897
- - **TTL-based**: Configurable time-to-live
898
- - **Version Tracking**: Content-based versioning (hash)
899
- - **Concurrency Safe**: Prevents duplicate introspection
900
- - **On-Demand Refresh**: Manual or automatic refresh
901
-
902
- ## Query Tracking
903
-
904
- The server maintains per-database query history:
905
-
906
- - Timestamp and SQL text
907
- - Execution time and row count
908
- - Referenced tables (best-effort extraction)
909
- - Error tracking
910
- - Aggregate statistics
911
-
912
- Use this data to:
913
- - Monitor query performance
914
- - Identify frequently accessed tables
915
- - Detect query patterns
916
- - Debug issues
917
-
918
- ## Development
919
-
920
- ```bash
921
- # Install dependencies
922
- npm install
923
-
924
- # Run in development mode
925
- npm run dev
926
-
927
- # Build
928
- npm run build
929
-
930
- # Run tests
931
- npm test
932
-
933
- # Run tests with coverage
934
- npm run test:coverage
935
-
936
- # Lint
937
- npm run lint
938
-
939
- # Format code
940
- npm run format
941
-
942
- # Type check
943
- npm run typecheck
944
- ```
945
-
946
- ## Project Structure
947
-
948
- ```
949
- src/
950
- β”œβ”€β”€ adapters/ # Database adapters
951
- β”‚ β”œβ”€β”€ base.ts # Base adapter class
952
- β”‚ β”œβ”€β”€ postgres.ts # PostgreSQL adapter
953
- β”‚ β”œβ”€β”€ mysql.ts # MySQL adapter
954
- β”‚ β”œβ”€β”€ sqlite.ts # SQLite adapter
955
- β”‚ β”œβ”€β”€ mssql.ts # SQL Server adapter
956
- β”‚ β”œβ”€β”€ oracle.ts # Oracle adapter (stub)
957
- β”‚ └── index.ts # Adapter factory
958
- β”œβ”€β”€ cache.ts # Schema caching
959
- β”œβ”€β”€ config.ts # Configuration loader
960
- β”œβ”€β”€ database-manager.ts # Database orchestration
961
- β”œβ”€β”€ logger.ts # Logging setup
962
- β”œβ”€β”€ mcp-server.ts # MCP server implementation
963
- β”œβ”€β”€ query-tracker.ts # Query history tracking
964
- β”œβ”€β”€ types.ts # TypeScript types
965
- β”œβ”€β”€ utils.ts # Utility functions
966
- └── index.ts # Entry point
967
- ```
968
-
969
- ## Adding New Database Adapters
970
-
971
- 1. Implement the `DatabaseAdapter` interface in `src/adapters/`
972
- 2. Follow the pattern from existing adapters
973
- 3. Add to adapter factory in `src/adapters/index.ts`
974
- 4. Update type definitions if needed
975
- 5. Add tests
976
-
977
- Example:
978
-
979
- ```typescript
980
- import { BaseAdapter } from './base.js';
981
-
982
- export class CustomAdapter extends BaseAdapter {
983
- async connect(): Promise<void> { /* ... */ }
984
- async disconnect(): Promise<void> { /* ... */ }
985
- async introspect(): Promise<DatabaseSchema> { /* ... */ }
986
- async query(): Promise<QueryResult> { /* ... */ }
987
- async explain(): Promise<ExplainResult> { /* ... */ }
988
- async testConnection(): Promise<boolean> { /* ... */ }
989
- async getVersion(): Promise<string> { /* ... */ }
990
- }
991
- ```
992
-
993
- ## Troubleshooting
994
-
995
- ### Connection Issues
996
-
997
- - Verify connection strings and credentials
998
- - Check network connectivity and firewall rules
999
- - Enable debug logging: `"logging": { "level": "debug" }`
1000
- - Use `health_check` tool to test connectivity
1001
-
1002
- ### Cache Issues
1003
-
1004
- - Clear cache: Use `clear_cache` tool
1005
- - Check cache directory permissions
1006
- - Verify TTL settings
1007
- - Review cache status with `cache_status` tool
1008
-
1009
- ### Performance
1010
-
1011
- - Adjust connection pool settings
1012
- - Use `maxTables` to limit introspection scope
1013
- - Set appropriate cache TTL
1014
- - Enable read-only mode when possible
1015
-
1016
- ### Oracle Setup
1017
-
1018
- The Oracle adapter requires additional setup:
1019
-
1020
- 1. Install Oracle Instant Client
1021
- 2. Set environment variables (`LD_LIBRARY_PATH` or `PATH`)
1022
- 3. Install `oracledb` package
1023
- 4. Implement stub methods in `src/adapters/oracle.ts`
1024
-
1025
- ## Security Considerations
1026
-
1027
- - Always use read-only mode in production unless write access is required
1028
- - Use environment variables for credentials, never hardcode
1029
- - Enable secret redaction in logs
1030
- - Restrict write operations with `allowedWriteOperations`
1031
- - Use connection string encryption where supported
1032
- - Regular security audits of configurations
1033
-
1034
- ## License
1035
-
1036
- MIT
1037
-
1038
- ## Contributing
1039
-
1040
- Contributions welcome! Please:
1041
-
1042
- 1. Fork the repository
1043
- 2. Create a feature branch
1044
- 3. Add tests for new functionality
1045
- 4. Ensure all tests pass
1046
- 5. Submit a pull request
1047
-
1048
- ## Support
1049
-
1
+ # @adevguide/mcp-database-server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40adevguide%2Fmcp-database-server)](https://www.npmjs.com/package/@adevguide/mcp-database-server)
4
+ [![npm downloads](https://img.shields.io/npm/dm/%40adevguide%2Fmcp-database-server)](https://www.npmjs.com/package/@adevguide/mcp-database-server)
5
+
6
+ Production-grade Model Context Protocol (MCP) server for unified SQL database access. Connect multiple databases through a single MCP server with schema discovery, relationship mapping, caching, and safety controls.
7
+
8
+ - npm: https://www.npmjs.com/package/@adevguide/mcp-database-server
9
+ - GitHub: https://github.com/iPraBhu/mcp-database-server
10
+
11
+ ## Contents
12
+
13
+ - [Features](#features)
14
+ - [Why this exists](#why-this-exists)
15
+ - [Installation](#installation)
16
+ - [Configuration](#configuration)
17
+ - [MCP client integration](#mcp-client-integration)
18
+
19
+ ## Features
20
+
21
+ - Multi-database support: PostgreSQL, MySQL/MariaDB, SQLite, SQL Server, Oracle
22
+ - Automatic schema discovery: tables, columns, indexes, foreign keys, relationships
23
+ - Persistent schema caching: TTL + versioning, manual refresh, cache stats
24
+ - Relationship inference: foreign keys + heuristics
25
+ - Query intelligence: tracking, statistics, timeouts
26
+ - Join assistance: suggested join paths based on relationship graphs
27
+ - Safety controls: read-only mode, allow/deny write operations, secret redaction
28
+ - **Query optimization**: index recommendations, performance profiling, slow query detection
29
+ - **Performance monitoring**: detailed execution analytics, bottleneck identification
30
+ - **Query rewriting**: automated optimization suggestions with performance impact estimates
31
+
32
+ ## Why this exists
33
+
34
+ This project was originally vibe-coded to solve real issues I was facing when wiring LLM tools to multiple SQL databases (consistent connectivity, schema discovery, and safe query execution). It has since been hardened into a reusable MCP server with caching and security defaults.
35
+
36
+ ## Architecture
37
+
38
+ ```
39
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
40
+ β”‚ MCP Client β”‚
41
+ β”‚ (Claude Desktop, IDEs, etc.) β”‚
42
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
43
+ β”‚ JSON-RPC over stdio
44
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
45
+ β”‚ MCP Database Server β”‚
46
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
47
+ β”‚ β”‚ Schema Cache (TTL + Versioning) β”‚ β”‚
48
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
49
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
50
+ β”‚ β”‚ Query Tracker (History + Statistics) β”‚ β”‚
51
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
52
+ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
53
+ β”‚ β”‚ Security Layer (Read-only, Operation Controls) β”‚ β”‚
54
+ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
55
+ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
56
+ β”‚ β”‚ β”‚ β”‚ β”‚
57
+ β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β” β”Œβ”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”
58
+ β”‚Postgresβ”‚ β”‚ MySQL β”‚ β”‚ SQLite β”‚ β”‚ MSSQL β”‚ β”‚ Oracle β”‚
59
+ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
60
+ ```
61
+
62
+ ## Supported Databases
63
+
64
+ | Database | Driver | Status | Notes |
65
+ |----------|--------|--------|-------|
66
+ | PostgreSQL | `pg` | βœ… Full Support | Includes CockroachDB compatibility |
67
+ | MySQL/MariaDB | `mysql2` | βœ… Full Support | Includes Amazon Aurora MySQL compatibility |
68
+ | SQLite | `better-sqlite3` | βœ… Full Support | File-based databases |
69
+ | SQL Server | `tedious` | βœ… Full Support | Microsoft SQL Server / Azure SQL |
70
+ | Oracle | `oracledb` | ⚠️ Stub | Requires Oracle Instant Client |
71
+
72
+ ## Installation
73
+
74
+ ### Global install (recommended)
75
+
76
+ ```bash
77
+ npm install -g @adevguide/mcp-database-server
78
+ ```
79
+
80
+ Run:
81
+
82
+ ```bash
83
+ mcp-database-server --config /absolute/path/to/.mcp-database-server.config
84
+ ```
85
+
86
+ ### Run via npx (no global install)
87
+
88
+ ```bash
89
+ npx -y @adevguide/mcp-database-server --config /absolute/path/to/.mcp-database-server.config
90
+ ```
91
+
92
+ ### Install from source
93
+
94
+ ```bash
95
+ git clone https://github.com/iPraBhu/mcp-database-server.git
96
+ cd mcp-database-server
97
+ npm install
98
+ npm run build
99
+ node dist/index.js --config ./.mcp-database-server.config
100
+ ```
101
+
102
+ ## Configuration
103
+
104
+ Create a `.mcp-database-server.config` file in your project root:
105
+
106
+ > **Note:** The config file is automatically discovered! If you don't specify `--config`, the tool first tries to locate your project root (by looking for `package.json`, `.git`, etc.) and searches for `.mcp-database-server.config` starting from there and moving up. If no project root is found, it searches from the current directory. This means you can run the tool from any subdirectory of your project and it will find the config file.
107
+
108
+ ```json
109
+ {
110
+ "databases": [
111
+ {
112
+ "id": "postgres-main",
113
+ "type": "postgres",
114
+ "url": "${DB_URL_POSTGRES}",
115
+ "readOnly": false,
116
+ "pool": {
117
+ "min": 2,
118
+ "max": 10,
119
+ "idleTimeoutMillis": 30000
120
+ },
121
+ "introspection": {
122
+ "includeViews": true,
123
+ "excludeSchemas": ["pg_catalog"]
124
+ }
125
+ },
126
+ {
127
+ "id": "sqlite-local",
128
+ "type": "sqlite",
129
+ "path": "./data/app.db"
130
+ }
131
+ ],
132
+ "cache": {
133
+ "directory": ".sql-mcp-cache",
134
+ "ttlMinutes": 10
135
+ },
136
+ "security": {
137
+ "allowWrite": false,
138
+ "allowedWriteOperations": ["INSERT", "UPDATE"],
139
+ "disableDangerousOperations": true,
140
+ "redactSecrets": true
141
+ },
142
+ "logging": {
143
+ "level": "info",
144
+ "pretty": false
145
+ }
146
+ }
147
+ ```
148
+
149
+ ### Configuration Reference
150
+
151
+ #### Database Configuration
152
+
153
+ Each database in the `databases` array represents a connection to a SQL database.
154
+
155
+ ##### Core Properties
156
+
157
+ | Property | Type | Required | Default | Description |
158
+ |----------|------|----------|---------|-------------|
159
+ | `id` | string | βœ… Yes | - | Unique identifier for this database connection. Used in all MCP tool calls. Must be unique across all databases. |
160
+ | `type` | enum | βœ… Yes | - | Database system type. Valid values: `postgres`, `mysql`, `sqlite`, `mssql`, `oracle` |
161
+ | `url` | string | Conditional* | - | Database connection string. Required for all databases except SQLite. Supports environment variable interpolation: `${DB_URL}` |
162
+ | `path` | string | Conditional** | - | Filesystem path to SQLite database file. Required only for `type: sqlite`. Can be relative or absolute. |
163
+ | `readOnly` | boolean | No | `true` | When `true`, blocks all write operations (INSERT, UPDATE, DELETE, etc.). Recommended for production safety. |
164
+ | `eagerConnect` | boolean | No | `false` | When `true`, connects to database immediately at startup (fail-fast). When `false`, connects on first query (lazy loading). |
165
+
166
+ <sub>* Required for postgres, mysql, mssql, oracle</sub>
167
+ <sub>** Required for sqlite only</sub>
168
+
169
+ **Connection String Formats:**
170
+ ```
171
+ PostgreSQL: postgresql://username:password@host:5432/database
172
+ MySQL: mysql://username:password@host:3306/database
173
+ SQL Server: Server=host,1433;Database=dbname;User Id=user;Password=pass
174
+ SQLite: (use path property instead)
175
+ Oracle: username/password@host:1521/servicename
176
+ ```
177
+
178
+ ##### Connection Pool Configuration
179
+
180
+ The `pool` object controls connection pooling behavior. Improves performance by reusing database connections.
181
+
182
+ | Property | Type | Required | Default | Description |
183
+ |----------|------|----------|---------|-------------|
184
+ | `min` | number | No | `2` | Minimum number of connections to maintain in the pool. Kept alive even when idle. |
185
+ | `max` | number | No | `10` | Maximum number of concurrent connections. Do not exceed your database's connection limit. |
186
+ | `idleTimeoutMillis` | number | No | `30000` | Time (ms) to keep idle connections alive before closing. Example: `60000` = 1 minute. |
187
+ | `connectionTimeoutMillis` | number | No | `10000` | Time (ms) to wait when establishing a connection before timing out. Fail-fast if database is unreachable. |
188
+
189
+ **Recommendations:**
190
+ - **Development:** `min: 1`, `max: 5`
191
+ - **Production (Low Traffic):** `min: 2`, `max: 10`
192
+ - **Production (High Traffic):** `min: 5`, `max: 20`
193
+
194
+ ##### Introspection Configuration
195
+
196
+ The `introspection` object controls schema discovery behavior. Determines what database objects are analyzed.
197
+
198
+ | Property | Type | Required | Default | Description |
199
+ |----------|------|----------|---------|-------------|
200
+ | `includeViews` | boolean | No | `true` | Include database views in schema discovery. Set to `false` if views cause performance issues. |
201
+ | `includeRoutines` | boolean | No | `false` | Include stored procedures and functions. (Not fully implemented - planned feature) |
202
+ | `maxTables` | number | No | unlimited | Limit introspection to first N tables. Useful for databases with 1000+ tables. May result in incomplete relationship discovery. |
203
+ | `includeSchemas` | string[] | No | all | Whitelist of schemas to introspect. Only applicable to PostgreSQL and SQL Server. Example: `["public", "app"]` |
204
+ | `excludeSchemas` | string[] | No | none | Blacklist of schemas to skip. Common values: `["pg_catalog", "information_schema", "sys"]` |
205
+
206
+ **Schema vs Database:**
207
+ - **PostgreSQL/SQL Server:** Support multiple schemas per database. Use `includeSchemas`/`excludeSchemas`.
208
+ - **MySQL/MariaDB:** Schema = database. Use database name in connection string.
209
+ - **SQLite:** Single-file database, no schema concept.
210
+
211
+ #### Cache Configuration
212
+
213
+ Controls schema metadata caching to improve startup performance and reduce database load.
214
+
215
+ | Property | Type | Required | Default | Description |
216
+ |----------|------|----------|---------|-------------|
217
+ | `directory` | string | No | `.sql-mcp-cache` | Directory path where cached schema files are stored. One JSON file per database. |
218
+ | `ttlMinutes` | number | No | `10` | Time-To-Live in minutes. How long cached schema is considered valid before automatic refresh. |
219
+
220
+ **Cache Behavior:**
221
+ - **On Startup:** Loads schema from cache if available and not expired
222
+ - **After TTL Expiry:** Next query triggers automatic re-introspection
223
+ - **Manual Refresh:** Use `clear_cache` tool or `introspect_schema` with `forceRefresh: true`
224
+ - **Cache Files:** Stored as `{database-id}.json` (e.g., `postgres-main.json`)
225
+
226
+ **Recommended TTL Values:**
227
+ - **Development:** `5` minutes (schema changes frequently)
228
+ - **Staging:** `30-60` minutes
229
+ - **Production (Static):** `1440` minutes (24 hours)
230
+ - **Production (Active):** `60-240` minutes (1-4 hours)
231
+
232
+ #### Security Configuration
233
+
234
+ Comprehensive security controls to protect your databases from unauthorized or dangerous operations.
235
+
236
+ | Property | Type | Required | Default | Description |
237
+ |----------|------|----------|---------|-------------|
238
+ | `allowWrite` | boolean | No | `false` | Master switch for write operations. When `false`, all writes are blocked across all databases. |
239
+ | `allowedWriteOperations` | string[] | No | all | Whitelist of allowed SQL operations when `allowWrite: true`. Valid values: `INSERT`, `UPDATE`, `DELETE`, `CREATE`, `ALTER`, `DROP`, `TRUNCATE`, `REPLACE`, `MERGE` |
240
+ | `disableDangerousOperations` | boolean | No | `true` | **Extra safety layer.** When `true`, blocks `DELETE`, `TRUNCATE`, and `DROP` operations even if writes are allowed. Prevents accidental data loss. |
241
+ | `redactSecrets` | boolean | No | `true` | Automatically redact passwords and credentials in logs and error messages. |
242
+
243
+ **Security Layers (Evaluated in Order):**
244
+
245
+ 1. **Database-level `readOnly`** β†’ Blocks all writes for specific database
246
+ 2. **Global `allowWrite`** β†’ Master switch for all databases
247
+ 3. **`disableDangerousOperations`** β†’ Blocks DELETE/TRUNCATE/DROP specifically
248
+ 4. **`allowedWriteOperations`** β†’ Whitelist of permitted operations
249
+
250
+ **Example Configurations:**
251
+
252
+ ```json
253
+ // Read-only access (default - safest)
254
+ {
255
+ "allowWrite": false
256
+ }
257
+
258
+ // Allow INSERT and UPDATE only (no deletes)
259
+ {
260
+ "allowWrite": true,
261
+ "allowedWriteOperations": ["INSERT", "UPDATE"],
262
+ "disableDangerousOperations": true
263
+ }
264
+
265
+ // Full write access (development only - dangerous!)
266
+ {
267
+ "allowWrite": true,
268
+ "disableDangerousOperations": false
269
+ }
270
+ ```
271
+
272
+ #### Logging Configuration
273
+
274
+ Controls log output verbosity and formatting.
275
+
276
+ | Property | Type | Required | Default | Description |
277
+ |----------|------|----------|---------|-------------|
278
+ | `level` | enum | No | `info` | Log level. Valid values: `trace`, `debug`, `info`, `warn`, `error`. Lower levels include higher levels. |
279
+ | `pretty` | boolean | No | `false` | When `true`, formats logs as human-readable text. When `false`, outputs structured JSON (better for production log aggregation). |
280
+
281
+ **Log Levels:**
282
+ - **`trace`:** Everything (extremely verbose - use for debugging only)
283
+ - **`debug`:** Detailed diagnostic information
284
+ - **`info`:** General informational messages (recommended for production)
285
+ - **`warn`:** Warning messages that don't prevent operation
286
+ - **`error`:** Error messages only
287
+
288
+ **Recommendations:**
289
+ - **Development:** `level: "debug"`, `pretty: true`
290
+ - **Production:** `level: "info"`, `pretty: false`
291
+ - **Troubleshooting:** `level: "trace"`, `pretty: true`
292
+
293
+ ---
294
+
295
+ ### Complete Configuration Example
296
+
297
+ ```json
298
+ {
299
+ "databases": [
300
+ {
301
+ "id": "postgres-production",
302
+ "type": "postgres",
303
+ "url": "${DATABASE_URL}",
304
+ "readOnly": true,
305
+ "pool": {
306
+ "min": 5,
307
+ "max": 20,
308
+ "idleTimeoutMillis": 60000,
309
+ "connectionTimeoutMillis": 5000
310
+ },
311
+ "introspection": {
312
+ "includeViews": true,
313
+ "includeRoutines": false,
314
+ "excludeSchemas": ["pg_catalog", "information_schema"]
315
+ },
316
+ "eagerConnect": true
317
+ },
318
+ {
319
+ "id": "mysql-analytics",
320
+ "type": "mysql",
321
+ "url": "${MYSQL_URL}",
322
+ "readOnly": true,
323
+ "pool": {
324
+ "min": 2,
325
+ "max": 10
326
+ },
327
+ "introspection": {
328
+ "includeViews": true,
329
+ "maxTables": 100
330
+ }
331
+ },
332
+ {
333
+ "id": "sqlite-local",
334
+ "type": "sqlite",
335
+ "path": "./data/app.db",
336
+ "readOnly": false
337
+ }
338
+ ],
339
+ "cache": {
340
+ "directory": ".sql-mcp-cache",
341
+ "ttlMinutes": 60
342
+ },
343
+ "security": {
344
+ "allowWrite": false,
345
+ "allowedWriteOperations": ["INSERT", "UPDATE"],
346
+ "disableDangerousOperations": true,
347
+ "redactSecrets": true
348
+ },
349
+ "logging": {
350
+ "level": "info",
351
+ "pretty": false
352
+ }
353
+ }
354
+ ```
355
+
356
+ ---
357
+
358
+ ### Environment Variables
359
+
360
+ **Secure Configuration with Environment Variables:**
361
+
362
+ The server supports environment variable interpolation using `${VARIABLE_NAME}` syntax. This is the recommended approach for managing sensitive credentials.
363
+
364
+ **Example Configuration:**
365
+ ```json
366
+ {
367
+ "databases": [
368
+ {
369
+ "id": "production-db",
370
+ "type": "postgres",
371
+ "url": "${DATABASE_URL}"
372
+ }
373
+ ]
374
+ }
375
+ ```
376
+
377
+ **Environment File (`.env`):**
378
+ ```env
379
+ DATABASE_URL=postgresql://user:password@localhost:5432/dbname
380
+ DB_URL_MYSQL=mysql://user:password@localhost:3306/dbname
381
+ DB_URL_MSSQL=Server=host,1433;Database=db;User Id=sa;Password=pass
382
+ ```
383
+
384
+ **Best Practices:**
385
+ - βœ… Store `.env` file outside version control (add to `.gitignore`)
386
+ - βœ… Use different `.env` files for each environment (dev, staging, prod)
387
+ - βœ… Never commit credentials to git repositories
388
+ - βœ… Use secret management services (AWS Secrets Manager, HashiCorp Vault) in production
389
+
390
+ ---
391
+
392
+ ### Connection String Reference
393
+
394
+ | Database | Format | Example |
395
+ |----------|--------|---------|
396
+ | **PostgreSQL** | `postgresql://user:pass@host:port/db` | `postgresql://admin:secret@localhost:5432/myapp` |
397
+ | **MySQL** | `mysql://user:pass@host:port/db` | `mysql://root:password@localhost:3306/myapp` |
398
+ | **SQL Server** | `Server=host,port;Database=db;User Id=user;Password=pass` | `Server=localhost,1433;Database=myapp;User Id=sa;Password=secret` |
399
+ | **SQLite** | Use `path` property | `"path": "./data/app.db"` or `"path": "/var/db/app.sqlite"` |
400
+ | **Oracle** | `user/pass@host:port/service` | `admin/secret@localhost:1521/XEPDB1` |
401
+
402
+ **Additional Parameters:**
403
+
404
+ **PostgreSQL:**
405
+ ```
406
+ postgresql://user:pass@host:5432/db?sslmode=require&connect_timeout=10
407
+ ```
408
+
409
+ **MySQL:**
410
+ ```
411
+ mysql://user:pass@host:3306/db?charset=utf8mb4&timezone=Z
412
+ ```
413
+
414
+ **SQL Server:**
415
+ ```
416
+ Server=host;Database=db;User Id=user;Password=pass;Encrypt=true;TrustServerCertificate=false
417
+ ```
418
+
419
+ ---
420
+
421
+ ## MCP Client Integration
422
+
423
+ ### Configuration File Locations
424
+
425
+ | MCP Client | Configuration File Path |
426
+ |------------|------------------------|
427
+ | **Claude Desktop** (macOS) | `~/Library/Application Support/Claude/claude_desktop_config.json` |
428
+ | **Claude Desktop** (Windows) | `%APPDATA%\Claude\claude_desktop_config.json` |
429
+ | **Cline** (VS Code) | VS Code settings β†’ MCP Servers |
430
+ | **Other Clients** | Refer to client-specific documentation |
431
+
432
+ ### Setup Methods
433
+
434
+ #### Method 1: Global npm Installation
435
+
436
+ **Configuration:**
437
+ ```json
438
+ {
439
+ "mcpServers": {
440
+ "database": {
441
+ "command": "mcp-database-server",
442
+ "args": ["--config", "/absolute/path/to/.mcp-database-server.config"],
443
+ "env": {
444
+ "DATABASE_URL": "postgresql://user:pass@localhost:5432/db"
445
+ }
446
+ }
447
+ }
448
+ }
449
+ ```
450
+
451
+ #### Method 2: Source Installation
452
+
453
+ **Configuration:**
454
+ ```json
455
+ {
456
+ "mcpServers": {
457
+ "database": {
458
+ "command": "node",
459
+ "args": [
460
+ "/absolute/path/to/mcp-database-server/dist/index.js",
461
+ "--config",
462
+ "/absolute/path/to/.mcp-database-server.config"
463
+ ],
464
+ "env": {
465
+ "DATABASE_URL": "postgresql://user:pass@localhost:5432/db"
466
+ }
467
+ }
468
+ }
469
+ }
470
+ ```
471
+
472
+ ### Configuration Properties
473
+
474
+ | Property | Description | Example |
475
+ |----------|-------------|---------|
476
+ | `command` | Executable to run. Use `mcp-database-server` for npm install, `node` for source install. | `"mcp-database-server"` |
477
+ | `args` | Array of command-line arguments. First arg is usually `--config` followed by config file path. | `["--config", "/path/to/config"]` |
478
+ | `env` | Environment variables passed to the server. Used for secure credential management. | `{"DATABASE_URL": "..."}` |
479
+
480
+ **Finding Absolute Paths:**
481
+ ```bash
482
+ # macOS/Linux
483
+ cd /path/to/mcp-database-server
484
+ pwd # prints: /Users/username/projects/mcp-database-server
485
+
486
+ # Windows (PowerShell)
487
+ cd C:\path\to\mcp-database-server
488
+ $PWD.Path # prints: C:\Users\username\projects\mcp-database-server
489
+ ```
490
+
491
+ ---
492
+
493
+ ## Available MCP Tools
494
+
495
+ This server provides 14 tools for comprehensive database interaction and optimization.
496
+
497
+ ### Tool Reference
498
+
499
+ | Tool | Purpose | Write Access | Cached Data |
500
+ |------|---------|--------------|-------------|
501
+ | `list_databases` | List all configured databases with status | No | Uses cache |
502
+ | `introspect_schema` | Discover and cache database schema | No | Writes cache |
503
+ | `get_schema` | Retrieve cached schema metadata | No | Reads cache |
504
+ | `run_query` | Execute SQL queries with safety controls | Conditional* | Updates stats |
505
+ | `explain_query` | Analyze query execution plans | No | No cache |
506
+ | `suggest_joins` | Get intelligent join path recommendations | No | Uses cache |
507
+ | `clear_cache` | Clear schema cache and statistics | No | Clears cache |
508
+ | `cache_status` | View cache health and statistics | No | Reads cache |
509
+ | `health_check` | Test database connectivity | No | No cache |
510
+ | `analyze_performance` | Get detailed performance analytics | No | Uses stats |
511
+ | `suggest_indexes` | Analyze queries and recommend indexes | No | Uses stats |
512
+ | `detect_slow_queries` | Identify and alert on slow queries | No | Uses stats |
513
+ | `rewrite_query` | Suggest optimized query versions | No | Uses cache |
514
+ | `profile_query` | Profile query performance with bottlenecks | No | No cache |
515
+
516
+ <sub>* Requires `allowWrite: true` and respects security settings</sub>
517
+
518
+ ---
519
+
520
+ ### 1. list_databases
521
+
522
+ Lists all configured databases with their connection status and cache information.
523
+
524
+ **Input Parameters:**
525
+
526
+ None required.
527
+
528
+ **Response:**
529
+ ```json
530
+ [
531
+ {
532
+ "id": "postgres-main",
533
+ "type": "postgres",
534
+ "connected": true,
535
+ "cached": true,
536
+ "cacheAge": 45000,
537
+ "version": "abc123"
538
+ }
539
+ ]
540
+ ```
541
+
542
+ **Response Fields:**
543
+
544
+ | Field | Type | Description |
545
+ |-------|------|-------------|
546
+ | `id` | string | Database identifier from configuration |
547
+ | `type` | string | Database type (postgres, mysql, sqlite, mssql, oracle) |
548
+ | `connected` | boolean | Whether database connection is active |
549
+ | `cached` | boolean | Whether schema is currently cached |
550
+ | `cacheAge` | number | Age of cached schema in milliseconds (if cached) |
551
+ | `version` | string | Cache version hash (if cached) |
552
+
553
+ ---
554
+
555
+ ### 2. introspect_schema
556
+
557
+ Discovers and caches complete database schema including tables, columns, indexes, foreign keys, and relationships.
558
+
559
+ **Input Parameters:**
560
+
561
+ | Parameter | Type | Required | Description |
562
+ |-----------|------|----------|-------------|
563
+ | `dbId` | string | Yes | Database identifier to introspect |
564
+ | `forceRefresh` | boolean | No | Force re-introspection even if cache is valid (default: `false`) |
565
+ | `schemaFilter` | object | No | Filter which objects to introspect |
566
+ | `schemaFilter.includeSchemas` | string[] | No | Only introspect these schemas (PostgreSQL/SQL Server) |
567
+ | `schemaFilter.excludeSchemas` | string[] | No | Skip these schemas during introspection |
568
+ | `schemaFilter.includeViews` | boolean | No | Include database views (default: `true`) |
569
+ | `schemaFilter.maxTables` | number | No | Limit to first N tables |
570
+
571
+ **Example Request:**
572
+ ```json
573
+ {
574
+ "dbId": "postgres-main",
575
+ "forceRefresh": false,
576
+ "schemaFilter": {
577
+ "includeSchemas": ["public"],
578
+ "excludeSchemas": ["temp"],
579
+ "includeViews": true,
580
+ "maxTables": 100
581
+ }
582
+ }
583
+ ```
584
+
585
+ **Response:**
586
+ ```json
587
+ {
588
+ "dbId": "postgres-main",
589
+ "version": "a1b2c3d4",
590
+ "introspectedAt": "2026-01-26T10:00:00.000Z",
591
+ "schemas": [
592
+ {
593
+ "name": "public",
594
+ "tableCount": 15,
595
+ "viewCount": 3
596
+ }
597
+ ],
598
+ "totalTables": 15,
599
+ "totalRelationships": 12
600
+ }
601
+ ```
602
+
603
+ ---
604
+
605
+ ### 3. get_schema
606
+
607
+ Retrieves detailed schema metadata from cache without querying the database.
608
+
609
+ **Input Parameters:**
610
+
611
+ | Parameter | Type | Required | Description |
612
+ |-----------|------|----------|-------------|
613
+ | `dbId` | string | Yes | Database identifier |
614
+ | `schema` | string | No | Filter to specific schema name |
615
+ | `table` | string | No | Filter to specific table name |
616
+
617
+ **Example Request:**
618
+ ```json
619
+ {
620
+ "dbId": "postgres-main",
621
+ "schema": "public",
622
+ "table": "users"
623
+ }
624
+ ```
625
+
626
+ **Response:** Complete schema metadata including tables, columns, data types, indexes, foreign keys, and inferred relationships.
627
+
628
+ ---
629
+
630
+ ### 4. run_query
631
+
632
+ Executes SQL queries with automatic schema caching, relationship annotation, and comprehensive security controls.
633
+
634
+ **Input Parameters:**
635
+
636
+ | Parameter | Type | Required | Description |
637
+ |-----------|------|----------|-------------|
638
+ | `dbId` | string | Yes | Database identifier to query |
639
+ | `sql` | string | Yes | SQL query to execute |
640
+ | `params` | array | No | Parameterized query values (prevents SQL injection) |
641
+ | `limit` | number | No | Maximum number of rows to return |
642
+ | `timeoutMs` | number | No | Query timeout in milliseconds |
643
+
644
+ **Example Request:**
645
+ ```json
646
+ {
647
+ "dbId": "postgres-main",
648
+ "sql": "SELECT * FROM users WHERE active = $1 LIMIT $2",
649
+ "params": [true, 10],
650
+ "timeoutMs": 5000
651
+ }
652
+ ```
653
+
654
+ **Response:**
655
+ ```json
656
+ {
657
+ "rows": [
658
+ {"id": 1, "name": "Alice", "email": "alice@example.com", "active": true},
659
+ {"id": 2, "name": "Bob", "email": "bob@example.com", "active": true}
660
+ ],
661
+ "columns": ["id", "name", "email", "active"],
662
+ "rowCount": 2,
663
+ "executionTimeMs": 15,
664
+ "metadata": {
665
+ "relationships": [...],
666
+ "queryStats": {
667
+ "totalQueries": 10,
668
+ "avgExecutionTime": 20,
669
+ "errorCount": 0
670
+ }
671
+ }
672
+ }
673
+ ```
674
+
675
+ **Security Controls:**
676
+ - βœ… Write operations blocked by default (`allowWrite: false`)
677
+ - βœ… Dangerous operations (DELETE, TRUNCATE, DROP) disabled by default
678
+ - βœ… Specific operations can be whitelisted via `allowedWriteOperations`
679
+ - βœ… Per-database `readOnly` mode
680
+
681
+ ---
682
+
683
+ ### 5. explain_query
684
+
685
+ Retrieves database query execution plan without executing the query.
686
+
687
+ **Input Parameters:**
688
+
689
+ | Parameter | Type | Required | Description |
690
+ |-----------|------|----------|-------------|
691
+ | `dbId` | string | Yes | Database identifier |
692
+ | `sql` | string | Yes | SQL query to analyze |
693
+ | `params` | array | No | Query parameters (for parameterized queries) |
694
+
695
+ **Example Request:**
696
+ ```json
697
+ {
698
+ "dbId": "postgres-main",
699
+ "sql": "SELECT * FROM users JOIN orders ON users.id = orders.user_id WHERE users.active = $1",
700
+ "params": [true]
701
+ }
702
+ ```
703
+
704
+ **Response:** Database-native execution plan (format varies by database type).
705
+
706
+ ---
707
+
708
+ ### 6. suggest_joins
709
+
710
+ Analyzes relationship graph to recommend optimal join paths between multiple tables.
711
+
712
+ **Input Parameters:**
713
+
714
+ | Parameter | Type | Required | Description |
715
+ |-----------|------|----------|-------------|
716
+ | `dbId` | string | Yes | Database identifier |
717
+ | `tables` | string[] | Yes | Array of table names to join (2-10 tables) |
718
+
719
+ **Example Request:**
720
+ ```json
721
+ {
722
+ "dbId": "postgres-main",
723
+ "tables": ["users", "orders", "products"]
724
+ }
725
+ ```
726
+
727
+ **Response:**
728
+ ```json
729
+ [
730
+ {
731
+ "tables": ["users", "orders", "products"],
732
+ "joins": [
733
+ {
734
+ "fromTable": "users",
735
+ "toTable": "orders",
736
+ "relationship": {
737
+ "type": "one-to-many",
738
+ "confidence": 1.0
739
+ },
740
+ "joinCondition": "users.id = orders.user_id"
741
+ },
742
+ {
743
+ "fromTable": "orders",
744
+ "toTable": "products",
745
+ "relationship": {
746
+ "type": "many-to-one",
747
+ "confidence": 1.0
748
+ },
749
+ "joinCondition": "orders.product_id = products.id"
750
+ }
751
+ ],
752
+ "sql": "FROM users JOIN orders ON users.id = orders.user_id JOIN products ON orders.product_id = products.id"
753
+ }
754
+ ]
755
+ ```
756
+
757
+ ---
758
+
759
+ ### 7. clear_cache
760
+
761
+ Clears schema cache and query statistics for one or all databases.
762
+
763
+ **Input Parameters:**
764
+
765
+ | Parameter | Type | Required | Description |
766
+ |-----------|------|----------|-------------|
767
+ | `dbId` | string | No | Database to clear (omit to clear all) |
768
+
769
+ **Example Request:**
770
+ ```json
771
+ {
772
+ "dbId": "postgres-main"
773
+ }
774
+ ```
775
+
776
+ **Response:** Confirmation message.
777
+
778
+ ---
779
+
780
+ ### 8. cache_status
781
+
782
+ Retrieves detailed cache statistics and health information.
783
+
784
+ **Input Parameters:**
785
+
786
+ None required.
787
+
788
+ **Response:**
789
+ ```json
790
+ {
791
+ "directory": ".sql-mcp-cache",
792
+ "ttlMinutes": 10,
793
+ "databases": [
794
+ {
795
+ "dbId": "postgres-main",
796
+ "cached": true,
797
+ "version": "abc123",
798
+ "age": 120000,
799
+ "expired": false,
800
+ "tableCount": 15,
801
+ "sizeBytes": 45678
802
+ }
803
+ ]
804
+ }
805
+ ```
806
+
807
+ ---
808
+
809
+ ### 9. health_check
810
+
811
+ Tests database connectivity and returns status information.
812
+
813
+ **Input Parameters:**
814
+
815
+ | Parameter | Type | Required | Description |
816
+ |-----------|------|----------|-------------|
817
+ | `dbId` | string | No | Database to check (omit to check all) |
818
+
819
+ **Response:**
820
+ ```json
821
+ {
822
+ "databases": [
823
+ {
824
+ "dbId": "postgres-main",
825
+ "healthy": true,
826
+ "connected": true,
827
+ "version": "PostgreSQL 15.3",
828
+ "responseTimeMs": 12
829
+ }
830
+ ]
831
+ }
832
+ ```
833
+
834
+ ---
835
+
836
+ ### 10. analyze_performance
837
+
838
+ Get comprehensive performance analytics across all queries for a database.
839
+
840
+ **Input Parameters:**
841
+
842
+ | Parameter | Type | Required | Description |
843
+ |-----------|------|----------|-------------|
844
+ | `dbId` | string | Yes | Database to analyze |
845
+
846
+ **Response:**
847
+ ```json
848
+ {
849
+ "totalQueries": 1250,
850
+ "slowQueries": 23,
851
+ "avgExecutionTime": 45.67,
852
+ "p95ExecutionTime": 234.5,
853
+ "errorRate": 1.2,
854
+ "mostFrequentTables": [
855
+ { "table": "users", "count": 456 },
856
+ { "table": "orders", "count": 234 }
857
+ ],
858
+ "performanceTrend": "improving"
859
+ }
860
+ ```
861
+
862
+ ---
863
+
864
+ ### 11. suggest_indexes
865
+
866
+ Analyze query patterns and recommend optimal database indexes.
867
+
868
+ **Input Parameters:**
869
+
870
+ | Parameter | Type | Required | Description |
871
+ |-----------|------|----------|-------------|
872
+ | `dbId` | string | Yes | Database to analyze |
873
+
874
+ **Response:**
875
+ ```json
876
+ [
877
+ {
878
+ "table": "orders",
879
+ "columns": ["customer_id", "order_date"],
880
+ "type": "composite",
881
+ "reason": "Frequently used in WHERE and JOIN conditions",
882
+ "impact": "high"
883
+ },
884
+ {
885
+ "table": "products",
886
+ "columns": ["category_id"],
887
+ "type": "single",
888
+ "reason": "Column category_id is frequently queried",
889
+ "impact": "medium"
890
+ }
891
+ ]
892
+ ```
893
+
894
+ ---
895
+
896
+ ### 12. detect_slow_queries
897
+
898
+ Identify queries that exceed performance thresholds and provide alerts.
899
+
900
+ **Input Parameters:**
901
+
902
+ | Parameter | Type | Required | Description |
903
+ |-----------|------|----------|-------------|
904
+ | `dbId` | string | Yes | Database to analyze |
905
+
906
+ **Response:**
907
+ ```json
908
+ [
909
+ {
910
+ "dbId": "postgres-main",
911
+ "queryId": "a1b2c3",
912
+ "sql": "SELECT * FROM large_table WHERE slow_column = ?",
913
+ "executionTimeMs": 2500,
914
+ "thresholdMs": 1000,
915
+ "timestamp": "2024-01-27T10:30:00Z",
916
+ "frequency": 5,
917
+ "recommendations": [
918
+ {
919
+ "type": "add_index",
920
+ "description": "Add index on slow_column for better performance",
921
+ "impact": "high",
922
+ "effort": "medium"
923
+ }
924
+ ]
925
+ }
926
+ ]
927
+ ```
928
+
929
+ ---
930
+
931
+ ### 13. rewrite_query
932
+
933
+ Suggest optimized versions of SQL queries with performance improvements.
934
+
935
+ **Input Parameters:**
936
+
937
+ | Parameter | Type | Required | Description |
938
+ |-----------|------|----------|-------------|
939
+ | `dbId` | string | Yes | Database ID |
940
+ | `sql` | string | Yes | SQL query to optimize |
941
+
942
+ **Response:**
943
+ ```json
944
+ {
945
+ "originalQuery": "SELECT * FROM users WHERE active = 1",
946
+ "optimizedQuery": "SELECT id, name, email FROM users WHERE active = 1 LIMIT 1000",
947
+ "improvements": [
948
+ "Removed unnecessary SELECT *",
949
+ "Added LIMIT clause to prevent large result sets"
950
+ ],
951
+ "performanceGain": 35,
952
+ "confidence": "high"
953
+ }
954
+ ```
955
+
956
+ ---
957
+
958
+ ### 14. profile_query
959
+
960
+ Profile a specific query's performance with detailed bottleneck analysis.
961
+
962
+ **Input Parameters:**
963
+
964
+ | Parameter | Type | Required | Description |
965
+ |-----------|------|----------|-------------|
966
+ | `dbId` | string | Yes | Database ID |
967
+ | `sql` | string | Yes | SQL query to profile |
968
+ | `params` | array | No | Query parameters |
969
+
970
+ **Response:**
971
+ ```json
972
+ {
973
+ "queryId": "def456",
974
+ "sql": "SELECT u.name, COUNT(o.id) FROM users u JOIN orders o ON u.id = o.user_id GROUP BY u.id",
975
+ "executionTimeMs": 1250,
976
+ "rowCount": 5000,
977
+ "bottlenecks": [
978
+ {
979
+ "type": "join",
980
+ "severity": "high",
981
+ "description": "Nested loop join on large tables",
982
+ "estimatedCost": 150
983
+ }
984
+ ],
985
+ "recommendations": [
986
+ {
987
+ "type": "add_index",
988
+ "description": "Add index on orders.user_id",
989
+ "impact": "high",
990
+ "effort": "low"
991
+ }
992
+ ],
993
+ "overallScore": 65
994
+ }
995
+ ```
996
+
997
+ ## Resources
998
+
999
+ The server exposes cached schemas as MCP resources:
1000
+
1001
+ - **URI:** `schema://{dbId}`
1002
+ - **MIME Type:** `application/json`
1003
+ - **Content:** Complete cached schema metadata
1004
+
1005
+ ## Schema Introspection
1006
+
1007
+ ### Automatic Discovery
1008
+
1009
+ The server automatically discovers:
1010
+
1011
+ 1. **Tables and Views**: All user tables and optionally views
1012
+ 2. **Columns**: Name, data type, nullability, defaults, auto-increment
1013
+ 3. **Indexes**: Including primary keys and unique constraints
1014
+ 4. **Foreign Keys**: Explicit relationship metadata
1015
+ 5. **Relationships**: Both explicit and inferred
1016
+
1017
+ ### Relationship Inference
1018
+
1019
+ When foreign keys are not defined, the server infers relationships using heuristics:
1020
+
1021
+ - Column names matching `{table}_id` or `{table}Id`
1022
+ - Data type compatibility with target primary key
1023
+ - Confidence scoring for inferred relationships
1024
+
1025
+ ### Caching Strategy
1026
+
1027
+ - **Memory + Disk**: Dual-layer caching for performance
1028
+ - **TTL-based**: Configurable time-to-live
1029
+ - **Version Tracking**: Content-based versioning (hash)
1030
+ - **Concurrency Safe**: Prevents duplicate introspection
1031
+ - **On-Demand Refresh**: Manual or automatic refresh
1032
+
1033
+ ## Query Tracking
1034
+
1035
+ The server maintains per-database query history:
1036
+
1037
+ - Timestamp and SQL text
1038
+ - Execution time and row count
1039
+ - Referenced tables (best-effort extraction)
1040
+ - Error tracking
1041
+ - Aggregate statistics
1042
+
1043
+ Use this data to:
1044
+ - Monitor query performance
1045
+ - Identify frequently accessed tables
1046
+ - Detect query patterns
1047
+ - Debug issues
1048
+
1049
+ ## Development
1050
+
1051
+ ```bash
1052
+ # Install dependencies
1053
+ npm install
1054
+
1055
+ # Run in development mode
1056
+ npm run dev
1057
+
1058
+ # Build
1059
+ npm run build
1060
+
1061
+ # Run tests
1062
+ npm test
1063
+
1064
+ # Run tests with coverage
1065
+ npm run test:coverage
1066
+
1067
+ # Lint
1068
+ npm run lint
1069
+
1070
+ # Format code
1071
+ npm run format
1072
+
1073
+ # Type check
1074
+ npm run typecheck
1075
+ ```
1076
+
1077
+ ## Project Structure
1078
+
1079
+ ```
1080
+ src/
1081
+ β”œβ”€β”€ adapters/ # Database adapters
1082
+ β”‚ β”œβ”€β”€ base.ts # Base adapter class
1083
+ β”‚ β”œβ”€β”€ postgres.ts # PostgreSQL adapter
1084
+ β”‚ β”œβ”€β”€ mysql.ts # MySQL adapter
1085
+ β”‚ β”œβ”€β”€ sqlite.ts # SQLite adapter
1086
+ β”‚ β”œβ”€β”€ mssql.ts # SQL Server adapter
1087
+ β”‚ β”œβ”€β”€ oracle.ts # Oracle adapter (stub)
1088
+ β”‚ └── index.ts # Adapter factory
1089
+ β”œβ”€β”€ cache.ts # Schema caching
1090
+ β”œβ”€β”€ config.ts # Configuration loader
1091
+ β”œβ”€β”€ database-manager.ts # Database orchestration
1092
+ β”œβ”€β”€ logger.ts # Logging setup
1093
+ β”œβ”€β”€ mcp-server.ts # MCP server implementation
1094
+ β”œβ”€β”€ query-tracker.ts # Query history tracking
1095
+ β”œβ”€β”€ types.ts # TypeScript types
1096
+ β”œβ”€β”€ utils.ts # Utility functions
1097
+ └── index.ts # Entry point
1098
+ ```
1099
+
1100
+ ## Adding New Database Adapters
1101
+
1102
+ 1. Implement the `DatabaseAdapter` interface in `src/adapters/`
1103
+ 2. Follow the pattern from existing adapters
1104
+ 3. Add to adapter factory in `src/adapters/index.ts`
1105
+ 4. Update type definitions if needed
1106
+ 5. Add tests
1107
+
1108
+ Example:
1109
+
1110
+ ```typescript
1111
+ import { BaseAdapter } from './base.js';
1112
+
1113
+ export class CustomAdapter extends BaseAdapter {
1114
+ async connect(): Promise<void> { /* ... */ }
1115
+ async disconnect(): Promise<void> { /* ... */ }
1116
+ async introspect(): Promise<DatabaseSchema> { /* ... */ }
1117
+ async query(): Promise<QueryResult> { /* ... */ }
1118
+ async explain(): Promise<ExplainResult> { /* ... */ }
1119
+ async testConnection(): Promise<boolean> { /* ... */ }
1120
+ async getVersion(): Promise<string> { /* ... */ }
1121
+ }
1122
+ ```
1123
+
1124
+ ## Troubleshooting
1125
+
1126
+ ### Connection Issues
1127
+
1128
+ - Verify connection strings and credentials
1129
+ - Check network connectivity and firewall rules
1130
+ - Enable debug logging: `"logging": { "level": "debug" }`
1131
+ - Use `health_check` tool to test connectivity
1132
+
1133
+ ### Cache Issues
1134
+
1135
+ - Clear cache: Use `clear_cache` tool
1136
+ - Check cache directory permissions
1137
+ - Verify TTL settings
1138
+ - Review cache status with `cache_status` tool
1139
+
1140
+ ### Performance
1141
+
1142
+ - Adjust connection pool settings
1143
+ - Use `maxTables` to limit introspection scope
1144
+ - Set appropriate cache TTL
1145
+ - Enable read-only mode when possible
1146
+
1147
+ ### Oracle Setup
1148
+
1149
+ The Oracle adapter requires additional setup:
1150
+
1151
+ 1. Install Oracle Instant Client
1152
+ 2. Set environment variables (`LD_LIBRARY_PATH` or `PATH`)
1153
+ 3. Install `oracledb` package
1154
+ 4. Implement stub methods in `src/adapters/oracle.ts`
1155
+
1156
+ ## Security Considerations
1157
+
1158
+ - Always use read-only mode in production unless write access is required
1159
+ - Use environment variables for credentials, never hardcode
1160
+ - Enable secret redaction in logs
1161
+ - Restrict write operations with `allowedWriteOperations`
1162
+ - Use connection string encryption where supported
1163
+ - Regular security audits of configurations
1164
+
1165
+ ## License
1166
+
1167
+ MIT
1168
+
1169
+ ## Contributing
1170
+
1171
+ Contributions welcome! Please:
1172
+
1173
+ 1. Fork the repository
1174
+ 2. Create a feature branch
1175
+ 3. Add tests for new functionality
1176
+ 4. Ensure all tests pass
1177
+ 5. Submit a pull request
1178
+
1179
+ ## Support
1180
+
1050
1181
  For issues, questions, or feature requests, please open an issue on GitHub.