@bytebase/dbhub 0.1.0 → 0.1.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.
Files changed (33) hide show
  1. package/README.md +34 -33
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +1489 -13
  4. package/dist/resources/employee-sqlite/employee.sql +117 -0
  5. package/dist/resources/employee-sqlite/load_department.sql +10 -0
  6. package/dist/resources/employee-sqlite/load_dept_emp.sql +1103 -0
  7. package/dist/resources/employee-sqlite/load_dept_manager.sql +17 -0
  8. package/dist/resources/employee-sqlite/load_employee.sql +1000 -0
  9. package/dist/resources/employee-sqlite/load_salary1.sql +9488 -0
  10. package/dist/resources/employee-sqlite/load_title.sql +1470 -0
  11. package/dist/resources/employee-sqlite/object.sql +74 -0
  12. package/dist/resources/employee-sqlite/show_elapsed.sql +4 -0
  13. package/dist/resources/employee-sqlite/test_employee_md5.sql +119 -0
  14. package/package.json +5 -4
  15. package/dist/config/demo-loader.js +0 -45
  16. package/dist/config/env.js +0 -146
  17. package/dist/connectors/interface.js +0 -55
  18. package/dist/connectors/manager.js +0 -91
  19. package/dist/connectors/mysql/index.js +0 -169
  20. package/dist/connectors/postgres/index.js +0 -172
  21. package/dist/connectors/sqlite/index.js +0 -208
  22. package/dist/connectors/sqlserver/index.js +0 -186
  23. package/dist/prompts/db-explainer.js +0 -201
  24. package/dist/prompts/index.js +0 -11
  25. package/dist/prompts/sql-generator.js +0 -114
  26. package/dist/resources/index.js +0 -12
  27. package/dist/resources/schema.js +0 -36
  28. package/dist/resources/tables.js +0 -17
  29. package/dist/server.js +0 -140
  30. package/dist/tools/index.js +0 -11
  31. package/dist/tools/list-connectors.js +0 -43
  32. package/dist/tools/run-query.js +0 -32
  33. package/dist/utils/response-formatter.js +0 -109
package/dist/server.js DELETED
@@ -1,140 +0,0 @@
1
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
3
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
- import express from 'express';
5
- import path from 'path';
6
- import { readFileSync } from 'fs';
7
- import { fileURLToPath } from 'url';
8
- import { ConnectorManager } from './connectors/manager.js';
9
- import { ConnectorRegistry } from './connectors/interface.js';
10
- import { resolveDSN, resolveTransport, resolvePort } from './config/env.js';
11
- import { getSqliteInMemorySetupSql } from './config/demo-loader.js';
12
- import { registerResources } from './resources/index.js';
13
- import { registerTools } from './tools/index.js';
14
- import { registerPrompts } from './prompts/index.js';
15
- // Create __dirname equivalent for ES modules
16
- const __filename = fileURLToPath(import.meta.url);
17
- const __dirname = path.dirname(__filename);
18
- // Load package.json to get version
19
- const packageJsonPath = path.join(__dirname, '..', 'package.json');
20
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
21
- // Server info
22
- export const SERVER_NAME = "DBHub MCP Server";
23
- export const SERVER_VERSION = packageJson.version;
24
- /**
25
- * Generate ASCII art banner with version information
26
- */
27
- export function generateBanner(version, isDemo = false) {
28
- const demoText = isDemo ? " [DEMO MODE]" : "";
29
- return `
30
- _____ ____ _ _ _
31
- | __ \\| _ \\| | | | | |
32
- | | | | |_) | |_| |_ _| |__
33
- | | | | _ <| _ | | | | '_ \\
34
- | |__| | |_) | | | | |_| | |_) |
35
- |_____/|____/|_| |_|\\__,_|_.__/
36
-
37
- v${version}${demoText} - Universal Database MCP Server
38
- `;
39
- }
40
- /**
41
- * Initialize and start the DBHub server
42
- */
43
- export async function main() {
44
- try {
45
- // Resolve DSN from command line args, environment variables, or .env files
46
- const dsnData = resolveDSN();
47
- if (!dsnData) {
48
- const samples = ConnectorRegistry.getAllSampleDSNs();
49
- const sampleFormats = Object.entries(samples)
50
- .map(([id, dsn]) => ` - ${id}: ${dsn}`)
51
- .join('\n');
52
- console.error(`
53
- ERROR: Database connection string (DSN) is required.
54
- Please provide the DSN in one of these ways (in order of priority):
55
-
56
- 1. Use demo mode: --demo (uses in-memory SQLite with sample employee database)
57
- 2. Command line argument: --dsn="your-connection-string"
58
- 3. Environment variable: export DSN="your-connection-string"
59
- 4. .env file: DSN=your-connection-string
60
-
61
- Example formats:
62
- ${sampleFormats}
63
-
64
- See documentation for more details on configuring database connections.
65
- `);
66
- process.exit(1);
67
- }
68
- // Create MCP server
69
- const server = new McpServer({
70
- name: SERVER_NAME,
71
- version: SERVER_VERSION
72
- });
73
- // Register resources, tools, and prompts
74
- registerResources(server);
75
- registerTools(server);
76
- registerPrompts(server);
77
- // Create connector manager and connect to database
78
- const connectorManager = new ConnectorManager();
79
- console.error(`Connecting with DSN: ${dsnData.dsn}`);
80
- console.error(`DSN source: ${dsnData.source}`);
81
- // If in demo mode, load the employee database
82
- if (dsnData.isDemo) {
83
- console.error('Running in demo mode with sample employee database');
84
- const initScript = getSqliteInMemorySetupSql();
85
- await connectorManager.connectWithDSN(dsnData.dsn, initScript);
86
- }
87
- else {
88
- await connectorManager.connectWithDSN(dsnData.dsn);
89
- }
90
- // Resolve transport type
91
- const transportData = resolveTransport();
92
- console.error(`Using transport: ${transportData.type}`);
93
- console.error(`Transport source: ${transportData.source}`);
94
- // Print ASCII art banner with version and slogan
95
- console.error(generateBanner(SERVER_VERSION, dsnData.isDemo));
96
- // Set up transport based on type
97
- if (transportData.type === 'sse') {
98
- // Set up Express server for SSE transport
99
- const app = express();
100
- let transport;
101
- app.get("/sse", async (req, res) => {
102
- transport = new SSEServerTransport("/message", res);
103
- console.error("Client connected", transport?.['_sessionId']);
104
- await server.connect(transport);
105
- // Listen for connection close
106
- res.on('close', () => {
107
- console.error("Client Disconnected", transport?.['_sessionId']);
108
- });
109
- });
110
- app.post("/message", async (req, res) => {
111
- console.error("Client Message", transport?.['_sessionId']);
112
- await transport.handlePostMessage(req, res, req.body);
113
- });
114
- // Start the HTTP server (port is only relevant for SSE transport)
115
- const portData = resolvePort();
116
- const port = portData.port;
117
- console.error(`Port source: ${portData.source}`);
118
- app.listen(port, () => {
119
- console.error(`DBHub server listening at http://localhost:${port}`);
120
- console.error(`Connect to MCP server at http://localhost:${port}/sse`);
121
- });
122
- }
123
- else {
124
- // Set up STDIO transport
125
- const transport = new StdioServerTransport();
126
- console.error("Starting with STDIO transport");
127
- await server.connect(transport);
128
- // Listen for SIGINT to gracefully shut down
129
- process.on('SIGINT', async () => {
130
- console.error('Shutting down...');
131
- await transport.close();
132
- process.exit(0);
133
- });
134
- }
135
- }
136
- catch (err) {
137
- console.error("Fatal error:", err);
138
- process.exit(1);
139
- }
140
- }
@@ -1,11 +0,0 @@
1
- import { runQueryToolHandler, runQuerySchema } from './run-query.js';
2
- import { listConnectorsToolHandler } from './list-connectors.js';
3
- /**
4
- * Register all tool handlers with the MCP server
5
- */
6
- export function registerTools(server) {
7
- // Tool to run a SQL query (read-only for safety)
8
- server.tool("run_query", runQuerySchema, runQueryToolHandler);
9
- // Tool to list available database connectors
10
- server.tool("list_connectors", {}, listConnectorsToolHandler);
11
- }
@@ -1,43 +0,0 @@
1
- import { ConnectorManager } from '../connectors/manager.js';
2
- import { ConnectorRegistry } from '../connectors/interface.js';
3
- import { createToolSuccessResponse } from '../utils/response-formatter.js';
4
- import { isDemoMode } from '../config/env.js';
5
- /**
6
- * list_connectors tool handler
7
- * Lists all available database connectors and their sample DSNs
8
- * Indicates which connector is active based on current DSN
9
- */
10
- export async function listConnectorsToolHandler(_args, _extra) {
11
- const connectors = ConnectorManager.getAvailableConnectors();
12
- const samples = ConnectorRegistry.getAllSampleDSNs();
13
- // Get active connector if possible
14
- let activeConnectorId = null;
15
- try {
16
- // Check if we have an active connection using static method
17
- const activeConnector = ConnectorManager.getCurrentConnector();
18
- activeConnectorId = activeConnector.id;
19
- }
20
- catch (error) {
21
- // No active connector yet or not connected
22
- }
23
- // If we're in demo mode, SQLite should be active
24
- const isDemo = isDemoMode();
25
- if (isDemo && !activeConnectorId) {
26
- activeConnectorId = 'sqlite';
27
- }
28
- // Convert to a more structured format
29
- const sampleObjects = Object.entries(samples).map(([id, dsn]) => ({
30
- id,
31
- dsn,
32
- active: id === activeConnectorId
33
- }));
34
- // Prepare response data
35
- const responseData = {
36
- connectors: sampleObjects,
37
- count: sampleObjects.length,
38
- activeConnector: activeConnectorId,
39
- demoMode: isDemo
40
- };
41
- // Use the utility to create a standardized response
42
- return createToolSuccessResponse(responseData);
43
- }
@@ -1,32 +0,0 @@
1
- import { z } from "zod";
2
- import { ConnectorManager } from '../connectors/manager.js';
3
- import { createToolSuccessResponse, createToolErrorResponse } from '../utils/response-formatter.js';
4
- // Schema for run_query tool
5
- export const runQuerySchema = {
6
- query: z.string().describe("SQL query to execute (SELECT only)")
7
- };
8
- /**
9
- * run_query tool handler
10
- * Executes a SQL query and returns the results
11
- */
12
- export async function runQueryToolHandler({ query }, _extra) {
13
- const connector = ConnectorManager.getCurrentConnector();
14
- try {
15
- // Validate the query before execution
16
- const validationResult = connector.validateQuery(query);
17
- if (!validationResult.isValid) {
18
- return createToolErrorResponse(validationResult.message ?? "Unknown validation error", "VALIDATION_ERROR");
19
- }
20
- // Execute the query if validation passed
21
- const result = await connector.executeQuery(query);
22
- // Build response data
23
- const responseData = {
24
- rows: result.rows,
25
- count: result.rows.length
26
- };
27
- return createToolSuccessResponse(responseData);
28
- }
29
- catch (error) {
30
- return createToolErrorResponse(error.message, "EXECUTION_ERROR");
31
- }
32
- }
@@ -1,109 +0,0 @@
1
- /**
2
- * Response formatter utility for consistent API responses
3
- * Provides formatting for resources, tools, and prompts
4
- */
5
- /**
6
- * Create a success response with the given data
7
- */
8
- export function formatSuccessResponse(data, meta = {}) {
9
- return {
10
- success: true,
11
- data,
12
- ...(Object.keys(meta).length > 0 ? { meta } : {})
13
- };
14
- }
15
- /**
16
- * Create an error response with the given message and code
17
- */
18
- export function formatErrorResponse(error, code = 'ERROR', details) {
19
- return {
20
- success: false,
21
- error,
22
- code,
23
- ...(details ? { details } : {})
24
- };
25
- }
26
- /**
27
- * Create a tool error response object
28
- */
29
- export function createToolErrorResponse(error, code = 'ERROR', details) {
30
- return {
31
- content: [{
32
- type: "text",
33
- text: JSON.stringify(formatErrorResponse(error, code, details), null, 2),
34
- mimeType: "application/json"
35
- }],
36
- isError: true
37
- };
38
- }
39
- /**
40
- * Create a tool success response object
41
- */
42
- export function createToolSuccessResponse(data, meta = {}) {
43
- return {
44
- content: [{
45
- type: "text",
46
- text: JSON.stringify(formatSuccessResponse(data, meta), null, 2),
47
- mimeType: "application/json"
48
- }]
49
- };
50
- }
51
- /**
52
- * Create a resource error response object
53
- */
54
- export function createResourceErrorResponse(uri, error, code = 'ERROR', details) {
55
- return {
56
- contents: [{
57
- uri,
58
- text: JSON.stringify(formatErrorResponse(error, code, details), null, 2),
59
- mimeType: "application/json"
60
- }]
61
- };
62
- }
63
- /**
64
- * Create a resource success response object
65
- */
66
- export function createResourceSuccessResponse(uri, data, meta = {}) {
67
- return {
68
- contents: [{
69
- uri,
70
- text: JSON.stringify(formatSuccessResponse(data, meta), null, 2),
71
- mimeType: "application/json"
72
- }]
73
- };
74
- }
75
- /**
76
- * Format a successful prompt response in the MCP format
77
- */
78
- export function formatPromptSuccessResponse(text, references = []) {
79
- return {
80
- messages: [
81
- {
82
- role: 'assistant',
83
- content: {
84
- type: 'text',
85
- text
86
- }
87
- }
88
- ],
89
- ...(references.length > 0 ? { references } : {})
90
- };
91
- }
92
- /**
93
- * Format an error prompt response in the MCP format
94
- */
95
- export function formatPromptErrorResponse(error, code = 'ERROR') {
96
- return {
97
- messages: [
98
- {
99
- role: 'assistant',
100
- content: {
101
- type: 'text',
102
- text: `Error: ${error}`
103
- }
104
- }
105
- ],
106
- error,
107
- code
108
- };
109
- }