@arvoretech/mysql-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/README.md +182 -0
- package/dist/database.d.ts +15 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +125 -0
- package/dist/database.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +106 -0
- package/dist/server.js.map +1 -0
- package/dist/tools.d.ts +11 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +153 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +79 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/eslint.config.js +54 -0
- package/package.json +42 -0
- package/src/database.test.ts +298 -0
- package/src/database.ts +163 -0
- package/src/index.ts +26 -0
- package/src/server.ts +157 -0
- package/src/tools.test.ts +228 -0
- package/src/tools.ts +212 -0
- package/src/types.ts +71 -0
- package/tsconfig.json +21 -0
- package/vitest.config.ts +13 -0
package/README.md
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# MySQL MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://cursor.com/en/install-mcp?name=mysql-mcp®istry=https://npm.pkg.github.com&packageName=@arvoretech/mysql-mcp)
|
|
4
|
+
|
|
5
|
+
A Model Context Protocol (MCP) server implementation for MySQL that enables read-only database operations through a standardized protocol for integration with LLMs and AI tools.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- ✅ **Read-only**: Executes only SELECT, SHOW, DESCRIBE and EXPLAIN queries
|
|
10
|
+
- 🔒 **Secure**: Validates queries to prevent write operations
|
|
11
|
+
- 🚀 **Fast**: Direct MySQL connection using mysql2
|
|
12
|
+
- 📡 **MCP Protocol**: Communication via stdio transport
|
|
13
|
+
- 🛠️ **TypeScript**: Fully typed with Zod validation
|
|
14
|
+
- 🌍 **Environment Configuration**: Easy setup via environment variables
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install -g @arvoretech/mysql-mcp --registry=https://npm.pkg.github.com
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Or configure your `.npmrc`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
echo "@arvoretech:registry=https://npm.pkg.github.com" >> ~/.npmrc
|
|
26
|
+
npm install -g @arvoretech/mysql-mcp
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
The server is configured via environment variables:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
export MYSQL_HOST=localhost
|
|
35
|
+
export MYSQL_PORT=3306
|
|
36
|
+
export MYSQL_USER=root
|
|
37
|
+
export MYSQL_PASSWORD=secret
|
|
38
|
+
export MYSQL_DATABASE=mydb
|
|
39
|
+
export MYSQL_SSL=false
|
|
40
|
+
export MYSQL_CONNECTION_TIMEOUT=30000
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Development
|
|
47
|
+
pnpm dev
|
|
48
|
+
|
|
49
|
+
# Production
|
|
50
|
+
node dist/index.js
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Available MCP Tools
|
|
54
|
+
|
|
55
|
+
### `read_query`
|
|
56
|
+
|
|
57
|
+
Executes SELECT queries on the MySQL database.
|
|
58
|
+
|
|
59
|
+
**Parameters:**
|
|
60
|
+
|
|
61
|
+
- `query` (string): SQL SELECT statement
|
|
62
|
+
|
|
63
|
+
**Example:**
|
|
64
|
+
|
|
65
|
+
```json
|
|
66
|
+
{
|
|
67
|
+
"query": "SELECT * FROM users LIMIT 10"
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### `list_tables`
|
|
72
|
+
|
|
73
|
+
Lists all tables in the current database.
|
|
74
|
+
|
|
75
|
+
**Parameters:** None
|
|
76
|
+
|
|
77
|
+
### `describe_table`
|
|
78
|
+
|
|
79
|
+
Gets structure and schema information for a specific table.
|
|
80
|
+
|
|
81
|
+
**Parameters:**
|
|
82
|
+
|
|
83
|
+
- `tableName` (string): Name of the table
|
|
84
|
+
|
|
85
|
+
### `show_databases`
|
|
86
|
+
|
|
87
|
+
Lists all available databases on the MySQL server.
|
|
88
|
+
|
|
89
|
+
**Parameters:** None
|
|
90
|
+
|
|
91
|
+
## Programmatic Usage
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
import { MySQLMCPServer } from "mysql-mcp-server";
|
|
95
|
+
|
|
96
|
+
const server = new MySQLMCPServer({
|
|
97
|
+
host: "localhost",
|
|
98
|
+
port: 3306,
|
|
99
|
+
user: "root",
|
|
100
|
+
password: "secret",
|
|
101
|
+
database: "mydb",
|
|
102
|
+
ssl: false,
|
|
103
|
+
connectionTimeout: 30000,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// Setup graceful shutdown
|
|
107
|
+
server.setupGracefulShutdown();
|
|
108
|
+
|
|
109
|
+
// Start server
|
|
110
|
+
await server.start();
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Claude Desktop Integration
|
|
114
|
+
|
|
115
|
+
Add to your Claude Desktop configuration file (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{
|
|
119
|
+
"mcpServers": {
|
|
120
|
+
"mysql": {
|
|
121
|
+
"command": "npx",
|
|
122
|
+
"args": ["-y", "@arvoretech/mysql-mcp"],
|
|
123
|
+
"env": {
|
|
124
|
+
"MYSQL_HOST": "localhost",
|
|
125
|
+
"MYSQL_PORT": "3306",
|
|
126
|
+
"MYSQL_USER": "root",
|
|
127
|
+
"MYSQL_PASSWORD": "secret",
|
|
128
|
+
"MYSQL_DATABASE": "mydb",
|
|
129
|
+
"MYSQL_SSL": "false",
|
|
130
|
+
"MYSQL_CONNECTION_TIMEOUT": "30000"
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## Security
|
|
138
|
+
|
|
139
|
+
- **Query validation**: Only read operations are allowed
|
|
140
|
+
- **Parameter escaping**: Uses prepared statements when possible
|
|
141
|
+
- **Connection timeout**: Prevents hanging connections
|
|
142
|
+
- **Error handling**: MySQL errors are caught and handled appropriately
|
|
143
|
+
|
|
144
|
+
## Development
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Install dependencies
|
|
148
|
+
pnpm install
|
|
149
|
+
|
|
150
|
+
# Run in development mode
|
|
151
|
+
pnpm dev
|
|
152
|
+
|
|
153
|
+
# Build
|
|
154
|
+
pnpm build
|
|
155
|
+
|
|
156
|
+
# Linting
|
|
157
|
+
pnpm lint
|
|
158
|
+
pnpm lint:fix
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Architecture
|
|
162
|
+
|
|
163
|
+
- **`MySQLConnection`**: Manages MySQL connection
|
|
164
|
+
- **`MySQLMCPTools`**: Implements MCP tools
|
|
165
|
+
- **`MySQLMCPServer`**: Main MCP server with stdio transport
|
|
166
|
+
- **Validation**: Uses Zod for type and parameter validation
|
|
167
|
+
|
|
168
|
+
## Connection Management
|
|
169
|
+
|
|
170
|
+
The server uses a **connection-per-query** approach for optimal reliability:
|
|
171
|
+
|
|
172
|
+
- **Fresh connections**: Each query opens and closes its own connection
|
|
173
|
+
- **No persistent connections**: Prevents timeout and stale connection issues
|
|
174
|
+
- **Automatic cleanup**: Connections are always properly closed after each operation
|
|
175
|
+
- **Improved stability**: Eliminates bugs caused by long-running connections
|
|
176
|
+
|
|
177
|
+
## Limitations
|
|
178
|
+
|
|
179
|
+
- Read-only operations only (SELECT, SHOW, DESCRIBE, EXPLAIN)
|
|
180
|
+
- Connection-per-query (no connection pooling)
|
|
181
|
+
- MySQL only (not PostgreSQL, SQLite, etc.)
|
|
182
|
+
- Stdio transport only (no HTTP/WebSocket)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { MySQLConfigInput, QueryResult, TableInfo, ColumnInfo, DatabaseInfo } from "./types.js";
|
|
2
|
+
export declare class MySQLConnection {
|
|
3
|
+
private readonly config;
|
|
4
|
+
constructor(config: MySQLConfigInput);
|
|
5
|
+
private createConnection;
|
|
6
|
+
connect(): Promise<void>;
|
|
7
|
+
disconnect(): Promise<void>;
|
|
8
|
+
private validateReadOnlyQuery;
|
|
9
|
+
executeQuery(query: string): Promise<QueryResult>;
|
|
10
|
+
listTables(): Promise<TableInfo[]>;
|
|
11
|
+
describeTable(tableName: string): Promise<ColumnInfo[]>;
|
|
12
|
+
showDatabases(): Promise<DatabaseInfo[]>;
|
|
13
|
+
testConnection(): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=database.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,gBAAgB,EAEhB,WAAW,EACX,SAAS,EACT,UAAU,EACV,YAAY,EAEb,MAAM,YAAY,CAAC;AAEpB,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,MAAM,EAAE,gBAAgB;YAItB,gBAAgB;IA0BxB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAKxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAIjC,OAAO,CAAC,qBAAqB;IAsBvB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAkCjD,UAAU,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;IAclC,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAmBvD,aAAa,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAKxC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAczC"}
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import mysql from "mysql2/promise";
|
|
2
|
+
import { MySQLConfigSchema, MySQLMCPError, } from "./types.js";
|
|
3
|
+
export class MySQLConnection {
|
|
4
|
+
config;
|
|
5
|
+
constructor(config) {
|
|
6
|
+
this.config = MySQLConfigSchema.parse(config);
|
|
7
|
+
}
|
|
8
|
+
async createConnection() {
|
|
9
|
+
try {
|
|
10
|
+
const connectionOptions = {
|
|
11
|
+
host: this.config.host,
|
|
12
|
+
port: this.config.port,
|
|
13
|
+
user: this.config.user,
|
|
14
|
+
password: this.config.password,
|
|
15
|
+
database: this.config.database,
|
|
16
|
+
connectTimeout: this.config.connectionTimeout,
|
|
17
|
+
};
|
|
18
|
+
if (this.config.ssl) {
|
|
19
|
+
connectionOptions.ssl = {};
|
|
20
|
+
}
|
|
21
|
+
return await mysql.createConnection(connectionOptions);
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
throw new MySQLMCPError(`Failed to connect to MySQL: ${error instanceof Error ? error.message : "Unknown error"}`, "CONNECTION_ERROR");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async connect() {
|
|
28
|
+
const connection = await this.createConnection();
|
|
29
|
+
await connection.end();
|
|
30
|
+
}
|
|
31
|
+
async disconnect() {
|
|
32
|
+
// No-op: connections are managed per-query
|
|
33
|
+
}
|
|
34
|
+
validateReadOnlyQuery(query) {
|
|
35
|
+
const trimmedQuery = query.trim().toLowerCase();
|
|
36
|
+
const readOnlyPatterns = [
|
|
37
|
+
/^select\s/,
|
|
38
|
+
/^show\s/,
|
|
39
|
+
/^describe\s/,
|
|
40
|
+
/^desc\s/,
|
|
41
|
+
/^explain\s/,
|
|
42
|
+
];
|
|
43
|
+
const isReadOnly = readOnlyPatterns.some((pattern) => pattern.test(trimmedQuery));
|
|
44
|
+
if (!isReadOnly) {
|
|
45
|
+
throw new MySQLMCPError("Only read-only queries are allowed (SELECT, SHOW, DESCRIBE, EXPLAIN)", "WRITE_OPERATION_NOT_ALLOWED");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async executeQuery(query) {
|
|
49
|
+
this.validateReadOnlyQuery(query);
|
|
50
|
+
const startTime = Date.now();
|
|
51
|
+
let connection = null;
|
|
52
|
+
try {
|
|
53
|
+
connection = await this.createConnection();
|
|
54
|
+
const [rows] = await connection.execute(query);
|
|
55
|
+
const executionTime = Date.now() - startTime;
|
|
56
|
+
const data = Array.isArray(rows)
|
|
57
|
+
? rows
|
|
58
|
+
: [];
|
|
59
|
+
return {
|
|
60
|
+
data,
|
|
61
|
+
rowCount: data.length,
|
|
62
|
+
executionTime,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const mysqlError = error;
|
|
67
|
+
throw new MySQLMCPError(`Query execution failed: ${mysqlError.message}`, mysqlError.code, mysqlError.sqlState);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
if (connection) {
|
|
71
|
+
await connection.end();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async listTables() {
|
|
76
|
+
const result = await this.executeQuery(`
|
|
77
|
+
SELECT
|
|
78
|
+
TABLE_NAME,
|
|
79
|
+
TABLE_TYPE,
|
|
80
|
+
TABLE_SCHEMA
|
|
81
|
+
FROM information_schema.TABLES
|
|
82
|
+
WHERE TABLE_SCHEMA = '${this.config.database}'
|
|
83
|
+
ORDER BY TABLE_NAME
|
|
84
|
+
`);
|
|
85
|
+
return result.data;
|
|
86
|
+
}
|
|
87
|
+
async describeTable(tableName) {
|
|
88
|
+
const result = await this.executeQuery(`
|
|
89
|
+
SELECT
|
|
90
|
+
COLUMN_NAME,
|
|
91
|
+
DATA_TYPE,
|
|
92
|
+
IS_NULLABLE,
|
|
93
|
+
COLUMN_DEFAULT,
|
|
94
|
+
COLUMN_KEY,
|
|
95
|
+
EXTRA,
|
|
96
|
+
COLUMN_COMMENT
|
|
97
|
+
FROM information_schema.COLUMNS
|
|
98
|
+
WHERE TABLE_SCHEMA = '${this.config.database}'
|
|
99
|
+
AND TABLE_NAME = '${tableName}'
|
|
100
|
+
ORDER BY ORDINAL_POSITION
|
|
101
|
+
`);
|
|
102
|
+
return result.data;
|
|
103
|
+
}
|
|
104
|
+
async showDatabases() {
|
|
105
|
+
const result = await this.executeQuery("SHOW DATABASES");
|
|
106
|
+
return result.data;
|
|
107
|
+
}
|
|
108
|
+
async testConnection() {
|
|
109
|
+
let connection = null;
|
|
110
|
+
try {
|
|
111
|
+
connection = await this.createConnection();
|
|
112
|
+
await connection.execute("SELECT 1 as test");
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
if (connection) {
|
|
120
|
+
await connection.end();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAsBA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { MySQLMCPServer } from "./server.js";
|
|
3
|
+
async function main() {
|
|
4
|
+
try {
|
|
5
|
+
const server = MySQLMCPServer.fromEnvironment();
|
|
6
|
+
server.setupGracefulShutdown();
|
|
7
|
+
await server.start();
|
|
8
|
+
}
|
|
9
|
+
catch (error) {
|
|
10
|
+
console.error("Failed to start MySQL MCP Server:", error);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
15
|
+
main().catch((error) => {
|
|
16
|
+
console.error("Fatal error:", error);
|
|
17
|
+
process.exit(1);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
export { MySQLMCPServer } from "./server.js";
|
|
21
|
+
export { MySQLConnection } from "./database.js";
|
|
22
|
+
export { MySQLMCPTools } from "./tools.js";
|
|
23
|
+
export * from "./types.js";
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,KAAK,UAAU,IAAI;IACjB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,cAAc,CAAC,eAAe,EAAE,CAAC;QAChD,MAAM,CAAC,qBAAqB,EAAE,CAAC;QAC/B,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,KAAK,CAAC,CAAC;QAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACpD,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,cAAc,YAAY,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { MySQLConfig } from "./types.js";
|
|
2
|
+
export declare class MySQLMCPServer {
|
|
3
|
+
private server;
|
|
4
|
+
private db;
|
|
5
|
+
private tools;
|
|
6
|
+
constructor(config: MySQLConfig);
|
|
7
|
+
static fromEnvironment(): MySQLMCPServer;
|
|
8
|
+
private setupTools;
|
|
9
|
+
start(): Promise<void>;
|
|
10
|
+
cleanup(): Promise<void>;
|
|
11
|
+
setupGracefulShutdown(): void;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,WAAW,EAOZ,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,EAAE,CAAkB;IAC5B,OAAO,CAAC,KAAK,CAAgB;gBAEjB,MAAM,EAAE,WAAW;IAY/B,MAAM,CAAC,eAAe,IAAI,cAAc;IAiBxC,OAAO,CAAC,UAAU;IAmDZ,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA0BtB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAW9B,qBAAqB,IAAI,IAAI;CAoB9B"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { MySQLConnection } from "./database.js";
|
|
4
|
+
import { MySQLMCPTools } from "./tools.js";
|
|
5
|
+
import { MySQLConfigSchema, ReadQueryParamsSchema, DescribeTableParamsSchema, MySQLMCPError, } from "./types.js";
|
|
6
|
+
export class MySQLMCPServer {
|
|
7
|
+
server;
|
|
8
|
+
db;
|
|
9
|
+
tools;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.server = new McpServer({
|
|
12
|
+
name: "mysql-mcp-server",
|
|
13
|
+
version: "1.0.0",
|
|
14
|
+
});
|
|
15
|
+
this.db = new MySQLConnection(config);
|
|
16
|
+
this.tools = new MySQLMCPTools(this.db);
|
|
17
|
+
this.setupTools();
|
|
18
|
+
}
|
|
19
|
+
static fromEnvironment() {
|
|
20
|
+
const config = MySQLConfigSchema.parse({
|
|
21
|
+
host: process.env.MYSQL_HOST || "localhost",
|
|
22
|
+
port: parseInt(process.env.MYSQL_PORT || "3306", 10),
|
|
23
|
+
user: process.env.MYSQL_USER || "root",
|
|
24
|
+
password: process.env.MYSQL_PASSWORD || "",
|
|
25
|
+
database: process.env.MYSQL_DATABASE || "test",
|
|
26
|
+
ssl: process.env.MYSQL_SSL === "true",
|
|
27
|
+
connectionTimeout: parseInt(process.env.MYSQL_CONNECTION_TIMEOUT || "30000", 10),
|
|
28
|
+
});
|
|
29
|
+
return new MySQLMCPServer(config);
|
|
30
|
+
}
|
|
31
|
+
setupTools() {
|
|
32
|
+
this.server.registerTool("read_query", {
|
|
33
|
+
title: "Execute Read Query",
|
|
34
|
+
description: "Execute a SELECT query on the MySQL database",
|
|
35
|
+
inputSchema: { query: ReadQueryParamsSchema.shape.query },
|
|
36
|
+
}, async (params) => {
|
|
37
|
+
return this.tools.readQuery(params);
|
|
38
|
+
});
|
|
39
|
+
this.server.registerTool("list_tables", {
|
|
40
|
+
title: "List Tables",
|
|
41
|
+
description: "List all tables in the current database",
|
|
42
|
+
inputSchema: {},
|
|
43
|
+
}, async () => {
|
|
44
|
+
return this.tools.listTables();
|
|
45
|
+
});
|
|
46
|
+
this.server.registerTool("describe_table", {
|
|
47
|
+
title: "Describe Table",
|
|
48
|
+
description: "Get the structure and schema information of a specific table",
|
|
49
|
+
inputSchema: { tableName: DescribeTableParamsSchema.shape.tableName },
|
|
50
|
+
}, async (params) => {
|
|
51
|
+
return this.tools.describeTable(params);
|
|
52
|
+
});
|
|
53
|
+
this.server.registerTool("show_databases", {
|
|
54
|
+
title: "Show Databases",
|
|
55
|
+
description: "List all available databases on the MySQL server",
|
|
56
|
+
inputSchema: {},
|
|
57
|
+
}, async () => {
|
|
58
|
+
return this.tools.showDatabases();
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
async start() {
|
|
62
|
+
try {
|
|
63
|
+
await this.db.connect();
|
|
64
|
+
const isConnected = await this.db.testConnection();
|
|
65
|
+
if (!isConnected) {
|
|
66
|
+
throw new MySQLMCPError("Database connection test failed", "CONNECTION_TEST_FAILED");
|
|
67
|
+
}
|
|
68
|
+
const transport = new StdioServerTransport();
|
|
69
|
+
await this.server.connect(transport);
|
|
70
|
+
console.error("MySQL MCP Server started successfully");
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error("Failed to start MySQL MCP Server:", error instanceof Error ? error.message : error);
|
|
74
|
+
await this.cleanup();
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async cleanup() {
|
|
79
|
+
try {
|
|
80
|
+
await this.db.disconnect();
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
console.error("Error during cleanup:", error instanceof Error ? error.message : error);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
setupGracefulShutdown() {
|
|
87
|
+
const shutdown = async (signal) => {
|
|
88
|
+
console.error(`Received ${signal}, shutting down gracefully...`);
|
|
89
|
+
await this.cleanup();
|
|
90
|
+
process.exit(0);
|
|
91
|
+
};
|
|
92
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
93
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
94
|
+
process.on("uncaughtException", async (error) => {
|
|
95
|
+
console.error("Uncaught exception:", error);
|
|
96
|
+
await this.cleanup();
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
|
99
|
+
process.on("unhandledRejection", async (reason) => {
|
|
100
|
+
console.error("Unhandled rejection:", reason);
|
|
101
|
+
await this.cleanup();
|
|
102
|
+
process.exit(1);
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tools.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { MySQLConnection } from "./database.js";
|
|
2
|
+
import { ReadQueryParams, DescribeTableParams, McpToolResult } from "./types.js";
|
|
3
|
+
export declare class MySQLMCPTools {
|
|
4
|
+
private db;
|
|
5
|
+
constructor(db: MySQLConnection);
|
|
6
|
+
readQuery(params: ReadQueryParams): Promise<McpToolResult>;
|
|
7
|
+
listTables(): Promise<McpToolResult>;
|
|
8
|
+
describeTable(params: DescribeTableParams): Promise<McpToolResult>;
|
|
9
|
+
showDatabases(): Promise<McpToolResult>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=tools.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,aAAa,EAEd,MAAM,YAAY,CAAC;AAEpB,qBAAa,aAAa;IACZ,OAAO,CAAC,EAAE;gBAAF,EAAE,EAAE,eAAe;IAEjC,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAiD1D,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC;IAkDpC,aAAa,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwDlE,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC;CA6C9C"}
|
package/dist/tools.js
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { MySQLMCPError, } from "./types.js";
|
|
2
|
+
export class MySQLMCPTools {
|
|
3
|
+
db;
|
|
4
|
+
constructor(db) {
|
|
5
|
+
this.db = db;
|
|
6
|
+
}
|
|
7
|
+
async readQuery(params) {
|
|
8
|
+
try {
|
|
9
|
+
const result = await this.db.executeQuery(params.query);
|
|
10
|
+
const resultText = JSON.stringify({
|
|
11
|
+
query: params.query,
|
|
12
|
+
rowCount: result.rowCount,
|
|
13
|
+
executionTime: `${result.executionTime}ms`,
|
|
14
|
+
data: result.data,
|
|
15
|
+
}, null, 2);
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: resultText,
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
const errorMessage = error instanceof MySQLMCPError
|
|
27
|
+
? `MySQL Error: ${error.message}`
|
|
28
|
+
: `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify({
|
|
34
|
+
error: errorMessage,
|
|
35
|
+
query: params.query,
|
|
36
|
+
}, null, 2),
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async listTables() {
|
|
43
|
+
try {
|
|
44
|
+
const tables = await this.db.listTables();
|
|
45
|
+
const resultText = JSON.stringify({
|
|
46
|
+
tableCount: tables.length,
|
|
47
|
+
tables: tables.map((table) => ({
|
|
48
|
+
name: table.TABLE_NAME,
|
|
49
|
+
type: table.TABLE_TYPE,
|
|
50
|
+
schema: table.TABLE_SCHEMA,
|
|
51
|
+
})),
|
|
52
|
+
}, null, 2);
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: resultText,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
const errorMessage = error instanceof MySQLMCPError
|
|
64
|
+
? `MySQL Error: ${error.message}`
|
|
65
|
+
: `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: JSON.stringify({
|
|
71
|
+
error: errorMessage,
|
|
72
|
+
}, null, 2),
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async describeTable(params) {
|
|
79
|
+
try {
|
|
80
|
+
const columns = await this.db.describeTable(params.tableName);
|
|
81
|
+
const resultText = JSON.stringify({
|
|
82
|
+
tableName: params.tableName,
|
|
83
|
+
columnCount: columns.length,
|
|
84
|
+
columns: columns.map((column) => ({
|
|
85
|
+
name: column.COLUMN_NAME,
|
|
86
|
+
type: column.DATA_TYPE,
|
|
87
|
+
nullable: column.IS_NULLABLE === "YES",
|
|
88
|
+
default: column.COLUMN_DEFAULT,
|
|
89
|
+
key: column.COLUMN_KEY,
|
|
90
|
+
extra: column.EXTRA,
|
|
91
|
+
comment: column.COLUMN_COMMENT,
|
|
92
|
+
})),
|
|
93
|
+
}, null, 2);
|
|
94
|
+
return {
|
|
95
|
+
content: [
|
|
96
|
+
{
|
|
97
|
+
type: "text",
|
|
98
|
+
text: resultText,
|
|
99
|
+
},
|
|
100
|
+
],
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
const errorMessage = error instanceof MySQLMCPError
|
|
105
|
+
? `MySQL Error: ${error.message}`
|
|
106
|
+
: `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
107
|
+
return {
|
|
108
|
+
content: [
|
|
109
|
+
{
|
|
110
|
+
type: "text",
|
|
111
|
+
text: JSON.stringify({
|
|
112
|
+
error: errorMessage,
|
|
113
|
+
tableName: params.tableName,
|
|
114
|
+
}, null, 2),
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
async showDatabases() {
|
|
121
|
+
try {
|
|
122
|
+
const databases = await this.db.showDatabases();
|
|
123
|
+
const resultText = JSON.stringify({
|
|
124
|
+
databaseCount: databases.length,
|
|
125
|
+
databases: databases.map((db) => db.Database),
|
|
126
|
+
}, null, 2);
|
|
127
|
+
return {
|
|
128
|
+
content: [
|
|
129
|
+
{
|
|
130
|
+
type: "text",
|
|
131
|
+
text: resultText,
|
|
132
|
+
},
|
|
133
|
+
],
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
const errorMessage = error instanceof MySQLMCPError
|
|
138
|
+
? `MySQL Error: ${error.message}`
|
|
139
|
+
: `Unexpected error: ${error instanceof Error ? error.message : "Unknown error"}`;
|
|
140
|
+
return {
|
|
141
|
+
content: [
|
|
142
|
+
{
|
|
143
|
+
type: "text",
|
|
144
|
+
text: JSON.stringify({
|
|
145
|
+
error: errorMessage,
|
|
146
|
+
}, null, 2),
|
|
147
|
+
},
|
|
148
|
+
],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=tools.js.map
|