@pilat/mcp-datalink 1.0.3 → 1.2.0
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 +30 -387
- package/dist/adapters/factory.d.ts +0 -4
- package/dist/adapters/factory.d.ts.map +1 -1
- package/dist/adapters/factory.js +3 -8
- package/dist/adapters/factory.js.map +1 -1
- package/dist/adapters/mysql/adapter.d.ts +2 -31
- package/dist/adapters/mysql/adapter.d.ts.map +1 -1
- package/dist/adapters/mysql/adapter.js +27 -283
- package/dist/adapters/mysql/adapter.js.map +1 -1
- package/dist/adapters/postgresql/adapter.d.ts +2 -22
- package/dist/adapters/postgresql/adapter.d.ts.map +1 -1
- package/dist/adapters/postgresql/adapter.js +18 -175
- package/dist/adapters/postgresql/adapter.js.map +1 -1
- package/dist/adapters/sqlite/adapter.d.ts +3 -25
- package/dist/adapters/sqlite/adapter.d.ts.map +1 -1
- package/dist/adapters/sqlite/adapter.js +65 -364
- package/dist/adapters/sqlite/adapter.js.map +1 -1
- package/dist/adapters/sqlite/pragma-check.d.ts +19 -0
- package/dist/adapters/sqlite/pragma-check.d.ts.map +1 -0
- package/dist/adapters/sqlite/pragma-check.js +25 -0
- package/dist/adapters/sqlite/pragma-check.js.map +1 -0
- package/dist/adapters/sqlite/url-parser.d.ts +34 -0
- package/dist/adapters/sqlite/url-parser.d.ts.map +1 -0
- package/dist/adapters/sqlite/url-parser.js +73 -0
- package/dist/adapters/sqlite/url-parser.js.map +1 -0
- package/dist/adapters/types.d.ts +10 -113
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/config/loader.d.ts +10 -7
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +20 -97
- package/dist/config/loader.js.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -9
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +113 -40
- package/dist/server.js.map +1 -1
- package/dist/tools/describe-table.d.ts +5 -6
- package/dist/tools/describe-table.d.ts.map +1 -1
- package/dist/tools/describe-table.js +65 -9
- package/dist/tools/describe-table.js.map +1 -1
- package/dist/tools/execute.d.ts +5 -6
- package/dist/tools/execute.d.ts.map +1 -1
- package/dist/tools/execute.js +13 -11
- package/dist/tools/execute.js.map +1 -1
- package/dist/tools/explain.d.ts +5 -10
- package/dist/tools/explain.d.ts.map +1 -1
- package/dist/tools/explain.js +25 -26
- package/dist/tools/explain.js.map +1 -1
- package/dist/tools/list-databases.d.ts +5 -7
- package/dist/tools/list-databases.d.ts.map +1 -1
- package/dist/tools/list-databases.js +31 -0
- package/dist/tools/list-databases.js.map +1 -1
- package/dist/tools/list-tables.d.ts +5 -10
- package/dist/tools/list-tables.d.ts.map +1 -1
- package/dist/tools/list-tables.js +27 -9
- package/dist/tools/list-tables.js.map +1 -1
- package/dist/tools/query.d.ts +1 -6
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +7 -27
- package/dist/tools/query.js.map +1 -1
- package/dist/types.d.ts +39 -12
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/formatter.d.ts +7 -4
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +20 -10
- package/dist/utils/formatter.js.map +1 -1
- package/dist/utils/sql-parser.d.ts +51 -0
- package/dist/utils/sql-parser.d.ts.map +1 -0
- package/dist/utils/sql-parser.js +310 -0
- package/dist/utils/sql-parser.js.map +1 -0
- package/dist/utils/truncate.d.ts +4 -13
- package/dist/utils/truncate.d.ts.map +1 -1
- package/dist/utils/truncate.js +38 -18
- package/dist/utils/truncate.js.map +1 -1
- package/dist/utils/validation.d.ts +35 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +89 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +11 -13
- package/databases.example.json +0 -18
package/README.md
CHANGED
|
@@ -1,414 +1,57 @@
|
|
|
1
|
-
|
|
1
|
+
# @pilat/mcp-datalink
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
<strong>Secure database access for AI assistants via Model Context Protocol</strong>
|
|
5
|
-
</p>
|
|
3
|
+
MCP server for PostgreSQL, MySQL, and SQLite. Gives AI assistants secure database access via [Model Context Protocol](https://modelcontextprotocol.io).
|
|
6
4
|
|
|
7
|
-
<p align="center">
|
|
8
|
-
<a href="https://www.npmjs.com/package/@pilat/mcp-datalink"><img src="https://img.shields.io/npm/v/@pilat/mcp-datalink.svg?style=flat-square&color=blue" alt="npm version" /></a>
|
|
9
|
-
<a href="https://www.npmjs.com/package/@pilat/mcp-datalink"><img src="https://img.shields.io/npm/dm/@pilat/mcp-datalink.svg?style=flat-square&color=green" alt="npm downloads" /></a>
|
|
10
|
-
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg?style=flat-square" alt="License: MIT" /></a>
|
|
11
|
-
<a href="https://github.com/pilat/mcp-datalink"><img src="https://img.shields.io/github/stars/pilat/mcp-datalink?style=flat-square&color=orange" alt="GitHub stars" /></a>
|
|
12
|
-
<img src="https://img.shields.io/badge/Node.js-20+-339933?style=flat-square&logo=node.js&logoColor=white" alt="Node.js 20+" />
|
|
13
|
-
</p>
|
|
14
|
-
|
|
15
|
-
<p align="center">
|
|
16
|
-
<a href="#quick-start">Quick Start</a> |
|
|
17
|
-
<a href="#supported-databases">Databases</a> |
|
|
18
|
-
<a href="#mcp-client-configuration">Clients</a> |
|
|
19
|
-
<a href="#available-tools">Tools</a> |
|
|
20
|
-
<a href="#security">Security</a> |
|
|
21
|
-
<a href="#configuration">Configuration</a>
|
|
22
|
-
</p>
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
MCP Datalink is an [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that gives AI assistants secure, read/write access to your databases. Connect your favorite AI tools to PostgreSQL, MySQL, or SQLite with enterprise-grade security controls.
|
|
27
|
-
|
|
28
|
-
```
|
|
29
|
-
AI Assistant <--> MCP Datalink <--> Your Databases
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Why MCP Datalink?
|
|
33
|
-
|
|
34
|
-
- **Universal Compatibility** - Works with any MCP-compatible client: Claude Desktop, Claude Code, Cursor, Cline, and more
|
|
35
|
-
- **Multi-Database Support** - Connect PostgreSQL, MySQL, and SQLite simultaneously
|
|
36
|
-
- **Security-First Design** - Prepared statements, query validation, readonly modes, and DDL blocking
|
|
37
|
-
- **Context-Aware Output** - Smart truncation prevents context overflow in AI conversations
|
|
38
|
-
- **Zero-Install Option** - Run directly with `npx` - no global installation required
|
|
39
|
-
- **Production Ready** - Battle-tested with comprehensive test coverage
|
|
40
|
-
|
|
41
|
-
## Supported Databases
|
|
42
|
-
|
|
43
|
-
| Database | Status | Driver |
|
|
44
|
-
|----------|--------|--------|
|
|
45
|
-
| <img src="https://img.shields.io/badge/PostgreSQL-4169E1?style=flat-square&logo=postgresql&logoColor=white" alt="PostgreSQL" /> | Stable | node-postgres |
|
|
46
|
-
| <img src="https://img.shields.io/badge/MySQL-4479A1?style=flat-square&logo=mysql&logoColor=white" alt="MySQL" /> | Stable | mysql2 |
|
|
47
|
-
| <img src="https://img.shields.io/badge/SQLite-003B57?style=flat-square&logo=sqlite&logoColor=white" alt="SQLite" /> | Stable | better-sqlite3 |
|
|
48
|
-
|
|
49
|
-
## Quick Start
|
|
50
|
-
|
|
51
|
-
### 1. Create a configuration file
|
|
52
|
-
|
|
53
|
-
Create `databases.json` in your project directory:
|
|
54
|
-
|
|
55
|
-
```json
|
|
56
|
-
{
|
|
57
|
-
"databases": {
|
|
58
|
-
"mydb": {
|
|
59
|
-
"url": "postgresql://user:password@localhost:5432/myapp"
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
5
|
```
|
|
64
|
-
|
|
65
|
-
### 2. Add to your MCP client
|
|
66
|
-
|
|
67
|
-
Add to your client's MCP configuration (see [client-specific examples](#mcp-client-configuration) below):
|
|
68
|
-
|
|
69
|
-
```json
|
|
70
|
-
{
|
|
71
|
-
"mcpServers": {
|
|
72
|
-
"datalink": {
|
|
73
|
-
"command": "npx",
|
|
74
|
-
"args": ["-y", "@pilat/mcp-datalink", "--config", "./databases.json"]
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
6
|
+
npx @pilat/mcp-datalink
|
|
78
7
|
```
|
|
79
8
|
|
|
80
|
-
|
|
9
|
+
Works with Claude Desktop, Claude Code, Cursor, Cline, and any MCP-compatible client.
|
|
81
10
|
|
|
82
|
-
|
|
11
|
+
## Installation
|
|
83
12
|
|
|
84
|
-
|
|
85
|
-
- `list_tables` - Browse tables with row estimates
|
|
86
|
-
- `describe_table` - Inspect schemas, indexes, and foreign keys
|
|
87
|
-
- `query` - Execute SELECT queries safely
|
|
88
|
-
- `execute` - Run INSERT/UPDATE/DELETE with write protection
|
|
89
|
-
- `explain` - Analyze query execution plans
|
|
90
|
-
|
|
91
|
-
## MCP Client Configuration
|
|
92
|
-
|
|
93
|
-
MCP Datalink works with any MCP-compatible client. Here are setup instructions for popular tools:
|
|
94
|
-
|
|
95
|
-
<details>
|
|
96
|
-
<summary><strong>Claude Desktop</strong></summary>
|
|
97
|
-
|
|
98
|
-
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
13
|
+
Add to your MCP client config:
|
|
99
14
|
|
|
100
15
|
```json
|
|
101
16
|
{
|
|
102
17
|
"mcpServers": {
|
|
103
18
|
"datalink": {
|
|
104
19
|
"command": "npx",
|
|
105
|
-
"args": ["-y", "@pilat/mcp-datalink",
|
|
20
|
+
"args": ["-y", "@pilat/mcp-datalink"],
|
|
21
|
+
"env": {
|
|
22
|
+
"DATALINK_MYDB_URL": "postgresql://user:password@localhost:5432/myapp"
|
|
23
|
+
}
|
|
106
24
|
}
|
|
107
25
|
}
|
|
108
26
|
}
|
|
109
27
|
```
|
|
110
28
|
|
|
111
|
-
|
|
29
|
+
| Variable | Description |
|
|
30
|
+
|----------|-------------|
|
|
31
|
+
| `DATALINK_{NAME}_URL` | Connection URL (creates database named `{name}`) |
|
|
32
|
+
| `DATALINK_{NAME}_READONLY` | Set to `true` to block writes |
|
|
112
33
|
|
|
113
|
-
|
|
114
|
-
<summary><strong>Claude Code (CLI)</strong></summary>
|
|
34
|
+
**Config locations:** Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`), Claude Code (`~/.claude/settings.json`), Cursor (Settings > MCP), Cline (`cline.mcpServers` in VS Code settings).
|
|
115
35
|
|
|
116
|
-
|
|
36
|
+
## Tools
|
|
117
37
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Or use the CLI command:
|
|
130
|
-
|
|
131
|
-
```bash
|
|
132
|
-
claude mcp add datalink -- npx -y @pilat/mcp-datalink --config ./databases.json
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
</details>
|
|
136
|
-
|
|
137
|
-
<details>
|
|
138
|
-
<summary><strong>Cursor</strong></summary>
|
|
139
|
-
|
|
140
|
-
Add to your Cursor MCP settings (Settings > MCP):
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"mcpServers": {
|
|
145
|
-
"datalink": {
|
|
146
|
-
"command": "npx",
|
|
147
|
-
"args": ["-y", "@pilat/mcp-datalink", "--config", "./databases.json"]
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
</details>
|
|
154
|
-
|
|
155
|
-
<details>
|
|
156
|
-
<summary><strong>Cline (VS Code Extension)</strong></summary>
|
|
157
|
-
|
|
158
|
-
Add to your Cline MCP configuration in VS Code settings:
|
|
159
|
-
|
|
160
|
-
```json
|
|
161
|
-
{
|
|
162
|
-
"cline.mcpServers": {
|
|
163
|
-
"datalink": {
|
|
164
|
-
"command": "npx",
|
|
165
|
-
"args": ["-y", "@pilat/mcp-datalink", "--config", "./databases.json"]
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
</details>
|
|
172
|
-
|
|
173
|
-
<details>
|
|
174
|
-
<summary><strong>Custom MCP Clients</strong></summary>
|
|
175
|
-
|
|
176
|
-
For any MCP-compatible client, use the standard server configuration:
|
|
177
|
-
|
|
178
|
-
```json
|
|
179
|
-
{
|
|
180
|
-
"command": "npx",
|
|
181
|
-
"args": ["-y", "@pilat/mcp-datalink", "--config", "/absolute/path/to/databases.json"]
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
Or with global installation:
|
|
186
|
-
|
|
187
|
-
```bash
|
|
188
|
-
npm install -g @pilat/mcp-datalink
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
```json
|
|
192
|
-
{
|
|
193
|
-
"command": "mcp-datalink",
|
|
194
|
-
"args": ["--config", "/absolute/path/to/databases.json"]
|
|
195
|
-
}
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
</details>
|
|
199
|
-
|
|
200
|
-
## Available Tools
|
|
201
|
-
|
|
202
|
-
| Tool | Description | Example Use Case |
|
|
203
|
-
|------|-------------|------------------|
|
|
204
|
-
| `list_databases` | List all configured database connections | "What databases do I have access to?" |
|
|
205
|
-
| `list_tables` | List tables with row estimates and types | "Show me all tables in the main database" |
|
|
206
|
-
| `describe_table` | Get detailed schema information | "What columns does the users table have?" |
|
|
207
|
-
| `query` | Execute SELECT queries (returns Markdown) | "Find all users created this month" |
|
|
208
|
-
| `execute` | Execute INSERT/UPDATE/DELETE | "Update the user's email address" |
|
|
209
|
-
| `explain` | Show query execution plans | "Why is this query slow?" |
|
|
210
|
-
|
|
211
|
-
### Example Interaction
|
|
212
|
-
|
|
213
|
-
```
|
|
214
|
-
You: "What tables are in my database?"
|
|
215
|
-
AI: Let me check...
|
|
216
|
-
[Uses list_tables tool]
|
|
217
|
-
|
|
218
|
-
Found 5 tables:
|
|
219
|
-
- users (15,234 rows)
|
|
220
|
-
- orders (48,291 rows)
|
|
221
|
-
- products (1,205 rows)
|
|
222
|
-
- categories (24 rows)
|
|
223
|
-
- order_items (142,891 rows)
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
## Configuration
|
|
227
|
-
|
|
228
|
-
### Configuration File
|
|
229
|
-
|
|
230
|
-
Create a `databases.json` file with your database connections:
|
|
231
|
-
|
|
232
|
-
```json
|
|
233
|
-
{
|
|
234
|
-
"databases": {
|
|
235
|
-
"production": {
|
|
236
|
-
"url": "postgresql://user:pass@prod.example.com:5432/app",
|
|
237
|
-
"readonly": true
|
|
238
|
-
},
|
|
239
|
-
"development": {
|
|
240
|
-
"url": "postgresql://dev:dev@localhost:5432/app_dev",
|
|
241
|
-
"readonly": false
|
|
242
|
-
},
|
|
243
|
-
"analytics": {
|
|
244
|
-
"url": "mysql://analyst:pass@analytics.example.com:3306/warehouse",
|
|
245
|
-
"readonly": true
|
|
246
|
-
},
|
|
247
|
-
"local": {
|
|
248
|
-
"url": "sqlite:///path/to/database.db"
|
|
249
|
-
}
|
|
250
|
-
},
|
|
251
|
-
"defaults": {
|
|
252
|
-
"timeout": 30000,
|
|
253
|
-
"maxRows": 100,
|
|
254
|
-
"maxCellLength": 500,
|
|
255
|
-
"maxTotalSize": 65536
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
### Connection Options
|
|
261
|
-
|
|
262
|
-
| Option | Type | Default | Description |
|
|
263
|
-
|--------|------|---------|-------------|
|
|
264
|
-
| `url` | string | required | Database connection string |
|
|
265
|
-
| `readonly` | boolean | `false` | Block INSERT/UPDATE/DELETE operations |
|
|
266
|
-
| `maxRows` | number | `100` | Maximum rows returned per query |
|
|
267
|
-
|
|
268
|
-
### URL Formats
|
|
269
|
-
|
|
270
|
-
```bash
|
|
271
|
-
# PostgreSQL
|
|
272
|
-
postgresql://user:password@host:5432/database
|
|
273
|
-
|
|
274
|
-
# MySQL
|
|
275
|
-
mysql://user:password@host:3306/database
|
|
276
|
-
|
|
277
|
-
# SQLite
|
|
278
|
-
sqlite:///absolute/path/to/database.db
|
|
279
|
-
sqlite://./relative/path/to/database.db
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
### Environment Variables
|
|
283
|
-
|
|
284
|
-
Alternative to config file - set connections via environment variables:
|
|
285
|
-
|
|
286
|
-
```bash
|
|
287
|
-
DB_MCP_PRODUCTION_URL=postgresql://user:pass@prod.example.com:5432/app
|
|
288
|
-
DB_MCP_DEVELOPMENT_URL=postgresql://dev:dev@localhost:5432/app_dev
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
Pattern: `DB_MCP_{NAME}_URL` creates a connection named `{name}` (lowercase).
|
|
292
|
-
|
|
293
|
-
### Config Resolution Order
|
|
294
|
-
|
|
295
|
-
1. CLI argument: `--config ./path/to/config.json`
|
|
296
|
-
2. Environment variable: `DB_MCP_CONFIG=/path/to/config.json`
|
|
297
|
-
3. Current directory: `./databases.json`
|
|
298
|
-
4. Home directory: `~/.config/db-mcp/databases.json`
|
|
38
|
+
| Tool | Description |
|
|
39
|
+
|------|-------------|
|
|
40
|
+
| `list_databases` | List configured database connections |
|
|
41
|
+
| `list_tables` | List tables with row counts |
|
|
42
|
+
| `describe_table` | Get schema, indexes, foreign keys |
|
|
43
|
+
| `query` | Run SELECT queries |
|
|
44
|
+
| `execute` | Run INSERT/UPDATE/DELETE |
|
|
45
|
+
| `explain` | Show query execution plans |
|
|
299
46
|
|
|
300
47
|
## Security
|
|
301
48
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
| **Query Validation** | SQL parser validates and restricts query types |
|
|
308
|
-
| **Single Statement Only** | Multi-statement queries are rejected |
|
|
309
|
-
| **DDL Blocking** | CREATE, DROP, ALTER, TRUNCATE are forbidden |
|
|
310
|
-
| **Readonly Mode** | Per-connection write protection |
|
|
311
|
-
| **Connection Isolation** | Fresh connection per request, no connection reuse |
|
|
312
|
-
| **Output Limits** | Prevents context overflow with configurable size limits |
|
|
313
|
-
|
|
314
|
-
### Output Limits
|
|
315
|
-
|
|
316
|
-
To prevent overwhelming AI context windows, all outputs are automatically limited:
|
|
317
|
-
|
|
318
|
-
| Parameter | Default | Maximum |
|
|
319
|
-
|-----------|---------|---------|
|
|
320
|
-
| `maxRows` | 100 | 500 |
|
|
321
|
-
| `maxCellLength` | 500 chars | 1,000 chars |
|
|
322
|
-
| `maxTotalSize` | 64 KB | 256 KB |
|
|
323
|
-
| `maxColumns` | 50 | 100 |
|
|
324
|
-
|
|
325
|
-
When limits are exceeded, responses include `truncated: true` with pagination hints.
|
|
326
|
-
|
|
327
|
-
## Installation Options
|
|
328
|
-
|
|
329
|
-
### Zero-Install (Recommended)
|
|
330
|
-
|
|
331
|
-
Run directly with `npx` - the package is downloaded automatically:
|
|
332
|
-
|
|
333
|
-
```bash
|
|
334
|
-
npx @pilat/mcp-datalink --config ./databases.json
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Global Installation
|
|
338
|
-
|
|
339
|
-
```bash
|
|
340
|
-
npm install -g @pilat/mcp-datalink
|
|
341
|
-
mcp-datalink --config ./databases.json
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
### Local Installation
|
|
345
|
-
|
|
346
|
-
```bash
|
|
347
|
-
npm install @pilat/mcp-datalink
|
|
348
|
-
npx mcp-datalink --config ./databases.json
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
## Development
|
|
352
|
-
|
|
353
|
-
```bash
|
|
354
|
-
# Clone the repository
|
|
355
|
-
git clone https://github.com/pilat/mcp-datalink.git
|
|
356
|
-
cd mcp-datalink
|
|
357
|
-
|
|
358
|
-
# Install dependencies
|
|
359
|
-
npm install
|
|
360
|
-
|
|
361
|
-
# Build
|
|
362
|
-
npm run build
|
|
363
|
-
|
|
364
|
-
# Run tests
|
|
365
|
-
npm run test:unit # Unit tests (fast, no external deps)
|
|
366
|
-
npm run test:integration # Integration tests (uses testcontainers)
|
|
367
|
-
npm test # All tests
|
|
368
|
-
|
|
369
|
-
# Development mode
|
|
370
|
-
npm run dev # Watch mode with auto-rebuild
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Testing with MCP Inspector
|
|
374
|
-
|
|
375
|
-
```bash
|
|
376
|
-
npx @modelcontextprotocol/inspector node dist/index.js -- --config ./databases.json
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
## Contributing
|
|
380
|
-
|
|
381
|
-
Contributions are welcome! Please read our contributing guidelines:
|
|
382
|
-
|
|
383
|
-
1. Fork the repository
|
|
384
|
-
2. Create a feature branch (`git checkout -b feature/amazing-feature`)
|
|
385
|
-
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
|
|
386
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
387
|
-
5. Open a Pull Request
|
|
388
|
-
|
|
389
|
-
### Commit Convention
|
|
390
|
-
|
|
391
|
-
We use [Conventional Commits](https://www.conventionalcommits.org/):
|
|
392
|
-
|
|
393
|
-
```
|
|
394
|
-
feat(tools): add new database tool
|
|
395
|
-
fix(security): enforce query validation
|
|
396
|
-
docs: update README
|
|
397
|
-
```
|
|
398
|
-
|
|
399
|
-
## Links
|
|
400
|
-
|
|
401
|
-
- [GitHub Repository](https://github.com/pilat/mcp-datalink)
|
|
402
|
-
- [npm Package](https://www.npmjs.com/package/@pilat/mcp-datalink)
|
|
403
|
-
- [Issue Tracker](https://github.com/pilat/mcp-datalink/issues)
|
|
404
|
-
- [MCP Documentation](https://modelcontextprotocol.io)
|
|
49
|
+
- Prepared statements only (no SQL injection)
|
|
50
|
+
- Single statement per query (no chaining)
|
|
51
|
+
- DDL blocked (no DROP, ALTER, TRUNCATE)
|
|
52
|
+
- Readonly mode per connection
|
|
53
|
+
- Output truncation (100 rows, 64KB max)
|
|
405
54
|
|
|
406
55
|
## License
|
|
407
56
|
|
|
408
|
-
MIT
|
|
409
|
-
|
|
410
|
-
---
|
|
411
|
-
|
|
412
|
-
<p align="center">
|
|
413
|
-
<sub>Built with care by <a href="https://github.com/pilat">@pilat</a></sub>
|
|
414
|
-
</p>
|
|
57
|
+
MIT
|
|
@@ -2,10 +2,6 @@
|
|
|
2
2
|
* Database Adapter Factory
|
|
3
3
|
*
|
|
4
4
|
* Creates the appropriate database adapter based on connection URL scheme.
|
|
5
|
-
*
|
|
6
|
-
* Phase 1: PostgreSQL - DONE
|
|
7
|
-
* Phase 2: MySQL - DONE
|
|
8
|
-
* Phase 3: SQLite - DONE
|
|
9
5
|
*/
|
|
10
6
|
import type { DatabaseAdapter } from './types.js';
|
|
11
7
|
import type { DatabaseConfig, DefaultsConfig } from '../types.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAiB,eAAe,EAAE,MAAM,YAAY,CAAC;AACjE,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgFlE;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,cAAc,GACvB,eAAe,CASjB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOnD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOlD"}
|
package/dist/adapters/factory.js
CHANGED
|
@@ -2,13 +2,9 @@
|
|
|
2
2
|
* Database Adapter Factory
|
|
3
3
|
*
|
|
4
4
|
* Creates the appropriate database adapter based on connection URL scheme.
|
|
5
|
-
*
|
|
6
|
-
* Phase 1: PostgreSQL - DONE
|
|
7
|
-
* Phase 2: MySQL - DONE
|
|
8
|
-
* Phase 3: SQLite - DONE
|
|
9
5
|
*/
|
|
10
|
-
import { PostgreSqlAdapter } from './postgresql/adapter.js';
|
|
11
6
|
import { MySqlAdapter } from './mysql/adapter.js';
|
|
7
|
+
import { PostgreSqlAdapter } from './postgresql/adapter.js';
|
|
12
8
|
import { SqliteAdapter } from './sqlite/adapter.js';
|
|
13
9
|
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
14
10
|
/**
|
|
@@ -103,9 +99,8 @@ export function isSupportedUrl(url) {
|
|
|
103
99
|
*/
|
|
104
100
|
export function isImplemented(url) {
|
|
105
101
|
try {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
return scheme === 'postgresql' || scheme === 'mysql' || scheme === 'sqlite';
|
|
102
|
+
detectScheme(url);
|
|
103
|
+
return true;
|
|
109
104
|
}
|
|
110
105
|
catch {
|
|
111
106
|
return false;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/adapters/factory.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAO3D;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,GAAW;IAC/B,2CAA2C;IAC3C,IAAI,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,aAAa,CAAC,EAAE,CAAC;QACrE,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,kBAAkB;IAClB,IAAI,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,gEAAgE;IAChE,IACE,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC;QAC3B,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnB,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;QACvB,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EACxB,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,cAAc,EACxB,gCAAgC,GAAG,IAAI;QACrC,oEAAoE,EACtE,EAAE,GAAG,EAAE,CACR,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,iBAAiB,CACxB,MAAqB,EACrB,MAAsB;IAEtB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,YAAY;YACf,OAAO,IAAI,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAEvC,KAAK,OAAO;YACV,OAAO,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;QAElC,KAAK,QAAQ;YACX,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QAEnC,OAAO,CAAC,CAAC,CAAC;YACR,8BAA8B;YAC9B,MAAM,WAAW,GAAU,MAAM,CAAC;YAClC,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,cAAc,EACxB,+BAA+B,WAAW,EAAE,CAC7C,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAwB,EACxB,QAAwB;IAExB,MAAM,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;IAE1C,MAAM,MAAM,GAAkB;QAC5B,QAAQ;QACR,QAAQ;KACT,CAAC;IAEF,OAAO,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,CAAC,CAAC;QAClB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -4,16 +4,8 @@
|
|
|
4
4
|
* Implements DatabaseAdapter interface for MySQL databases.
|
|
5
5
|
* Uses mysql2/promise driver with per-request connection recycling.
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
7
|
+
import type { AdapterConfig, AdapterConnection, DatabaseAdapter } from '../types.js';
|
|
8
8
|
import type { ParsedQuery } from '../../types.js';
|
|
9
|
-
/**
|
|
10
|
-
* Strip SQL comments from a query
|
|
11
|
-
*/
|
|
12
|
-
declare function stripComments(sql: string): string;
|
|
13
|
-
/**
|
|
14
|
-
* String-aware statement splitting
|
|
15
|
-
*/
|
|
16
|
-
declare function splitStatements(sql: string): string[];
|
|
17
9
|
/**
|
|
18
10
|
* MySQL database adapter
|
|
19
11
|
*
|
|
@@ -24,38 +16,17 @@ export declare class MySqlAdapter implements DatabaseAdapter {
|
|
|
24
16
|
private readonly connectionUrl;
|
|
25
17
|
private readonly timeout;
|
|
26
18
|
constructor(config: AdapterConfig);
|
|
27
|
-
/**
|
|
28
|
-
* Get the default schema name for MySQL (database name from URL)
|
|
29
|
-
*/
|
|
30
19
|
getDefaultSchema(): string;
|
|
31
|
-
/**
|
|
32
|
-
* Parse and validate a SQL query
|
|
33
|
-
*/
|
|
34
20
|
parseQuery(sql: string): ParsedQuery;
|
|
35
|
-
/**
|
|
36
|
-
* Inject a LIMIT clause into a SELECT query if it doesn't have one
|
|
37
|
-
*/
|
|
38
21
|
injectLimit(sql: string, limit: number): string;
|
|
39
|
-
/**
|
|
40
|
-
* Validate that a SQL query is appropriate for a specific tool
|
|
41
|
-
*/
|
|
42
22
|
validateQueryForTool(sql: string, tool: 'query' | 'execute'): void;
|
|
43
|
-
/**
|
|
44
|
-
* Get the EXPLAIN prefix for MySQL
|
|
45
|
-
*/
|
|
46
23
|
getExplainPrefix(analyze: boolean): string;
|
|
47
|
-
/**
|
|
48
|
-
* Convert PostgreSQL-style placeholders ($1, $2) to MySQL-style (?)
|
|
49
|
-
*/
|
|
24
|
+
/** Convert $1, $2 placeholders to ? for MySQL */
|
|
50
25
|
convertPlaceholders(sql: string): string;
|
|
51
26
|
/**
|
|
52
27
|
* Execute a function with a managed MySQL connection
|
|
53
28
|
*/
|
|
54
29
|
withConnection<T>(fn: (conn: AdapterConnection) => Promise<T>): Promise<T>;
|
|
55
|
-
/**
|
|
56
|
-
* Clean up resources (no persistent resources in this adapter)
|
|
57
|
-
*/
|
|
58
30
|
dispose(): Promise<void>;
|
|
59
31
|
}
|
|
60
|
-
export { stripComments, splitStatements };
|
|
61
32
|
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/mysql/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/mysql/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,aAAa,EACb,iBAAiB,EACjB,eAAe,EAGhB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAIV,WAAW,EAGZ,MAAM,gBAAgB,CAAC;AAqDxB;;;;GAIG;AACH,qBAAa,YAAa,YAAW,eAAe;IAClD,QAAQ,CAAC,IAAI,EAAG,OAAO,CAAU;IAEjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,MAAM,EAAE,aAAa;IAKjC,gBAAgB,IAAI,MAAM;IAa1B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW;IAiBpC,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IAI/C,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI;IAKlE,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM;IAI1C,iDAAiD;IACjD,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAIxC;;OAEG;IACG,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAqC1E,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAG/B"}
|