@johnroshan/universal-db-mcp 1.0.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/LICENCE +21 -0
- package/README.md +146 -0
- package/index.js +368 -0
- package/package.json +42 -0
package/LICENCE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 [John Roshan]
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Universal Database MCP Server
|
|
2
|
+
|
|
3
|
+
Model Context Protocol server for PostgreSQL and MySQL databases. Enables Claude to query and manage your databases.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @johnroshan/universal-db-mcp
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
Edit Claude Desktop config file:
|
|
14
|
+
|
|
15
|
+
macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
16
|
+
Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
17
|
+
|
|
18
|
+
### PostgreSQL
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"postgres": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "@johnroshan/universal-db-mcp"],
|
|
26
|
+
"env": {
|
|
27
|
+
"DB_TYPE": "postgres",
|
|
28
|
+
"DATABASE_URL": "postgresql://user:password@localhost:5432/mydb"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Or use individual parameters:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"postgres": {
|
|
41
|
+
"command": "npx",
|
|
42
|
+
"args": ["-y", "@johnroshan/universal-db-mcp"],
|
|
43
|
+
"env": {
|
|
44
|
+
"DB_TYPE": "postgres",
|
|
45
|
+
"DB_HOST": "localhost",
|
|
46
|
+
"DB_PORT": "5432",
|
|
47
|
+
"DB_NAME": "mydb",
|
|
48
|
+
"DB_USER": "postgres",
|
|
49
|
+
"DB_PASSWORD": "your_password"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### MySQL
|
|
57
|
+
|
|
58
|
+
```json
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"mysql": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@johnroshan/universal-db-mcp"],
|
|
64
|
+
"env": {
|
|
65
|
+
"DB_TYPE": "mysql",
|
|
66
|
+
"DATABASE_URL": "mysql://user:password@localhost:3306/mydb"
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Available Tools
|
|
74
|
+
|
|
75
|
+
- `query` - Execute SQL queries
|
|
76
|
+
- `list_tables` - List all tables
|
|
77
|
+
- `describe_table` - Get table schema
|
|
78
|
+
- `list_databases` - List databases
|
|
79
|
+
- `table_row_count` - Count rows in table
|
|
80
|
+
- `search_table` - Search records with pattern matching
|
|
81
|
+
|
|
82
|
+
## Usage Examples
|
|
83
|
+
|
|
84
|
+
After configuration, ask Claude:
|
|
85
|
+
|
|
86
|
+
- "Show me all tables in my database"
|
|
87
|
+
- "What is the schema of the users table"
|
|
88
|
+
- "How many rows are in the orders table"
|
|
89
|
+
- "Find all users with gmail addresses"
|
|
90
|
+
- "Show me the last 10 orders"
|
|
91
|
+
|
|
92
|
+
## Environment Variables
|
|
93
|
+
|
|
94
|
+
| Variable | Required | Description |
|
|
95
|
+
|----------|----------|-------------|
|
|
96
|
+
| DB_TYPE | Yes | postgres or mysql |
|
|
97
|
+
| DATABASE_URL | No | Full connection string |
|
|
98
|
+
| DB_HOST | No | Database host |
|
|
99
|
+
| DB_PORT | No | Database port |
|
|
100
|
+
| DB_NAME | No | Database name |
|
|
101
|
+
| DB_USER | No | Database user |
|
|
102
|
+
| DB_PASSWORD | No | Database password |
|
|
103
|
+
|
|
104
|
+
Either DATABASE_URL or DB_NAME + DB_USER is required.
|
|
105
|
+
|
|
106
|
+
## Security
|
|
107
|
+
|
|
108
|
+
This server runs locally on your machine. Database credentials remain on your device.
|
|
109
|
+
|
|
110
|
+
Consider creating a read-only database user:
|
|
111
|
+
|
|
112
|
+
PostgreSQL:
|
|
113
|
+
```sql
|
|
114
|
+
CREATE USER claude_readonly WITH PASSWORD 'password';
|
|
115
|
+
GRANT CONNECT ON DATABASE mydb TO claude_readonly;
|
|
116
|
+
GRANT USAGE ON SCHEMA public TO claude_readonly;
|
|
117
|
+
GRANT SELECT ON ALL TABLES IN SCHEMA public TO claude_readonly;
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
MySQL:
|
|
121
|
+
```sql
|
|
122
|
+
CREATE USER 'claude_readonly'@'localhost' IDENTIFIED BY 'password';
|
|
123
|
+
GRANT SELECT ON mydb.* TO 'claude_readonly'@'localhost';
|
|
124
|
+
FLUSH PRIVILEGES;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Troubleshooting
|
|
128
|
+
|
|
129
|
+
Connection refused:
|
|
130
|
+
- Verify database is running
|
|
131
|
+
- Check host and port
|
|
132
|
+
- Check firewall settings
|
|
133
|
+
|
|
134
|
+
Authentication failed:
|
|
135
|
+
- Verify credentials
|
|
136
|
+
- Check user permissions
|
|
137
|
+
- For PostgreSQL check pg_hba.conf
|
|
138
|
+
|
|
139
|
+
Claude does not see server:
|
|
140
|
+
- Restart Claude Desktop
|
|
141
|
+
- Check config file syntax
|
|
142
|
+
- Check logs at ~/Library/Logs/Claude/mcp*.log
|
|
143
|
+
|
|
144
|
+
## License
|
|
145
|
+
|
|
146
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import {
|
|
6
|
+
CallToolRequestSchema,
|
|
7
|
+
ListToolsRequestSchema,
|
|
8
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
import pg from "pg";
|
|
10
|
+
import mysql from "mysql2/promise";
|
|
11
|
+
|
|
12
|
+
const { Client: PgClient } = pg;
|
|
13
|
+
|
|
14
|
+
const DB_TYPE = process.env.DB_TYPE;
|
|
15
|
+
const DB_HOST = process.env.DB_HOST || "localhost";
|
|
16
|
+
const DB_PORT = process.env.DB_PORT;
|
|
17
|
+
const DB_NAME = process.env.DB_NAME;
|
|
18
|
+
const DB_USER = process.env.DB_USER;
|
|
19
|
+
const DB_PASSWORD = process.env.DB_PASSWORD;
|
|
20
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
21
|
+
|
|
22
|
+
if (!DB_TYPE) {
|
|
23
|
+
console.error("Error: DB_TYPE environment variable required (postgres or mysql)");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!DATABASE_URL && (!DB_NAME || !DB_USER)) {
|
|
28
|
+
console.error("Error: Either DATABASE_URL or DB_NAME, DB_USER required");
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const server = new Server(
|
|
33
|
+
{
|
|
34
|
+
name: "universal-db-mcp",
|
|
35
|
+
version: "1.0.0",
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
capabilities: {
|
|
39
|
+
tools: {},
|
|
40
|
+
},
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
async function getConnection() {
|
|
45
|
+
if (DB_TYPE === "postgres") {
|
|
46
|
+
const client = new PgClient(
|
|
47
|
+
DATABASE_URL || {
|
|
48
|
+
host: DB_HOST,
|
|
49
|
+
port: DB_PORT || 5432,
|
|
50
|
+
database: DB_NAME,
|
|
51
|
+
user: DB_USER,
|
|
52
|
+
password: DB_PASSWORD,
|
|
53
|
+
}
|
|
54
|
+
);
|
|
55
|
+
await client.connect();
|
|
56
|
+
return {
|
|
57
|
+
client,
|
|
58
|
+
async query(sql, params = []) {
|
|
59
|
+
const result = await client.query(sql, params);
|
|
60
|
+
return result.rows;
|
|
61
|
+
},
|
|
62
|
+
async close() {
|
|
63
|
+
await client.end();
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
} else if (DB_TYPE === "mysql") {
|
|
67
|
+
const connection = await mysql.createConnection(
|
|
68
|
+
DATABASE_URL || {
|
|
69
|
+
host: DB_HOST,
|
|
70
|
+
port: DB_PORT || 3306,
|
|
71
|
+
database: DB_NAME,
|
|
72
|
+
user: DB_USER,
|
|
73
|
+
password: DB_PASSWORD,
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
return {
|
|
77
|
+
client: connection,
|
|
78
|
+
async query(sql, params = []) {
|
|
79
|
+
const [rows] = await connection.execute(sql, params);
|
|
80
|
+
return rows;
|
|
81
|
+
},
|
|
82
|
+
async close() {
|
|
83
|
+
await connection.end();
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
} else {
|
|
87
|
+
throw new Error(`Unsupported database type: ${DB_TYPE}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
92
|
+
return {
|
|
93
|
+
tools: [
|
|
94
|
+
{
|
|
95
|
+
name: "query",
|
|
96
|
+
description: "Execute a SQL query on the database. Returns results as JSON.",
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: "object",
|
|
99
|
+
properties: {
|
|
100
|
+
sql: {
|
|
101
|
+
type: "string",
|
|
102
|
+
description: "SQL query to execute",
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
required: ["sql"],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: "list_tables",
|
|
110
|
+
description: "List all tables in the current database",
|
|
111
|
+
inputSchema: {
|
|
112
|
+
type: "object",
|
|
113
|
+
properties: {},
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
name: "describe_table",
|
|
118
|
+
description: "Get detailed schema information for a specific table",
|
|
119
|
+
inputSchema: {
|
|
120
|
+
type: "object",
|
|
121
|
+
properties: {
|
|
122
|
+
table: {
|
|
123
|
+
type: "string",
|
|
124
|
+
description: "Name of the table to describe",
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
required: ["table"],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: "list_databases",
|
|
132
|
+
description: "List all available databases on the server",
|
|
133
|
+
inputSchema: {
|
|
134
|
+
type: "object",
|
|
135
|
+
properties: {},
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: "table_row_count",
|
|
140
|
+
description: "Get the number of rows in a table",
|
|
141
|
+
inputSchema: {
|
|
142
|
+
type: "object",
|
|
143
|
+
properties: {
|
|
144
|
+
table: {
|
|
145
|
+
type: "string",
|
|
146
|
+
description: "Table name",
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
required: ["table"],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
name: "search_table",
|
|
154
|
+
description: "Search for records in a table matching a condition",
|
|
155
|
+
inputSchema: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
table: {
|
|
159
|
+
type: "string",
|
|
160
|
+
description: "Table name",
|
|
161
|
+
},
|
|
162
|
+
column: {
|
|
163
|
+
type: "string",
|
|
164
|
+
description: "Column to search in",
|
|
165
|
+
},
|
|
166
|
+
value: {
|
|
167
|
+
type: "string",
|
|
168
|
+
description: "Value to search for",
|
|
169
|
+
},
|
|
170
|
+
limit: {
|
|
171
|
+
type: "number",
|
|
172
|
+
description: "Maximum number of results",
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
required: ["table", "column", "value"],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
],
|
|
179
|
+
};
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
183
|
+
const { name, arguments: args } = request.params;
|
|
184
|
+
let conn;
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
conn = await getConnection();
|
|
188
|
+
|
|
189
|
+
if (name === "query") {
|
|
190
|
+
const results = await conn.query(args.sql);
|
|
191
|
+
return {
|
|
192
|
+
content: [
|
|
193
|
+
{
|
|
194
|
+
type: "text",
|
|
195
|
+
text: JSON.stringify(
|
|
196
|
+
{
|
|
197
|
+
rowCount: results.length,
|
|
198
|
+
rows: results,
|
|
199
|
+
},
|
|
200
|
+
null,
|
|
201
|
+
2
|
|
202
|
+
),
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (name === "list_tables") {
|
|
209
|
+
let results;
|
|
210
|
+
if (DB_TYPE === "postgres") {
|
|
211
|
+
results = await conn.query(`
|
|
212
|
+
SELECT table_name, table_type
|
|
213
|
+
FROM information_schema.tables
|
|
214
|
+
WHERE table_schema = 'public'
|
|
215
|
+
ORDER BY table_name
|
|
216
|
+
`);
|
|
217
|
+
} else {
|
|
218
|
+
results = await conn.query(`
|
|
219
|
+
SELECT table_name, table_type
|
|
220
|
+
FROM information_schema.tables
|
|
221
|
+
WHERE table_schema = ?
|
|
222
|
+
ORDER BY table_name
|
|
223
|
+
`, [DB_NAME]);
|
|
224
|
+
}
|
|
225
|
+
return {
|
|
226
|
+
content: [
|
|
227
|
+
{
|
|
228
|
+
type: "text",
|
|
229
|
+
text: JSON.stringify(results, null, 2),
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (name === "describe_table") {
|
|
236
|
+
let results;
|
|
237
|
+
if (DB_TYPE === "postgres") {
|
|
238
|
+
results = await conn.query(`
|
|
239
|
+
SELECT
|
|
240
|
+
column_name,
|
|
241
|
+
data_type,
|
|
242
|
+
character_maximum_length,
|
|
243
|
+
is_nullable,
|
|
244
|
+
column_default
|
|
245
|
+
FROM information_schema.columns
|
|
246
|
+
WHERE table_name = $1
|
|
247
|
+
ORDER BY ordinal_position
|
|
248
|
+
`, [args.table]);
|
|
249
|
+
} else {
|
|
250
|
+
results = await conn.query(`
|
|
251
|
+
SELECT
|
|
252
|
+
column_name,
|
|
253
|
+
data_type,
|
|
254
|
+
character_maximum_length,
|
|
255
|
+
is_nullable,
|
|
256
|
+
column_default
|
|
257
|
+
FROM information_schema.columns
|
|
258
|
+
WHERE table_schema = ? AND table_name = ?
|
|
259
|
+
ORDER BY ordinal_position
|
|
260
|
+
`, [DB_NAME, args.table]);
|
|
261
|
+
}
|
|
262
|
+
return {
|
|
263
|
+
content: [
|
|
264
|
+
{
|
|
265
|
+
type: "text",
|
|
266
|
+
text: JSON.stringify(results, null, 2),
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (name === "list_databases") {
|
|
273
|
+
let results;
|
|
274
|
+
if (DB_TYPE === "postgres") {
|
|
275
|
+
results = await conn.query(`
|
|
276
|
+
SELECT datname as database_name
|
|
277
|
+
FROM pg_database
|
|
278
|
+
WHERE datistemplate = false
|
|
279
|
+
ORDER BY datname
|
|
280
|
+
`);
|
|
281
|
+
} else {
|
|
282
|
+
results = await conn.query(`SHOW DATABASES`);
|
|
283
|
+
}
|
|
284
|
+
return {
|
|
285
|
+
content: [
|
|
286
|
+
{
|
|
287
|
+
type: "text",
|
|
288
|
+
text: JSON.stringify(results, null, 2),
|
|
289
|
+
},
|
|
290
|
+
],
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (name === "table_row_count") {
|
|
295
|
+
const results = await conn.query(
|
|
296
|
+
`SELECT COUNT(*) as count FROM ${args.table}`
|
|
297
|
+
);
|
|
298
|
+
return {
|
|
299
|
+
content: [
|
|
300
|
+
{
|
|
301
|
+
type: "text",
|
|
302
|
+
text: JSON.stringify(results[0], null, 2),
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (name === "search_table") {
|
|
309
|
+
const limit = args.limit || 100;
|
|
310
|
+
let results;
|
|
311
|
+
|
|
312
|
+
if (DB_TYPE === "postgres") {
|
|
313
|
+
results = await conn.query(
|
|
314
|
+
`SELECT * FROM ${args.table} WHERE ${args.column}::text ILIKE $1 LIMIT $2`,
|
|
315
|
+
[`%${args.value}%`, limit]
|
|
316
|
+
);
|
|
317
|
+
} else {
|
|
318
|
+
results = await conn.query(
|
|
319
|
+
`SELECT * FROM ${args.table} WHERE ${args.column} LIKE ? LIMIT ?`,
|
|
320
|
+
[`%${args.value}%`, limit]
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
content: [
|
|
326
|
+
{
|
|
327
|
+
type: "text",
|
|
328
|
+
text: JSON.stringify(
|
|
329
|
+
{
|
|
330
|
+
matchCount: results.length,
|
|
331
|
+
results: results,
|
|
332
|
+
},
|
|
333
|
+
null,
|
|
334
|
+
2
|
|
335
|
+
),
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
return {
|
|
344
|
+
content: [
|
|
345
|
+
{
|
|
346
|
+
type: "text",
|
|
347
|
+
text: `Error: ${error.message}`,
|
|
348
|
+
},
|
|
349
|
+
],
|
|
350
|
+
isError: true,
|
|
351
|
+
};
|
|
352
|
+
} finally {
|
|
353
|
+
if (conn) {
|
|
354
|
+
await conn.close();
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
async function main() {
|
|
360
|
+
const transport = new StdioServerTransport();
|
|
361
|
+
await server.connect(transport);
|
|
362
|
+
console.error(`Universal Database MCP Server running (${DB_TYPE})`);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
main().catch((error) => {
|
|
366
|
+
console.error("Fatal error:", error);
|
|
367
|
+
process.exit(1);
|
|
368
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@johnroshan/universal-db-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for PostgreSQL and MySQL databases - enables Claude to query your databases",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"universal-db-mcp": "./index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"start": "node index.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"model-context-protocol",
|
|
16
|
+
"claude",
|
|
17
|
+
"database",
|
|
18
|
+
"postgresql",
|
|
19
|
+
"mysql",
|
|
20
|
+
"sql",
|
|
21
|
+
"ai",
|
|
22
|
+
"llm"
|
|
23
|
+
],
|
|
24
|
+
"author": "John Roshan <johnroshan2255@gmail.com>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/johnroshan2255/universal-db-mcp.git"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"files": ["index.js", "README.md", "LICENCE"],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
36
|
+
"pg": "^8.13.1",
|
|
37
|
+
"mysql2": "^3.11.5"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"eslint": "^9.17.0"
|
|
41
|
+
}
|
|
42
|
+
}
|