@bytebase/dbhub 0.5.0 → 0.6.1
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 +17 -17
- package/dist/index.js +61 -41
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -28,9 +28,9 @@ DBHub is a universal database gateway implementing the Model Context Protocol (M
|
|
|
28
28
|
MCP Clients MCP Server Databases
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
## Demo
|
|
31
|
+
## Demo HTTP Endpoint
|
|
32
32
|
|
|
33
|
-
https://demo.dbhub.ai/
|
|
33
|
+
https://demo.dbhub.ai/message connects a [sample employee database](https://github.com/bytebase/employee-sample-database). You can point Cursor or MCP Inspector to it to see it in action.
|
|
34
34
|
|
|
35
35
|

|
|
36
36
|
|
|
@@ -71,7 +71,7 @@ docker run --rm --init \
|
|
|
71
71
|
--name dbhub \
|
|
72
72
|
--publish 8080:8080 \
|
|
73
73
|
bytebase/dbhub \
|
|
74
|
-
--transport
|
|
74
|
+
--transport http \
|
|
75
75
|
--port 8080 \
|
|
76
76
|
--dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
|
|
77
77
|
```
|
|
@@ -82,7 +82,7 @@ docker run --rm --init \
|
|
|
82
82
|
--name dbhub \
|
|
83
83
|
--publish 8080:8080 \
|
|
84
84
|
bytebase/dbhub \
|
|
85
|
-
--transport
|
|
85
|
+
--transport http \
|
|
86
86
|
--port 8080 \
|
|
87
87
|
--demo
|
|
88
88
|
```
|
|
@@ -93,7 +93,7 @@ docker run --rm --init \
|
|
|
93
93
|
--name dbhub \
|
|
94
94
|
--publish 8080:8080 \
|
|
95
95
|
bytebase/dbhub \
|
|
96
|
-
--transport
|
|
96
|
+
--transport http \
|
|
97
97
|
--port 8080 \
|
|
98
98
|
--dsn "oracle://username:password@localhost:1521/service_name"
|
|
99
99
|
```
|
|
@@ -104,7 +104,7 @@ docker run --rm --init \
|
|
|
104
104
|
--name dbhub \
|
|
105
105
|
--publish 8080:8080 \
|
|
106
106
|
bytebase/dbhub-oracle-thick \
|
|
107
|
-
--transport
|
|
107
|
+
--transport http \
|
|
108
108
|
--port 8080 \
|
|
109
109
|
--dsn "oracle://username:password@localhost:1521/service_name"
|
|
110
110
|
```
|
|
@@ -113,12 +113,12 @@ docker run --rm --init \
|
|
|
113
113
|
|
|
114
114
|
```bash
|
|
115
115
|
# PostgreSQL example
|
|
116
|
-
npx @bytebase/dbhub --transport
|
|
116
|
+
npx @bytebase/dbhub --transport http --port 8080 --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
|
|
117
117
|
```
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
# Demo mode with sample employee database
|
|
121
|
-
npx @bytebase/dbhub --transport
|
|
121
|
+
npx @bytebase/dbhub --transport http --port 8080 --demo
|
|
122
122
|
```
|
|
123
123
|
|
|
124
124
|
> Note: The demo mode includes a bundled SQLite sample "employee" database with tables for employees, departments, salaries, and more.
|
|
@@ -170,7 +170,7 @@ npx @bytebase/dbhub --transport sse --port 8080 --demo
|
|
|
170
170
|
|
|
171
171
|

|
|
172
172
|
|
|
173
|
-
- Cursor supports both `stdio` and `
|
|
173
|
+
- Cursor supports both `stdio` and `http`.
|
|
174
174
|
- Follow [Cursor MCP guide](https://docs.cursor.com/context/model-context-protocol) and make sure to use [Agent](https://docs.cursor.com/chat/agent) mode.
|
|
175
175
|
|
|
176
176
|
## Usage
|
|
@@ -302,9 +302,9 @@ Extra query parameters:
|
|
|
302
302
|
npx @bytebase/dbhub --transport stdio --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
|
|
303
303
|
```
|
|
304
304
|
|
|
305
|
-
- **
|
|
305
|
+
- **http** - for browser and network clients:
|
|
306
306
|
```bash
|
|
307
|
-
npx @bytebase/dbhub --transport
|
|
307
|
+
npx @bytebase/dbhub --transport http --port 5678 --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
|
|
308
308
|
```
|
|
309
309
|
|
|
310
310
|
### Command line options
|
|
@@ -313,8 +313,8 @@ Extra query parameters:
|
|
|
313
313
|
| --------- | --------------------------------------------------------------- | ---------------------------- |
|
|
314
314
|
| demo | Run in demo mode with sample employee database | `false` |
|
|
315
315
|
| dsn | Database connection string | Required if not in demo mode |
|
|
316
|
-
| transport | Transport mode: `stdio` or `
|
|
317
|
-
| port | HTTP server port (only applicable when using `--transport=
|
|
316
|
+
| transport | Transport mode: `stdio` or `http` | `stdio` |
|
|
317
|
+
| port | HTTP server port (only applicable when using `--transport=http`) | `8080` |
|
|
318
318
|
| readonly | Restrict SQL execution to read-only operations | `false` |
|
|
319
319
|
|
|
320
320
|
The demo mode uses an in-memory SQLite database loaded with the [sample employee database](https://github.com/bytebase/dbhub/tree/main/resources/employee-sqlite) that includes tables for employees, departments, titles, salaries, department employees, and department managers. The sample database includes SQL scripts for table creation, data loading, and testing.
|
|
@@ -367,17 +367,17 @@ The project includes pre-commit hooks to run tests automatically before each com
|
|
|
367
367
|
TRANSPORT=stdio DSN="postgres://user:password@localhost:5432/dbname?sslmode=disable" npx @modelcontextprotocol/inspector node /path/to/dbhub/dist/index.js
|
|
368
368
|
```
|
|
369
369
|
|
|
370
|
-
####
|
|
370
|
+
#### HTTP
|
|
371
371
|
|
|
372
372
|
```bash
|
|
373
|
-
# Start DBHub with
|
|
374
|
-
pnpm dev --transport=
|
|
373
|
+
# Start DBHub with HTTP transport
|
|
374
|
+
pnpm dev --transport=http --port=8080
|
|
375
375
|
|
|
376
376
|
# Start the MCP Inspector in another terminal
|
|
377
377
|
npx @modelcontextprotocol/inspector
|
|
378
378
|
```
|
|
379
379
|
|
|
380
|
-
Connect to the DBHub server `/
|
|
380
|
+
Connect to the DBHub server `/message` endpoint
|
|
381
381
|
|
|
382
382
|
## Contributors
|
|
383
383
|
|
package/dist/index.js
CHANGED
|
@@ -1404,17 +1404,17 @@ var MySQLConnector = class {
|
|
|
1404
1404
|
}
|
|
1405
1405
|
try {
|
|
1406
1406
|
const results = await this.pool.query(sql2);
|
|
1407
|
-
|
|
1407
|
+
const [firstResult] = results;
|
|
1408
|
+
if (Array.isArray(firstResult) && firstResult.length > 0 && Array.isArray(firstResult[0]) && firstResult[0].length === 2) {
|
|
1408
1409
|
let allRows = [];
|
|
1409
|
-
for (const
|
|
1410
|
-
if (Array.isArray(
|
|
1411
|
-
allRows.push(...
|
|
1410
|
+
for (const [rows, _fields] of firstResult) {
|
|
1411
|
+
if (Array.isArray(rows)) {
|
|
1412
|
+
allRows.push(...rows);
|
|
1412
1413
|
}
|
|
1413
1414
|
}
|
|
1414
1415
|
return { rows: allRows };
|
|
1415
1416
|
} else {
|
|
1416
|
-
|
|
1417
|
-
return { rows, fields };
|
|
1417
|
+
return { rows: Array.isArray(firstResult) ? firstResult : [] };
|
|
1418
1418
|
}
|
|
1419
1419
|
} catch (error) {
|
|
1420
1420
|
console.error("Error executing query:", error);
|
|
@@ -1774,21 +1774,17 @@ var MariaDBConnector = class {
|
|
|
1774
1774
|
}
|
|
1775
1775
|
try {
|
|
1776
1776
|
const results = await this.pool.query(sql2);
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
}
|
|
1777
|
+
const [firstResult] = results;
|
|
1778
|
+
if (Array.isArray(firstResult) && firstResult.length > 0 && Array.isArray(firstResult[0]) && firstResult[0].length === 2) {
|
|
1779
|
+
let allRows = [];
|
|
1780
|
+
for (const [rows, _fields] of firstResult) {
|
|
1781
|
+
if (Array.isArray(rows)) {
|
|
1782
|
+
allRows.push(...rows);
|
|
1784
1783
|
}
|
|
1785
|
-
return { rows: allRows };
|
|
1786
|
-
} else {
|
|
1787
|
-
const [rows, fields] = results;
|
|
1788
|
-
return { rows, fields };
|
|
1789
1784
|
}
|
|
1785
|
+
return { rows: allRows };
|
|
1790
1786
|
} else {
|
|
1791
|
-
return { rows:
|
|
1787
|
+
return { rows: Array.isArray(firstResult) ? firstResult : [] };
|
|
1792
1788
|
}
|
|
1793
1789
|
} catch (error) {
|
|
1794
1790
|
console.error("Error executing query:", error);
|
|
@@ -2300,7 +2296,7 @@ ConnectorRegistry.register(new OracleConnector());
|
|
|
2300
2296
|
|
|
2301
2297
|
// src/server.ts
|
|
2302
2298
|
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2303
|
-
import {
|
|
2299
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
2304
2300
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
2305
2301
|
import express from "express";
|
|
2306
2302
|
import path3 from "path";
|
|
@@ -2477,11 +2473,11 @@ function resolveDSN() {
|
|
|
2477
2473
|
function resolveTransport() {
|
|
2478
2474
|
const args = parseCommandLineArgs();
|
|
2479
2475
|
if (args.transport) {
|
|
2480
|
-
const type = args.transport === "
|
|
2476
|
+
const type = args.transport === "http" ? "http" : "stdio";
|
|
2481
2477
|
return { type, source: "command line argument" };
|
|
2482
2478
|
}
|
|
2483
2479
|
if (process.env.TRANSPORT) {
|
|
2484
|
-
const type = process.env.TRANSPORT === "
|
|
2480
|
+
const type = process.env.TRANSPORT === "http" ? "http" : "stdio";
|
|
2485
2481
|
return { type, source: "environment variable" };
|
|
2486
2482
|
}
|
|
2487
2483
|
return { type: "stdio", source: "default" };
|
|
@@ -3444,13 +3440,16 @@ See documentation for more details on configuring database connections.
|
|
|
3444
3440
|
`);
|
|
3445
3441
|
process.exit(1);
|
|
3446
3442
|
}
|
|
3447
|
-
const
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3443
|
+
const createServer = () => {
|
|
3444
|
+
const server = new McpServer2({
|
|
3445
|
+
name: SERVER_NAME,
|
|
3446
|
+
version: SERVER_VERSION
|
|
3447
|
+
});
|
|
3448
|
+
registerResources(server);
|
|
3449
|
+
registerTools(server);
|
|
3450
|
+
registerPrompts(server);
|
|
3451
|
+
return server;
|
|
3452
|
+
};
|
|
3454
3453
|
const connectorManager = new ConnectorManager();
|
|
3455
3454
|
console.error(`Connecting with DSN: ${redactDSN(dsnData.dsn)}`);
|
|
3456
3455
|
console.error(`DSN source: ${dsnData.source}`);
|
|
@@ -3478,29 +3477,50 @@ See documentation for more details on configuring database connections.
|
|
|
3478
3477
|
console.error(`Running in ${activeModes.join(" and ")} mode - ${modeDescriptions.join(", ")}`);
|
|
3479
3478
|
}
|
|
3480
3479
|
console.error(generateBanner(SERVER_VERSION, activeModes));
|
|
3481
|
-
if (transportData.type === "
|
|
3480
|
+
if (transportData.type === "http") {
|
|
3482
3481
|
const app = express();
|
|
3483
|
-
|
|
3484
|
-
app.
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3482
|
+
app.use(express.json());
|
|
3483
|
+
app.use((req, res, next) => {
|
|
3484
|
+
const origin = req.headers.origin;
|
|
3485
|
+
if (origin && !origin.startsWith("http://localhost") && !origin.startsWith("https://localhost")) {
|
|
3486
|
+
return res.status(403).json({ error: "Forbidden origin" });
|
|
3487
|
+
}
|
|
3488
|
+
res.header("Access-Control-Allow-Origin", origin || "http://localhost");
|
|
3489
|
+
res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
3490
|
+
res.header("Access-Control-Allow-Headers", "Content-Type, Mcp-Session-Id");
|
|
3491
|
+
res.header("Access-Control-Allow-Credentials", "true");
|
|
3492
|
+
if (req.method === "OPTIONS") {
|
|
3493
|
+
return res.sendStatus(200);
|
|
3494
|
+
}
|
|
3495
|
+
next();
|
|
3491
3496
|
});
|
|
3492
3497
|
app.post("/message", async (req, res) => {
|
|
3493
|
-
|
|
3494
|
-
|
|
3498
|
+
try {
|
|
3499
|
+
const transport = new StreamableHTTPServerTransport({
|
|
3500
|
+
sessionIdGenerator: void 0,
|
|
3501
|
+
// Disable session management for stateless mode
|
|
3502
|
+
enableJsonResponse: false
|
|
3503
|
+
// Use SSE streaming
|
|
3504
|
+
});
|
|
3505
|
+
const server = createServer();
|
|
3506
|
+
await server.connect(transport);
|
|
3507
|
+
await transport.handleRequest(req, res, req.body);
|
|
3508
|
+
} catch (error) {
|
|
3509
|
+
console.error("Error handling request:", error);
|
|
3510
|
+
if (!res.headersSent) {
|
|
3511
|
+
res.status(500).json({ error: "Internal server error" });
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3495
3514
|
});
|
|
3496
3515
|
const portData = resolvePort();
|
|
3497
3516
|
const port = portData.port;
|
|
3498
3517
|
console.error(`Port source: ${portData.source}`);
|
|
3499
|
-
app.listen(port, () => {
|
|
3518
|
+
app.listen(port, "localhost", () => {
|
|
3500
3519
|
console.error(`DBHub server listening at http://localhost:${port}`);
|
|
3501
|
-
console.error(`Connect to MCP server at http://localhost:${port}/
|
|
3520
|
+
console.error(`Connect to MCP server at http://localhost:${port}/message`);
|
|
3502
3521
|
});
|
|
3503
3522
|
} else {
|
|
3523
|
+
const server = createServer();
|
|
3504
3524
|
const transport = new StdioServerTransport();
|
|
3505
3525
|
console.error("Starting with STDIO transport");
|
|
3506
3526
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytebase/dbhub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Universal Database MCP Server",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"license": "MIT",
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@azure/identity": "^4.8.0",
|
|
20
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
21
21
|
"better-sqlite3": "^11.9.0",
|
|
22
22
|
"dotenv": "^16.4.7",
|
|
23
23
|
"express": "^4.18.2",
|