mirror of
https://github.com/executeautomation/mcp-database-server.git
synced 2025-12-09 21:12:57 +08:00
Merge pull request #5 from executeautomation/Added-Support-for-MySql-Database
Add MySQL support to MCP Database Server
This commit is contained in:
@@ -68,6 +68,25 @@ node dist/src/index.js --postgresql --host localhost --database sample_db --user
|
|||||||
node dist/src/index.js --postgresql --host dbserver.example.com --database sample_db --user appuser --password Secure123! --port 5433 --ssl true
|
node dist/src/index.js --postgresql --host dbserver.example.com --database sample_db --user appuser --password Secure123! --port 5433 --ssl true
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## MySQL Connection Options
|
||||||
|
|
||||||
|
| Option | Description | Default | Required |
|
||||||
|
|--------|-------------|---------|----------|
|
||||||
|
| `--mysql` | Specifies MySQL mode | - | Yes |
|
||||||
|
| `--host` | MySQL hostname or IP | - | Yes |
|
||||||
|
| `--database` | Database name | - | Yes |
|
||||||
|
| `--user` | MySQL username | - | No |
|
||||||
|
| `--password` | MySQL password | - | No |
|
||||||
|
| `--port` | MySQL port | 3306 | No |
|
||||||
|
| `--ssl` | Use SSL connection (true/false or object) | false | No |
|
||||||
|
| `--connection-timeout` | Connection timeout in ms | 30000 | No |
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
node dist/src/index.js --mysql --host localhost --database sample_db --port 3306 --user root --password secret
|
||||||
|
```
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
Instead of specifying sensitive credentials on the command line, you can use environment variables:
|
Instead of specifying sensitive credentials on the command line, you can use environment variables:
|
||||||
|
|||||||
@@ -54,3 +54,11 @@
|
|||||||
- Schema introspection
|
- Schema introspection
|
||||||
- MCP integration for Claude Desktop
|
- MCP integration for Claude Desktop
|
||||||
- Node.js-based implementation for cross-platform support
|
- Node.js-based implementation for cross-platform support
|
||||||
|
|
||||||
|
## 1.1.0 (2024-05-30)
|
||||||
|
|
||||||
|
### Features
|
||||||
|
- Added MySQL database support (read/write/query, schema, etc.)
|
||||||
|
- Support for passing MySQL port via CLI and config
|
||||||
|
- Improved port validation and debug logging for MySQL
|
||||||
|
- Updated documentation and examples for MySQL and port usage
|
||||||
2
index.ts
2
index.ts
@@ -14,7 +14,7 @@ import sqlite3 from "sqlite3";
|
|||||||
const server = new Server(
|
const server = new Server(
|
||||||
{
|
{
|
||||||
name: "executeautomation/database-server",
|
name: "executeautomation/database-server",
|
||||||
version: "1.0.0",
|
version: "1.1.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
|
|||||||
100
package-lock.json
generated
100
package-lock.json
generated
@@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.9.0",
|
"@modelcontextprotocol/sdk": "1.9.0",
|
||||||
"mssql": "11.0.1",
|
"mssql": "11.0.1",
|
||||||
|
"mysql2": "^3.14.1",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"sqlite3": "5.1.7"
|
"sqlite3": "5.1.7"
|
||||||
},
|
},
|
||||||
@@ -639,6 +640,14 @@
|
|||||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/aws-ssl-profiles": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/balanced-match": {
|
"node_modules/balanced-match": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||||
@@ -1124,6 +1133,14 @@
|
|||||||
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
"node_modules/denque": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/depd": {
|
"node_modules/depd": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||||
@@ -1645,6 +1662,14 @@
|
|||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/generate-function": {
|
||||||
|
"version": "2.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
|
||||||
|
"integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-property": "^1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/get-intrinsic": {
|
"node_modules/get-intrinsic": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||||
@@ -2032,6 +2057,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
|
||||||
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
|
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/is-property": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g=="
|
||||||
|
},
|
||||||
"node_modules/is-stream": {
|
"node_modules/is-stream": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
|
||||||
@@ -2180,12 +2210,31 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/long": {
|
||||||
|
"version": "5.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
|
||||||
|
"integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="
|
||||||
|
},
|
||||||
"node_modules/lru-cache": {
|
"node_modules/lru-cache": {
|
||||||
"version": "10.4.3",
|
"version": "10.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
|
||||||
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/lru.min": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-Nv9KddBcQSlQopmBHXSsZVY5xsdlZkdH/Iey0BlcBYggMd4two7cZnKOK9vmy3nY0O5RGH99z1PCeTpPqszUYg==",
|
||||||
|
"engines": {
|
||||||
|
"bun": ">=1.0.0",
|
||||||
|
"deno": ">=1.30.0",
|
||||||
|
"node": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wellwelwel"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/make-fetch-happen": {
|
"node_modules/make-fetch-happen": {
|
||||||
"version": "9.1.0",
|
"version": "9.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz",
|
||||||
@@ -2545,6 +2594,44 @@
|
|||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mysql2": {
|
||||||
|
"version": "3.14.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.14.1.tgz",
|
||||||
|
"integrity": "sha512-7ytuPQJjQB8TNAYX/H2yhL+iQOnIBjAMam361R7UAL0lOVXWjtdrmoL9HYKqKoLp/8UUTRcvo1QPvK9KL7wA8w==",
|
||||||
|
"dependencies": {
|
||||||
|
"aws-ssl-profiles": "^1.1.1",
|
||||||
|
"denque": "^2.1.0",
|
||||||
|
"generate-function": "^2.3.1",
|
||||||
|
"iconv-lite": "^0.6.3",
|
||||||
|
"long": "^5.2.1",
|
||||||
|
"lru.min": "^1.0.0",
|
||||||
|
"named-placeholders": "^1.1.3",
|
||||||
|
"seq-queue": "^0.0.5",
|
||||||
|
"sqlstring": "^2.3.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/named-placeholders": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==",
|
||||||
|
"dependencies": {
|
||||||
|
"lru-cache": "^7.14.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/named-placeholders/node_modules/lru-cache": {
|
||||||
|
"version": "7.18.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
|
||||||
|
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/napi-build-utils": {
|
"node_modules/napi-build-utils": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
|
||||||
@@ -3413,6 +3500,11 @@
|
|||||||
"node": ">= 18"
|
"node": ">= 18"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/seq-queue": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz",
|
||||||
|
"integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q=="
|
||||||
|
},
|
||||||
"node_modules/serve-static": {
|
"node_modules/serve-static": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
|
||||||
@@ -3688,6 +3780,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sqlstring": {
|
||||||
|
"version": "2.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz",
|
||||||
|
"integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ssri": {
|
"node_modules/ssri": {
|
||||||
"version": "8.0.1",
|
"version": "8.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@executeautomation/database-server",
|
"name": "@executeautomation/database-server",
|
||||||
"version": "1.0.2",
|
"version": "1.1.0",
|
||||||
"description": "MCP server for interacting with SQLite and SQL Server databases by ExecuteAutomation",
|
"description": "MCP server for interacting with SQLite and SQL Server databases by ExecuteAutomation",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "ExecuteAutomation, Ltd (https://executeautomation.com)",
|
"author": "ExecuteAutomation, Ltd (https://executeautomation.com)",
|
||||||
@@ -25,6 +25,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.9.0",
|
"@modelcontextprotocol/sdk": "1.9.0",
|
||||||
"mssql": "11.0.1",
|
"mssql": "11.0.1",
|
||||||
|
"mysql2": "^3.14.1",
|
||||||
"pg": "^8.11.3",
|
"pg": "^8.11.3",
|
||||||
"sqlite3": "5.1.7"
|
"sqlite3": "5.1.7"
|
||||||
},
|
},
|
||||||
|
|||||||
46
readme.md
46
readme.md
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# MCP Database Server
|
# MCP Database Server
|
||||||
|
|
||||||
This MCP (Model Context Protocol) server provides database access capabilities to Claude, supporting SQLite, SQL Server, and PostgreSQL databases.
|
This MCP (Model Context Protocol) server provides database access capabilities to Claude, supporting SQLite, SQL Server, PostgreSQL, and MySQL databases.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
@@ -92,6 +92,25 @@ Optional parameters:
|
|||||||
- `--ssl`: Enable SSL connection (true/false)
|
- `--ssl`: Enable SSL connection (true/false)
|
||||||
- `--connection-timeout`: Connection timeout in milliseconds (default: 30000)
|
- `--connection-timeout`: Connection timeout in milliseconds (default: 30000)
|
||||||
|
|
||||||
|
### MySQL Database
|
||||||
|
|
||||||
|
To use with a MySQL database:
|
||||||
|
|
||||||
|
```
|
||||||
|
node dist/src/index.js --mysql --host <host-name> --database <database-name> --port <port> [--user <username> --password <password>]
|
||||||
|
```
|
||||||
|
|
||||||
|
Required parameters:
|
||||||
|
- `--host`: MySQL host name or IP address
|
||||||
|
- `--database`: Name of the database
|
||||||
|
- `--port`: Port number (default: 3306)
|
||||||
|
|
||||||
|
Optional parameters:
|
||||||
|
- `--user`: Username for MySQL authentication
|
||||||
|
- `--password`: Password for MySQL authentication
|
||||||
|
- `--ssl`: Enable SSL connection (true/false or object)
|
||||||
|
- `--connection-timeout`: Connection timeout in milliseconds (default: 30000)
|
||||||
|
|
||||||
## Configuring Claude Desktop
|
## Configuring Claude Desktop
|
||||||
|
|
||||||
### Direct Usage Configuration
|
### Direct Usage Configuration
|
||||||
@@ -132,6 +151,19 @@ If you installed the package globally, configure Claude Desktop with:
|
|||||||
"--user", "your-username",
|
"--user", "your-username",
|
||||||
"--password", "your-password"
|
"--password", "your-password"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"mysql": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@executeautomation/database-server",
|
||||||
|
"--mysql",
|
||||||
|
"--host", "your-host-name",
|
||||||
|
"--database", "your-database-name",
|
||||||
|
"--port", "3306",
|
||||||
|
"--user", "your-username",
|
||||||
|
"--password", "your-password"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,6 +204,18 @@ For local development, configure Claude Desktop to use your locally built versio
|
|||||||
"--user", "your-username",
|
"--user", "your-username",
|
||||||
"--password", "your-password"
|
"--password", "your-password"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"mysql": {
|
||||||
|
"command": "node",
|
||||||
|
"args": [
|
||||||
|
"/absolute/path/to/mcp-database-server/dist/src/index.js",
|
||||||
|
"--mysql",
|
||||||
|
"--host", "your-host-name",
|
||||||
|
"--database", "your-database-name",
|
||||||
|
"--port", "3306",
|
||||||
|
"--user", "your-username",
|
||||||
|
"--password", "your-password"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export interface DbAdapter {
|
|||||||
import { SqliteAdapter } from './sqlite-adapter.js';
|
import { SqliteAdapter } from './sqlite-adapter.js';
|
||||||
import { SqlServerAdapter } from './sqlserver-adapter.js';
|
import { SqlServerAdapter } from './sqlserver-adapter.js';
|
||||||
import { PostgresqlAdapter } from './postgresql-adapter.js';
|
import { PostgresqlAdapter } from './postgresql-adapter.js';
|
||||||
|
import { MysqlAdapter } from './mysql-adapter.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory function to create the appropriate database adapter
|
* Factory function to create the appropriate database adapter
|
||||||
@@ -72,6 +73,8 @@ export function createDbAdapter(type: string, connectionInfo: any): DbAdapter {
|
|||||||
case 'postgresql':
|
case 'postgresql':
|
||||||
case 'postgres':
|
case 'postgres':
|
||||||
return new PostgresqlAdapter(connectionInfo);
|
return new PostgresqlAdapter(connectionInfo);
|
||||||
|
case 'mysql':
|
||||||
|
return new MysqlAdapter(connectionInfo);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unsupported database type: ${type}`);
|
throw new Error(`Unsupported database type: ${type}`);
|
||||||
}
|
}
|
||||||
|
|||||||
145
src/db/mysql-adapter.ts
Normal file
145
src/db/mysql-adapter.ts
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import { DbAdapter } from "./adapter.js";
|
||||||
|
import mysql from "mysql2/promise";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MySQL database adapter implementation
|
||||||
|
*/
|
||||||
|
export class MysqlAdapter implements DbAdapter {
|
||||||
|
private connection: mysql.Connection | null = null;
|
||||||
|
private config: mysql.ConnectionOptions;
|
||||||
|
private host: string;
|
||||||
|
private database: string;
|
||||||
|
|
||||||
|
constructor(connectionInfo: {
|
||||||
|
host: string;
|
||||||
|
database: string;
|
||||||
|
user?: string;
|
||||||
|
password?: string;
|
||||||
|
port?: number;
|
||||||
|
ssl?: boolean | object;
|
||||||
|
connectionTimeout?: number;
|
||||||
|
}) {
|
||||||
|
this.host = connectionInfo.host;
|
||||||
|
this.database = connectionInfo.database;
|
||||||
|
this.config = {
|
||||||
|
host: connectionInfo.host,
|
||||||
|
database: connectionInfo.database,
|
||||||
|
port: connectionInfo.port || 3306,
|
||||||
|
user: connectionInfo.user,
|
||||||
|
password: connectionInfo.password,
|
||||||
|
connectTimeout: connectionInfo.connectionTimeout || 30000,
|
||||||
|
multipleStatements: true,
|
||||||
|
};
|
||||||
|
if (typeof connectionInfo.ssl === 'object' || typeof connectionInfo.ssl === 'string') {
|
||||||
|
this.config.ssl = connectionInfo.ssl;
|
||||||
|
} else if (connectionInfo.ssl === true) {
|
||||||
|
this.config.ssl = {};
|
||||||
|
}
|
||||||
|
// Validate port
|
||||||
|
if (connectionInfo.port && typeof connectionInfo.port !== 'number') {
|
||||||
|
const parsedPort = parseInt(connectionInfo.port as any, 10);
|
||||||
|
if (isNaN(parsedPort)) {
|
||||||
|
throw new Error(`Invalid port value for MySQL: ${connectionInfo.port}`);
|
||||||
|
}
|
||||||
|
this.config.port = parsedPort;
|
||||||
|
}
|
||||||
|
// Log the port for debugging
|
||||||
|
console.error(`[DEBUG] MySQL connection will use port: ${this.config.port}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize MySQL connection
|
||||||
|
*/
|
||||||
|
async init(): Promise<void> {
|
||||||
|
try {
|
||||||
|
console.error(`[INFO] Connecting to MySQL: ${this.host}, Database: ${this.database}`);
|
||||||
|
this.connection = await mysql.createConnection(this.config);
|
||||||
|
console.error(`[INFO] MySQL connection established successfully`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(`[ERROR] MySQL connection error: ${(err as Error).message}`);
|
||||||
|
throw new Error(`Failed to connect to MySQL: ${(err as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a SQL query and get all results
|
||||||
|
*/
|
||||||
|
async all(query: string, params: any[] = []): Promise<any[]> {
|
||||||
|
if (!this.connection) {
|
||||||
|
throw new Error("Database not initialized");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const [rows] = await this.connection.execute(query, params);
|
||||||
|
return Array.isArray(rows) ? rows : [];
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`MySQL query error: ${(err as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a SQL query that modifies data
|
||||||
|
*/
|
||||||
|
async run(query: string, params: any[] = []): Promise<{ changes: number, lastID: number }> {
|
||||||
|
if (!this.connection) {
|
||||||
|
throw new Error("Database not initialized");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const [result]: any = await this.connection.execute(query, params);
|
||||||
|
const changes = result.affectedRows || 0;
|
||||||
|
const lastID = result.insertId || 0;
|
||||||
|
return { changes, lastID };
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`MySQL query error: ${(err as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute multiple SQL statements
|
||||||
|
*/
|
||||||
|
async exec(query: string): Promise<void> {
|
||||||
|
if (!this.connection) {
|
||||||
|
throw new Error("Database not initialized");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.connection.query(query);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error(`MySQL batch error: ${(err as Error).message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the database connection
|
||||||
|
*/
|
||||||
|
async close(): Promise<void> {
|
||||||
|
if (this.connection) {
|
||||||
|
await this.connection.end();
|
||||||
|
this.connection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database metadata
|
||||||
|
*/
|
||||||
|
getMetadata(): { name: string; type: string; server: string; database: string } {
|
||||||
|
return {
|
||||||
|
name: "MySQL",
|
||||||
|
type: "mysql",
|
||||||
|
server: this.host,
|
||||||
|
database: this.database,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database-specific query for listing tables
|
||||||
|
*/
|
||||||
|
getListTablesQuery(): string {
|
||||||
|
return "SHOW TABLES";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get database-specific query for describing a table
|
||||||
|
*/
|
||||||
|
getDescribeTableQuery(tableName: string): string {
|
||||||
|
return `DESCRIBE \`${tableName}\``;
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/index.ts
44
src/index.ts
@@ -28,7 +28,7 @@ const logger = {
|
|||||||
const server = new Server(
|
const server = new Server(
|
||||||
{
|
{
|
||||||
name: "executeautomation/database-server",
|
name: "executeautomation/database-server",
|
||||||
version: "1.0.1",
|
version: "1.1.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
@@ -45,6 +45,7 @@ if (args.length === 0) {
|
|||||||
logger.error("Usage for SQLite: node index.js <database_file_path>");
|
logger.error("Usage for SQLite: node index.js <database_file_path>");
|
||||||
logger.error("Usage for SQL Server: node index.js --sqlserver --server <server> --database <database> [--user <user> --password <password>]");
|
logger.error("Usage for SQL Server: node index.js --sqlserver --server <server> --database <database> [--user <user> --password <password>]");
|
||||||
logger.error("Usage for PostgreSQL: node index.js --postgresql --host <host> --database <database> [--user <user> --password <password> --port <port>]");
|
logger.error("Usage for PostgreSQL: node index.js --postgresql --host <host> --database <database> [--user <user> --password <password> --port <port>]");
|
||||||
|
logger.error("Usage for MySQL: node index.js --mysql --host <host> --database <database> [--user <user> --password <password> --port <port>]");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +121,45 @@ else if (args.includes('--postgresql') || args.includes('--postgres')) {
|
|||||||
logger.error("Error: PostgreSQL requires --host and --database parameters");
|
logger.error("Error: PostgreSQL requires --host and --database parameters");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// Check if using MySQL
|
||||||
|
else if (args.includes('--mysql')) {
|
||||||
|
dbType = 'mysql';
|
||||||
|
connectionInfo = {
|
||||||
|
host: '',
|
||||||
|
database: '',
|
||||||
|
user: undefined,
|
||||||
|
password: undefined,
|
||||||
|
port: undefined,
|
||||||
|
ssl: undefined,
|
||||||
|
connectionTimeout: undefined
|
||||||
|
};
|
||||||
|
// Parse MySQL connection parameters
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (args[i] === '--host' && i + 1 < args.length) {
|
||||||
|
connectionInfo.host = args[i + 1];
|
||||||
|
} else if (args[i] === '--database' && i + 1 < args.length) {
|
||||||
|
connectionInfo.database = args[i + 1];
|
||||||
|
} else if (args[i] === '--user' && i + 1 < args.length) {
|
||||||
|
connectionInfo.user = args[i + 1];
|
||||||
|
} else if (args[i] === '--password' && i + 1 < args.length) {
|
||||||
|
connectionInfo.password = args[i + 1];
|
||||||
|
} else if (args[i] === '--port' && i + 1 < args.length) {
|
||||||
|
connectionInfo.port = parseInt(args[i + 1], 10);
|
||||||
|
} else if (args[i] === '--ssl' && i + 1 < args.length) {
|
||||||
|
const sslVal = args[i + 1];
|
||||||
|
if (sslVal === 'true') connectionInfo.ssl = true;
|
||||||
|
else if (sslVal === 'false') connectionInfo.ssl = false;
|
||||||
|
else connectionInfo.ssl = sslVal;
|
||||||
|
} else if (args[i] === '--connection-timeout' && i + 1 < args.length) {
|
||||||
|
connectionInfo.connectionTimeout = parseInt(args[i + 1], 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Validate MySQL connection info
|
||||||
|
if (!connectionInfo.host || !connectionInfo.database) {
|
||||||
|
logger.error("Error: MySQL requires --host and --database parameters");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// SQLite mode (default)
|
// SQLite mode (default)
|
||||||
dbType = 'sqlite';
|
dbType = 'sqlite';
|
||||||
@@ -178,6 +218,8 @@ async function runServer() {
|
|||||||
logger.info(`Server: ${connectionInfo.server}, Database: ${connectionInfo.database}`);
|
logger.info(`Server: ${connectionInfo.server}, Database: ${connectionInfo.database}`);
|
||||||
} else if (dbType === 'postgresql') {
|
} else if (dbType === 'postgresql') {
|
||||||
logger.info(`Host: ${connectionInfo.host}, Database: ${connectionInfo.database}`);
|
logger.info(`Host: ${connectionInfo.host}, Database: ${connectionInfo.database}`);
|
||||||
|
} else if (dbType === 'mysql') {
|
||||||
|
logger.info(`Host: ${connectionInfo.host}, Database: ${connectionInfo.database}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the database
|
// Initialize the database
|
||||||
|
|||||||
Reference in New Issue
Block a user