@cmd233/mcp-database-server 1.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.
@@ -0,0 +1,54 @@
1
+ import { dbAll, dbExec, dbRun } from '../db/index.js';
2
+ import { formatSuccessResponse } from '../utils/formatUtils.js';
3
+ /**
4
+ * Add a business insight to the memo
5
+ * @param insight Business insight text
6
+ * @returns Result of the operation
7
+ */
8
+ export async function appendInsight(insight) {
9
+ try {
10
+ if (!insight) {
11
+ throw new Error("Insight text is required");
12
+ }
13
+ // Create insights table if it doesn't exist
14
+ await dbExec(`
15
+ CREATE TABLE IF NOT EXISTS mcp_insights (
16
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
17
+ insight TEXT NOT NULL,
18
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
19
+ )
20
+ `);
21
+ // Insert the insight
22
+ await dbRun("INSERT INTO mcp_insights (insight) VALUES (?)", [insight]);
23
+ return formatSuccessResponse({ success: true, message: "Insight added" });
24
+ }
25
+ catch (error) {
26
+ throw new Error(`Error adding insight: ${error.message}`);
27
+ }
28
+ }
29
+ /**
30
+ * List all insights in the memo
31
+ * @returns Array of insights
32
+ */
33
+ export async function listInsights() {
34
+ try {
35
+ // Check if insights table exists
36
+ const tableExists = await dbAll("SELECT name FROM sqlite_master WHERE type='table' AND name = 'mcp_insights'");
37
+ if (tableExists.length === 0) {
38
+ // Create table if it doesn't exist
39
+ await dbExec(`
40
+ CREATE TABLE IF NOT EXISTS mcp_insights (
41
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
42
+ insight TEXT NOT NULL,
43
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
44
+ )
45
+ `);
46
+ return formatSuccessResponse([]);
47
+ }
48
+ const insights = await dbAll("SELECT * FROM mcp_insights ORDER BY created_at DESC");
49
+ return formatSuccessResponse(insights);
50
+ }
51
+ catch (error) {
52
+ throw new Error(`Error listing insights: ${error.message}`);
53
+ }
54
+ }
@@ -0,0 +1,73 @@
1
+ import { dbAll, dbRun } from '../db/index.js';
2
+ import { formatSuccessResponse, convertToCSV } from '../utils/formatUtils.js';
3
+ /**
4
+ * Execute a read-only SQL query
5
+ * @param query SQL query to execute
6
+ * @returns Query results
7
+ */
8
+ export async function readQuery(query) {
9
+ try {
10
+ if (!query.trim().toLowerCase().startsWith("select")) {
11
+ throw new Error("Only SELECT queries are allowed with read_query");
12
+ }
13
+ const result = await dbAll(query);
14
+ return formatSuccessResponse(result);
15
+ }
16
+ catch (error) {
17
+ throw new Error(`SQL Error: ${error.message}`);
18
+ }
19
+ }
20
+ /**
21
+ * Execute a data modification SQL query
22
+ * @param query SQL query to execute
23
+ * @returns Information about affected rows
24
+ */
25
+ export async function writeQuery(query) {
26
+ try {
27
+ const lowerQuery = query.trim().toLowerCase();
28
+ if (lowerQuery.startsWith("select")) {
29
+ throw new Error("Use read_query for SELECT operations");
30
+ }
31
+ if (!(lowerQuery.startsWith("insert") || lowerQuery.startsWith("update") || lowerQuery.startsWith("delete"))) {
32
+ throw new Error("Only INSERT, UPDATE, or DELETE operations are allowed with write_query");
33
+ }
34
+ const result = await dbRun(query);
35
+ return formatSuccessResponse({ affected_rows: result.changes });
36
+ }
37
+ catch (error) {
38
+ throw new Error(`SQL Error: ${error.message}`);
39
+ }
40
+ }
41
+ /**
42
+ * Export query results to CSV or JSON format
43
+ * @param query SQL query to execute
44
+ * @param format Output format (csv or json)
45
+ * @returns Formatted query results
46
+ */
47
+ export async function exportQuery(query, format) {
48
+ try {
49
+ if (!query.trim().toLowerCase().startsWith("select")) {
50
+ throw new Error("Only SELECT queries are allowed with export_query");
51
+ }
52
+ const result = await dbAll(query);
53
+ if (format === "csv") {
54
+ const csvData = convertToCSV(result);
55
+ return {
56
+ content: [{
57
+ type: "text",
58
+ text: csvData
59
+ }],
60
+ isError: false,
61
+ };
62
+ }
63
+ else if (format === "json") {
64
+ return formatSuccessResponse(result);
65
+ }
66
+ else {
67
+ throw new Error("Unsupported export format. Use 'csv' or 'json'");
68
+ }
69
+ }
70
+ catch (error) {
71
+ throw new Error(`Export Error: ${error.message}`);
72
+ }
73
+ }
@@ -0,0 +1,118 @@
1
+ import { dbAll, dbExec, getListTablesQuery, getDescribeTableQuery } from '../db/index.js';
2
+ import { formatSuccessResponse } from '../utils/formatUtils.js';
3
+ /**
4
+ * Create a new table in the database
5
+ * @param query CREATE TABLE SQL statement
6
+ * @returns Result of the operation
7
+ */
8
+ export async function createTable(query) {
9
+ try {
10
+ if (!query.trim().toLowerCase().startsWith("create table")) {
11
+ throw new Error("Only CREATE TABLE statements are allowed");
12
+ }
13
+ await dbExec(query);
14
+ return formatSuccessResponse({ success: true, message: "Table created successfully" });
15
+ }
16
+ catch (error) {
17
+ throw new Error(`SQL Error: ${error.message}`);
18
+ }
19
+ }
20
+ /**
21
+ * Alter an existing table schema
22
+ * @param query ALTER TABLE SQL statement
23
+ * @returns Result of the operation
24
+ */
25
+ export async function alterTable(query) {
26
+ try {
27
+ if (!query.trim().toLowerCase().startsWith("alter table")) {
28
+ throw new Error("Only ALTER TABLE statements are allowed");
29
+ }
30
+ await dbExec(query);
31
+ return formatSuccessResponse({ success: true, message: "Table altered successfully" });
32
+ }
33
+ catch (error) {
34
+ throw new Error(`SQL Error: ${error.message}`);
35
+ }
36
+ }
37
+ /**
38
+ * Drop a table from the database
39
+ * @param tableName Name of the table to drop
40
+ * @param confirm Safety confirmation flag
41
+ * @returns Result of the operation
42
+ */
43
+ export async function dropTable(tableName, confirm) {
44
+ try {
45
+ if (!tableName) {
46
+ throw new Error("Table name is required");
47
+ }
48
+ if (!confirm) {
49
+ return formatSuccessResponse({
50
+ success: false,
51
+ message: "Safety confirmation required. Set confirm=true to proceed with dropping the table."
52
+ });
53
+ }
54
+ // First check if table exists by directly querying for tables
55
+ const query = getListTablesQuery();
56
+ const tables = await dbAll(query);
57
+ const tableNames = tables.map(t => t.name);
58
+ if (!tableNames.includes(tableName)) {
59
+ throw new Error(`Table '${tableName}' does not exist`);
60
+ }
61
+ // Drop the table
62
+ await dbExec(`DROP TABLE "${tableName}"`);
63
+ return formatSuccessResponse({
64
+ success: true,
65
+ message: `Table '${tableName}' dropped successfully`
66
+ });
67
+ }
68
+ catch (error) {
69
+ throw new Error(`Error dropping table: ${error.message}`);
70
+ }
71
+ }
72
+ /**
73
+ * List all tables in the database
74
+ * @returns Array of table names
75
+ */
76
+ export async function listTables() {
77
+ try {
78
+ // Use adapter-specific query for listing tables
79
+ const query = getListTablesQuery();
80
+ const tables = await dbAll(query);
81
+ return formatSuccessResponse(tables.map((t) => t.name));
82
+ }
83
+ catch (error) {
84
+ throw new Error(`Error listing tables: ${error.message}`);
85
+ }
86
+ }
87
+ /**
88
+ * Get schema information for a specific table
89
+ * @param tableName Name of the table to describe
90
+ * @returns Column definitions for the table
91
+ */
92
+ export async function describeTable(tableName) {
93
+ try {
94
+ if (!tableName) {
95
+ throw new Error("Table name is required");
96
+ }
97
+ // First check if table exists by directly querying for tables
98
+ const query = getListTablesQuery();
99
+ const tables = await dbAll(query);
100
+ const tableNames = tables.map(t => t.name);
101
+ if (!tableNames.includes(tableName)) {
102
+ throw new Error(`Table '${tableName}' does not exist`);
103
+ }
104
+ // Use adapter-specific query for describing tables
105
+ const descQuery = getDescribeTableQuery(tableName);
106
+ const columns = await dbAll(descQuery);
107
+ return formatSuccessResponse(columns.map((col) => ({
108
+ name: col.name,
109
+ type: col.type,
110
+ notnull: !!col.notnull,
111
+ default_value: col.dflt_value,
112
+ primary_key: !!col.pk
113
+ })));
114
+ }
115
+ catch (error) {
116
+ throw new Error(`Error describing table: ${error.message}`);
117
+ }
118
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Convert data to CSV format
3
+ * @param data Array of objects to convert to CSV
4
+ * @returns CSV formatted string
5
+ */
6
+ export function convertToCSV(data) {
7
+ if (data.length === 0)
8
+ return '';
9
+ // Get headers
10
+ const headers = Object.keys(data[0]);
11
+ // Create CSV header row
12
+ let csv = headers.join(',') + '\n';
13
+ // Add data rows
14
+ data.forEach(row => {
15
+ const values = headers.map(header => {
16
+ const val = row[header];
17
+ // Handle strings with commas, quotes, etc.
18
+ if (typeof val === 'string') {
19
+ return `"${val.replace(/"/g, '""')}"`;
20
+ }
21
+ // Use empty string for null/undefined
22
+ return val === null || val === undefined ? '' : val;
23
+ });
24
+ csv += values.join(',') + '\n';
25
+ });
26
+ return csv;
27
+ }
28
+ /**
29
+ * Format error response
30
+ * @param error Error object or message
31
+ * @returns Formatted error response object
32
+ */
33
+ export function formatErrorResponse(error) {
34
+ const message = error instanceof Error ? error.message : error;
35
+ return {
36
+ content: [{
37
+ type: "text",
38
+ text: JSON.stringify({ error: message }, null, 2)
39
+ }],
40
+ isError: true
41
+ };
42
+ }
43
+ /**
44
+ * Format success response
45
+ * @param data Data to format
46
+ * @returns Formatted success response object
47
+ */
48
+ export function formatSuccessResponse(data) {
49
+ return {
50
+ content: [{
51
+ type: "text",
52
+ text: JSON.stringify(data, null, 2)
53
+ }],
54
+ isError: false
55
+ };
56
+ }
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@cmd233/mcp-database-server",
3
+ "version": "1.1.1",
4
+ "description": "MCP server for interacting with SQLite, SQL Server, PostgreSQL and MySQL databases (Fixed nullable field detection)",
5
+ "license": "MIT",
6
+ "author": "cmd233",
7
+ "homepage": "https://github.com/cmd233/mcp-database-server",
8
+ "bugs": "https://github.com/cmd233/mcp-database-server/issues",
9
+ "type": "module",
10
+ "bin": {
11
+ "ea-database-server": "dist/src/index.js"
12
+ },
13
+ "files": [
14
+ "dist"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc && shx chmod +x dist/src/index.js",
18
+ "prepare": "npm run build",
19
+ "watch": "tsc --watch",
20
+ "start": "node dist/src/index.js",
21
+ "dev": "tsc && node dist/src/index.js",
22
+ "example": "node examples/example.js",
23
+ "clean": "rimraf dist"
24
+ },
25
+ "dependencies": {
26
+ "@aws-sdk/rds-signer": "^3.0.0",
27
+ "@modelcontextprotocol/sdk": "1.9.0",
28
+ "mssql": "11.0.1",
29
+ "mysql2": "^3.14.1",
30
+ "pg": "^8.11.3",
31
+ "sqlite3": "5.1.7"
32
+ },
33
+ "devDependencies": {
34
+ "@types/mssql": "^9.1.5",
35
+ "@types/pg": "^8.11.13",
36
+ "@types/sqlite3": "5.1.0",
37
+ "rimraf": "^5.0.5",
38
+ "shx": "0.4.0",
39
+ "typescript": "5.8.3"
40
+ }
41
+ }
package/readme.md ADDED
@@ -0,0 +1,328 @@
1
+ [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/executeautomation-mcp-database-server-badge.png)](https://mseep.ai/app/executeautomation-mcp-database-server)
2
+
3
+ # MCP Database Server
4
+
5
+ This MCP (Model Context Protocol) server provides database access capabilities to Claude, supporting SQLite, SQL Server, PostgreSQL, and MySQL databases.
6
+
7
+ ## Installation
8
+
9
+ 1. Clone the repository:
10
+ ```
11
+ git clone https://github.com/executeautomation/mcp-database-server.git
12
+ cd mcp-database-server
13
+ ```
14
+
15
+ 2. Install dependencies:
16
+ ```
17
+ npm install
18
+ ```
19
+
20
+ 3. Build the project:
21
+ ```
22
+ npm run build
23
+ ```
24
+
25
+ ## Usage Options
26
+
27
+ There are two ways to use this MCP server with Claude:
28
+
29
+ 1. **Direct usage**: Install the package globally and use it directly
30
+ 2. **Local development**: Run from your local development environment
31
+
32
+ ### Direct Usage with NPM Package
33
+
34
+ The easiest way to use this MCP server is by installing it globally:
35
+
36
+ ```bash
37
+ npm install -g @executeautomation/database-server
38
+ ```
39
+
40
+ This allows you to use the server directly without building it locally.
41
+
42
+ ### Local Development Setup
43
+
44
+ If you want to modify the code or run from your local environment:
45
+
46
+ 1. Clone and build the repository as shown in the Installation section
47
+ 2. Run the server using the commands in the Usage section below
48
+
49
+ ## Usage
50
+
51
+ ### SQLite Database
52
+
53
+ To use with an SQLite database:
54
+
55
+ ```
56
+ node dist/src/index.js /path/to/your/database.db
57
+ ```
58
+
59
+ ### SQL Server Database
60
+
61
+ To use with a SQL Server database:
62
+
63
+ ```
64
+ node dist/src/index.js --sqlserver --server <server-name> --database <database-name> [--user <username> --password <password>]
65
+ ```
66
+
67
+ Required parameters:
68
+ - `--server`: SQL Server host name or IP address
69
+ - `--database`: Name of the database
70
+
71
+ Optional parameters:
72
+ - `--user`: Username for SQL Server authentication (if not provided, Windows Authentication will be used)
73
+ - `--password`: Password for SQL Server authentication
74
+ - `--port`: Port number (default: 1433)
75
+
76
+ ### PostgreSQL Database
77
+
78
+ To use with a PostgreSQL database:
79
+
80
+ ```
81
+ node dist/src/index.js --postgresql --host <host-name> --database <database-name> [--user <username> --password <password>]
82
+ ```
83
+
84
+ Required parameters:
85
+ - `--host`: PostgreSQL host name or IP address
86
+ - `--database`: Name of the database
87
+
88
+ Optional parameters:
89
+ - `--user`: Username for PostgreSQL authentication
90
+ - `--password`: Password for PostgreSQL authentication
91
+ - `--port`: Port number (default: 5432)
92
+ - `--ssl`: Enable SSL connection (true/false)
93
+ - `--connection-timeout`: Connection timeout in milliseconds (default: 30000)
94
+
95
+ ### MySQL Database
96
+
97
+ #### Standard Authentication
98
+
99
+ To use with a MySQL database:
100
+
101
+ ```
102
+ node dist/src/index.js --mysql --host <host-name> --database <database-name> --port <port> [--user <username> --password <password>]
103
+ ```
104
+
105
+ Required parameters:
106
+ - `--host`: MySQL host name or IP address
107
+ - `--database`: Name of the database
108
+ - `--port`: Port number (default: 3306)
109
+
110
+ Optional parameters:
111
+ - `--user`: Username for MySQL authentication
112
+ - `--password`: Password for MySQL authentication
113
+ - `--ssl`: Enable SSL connection (true/false or object)
114
+ - `--connection-timeout`: Connection timeout in milliseconds (default: 30000)
115
+
116
+ #### AWS IAM Authentication
117
+
118
+ For Amazon RDS MySQL instances with IAM database authentication:
119
+
120
+ **Prerequisites:**
121
+ - AWS credentials must be configured (the RDS Signer uses the default credential provider chain)
122
+ - Configure using one of these methods:
123
+ - `aws configure` (uses default profile)
124
+ - `AWS_PROFILE=myprofile` environment variable
125
+ - `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables
126
+ - IAM roles (if running on EC2)
127
+
128
+ ```
129
+ node dist/src/index.js --mysql --aws-iam-auth --host <rds-endpoint> --database <database-name> --user <aws-username> --aws-region <region>
130
+ ```
131
+
132
+ Required parameters:
133
+ - `--host`: RDS endpoint hostname
134
+ - `--database`: Name of the database
135
+ - `--aws-iam-auth`: Enable AWS IAM authentication
136
+ - `--user`: AWS IAM username (also the database user)
137
+ - `--aws-region`: AWS region where RDS instance is located
138
+
139
+ Note: SSL is automatically enabled for AWS IAM authentication
140
+
141
+ ## Configuring Claude Desktop
142
+
143
+ ### Direct Usage Configuration
144
+
145
+ If you installed the package globally, configure Claude Desktop with:
146
+
147
+ ```json
148
+ {
149
+ "mcpServers": {
150
+ "sqlite": {
151
+ "command": "npx",
152
+ "args": [
153
+ "-y",
154
+ "@executeautomation/database-server",
155
+ "/path/to/your/database.db"
156
+ ]
157
+ },
158
+ "sqlserver": {
159
+ "command": "npx",
160
+ "args": [
161
+ "-y",
162
+ "@executeautomation/database-server",
163
+ "--sqlserver",
164
+ "--server", "your-server-name",
165
+ "--database", "your-database-name",
166
+ "--user", "your-username",
167
+ "--password", "your-password"
168
+ ]
169
+ },
170
+ "postgresql": {
171
+ "command": "npx",
172
+ "args": [
173
+ "-y",
174
+ "@executeautomation/database-server",
175
+ "--postgresql",
176
+ "--host", "your-host-name",
177
+ "--database", "your-database-name",
178
+ "--user", "your-username",
179
+ "--password", "your-password"
180
+ ]
181
+ },
182
+ "mysql": {
183
+ "command": "npx",
184
+ "args": [
185
+ "-y",
186
+ "@executeautomation/database-server",
187
+ "--mysql",
188
+ "--host", "your-host-name",
189
+ "--database", "your-database-name",
190
+ "--port", "3306",
191
+ "--user", "your-username",
192
+ "--password", "your-password"
193
+ ]
194
+ },
195
+ "mysql-aws": {
196
+ "command": "npx",
197
+ "args": [
198
+ "-y",
199
+ "@executeautomation/database-server",
200
+ "--mysql",
201
+ "--aws-iam-auth",
202
+ "--host", "your-rds-endpoint.region.rds.amazonaws.com",
203
+ "--database", "your-database-name",
204
+ "--user", "your-aws-username",
205
+ "--aws-region", "us-east-1"
206
+ ]
207
+ }
208
+ }
209
+ }
210
+ ```
211
+
212
+ ### Local Development Configuration
213
+
214
+ For local development, configure Claude Desktop to use your locally built version:
215
+
216
+ ```json
217
+ {
218
+ "mcpServers": {
219
+ "sqlite": {
220
+ "command": "node",
221
+ "args": [
222
+ "/absolute/path/to/mcp-database-server/dist/src/index.js",
223
+ "/path/to/your/database.db"
224
+ ]
225
+ },
226
+ "sqlserver": {
227
+ "command": "node",
228
+ "args": [
229
+ "/absolute/path/to/mcp-database-server/dist/src/index.js",
230
+ "--sqlserver",
231
+ "--server", "your-server-name",
232
+ "--database", "your-database-name",
233
+ "--user", "your-username",
234
+ "--password", "your-password"
235
+ ]
236
+ },
237
+ "postgresql": {
238
+ "command": "node",
239
+ "args": [
240
+ "/absolute/path/to/mcp-database-server/dist/src/index.js",
241
+ "--postgresql",
242
+ "--host", "your-host-name",
243
+ "--database", "your-database-name",
244
+ "--user", "your-username",
245
+ "--password", "your-password"
246
+ ]
247
+ },
248
+ "mysql": {
249
+ "command": "node",
250
+ "args": [
251
+ "/absolute/path/to/mcp-database-server/dist/src/index.js",
252
+ "--mysql",
253
+ "--host", "your-host-name",
254
+ "--database", "your-database-name",
255
+ "--port", "3306",
256
+ "--user", "your-username",
257
+ "--password", "your-password"
258
+ ]
259
+ },
260
+ "mysql-aws": {
261
+ "command": "node",
262
+ "args": [
263
+ "/absolute/path/to/mcp-database-server/dist/src/index.js",
264
+ "--mysql",
265
+ "--aws-iam-auth",
266
+ "--host", "your-rds-endpoint.region.rds.amazonaws.com",
267
+ "--database", "your-database-name",
268
+ "--user", "your-aws-username",
269
+ "--aws-region", "us-east-1"
270
+ ]
271
+ }
272
+ }
273
+ }
274
+ ```
275
+
276
+ The Claude Desktop configuration file is typically located at:
277
+ - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
278
+ - Windows: `%APPDATA%\Claude\claude_desktop_config.json`
279
+ - Linux: `~/.config/Claude/claude_desktop_config.json`
280
+
281
+ ## Available Database Tools
282
+
283
+ The MCP Database Server provides the following tools that Claude can use:
284
+
285
+ | Tool | Description | Required Parameters |
286
+ |------|-------------|---------------------|
287
+ | `read_query` | Execute SELECT queries to read data | `query`: SQL SELECT statement |
288
+ | `write_query` | Execute INSERT, UPDATE, or DELETE queries | `query`: SQL modification statement |
289
+ | `create_table` | Create new tables in the database | `query`: CREATE TABLE statement |
290
+ | `alter_table` | Modify existing table schema | `query`: ALTER TABLE statement |
291
+ | `drop_table` | Remove a table from the database | `table_name`: Name of table<br>`confirm`: Safety flag (must be true) |
292
+ | `list_tables` | Get a list of all tables | None |
293
+ | `describe_table` | View schema information for a table | `table_name`: Name of table |
294
+ | `export_query` | Export query results as CSV/JSON | `query`: SQL SELECT statement<br>`format`: "csv" or "json" |
295
+ | `append_insight` | Add a business insight to memo | `insight`: Text of insight |
296
+ | `list_insights` | List all business insights | None |
297
+
298
+ For practical examples of how to use these tools with Claude, see [Usage Examples](docs/usage-examples.md).
299
+
300
+ ## Additional Documentation
301
+
302
+ - [SQL Server Setup Guide](docs/sql-server-setup.md): Details on connecting to SQL Server databases
303
+ - [PostgreSQL Setup Guide](docs/postgresql-setup.md): Details on connecting to PostgreSQL databases
304
+ - [Usage Examples](docs/usage-examples.md): Example queries and commands to use with Claude
305
+
306
+ ## Development
307
+
308
+ To run the server in development mode:
309
+
310
+ ```
311
+ npm run dev
312
+ ```
313
+
314
+ To watch for changes during development:
315
+
316
+ ```
317
+ npm run watch
318
+ ```
319
+
320
+ ## Requirements
321
+
322
+ - Node.js 18+
323
+ - For SQL Server connectivity: SQL Server 2012 or later
324
+ - For PostgreSQL connectivity: PostgreSQL 9.5 or later
325
+
326
+ ## License
327
+
328
+ MIT