mcp-dbutils 0.16.1__py3-none-any.whl → 0.17.0__py3-none-any.whl
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.
- mcp_dbutils/mysql/handler.py +60 -13
- mcp_dbutils/sqlite/handler.py +62 -20
- mcp_dbutils-0.17.0.dist-info/METADATA +308 -0
- {mcp_dbutils-0.16.1.dist-info → mcp_dbutils-0.17.0.dist-info}/RECORD +7 -7
- mcp_dbutils-0.16.1.dist-info/METADATA +0 -572
- {mcp_dbutils-0.16.1.dist-info → mcp_dbutils-0.17.0.dist-info}/WHEEL +0 -0
- {mcp_dbutils-0.16.1.dist-info → mcp_dbutils-0.17.0.dist-info}/entry_points.txt +0 -0
- {mcp_dbutils-0.16.1.dist-info → mcp_dbutils-0.17.0.dist-info}/licenses/LICENSE +0 -0
mcp_dbutils/mysql/handler.py
CHANGED
@@ -31,6 +31,35 @@ class MySQLHandler(ConnectionHandler):
|
|
31
31
|
self.log("debug", f"Configuring connection with parameters: {masked_params}")
|
32
32
|
self.pool = None
|
33
33
|
|
34
|
+
async def _check_table_exists(self, cursor, table_name: str) -> None:
|
35
|
+
"""检查表是否存在
|
36
|
+
|
37
|
+
Args:
|
38
|
+
cursor: 数据库游标
|
39
|
+
table_name: 表名
|
40
|
+
|
41
|
+
Raises:
|
42
|
+
ConnectionHandlerError: 如果表不存在
|
43
|
+
"""
|
44
|
+
cursor.execute("""
|
45
|
+
SELECT COUNT(*) as count
|
46
|
+
FROM information_schema.tables
|
47
|
+
WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s
|
48
|
+
""", (self.config.database, table_name))
|
49
|
+
table_exists = cursor.fetchone()
|
50
|
+
|
51
|
+
# Handle different formats of cursor results (dict or tuple)
|
52
|
+
if not table_exists:
|
53
|
+
raise ConnectionHandlerError(f"Table '{self.config.database}.{table_name}' doesn't exist")
|
54
|
+
|
55
|
+
# If fetchone returns a dictionary (dictionary=True was used)
|
56
|
+
if isinstance(table_exists, dict) and 'count' in table_exists and table_exists['count'] == 0:
|
57
|
+
raise ConnectionHandlerError(f"Table '{self.config.database}.{table_name}' doesn't exist")
|
58
|
+
|
59
|
+
# If fetchone returns a tuple
|
60
|
+
if isinstance(table_exists, tuple) and table_exists[0] == 0:
|
61
|
+
raise ConnectionHandlerError(f"Table '{self.config.database}.{table_name}' doesn't exist")
|
62
|
+
|
34
63
|
async def get_tables(self) -> list[types.Resource]:
|
35
64
|
"""Get all table resources"""
|
36
65
|
try:
|
@@ -119,24 +148,30 @@ class MySQLHandler(ConnectionHandler):
|
|
119
148
|
self.log("debug", f"Executing query: {sql}")
|
120
149
|
|
121
150
|
with conn.cursor(dictionary=True) as cur: # NOSONAR
|
122
|
-
#
|
123
|
-
|
151
|
+
# Check if the query is a SELECT statement
|
152
|
+
sql_upper = sql.strip().upper()
|
153
|
+
is_select = sql_upper.startswith("SELECT")
|
154
|
+
|
155
|
+
# Only set read-only transaction for SELECT statements
|
156
|
+
if is_select:
|
157
|
+
cur.execute("SET TRANSACTION READ ONLY")
|
124
158
|
try:
|
125
159
|
cur.execute(sql)
|
126
|
-
|
160
|
+
if not is_select:
|
161
|
+
conn.commit()
|
162
|
+
results = cur.fetchall() if is_select else []
|
163
|
+
if cur.description is None: # DDL statements
|
164
|
+
return "Query executed successfully"
|
127
165
|
columns = [desc[0] for desc in cur.description]
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
'columns': columns,
|
132
|
-
'rows': results,
|
133
|
-
'row_count': len(results)
|
166
|
+
return str({
|
167
|
+
"columns": columns,
|
168
|
+
"rows": results
|
134
169
|
})
|
135
|
-
|
136
|
-
self.log("
|
137
|
-
|
170
|
+
except mysql.connector.Error as e:
|
171
|
+
self.log("error", f"Query error: {str(e)}")
|
172
|
+
raise ConnectionHandlerError(str(e))
|
138
173
|
finally:
|
139
|
-
cur.
|
174
|
+
cur.close()
|
140
175
|
except mysql.connector.Error as e:
|
141
176
|
error_msg = f"[{self.db_type}] Query execution failed: {str(e)}"
|
142
177
|
raise ConnectionHandlerError(error_msg)
|
@@ -151,6 +186,9 @@ class MySQLHandler(ConnectionHandler):
|
|
151
186
|
conn_params = self.config.get_connection_params()
|
152
187
|
conn = mysql.connector.connect(**conn_params)
|
153
188
|
with conn.cursor(dictionary=True) as cur: # NOSONAR
|
189
|
+
# Check if table exists
|
190
|
+
await self._check_table_exists(cur, table_name)
|
191
|
+
|
154
192
|
# Get table information and comment
|
155
193
|
cur.execute("""
|
156
194
|
SELECT
|
@@ -243,6 +281,9 @@ class MySQLHandler(ConnectionHandler):
|
|
243
281
|
conn_params = self.config.get_connection_params()
|
244
282
|
conn = mysql.connector.connect(**conn_params)
|
245
283
|
with conn.cursor(dictionary=True) as cur: # NOSONAR
|
284
|
+
# Check if table exists
|
285
|
+
await self._check_table_exists(cur, table_name)
|
286
|
+
|
246
287
|
# Get index information
|
247
288
|
cur.execute("""
|
248
289
|
SELECT
|
@@ -302,6 +343,9 @@ class MySQLHandler(ConnectionHandler):
|
|
302
343
|
conn_params = self.config.get_connection_params()
|
303
344
|
conn = mysql.connector.connect(**conn_params)
|
304
345
|
with conn.cursor(dictionary=True) as cur: # NOSONAR
|
346
|
+
# Check if table exists
|
347
|
+
await self._check_table_exists(cur, table_name)
|
348
|
+
|
305
349
|
# Get table statistics
|
306
350
|
cur.execute("""
|
307
351
|
SELECT
|
@@ -367,6 +411,9 @@ class MySQLHandler(ConnectionHandler):
|
|
367
411
|
conn_params = self.config.get_connection_params()
|
368
412
|
conn = mysql.connector.connect(**conn_params)
|
369
413
|
with conn.cursor(dictionary=True) as cur: # NOSONAR
|
414
|
+
# Check if table exists
|
415
|
+
await self._check_table_exists(cur, table_name)
|
416
|
+
|
370
417
|
# Get constraint information
|
371
418
|
cur.execute("""
|
372
419
|
SELECT
|
mcp_dbutils/sqlite/handler.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"""SQLite connection handler implementation"""
|
2
2
|
|
3
3
|
import sqlite3
|
4
|
+
import time
|
4
5
|
|
5
6
|
import mcp.types as types
|
6
7
|
|
@@ -78,28 +79,51 @@ class SQLiteHandler(ConnectionHandler):
|
|
78
79
|
async def _execute_query(self, sql: str) -> str:
|
79
80
|
"""Execute SQL query"""
|
80
81
|
try:
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
conn.row_factory = sqlite3.Row
|
87
|
-
cur = conn.cursor()
|
88
|
-
self.log("debug", f"Executing query: {sql}")
|
89
|
-
|
90
|
-
cur.execute(sql)
|
91
|
-
results = cur.fetchall()
|
92
|
-
rows = [dict(row) for row in results]
|
82
|
+
# Check if the query is a DDL statement
|
83
|
+
sql_upper = sql.strip().upper()
|
84
|
+
is_ddl = sql_upper.startswith(("CREATE", "DROP", "ALTER", "TRUNCATE"))
|
85
|
+
is_dml = sql_upper.startswith(("INSERT", "UPDATE", "DELETE"))
|
86
|
+
is_select = sql_upper.startswith("SELECT")
|
93
87
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
})
|
88
|
+
if not (is_select or is_ddl or is_dml):
|
89
|
+
raise ConnectionHandlerError("Only SELECT, DDL, and DML statements are allowed")
|
90
|
+
|
91
|
+
conn = sqlite3.connect(self.config.path)
|
92
|
+
cur = conn.cursor()
|
100
93
|
|
101
|
-
|
102
|
-
|
94
|
+
try:
|
95
|
+
start_time = time.time()
|
96
|
+
cur.execute(sql)
|
97
|
+
conn.commit()
|
98
|
+
end_time = time.time()
|
99
|
+
elapsed_ms = (end_time - start_time) * 1000
|
100
|
+
self.log("debug", f"Query executed in {elapsed_ms:.2f}ms")
|
101
|
+
|
102
|
+
if is_select:
|
103
|
+
# Get column names
|
104
|
+
columns = [description[0] for description in cur.description]
|
105
|
+
# Fetch results and convert to dictionaries
|
106
|
+
results = []
|
107
|
+
for row in cur.fetchall():
|
108
|
+
# Convert each row to a dictionary
|
109
|
+
row_dict = {}
|
110
|
+
for i, col_name in enumerate(columns):
|
111
|
+
row_dict[col_name] = row[i]
|
112
|
+
results.append(row_dict)
|
113
|
+
|
114
|
+
return str({
|
115
|
+
"columns": columns,
|
116
|
+
"rows": results
|
117
|
+
})
|
118
|
+
else:
|
119
|
+
# For DDL/DML statements
|
120
|
+
return "Query executed successfully"
|
121
|
+
except sqlite3.Error as e:
|
122
|
+
self.log("error", f"Query error: {str(e)}")
|
123
|
+
raise ConnectionHandlerError(str(e))
|
124
|
+
finally:
|
125
|
+
cur.close()
|
126
|
+
conn.close()
|
103
127
|
except sqlite3.Error as e:
|
104
128
|
error_msg = f"[{self.db_type}] Query execution failed: {str(e)}"
|
105
129
|
raise ConnectionHandlerError(error_msg)
|
@@ -173,6 +197,12 @@ class SQLiteHandler(ConnectionHandler):
|
|
173
197
|
try:
|
174
198
|
with sqlite3.connect(self.config.path) as conn:
|
175
199
|
cur = conn.cursor()
|
200
|
+
|
201
|
+
# Check if table exists
|
202
|
+
cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
203
|
+
if not cur.fetchone():
|
204
|
+
raise ConnectionHandlerError(f"Table '{table_name}' doesn't exist")
|
205
|
+
|
176
206
|
# 获取索引列表
|
177
207
|
cur.execute(f"PRAGMA index_list({table_name})")
|
178
208
|
indexes = cur.fetchall()
|
@@ -221,6 +251,11 @@ class SQLiteHandler(ConnectionHandler):
|
|
221
251
|
with sqlite3.connect(self.config.path) as conn:
|
222
252
|
cur = conn.cursor()
|
223
253
|
|
254
|
+
# Check if table exists
|
255
|
+
cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
256
|
+
if not cur.fetchone():
|
257
|
+
raise ConnectionHandlerError(f"Table '{table_name}' doesn't exist")
|
258
|
+
|
224
259
|
# Get basic table information
|
225
260
|
cur.execute(f"PRAGMA table_info({table_name})")
|
226
261
|
columns = cur.fetchall()
|
@@ -382,6 +417,13 @@ class SQLiteHandler(ConnectionHandler):
|
|
382
417
|
with sqlite3.connect(self.config.path) as conn:
|
383
418
|
cur = conn.cursor()
|
384
419
|
|
420
|
+
# Check if the query is valid by preparing it
|
421
|
+
try:
|
422
|
+
# Use prepare to validate the query without executing it
|
423
|
+
conn.execute(f"EXPLAIN {sql}")
|
424
|
+
except sqlite3.Error as e:
|
425
|
+
raise ConnectionHandlerError(f"Failed to explain query: {str(e)}")
|
426
|
+
|
385
427
|
# Get EXPLAIN output
|
386
428
|
cur.execute(f"EXPLAIN QUERY PLAN {sql}")
|
387
429
|
plan = cur.fetchall()
|
@@ -0,0 +1,308 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mcp-dbutils
|
3
|
+
Version: 0.17.0
|
4
|
+
Summary: MCP Database Utilities Service
|
5
|
+
Author: Dong Hao
|
6
|
+
License-Expression: MIT
|
7
|
+
License-File: LICENSE
|
8
|
+
Requires-Python: >=3.10
|
9
|
+
Requires-Dist: mcp>=1.2.1
|
10
|
+
Requires-Dist: mysql-connector-python>=8.2.0
|
11
|
+
Requires-Dist: psycopg2-binary>=2.9.10
|
12
|
+
Requires-Dist: python-dotenv>=1.0.1
|
13
|
+
Requires-Dist: pyyaml>=6.0.2
|
14
|
+
Provides-Extra: test
|
15
|
+
Requires-Dist: aiosqlite>=0.19.0; extra == 'test'
|
16
|
+
Requires-Dist: docker>=7.0.0; extra == 'test'
|
17
|
+
Requires-Dist: pre-commit>=3.6.0; extra == 'test'
|
18
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
19
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
|
20
|
+
Requires-Dist: pytest-docker>=2.0.0; extra == 'test'
|
21
|
+
Requires-Dist: pytest>=7.0.0; extra == 'test'
|
22
|
+
Requires-Dist: ruff>=0.3.0; extra == 'test'
|
23
|
+
Requires-Dist: testcontainers>=3.7.0; extra == 'test'
|
24
|
+
Description-Content-Type: text/markdown
|
25
|
+
|
26
|
+
# MCP Database Utilities
|
27
|
+
|
28
|
+
<!-- 项目状态徽章 -->
|
29
|
+
[](https://github.com/donghao1393/mcp-dbutils/actions)
|
30
|
+
[](https://github.com/donghao1393/mcp-dbutils/actions)
|
31
|
+
[](https://sonarcloud.io/dashboard?id=donghao1393_mcp-dbutils)
|
32
|
+
|
33
|
+
<!-- 版本和安装徽章 -->
|
34
|
+
[](https://pypi.org/project/mcp-dbutils/)
|
35
|
+
[](https://pypi.org/project/mcp-dbutils/)
|
36
|
+
[](https://smithery.ai/server/@donghao1393/mcp-dbutils)
|
37
|
+
|
38
|
+
<!-- 技术规格徽章 -->
|
39
|
+
[](https://www.python.org/)
|
40
|
+
[](LICENSE)
|
41
|
+
[](https://github.com/donghao1393/mcp-dbutils/stargazers)
|
42
|
+
|
43
|
+
[中文文档](README_CN.md) | [Technical Guide](docs/technical-guide.md)
|
44
|
+
|
45
|
+
## What is MCP Database Utilities?
|
46
|
+
|
47
|
+
MCP Database Utilities is an all-in-one MCP service that enables your AI to do data analysis by accessing versatile types of database (SQLite, MySQL, PostgreSQL, and more) within a unified connection configuration in a safe way.
|
48
|
+
|
49
|
+
Think of it as a secure bridge between AI systems and your databases, allowing AI to read and analyze your data without direct database access or risking data modifications.
|
50
|
+
|
51
|
+
## Security and Privacy: Our Top Priority
|
52
|
+
|
53
|
+
MCP Database Utilities is built with a **security-first architecture**, making it ideal for businesses, startups, and individuals who value data protection. Our comprehensive security measures include:
|
54
|
+
|
55
|
+
### Data Protection
|
56
|
+
|
57
|
+
- **Strictly Read-Only**: All operations are limited to SELECT queries only - data cannot be modified
|
58
|
+
- **No Direct Database Access**: AI interacts with your database through our secure service, never directly
|
59
|
+
- **Isolated Connections**: Each database connection is managed separately and strictly isolated
|
60
|
+
- **On-Demand Connectivity**: Connects only when needed and disconnects immediately after task completion
|
61
|
+
- **Automatic Timeouts**: Long-running operations are automatically terminated to prevent resource abuse
|
62
|
+
|
63
|
+
### Privacy Safeguards
|
64
|
+
|
65
|
+
- **Local Processing**: All data processing occurs on your local machine - no data sent to external servers
|
66
|
+
- **Minimal Data Exposure**: Only requested data is returned, limiting exposure scope
|
67
|
+
- **Credential Protection**: Connection credentials are never exposed to the AI model
|
68
|
+
- **Sensitive Data Masking**: Passwords and connection details are automatically hidden in logs
|
69
|
+
|
70
|
+
### Enterprise-Ready Security
|
71
|
+
|
72
|
+
- **SSL/TLS Support**: Encrypted connections to remote databases
|
73
|
+
- **Configuration Separation**: YAML configuration files eliminate interpretation risks
|
74
|
+
- **User-Controlled Access**: You decide which databases are accessible
|
75
|
+
- **Secure Default Settings**: Secure by default with no additional configuration needed
|
76
|
+
|
77
|
+
For technical details about our security architecture, see the [Technical Guide](docs/technical-guide.md#通信模式与安全架构).
|
78
|
+
|
79
|
+
## Why Use MCP Database Utilities?
|
80
|
+
|
81
|
+
- **Universal AI Support**: Works with any AI system that supports the MCP protocol
|
82
|
+
- **Multiple Database Support**: Connect to SQLite, MySQL, PostgreSQL with the same interface
|
83
|
+
- **Simple Configuration**: Single YAML file for all your database connections
|
84
|
+
- **Advanced Capabilities**: Table exploration, schema analysis, and query execution
|
85
|
+
|
86
|
+
## System Requirements
|
87
|
+
|
88
|
+
- Python 3.10 or higher
|
89
|
+
- One of the following:
|
90
|
+
- **For uvx installation**: uv package manager
|
91
|
+
- **For Docker installation**: Docker Desktop
|
92
|
+
- **For Smithery installation**: Node.js 14+
|
93
|
+
- Supported databases:
|
94
|
+
- SQLite 3.x
|
95
|
+
- PostgreSQL 12+
|
96
|
+
- MySQL 8+
|
97
|
+
- Supported AI clients:
|
98
|
+
- Claude Desktop
|
99
|
+
- Cursor
|
100
|
+
- Any MCP-compatible client
|
101
|
+
|
102
|
+
## Getting Started
|
103
|
+
|
104
|
+
### 1. Installation Guide
|
105
|
+
|
106
|
+
Choose **ONE** of the following methods to install:
|
107
|
+
|
108
|
+
#### Option A: Using uvx (Recommended)
|
109
|
+
|
110
|
+
This method uses `uvx`, which is part of the Python package manager tool called "uv". Here's how to set it up:
|
111
|
+
|
112
|
+
1. **Install uv and uvx first:**
|
113
|
+
|
114
|
+
**On macOS or Linux:**
|
115
|
+
```bash
|
116
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
117
|
+
```
|
118
|
+
|
119
|
+
**On Windows:**
|
120
|
+
```powershell
|
121
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
122
|
+
```
|
123
|
+
|
124
|
+
After installation, verify that uv is installed correctly:
|
125
|
+
```bash
|
126
|
+
uv --version
|
127
|
+
# Should display something like: uv 0.5.5 (Homebrew 2024-11-27)
|
128
|
+
```
|
129
|
+
|
130
|
+
2. **Create a configuration file** named `config.yaml` with your database connection details:
|
131
|
+
|
132
|
+
```yaml
|
133
|
+
connections:
|
134
|
+
my-sqlite:
|
135
|
+
type: sqlite
|
136
|
+
path: /path/to/my-database.db
|
137
|
+
|
138
|
+
my-postgres:
|
139
|
+
type: postgres
|
140
|
+
host: localhost
|
141
|
+
port: 5432
|
142
|
+
dbname: my_database
|
143
|
+
user: my_user
|
144
|
+
password: my_password
|
145
|
+
```
|
146
|
+
|
147
|
+
> For advanced configuration options (SSL connections, connection pooling, etc.),
|
148
|
+
> please refer to the [Configuration System Details](docs/technical-guide.md#configuration-system-details) section in our technical guide.
|
149
|
+
|
150
|
+
3. **Add this configuration to your AI client:**
|
151
|
+
|
152
|
+
**For JSON-based MCP clients:**
|
153
|
+
- Locate and edit your client's MCP configuration file:
|
154
|
+
- **Claude Desktop (Mac)**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
155
|
+
- **Cline (Mac)**: `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
|
156
|
+
- **Other clients**: Refer to your client's documentation for the MCP configuration file location
|
157
|
+
- Add the following configuration to the JSON file:
|
158
|
+
|
159
|
+
```json
|
160
|
+
"dbutils": {
|
161
|
+
"command": "uvx",
|
162
|
+
"args": [
|
163
|
+
"mcp-dbutils",
|
164
|
+
"--config",
|
165
|
+
"/full/path/to/your/config.yaml"
|
166
|
+
]
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
170
|
+
**For Cursor:**
|
171
|
+
- Open Cursor
|
172
|
+
- Go to Settings → MCP
|
173
|
+
- Click "Add MCP Server" and fill in:
|
174
|
+
- Name: `Database Utility MCP`
|
175
|
+
- Type: `Command` (default)
|
176
|
+
- Command: `uvx mcp-dbutils --config /full/path/to/your/config.yaml`
|
177
|
+
|
178
|
+
> **Important Notes for uvx Setup:**
|
179
|
+
> - Replace `/full/path/to/your/config.yaml` with the actual full path to your config file
|
180
|
+
> - If you get an error about uvx not being found, make sure step 1 was completed successfully
|
181
|
+
> - You can verify uvx is installed by typing `uvx --version` in your terminal
|
182
|
+
|
183
|
+
#### Option B: Manual Installation with Docker
|
184
|
+
|
185
|
+
1. Install Docker from [docker.com](https://www.docker.com/products/docker-desktop/) if you don't have it
|
186
|
+
|
187
|
+
2. Create a configuration file (see next section for details)
|
188
|
+
|
189
|
+
3. Add this configuration to your AI client:
|
190
|
+
|
191
|
+
**For JSON-based MCP clients:**
|
192
|
+
- Locate and edit your client's MCP configuration file:
|
193
|
+
- **Claude Desktop (Mac)**: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
194
|
+
- **Cline (Mac)**: `~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json`
|
195
|
+
- **Other clients**: Refer to your client's documentation for the MCP configuration file location
|
196
|
+
- Add the following configuration to the JSON file:
|
197
|
+
|
198
|
+
```json
|
199
|
+
"dbutils": {
|
200
|
+
"command": "docker",
|
201
|
+
"args": [
|
202
|
+
"run",
|
203
|
+
"-i",
|
204
|
+
"--rm",
|
205
|
+
"-v",
|
206
|
+
"/full/path/to/your/config.yaml:/app/config.yaml",
|
207
|
+
"-v",
|
208
|
+
"/full/path/to/your/sqlite.db:/app/sqlite.db", // Only needed for SQLite
|
209
|
+
"mcp/dbutils",
|
210
|
+
"--config",
|
211
|
+
"/app/config.yaml"
|
212
|
+
]
|
213
|
+
}
|
214
|
+
```
|
215
|
+
|
216
|
+
**For Cursor:**
|
217
|
+
- Open Cursor
|
218
|
+
- Go to Settings → MCP
|
219
|
+
- Click "Add MCP Server" and fill in:
|
220
|
+
- Name: `Database Utility MCP`
|
221
|
+
- Type: `Command` (default)
|
222
|
+
- Command: `docker run -i --rm -v /full/path/to/your/config.yaml:/app/config.yaml -v /full/path/to/your/sqlite.db:/app/sqlite.db mcp/dbutils --config /app/config.yaml`
|
223
|
+
|
224
|
+
> **Important Notes for Docker:**
|
225
|
+
> - Replace `/full/path/to/your/config.yaml` with the actual full path to your config file
|
226
|
+
> - For SQLite databases, also replace the sqlite.db path with your actual database path
|
227
|
+
> - For other database types, remove the SQLite volume line entirely
|
228
|
+
|
229
|
+
#### Option C: Using Smithery (One-Click for Claude)
|
230
|
+
|
231
|
+
This method automatically installs AND configures the service for Claude:
|
232
|
+
|
233
|
+
```bash
|
234
|
+
npx -y @smithery/cli install @donghao1393/mcp-dbutils --client claude
|
235
|
+
```
|
236
|
+
|
237
|
+
After installation completes, skip to the "Using the Service" section.
|
238
|
+
|
239
|
+
### 4. Using the Service
|
240
|
+
|
241
|
+
Once installed and configured properly, your AI can now:
|
242
|
+
- List tables in your database
|
243
|
+
- View table structures
|
244
|
+
- Execute SQL queries safely
|
245
|
+
- Analyze data across multiple databases
|
246
|
+
|
247
|
+
**To verify everything is working:**
|
248
|
+
|
249
|
+
1. Ask your AI something like: "Can you check if you're able to connect to my database?"
|
250
|
+
2. If properly configured, the AI should reply that it can connect to the database specified in your config file
|
251
|
+
3. Try a simple command like: "List the tables in my database"
|
252
|
+
|
253
|
+
If you encounter any issues, check:
|
254
|
+
- Your configuration file syntax is correct
|
255
|
+
- The database connection details are accurate
|
256
|
+
- Your AI client has the MCP server properly configured
|
257
|
+
- Your database is accessible from your computer
|
258
|
+
|
259
|
+
## Example Interactions
|
260
|
+
|
261
|
+
**You**: "Can you list all the tables in my my-postgres database?"
|
262
|
+
|
263
|
+
**AI**: "I'll check that for you. Here are the tables in your my-postgres database:
|
264
|
+
- customers
|
265
|
+
- products
|
266
|
+
- orders
|
267
|
+
- inventory
|
268
|
+
- employees"
|
269
|
+
|
270
|
+
**You**: "What does the customers table look like?"
|
271
|
+
|
272
|
+
**AI**: "The customers table has the following structure:
|
273
|
+
- id (integer, primary key)
|
274
|
+
- name (text)
|
275
|
+
- email (text)
|
276
|
+
- registration_date (date)
|
277
|
+
- last_purchase (date)
|
278
|
+
- total_spent (numeric)"
|
279
|
+
|
280
|
+
**You**: "How many customers made purchases in the last month?"
|
281
|
+
|
282
|
+
**AI**: "Let me run a query to find out... According to the data, 128 customers made purchases in the last month. The total value of these purchases was $25,437.82."
|
283
|
+
|
284
|
+
## Available Tools
|
285
|
+
|
286
|
+
MCP Database Utilities provides several tools that your AI can use:
|
287
|
+
|
288
|
+
- **dbutils-list-tables**: Lists all tables in a database
|
289
|
+
- **dbutils-run-query**: Executes a SQL query (SELECT only)
|
290
|
+
- **dbutils-get-stats**: Gets statistics about a table
|
291
|
+
- **dbutils-list-constraints**: Lists table constraints
|
292
|
+
- **dbutils-explain-query**: Gets query execution plan
|
293
|
+
- **dbutils-get-performance**: Gets database performance metrics
|
294
|
+
- **dbutils-analyze-query**: Analyzes queries for optimization
|
295
|
+
|
296
|
+
## Need More Help?
|
297
|
+
|
298
|
+
- [Technical Documentation](docs/technical-guide.md) - For developers and advanced users
|
299
|
+
- [GitHub Issues](https://github.com/donghao1393/mcp-dbutils/issues) - Report bugs or request features
|
300
|
+
- [Smithery](https://smithery.ai/server/@donghao1393/mcp-dbutils) - Simplified installation and updates
|
301
|
+
|
302
|
+
## Star History
|
303
|
+
|
304
|
+
[](https://star-history.com/#donghao1393/mcp-dbutils&Date)
|
305
|
+
|
306
|
+
## License
|
307
|
+
|
308
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
@@ -5,7 +5,7 @@ mcp_dbutils/log.py,sha256=mqxi6I_IL-MF1F_pxBtnYZQKOHbGBJ74gsvZHVelr1w,823
|
|
5
5
|
mcp_dbutils/stats.py,sha256=wMqWPfGnEOg9v5YBtTsARV-1YsFUMM_pKdzitzSU9x4,7137
|
6
6
|
mcp_dbutils/mysql/__init__.py,sha256=gNhoHaxK1qhvMAH5AVl1vfV1rUpcbV9KZWUQb41aaQk,129
|
7
7
|
mcp_dbutils/mysql/config.py,sha256=BTPPFqlhoTp7EBFIeLJZh8x6bCn3q9NivHYz9yZHziw,9820
|
8
|
-
mcp_dbutils/mysql/handler.py,sha256=
|
8
|
+
mcp_dbutils/mysql/handler.py,sha256=fVmOq49ZDsB24NOkHCMu5e4WwMFEV8hBkElkNA8FFJo,21962
|
9
9
|
mcp_dbutils/mysql/server.py,sha256=1bWAu7qHYXVeTZu4wdEpS6gSVB0RoXKI3Smy_ix-y8A,8586
|
10
10
|
mcp_dbutils/postgres/__init__.py,sha256=-2zYuEJEQ2AMvmGhH5Z_umerSvt7S4xOa_XV4wgvGfI,154
|
11
11
|
mcp_dbutils/postgres/config.py,sha256=NyQOVhkXJ1S-JD0w-ePNjTKI1Ja-aZQkDUdHi6U7Vl4,7752
|
@@ -13,10 +13,10 @@ mcp_dbutils/postgres/handler.py,sha256=ppltSKtSk-BlPpp3iEVJlmoyl4AmqKcQHx_0zHlz0
|
|
13
13
|
mcp_dbutils/postgres/server.py,sha256=_CiJC9PitpI1NB99Q1Bcs5TYADNgDpYMwv88fRHQunE,8640
|
14
14
|
mcp_dbutils/sqlite/__init__.py,sha256=fK_3-WylCBYpBAzwuopi8hlwoIGJm2TPAlwcPWG46I0,134
|
15
15
|
mcp_dbutils/sqlite/config.py,sha256=j67TJ8mQJ2D886MthSa-zYMtvUUYyyxYLMlNxkYoqZE,4509
|
16
|
-
mcp_dbutils/sqlite/handler.py,sha256=
|
16
|
+
mcp_dbutils/sqlite/handler.py,sha256=iojyVhr_cgNOATKESXdSFYV58mdZQhywwDQVd4jXtvM,19740
|
17
17
|
mcp_dbutils/sqlite/server.py,sha256=jqpE8d9vJETMs5xYGB7P0tvNDPes6Yn5ZM_iCCF7Tv4,7181
|
18
|
-
mcp_dbutils-0.
|
19
|
-
mcp_dbutils-0.
|
20
|
-
mcp_dbutils-0.
|
21
|
-
mcp_dbutils-0.
|
22
|
-
mcp_dbutils-0.
|
18
|
+
mcp_dbutils-0.17.0.dist-info/METADATA,sha256=ZuJS8qq9D-Ru7TpXq18fQeTCB83hif0qR6luEMaAi1M,12075
|
19
|
+
mcp_dbutils-0.17.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
20
|
+
mcp_dbutils-0.17.0.dist-info/entry_points.txt,sha256=XTjt0QmYRgKOJQT6skR9bp1EMUfIrgpHeZJPZ3CJffs,49
|
21
|
+
mcp_dbutils-0.17.0.dist-info/licenses/LICENSE,sha256=1A_CwpWVlbjrKdVEYO77vYfnXlW7oxcilZ8FpA_BzCI,1065
|
22
|
+
mcp_dbutils-0.17.0.dist-info/RECORD,,
|
@@ -1,572 +0,0 @@
|
|
1
|
-
Metadata-Version: 2.4
|
2
|
-
Name: mcp-dbutils
|
3
|
-
Version: 0.16.1
|
4
|
-
Summary: MCP Database Utilities Service
|
5
|
-
Author: Dong Hao
|
6
|
-
License-Expression: MIT
|
7
|
-
License-File: LICENSE
|
8
|
-
Requires-Python: >=3.10
|
9
|
-
Requires-Dist: mcp>=1.2.1
|
10
|
-
Requires-Dist: mysql-connector-python>=8.2.0
|
11
|
-
Requires-Dist: psycopg2-binary>=2.9.10
|
12
|
-
Requires-Dist: python-dotenv>=1.0.1
|
13
|
-
Requires-Dist: pyyaml>=6.0.2
|
14
|
-
Provides-Extra: test
|
15
|
-
Requires-Dist: aiosqlite>=0.19.0; extra == 'test'
|
16
|
-
Requires-Dist: docker>=7.0.0; extra == 'test'
|
17
|
-
Requires-Dist: pre-commit>=3.6.0; extra == 'test'
|
18
|
-
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
|
19
|
-
Requires-Dist: pytest-cov>=4.1.0; extra == 'test'
|
20
|
-
Requires-Dist: pytest-docker>=2.0.0; extra == 'test'
|
21
|
-
Requires-Dist: pytest>=7.0.0; extra == 'test'
|
22
|
-
Requires-Dist: ruff>=0.3.0; extra == 'test'
|
23
|
-
Requires-Dist: testcontainers>=3.7.0; extra == 'test'
|
24
|
-
Description-Content-Type: text/markdown
|
25
|
-
|
26
|
-
# MCP Database Utilities
|
27
|
-
|
28
|
-

|
29
|
-

|
30
|
-
[](https://github.com/donghao1393/mcp-dbutils/actions)
|
31
|
-

|
32
|
-

|
33
|
-
[](https://smithery.ai/server/@donghao1393/mcp-dbutils)
|
34
|
-
|
35
|
-
[中文文档](README_CN.md)
|
36
|
-
|
37
|
-
## Overview
|
38
|
-
MCP Database Utilities is a unified database access service that supports multiple database types (PostgreSQL, SQLite, and MySQL). Through its abstraction layer design, it provides a simple and unified database operation interface for MCP servers.
|
39
|
-
|
40
|
-
## Features
|
41
|
-
- Unified database access interface
|
42
|
-
- Support for multiple database configurations
|
43
|
-
- Secure read-only query execution
|
44
|
-
- Table structure and schema information retrieval
|
45
|
-
- Database tables listing via MCP tools
|
46
|
-
- Intelligent connection management and resource cleanup
|
47
|
-
- Debug mode support
|
48
|
-
- SSL/TLS connection support for PostgreSQL and MySQL
|
49
|
-
|
50
|
-
## Installation and Configuration
|
51
|
-
|
52
|
-
### Installation Methods
|
53
|
-
#### Installing via Smithery
|
54
|
-
|
55
|
-
To install Database Utilities for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@donghao1393/mcp-dbutils):
|
56
|
-
|
57
|
-
```bash
|
58
|
-
npx -y @smithery/cli install @donghao1393/mcp-dbutils --client claude
|
59
|
-
```
|
60
|
-
|
61
|
-
#### Using uvx (Recommended)
|
62
|
-
No installation required, run directly using `uvx`:
|
63
|
-
```bash
|
64
|
-
uvx mcp-dbutils --config /path/to/config.yaml
|
65
|
-
```
|
66
|
-
|
67
|
-
Add to Claude configuration:
|
68
|
-
```json
|
69
|
-
"mcpServers": {
|
70
|
-
"dbutils": {
|
71
|
-
"command": "uvx",
|
72
|
-
"args": [
|
73
|
-
"mcp-dbutils",
|
74
|
-
"--config",
|
75
|
-
"/path/to/config.yaml"
|
76
|
-
],
|
77
|
-
"env": {
|
78
|
-
"MCP_DEBUG": "1" // Optional: Enable debug mode
|
79
|
-
}
|
80
|
-
}
|
81
|
-
}
|
82
|
-
```
|
83
|
-
|
84
|
-
#### Using pip
|
85
|
-
```bash
|
86
|
-
pip install mcp-dbutils
|
87
|
-
```
|
88
|
-
|
89
|
-
Add to Claude configuration:
|
90
|
-
```json
|
91
|
-
"mcpServers": {
|
92
|
-
"dbutils": {
|
93
|
-
"command": "python",
|
94
|
-
"args": [
|
95
|
-
"-m",
|
96
|
-
"mcp_dbutils",
|
97
|
-
"--config",
|
98
|
-
"/path/to/config.yaml"
|
99
|
-
],
|
100
|
-
"env": {
|
101
|
-
"MCP_DEBUG": "1" // Optional: Enable debug mode
|
102
|
-
}
|
103
|
-
}
|
104
|
-
}
|
105
|
-
```
|
106
|
-
|
107
|
-
#### Using Docker
|
108
|
-
```bash
|
109
|
-
docker run -i --rm \
|
110
|
-
-v /path/to/config.yaml:/app/config.yaml \
|
111
|
-
-v /path/to/sqlite.db:/app/sqlite.db \ # Optional: for SQLite database
|
112
|
-
-e MCP_DEBUG=1 \ # Optional: Enable debug mode
|
113
|
-
mcp/dbutils --config /app/config.yaml
|
114
|
-
```
|
115
|
-
|
116
|
-
Add to Claude configuration:
|
117
|
-
```json
|
118
|
-
"mcpServers": {
|
119
|
-
"dbutils": {
|
120
|
-
"command": "docker",
|
121
|
-
"args": [
|
122
|
-
"run",
|
123
|
-
"-i",
|
124
|
-
"--rm",
|
125
|
-
"-v",
|
126
|
-
"/path/to/config.yaml:/app/config.yaml",
|
127
|
-
"-v",
|
128
|
-
"/path/to/sqlite.db:/app/sqlite.db", // Optional: for SQLite database
|
129
|
-
"mcp/dbutils",
|
130
|
-
"--config",
|
131
|
-
"/app/config.yaml"
|
132
|
-
],
|
133
|
-
"env": {
|
134
|
-
"MCP_DEBUG": "1" // Optional: Enable debug mode
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
138
|
-
```
|
139
|
-
|
140
|
-
> **Note for Docker database connections:**
|
141
|
-
> - For SQLite: Mount your database file using `-v /path/to/sqlite.db:/app/sqlite.db`
|
142
|
-
> - For PostgreSQL running on host:
|
143
|
-
> - On Mac/Windows: Use `host.docker.internal` as host in config
|
144
|
-
> - On Linux: Use `172.17.0.1` (docker0 IP) or run with `--network="host"`
|
145
|
-
|
146
|
-
### Requirements
|
147
|
-
- Python 3.10+
|
148
|
-
- PostgreSQL (optional)
|
149
|
-
- SQLite3 (optional)
|
150
|
-
- MySQL (optional)
|
151
|
-
|
152
|
-
### Configuration File
|
153
|
-
The project requires a YAML configuration file, specified via the `--config` parameter. Configuration examples:
|
154
|
-
|
155
|
-
```yaml
|
156
|
-
connections:
|
157
|
-
# SQLite configuration examples
|
158
|
-
dev-db:
|
159
|
-
type: sqlite
|
160
|
-
path: /path/to/dev.db
|
161
|
-
# Password is optional
|
162
|
-
password:
|
163
|
-
|
164
|
-
# PostgreSQL standard configuration
|
165
|
-
test-db:
|
166
|
-
type: postgres
|
167
|
-
host: postgres.example.com
|
168
|
-
port: 5432
|
169
|
-
dbname: test_db
|
170
|
-
user: test_user
|
171
|
-
password: test_pass
|
172
|
-
|
173
|
-
# PostgreSQL URL configuration with SSL
|
174
|
-
prod-db:
|
175
|
-
type: postgres
|
176
|
-
url: postgresql://postgres.example.com:5432/prod-db?sslmode=verify-full
|
177
|
-
user: prod_user
|
178
|
-
password: prod_pass
|
179
|
-
|
180
|
-
# PostgreSQL full SSL configuration example
|
181
|
-
secure-db:
|
182
|
-
type: postgres
|
183
|
-
host: secure-db.example.com
|
184
|
-
port: 5432
|
185
|
-
dbname: secure_db
|
186
|
-
user: secure_user
|
187
|
-
password: secure_pass
|
188
|
-
ssl:
|
189
|
-
mode: verify-full # disable/require/verify-ca/verify-full
|
190
|
-
cert: /path/to/client-cert.pem
|
191
|
-
key: /path/to/client-key.pem
|
192
|
-
root: /path/to/root.crt
|
193
|
-
|
194
|
-
# MySQL standard configuration
|
195
|
-
sandbox-mysql:
|
196
|
-
type: mysql
|
197
|
-
host: localhost
|
198
|
-
port: 3306
|
199
|
-
database: sandbox_db
|
200
|
-
user: sandbox_user
|
201
|
-
password: sandbox_pass
|
202
|
-
charset: utf8mb4
|
203
|
-
|
204
|
-
# MySQL URL configuration
|
205
|
-
integration-mysql:
|
206
|
-
type: mysql
|
207
|
-
url: mysql://mysql.example.com:3306/integration_db?charset=utf8mb4
|
208
|
-
user: integration_user
|
209
|
-
password: integration_pass
|
210
|
-
|
211
|
-
# MySQL with SSL configuration
|
212
|
-
secure-mysql:
|
213
|
-
type: mysql
|
214
|
-
host: secure-mysql.example.com
|
215
|
-
port: 3306
|
216
|
-
database: secure_db
|
217
|
-
user: secure_user
|
218
|
-
password: secure_pass
|
219
|
-
charset: utf8mb4
|
220
|
-
ssl:
|
221
|
-
mode: verify_identity
|
222
|
-
ca: /path/to/ca.pem
|
223
|
-
cert: /path/to/client-cert.pem
|
224
|
-
key: /path/to/client-key.pem
|
225
|
-
```
|
226
|
-
|
227
|
-
Database SSL Configuration Options:
|
228
|
-
|
229
|
-
PostgreSQL SSL Configuration:
|
230
|
-
1. Using URL parameters:
|
231
|
-
```
|
232
|
-
postgresql://host:port/dbname?sslmode=verify-full&sslcert=/path/to/cert.pem
|
233
|
-
```
|
234
|
-
2. Using dedicated SSL configuration section:
|
235
|
-
```yaml
|
236
|
-
ssl:
|
237
|
-
mode: verify-full # SSL verification mode
|
238
|
-
cert: /path/to/cert.pem # Client certificate
|
239
|
-
key: /path/to/key.pem # Client private key
|
240
|
-
root: /path/to/root.crt # CA certificate
|
241
|
-
```
|
242
|
-
|
243
|
-
PostgreSQL SSL Modes:
|
244
|
-
- disable: No SSL
|
245
|
-
- require: Use SSL but no certificate verification
|
246
|
-
- verify-ca: Verify server certificate is signed by trusted CA
|
247
|
-
- verify-full: Verify server certificate and hostname match
|
248
|
-
|
249
|
-
MySQL SSL Configuration:
|
250
|
-
1. Using URL parameters:
|
251
|
-
```
|
252
|
-
mysql://host:port/dbname?ssl-mode=verify_identity&ssl-ca=/path/to/ca.pem
|
253
|
-
```
|
254
|
-
2. Using dedicated SSL configuration section:
|
255
|
-
```yaml
|
256
|
-
ssl:
|
257
|
-
mode: verify_identity # SSL verification mode
|
258
|
-
ca: /path/to/ca.pem # CA certificate
|
259
|
-
cert: /path/to/cert.pem # Client certificate
|
260
|
-
key: /path/to/key.pem # Client private key
|
261
|
-
```
|
262
|
-
|
263
|
-
MySQL SSL Modes:
|
264
|
-
- disabled: No SSL
|
265
|
-
- preferred: Use SSL if available, but allow unencrypted connection
|
266
|
-
- required: Always use SSL, but don't verify server certificate
|
267
|
-
- verify_ca: Verify server certificate is signed by trusted CA
|
268
|
-
- verify_identity: Verify server certificate and hostname match
|
269
|
-
|
270
|
-
SQLite Configuration Options:
|
271
|
-
1. Basic configuration with path:
|
272
|
-
```yaml
|
273
|
-
type: sqlite
|
274
|
-
path: /path/to/db.sqlite
|
275
|
-
password: optional_password # Optional encryption
|
276
|
-
```
|
277
|
-
2. Using URI parameters:
|
278
|
-
```yaml
|
279
|
-
type: sqlite
|
280
|
-
path: /path/to/db.sqlite?mode=ro&cache=shared
|
281
|
-
```
|
282
|
-
|
283
|
-
### Debug Mode
|
284
|
-
Set environment variable `MCP_DEBUG=1` to enable debug mode for detailed logging output.
|
285
|
-
|
286
|
-
## Architecture Design
|
287
|
-
|
288
|
-
### Core Concept: Abstraction Layer
|
289
|
-
|
290
|
-
```mermaid
|
291
|
-
graph TD
|
292
|
-
Client[Client] --> DatabaseServer[Database Server]
|
293
|
-
subgraph MCP Server
|
294
|
-
DatabaseServer
|
295
|
-
DatabaseHandler[Database Handler]
|
296
|
-
PostgresHandler[PostgreSQL Handler]
|
297
|
-
SQLiteHandler[SQLite Handler]
|
298
|
-
MySQLHandler[MySQL Handler]
|
299
|
-
DatabaseServer --> DatabaseHandler
|
300
|
-
DatabaseHandler --> PostgresHandler
|
301
|
-
DatabaseHandler --> SQLiteHandler
|
302
|
-
DatabaseHandler --> MySQLHandler
|
303
|
-
end
|
304
|
-
PostgresHandler --> PostgreSQL[(PostgreSQL)]
|
305
|
-
SQLiteHandler --> SQLite[(SQLite)]
|
306
|
-
MySQLHandler --> MySQL[(MySQL)]
|
307
|
-
```
|
308
|
-
|
309
|
-
The abstraction layer design is the core architectural concept in MCP Database Utilities. Just like a universal remote control that works with different devices, users only need to know the basic operations without understanding the underlying complexities.
|
310
|
-
|
311
|
-
#### 1. Simplified User Interaction
|
312
|
-
- Users only need to know the database configuration name (e.g., "my_postgres")
|
313
|
-
- No need to deal with connection parameters and implementation details
|
314
|
-
- MCP server automatically handles database connections and queries
|
315
|
-
|
316
|
-
#### 2. Unified Interface Design
|
317
|
-
- DatabaseHandler abstract class defines unified operation interfaces
|
318
|
-
- All specific database implementations (PostgreSQL/SQLite/MySQL) follow the same interface
|
319
|
-
- Users interact with different databases in the same way
|
320
|
-
|
321
|
-
#### 3. Configuration and Implementation Separation
|
322
|
-
- Complex database configuration parameters are encapsulated in configuration files
|
323
|
-
- Runtime access through simple database names
|
324
|
-
- Easy management and modification of database configurations without affecting business code
|
325
|
-
|
326
|
-
### System Components
|
327
|
-
1. DatabaseServer
|
328
|
-
- Core component of the MCP server
|
329
|
-
- Handles resource and tool requests
|
330
|
-
- Manages database connection lifecycle
|
331
|
-
|
332
|
-
2. DatabaseHandler
|
333
|
-
- Abstract base class defining unified interface
|
334
|
-
- Includes get_tables(), get_schema(), execute_query(), etc.
|
335
|
-
- Implemented by PostgreSQL, SQLite, and MySQL handlers
|
336
|
-
|
337
|
-
3. Configuration System
|
338
|
-
- YAML-based configuration file
|
339
|
-
- Support for multiple database configurations
|
340
|
-
- Type-safe configuration validation
|
341
|
-
|
342
|
-
4. Error Handling and Logging
|
343
|
-
- Unified error handling mechanism
|
344
|
-
- Detailed logging output
|
345
|
-
- Sensitive information masking
|
346
|
-
|
347
|
-
## Usage Examples
|
348
|
-
|
349
|
-
### Basic Query
|
350
|
-
```python
|
351
|
-
# Access through connection name
|
352
|
-
async with server.get_handler("my_postgres") as handler:
|
353
|
-
# Execute SQL query
|
354
|
-
result = await handler.execute_query("SELECT * FROM users")
|
355
|
-
```
|
356
|
-
|
357
|
-
### View Table Structure
|
358
|
-
```python
|
359
|
-
# Get all tables
|
360
|
-
tables = await handler.get_tables()
|
361
|
-
|
362
|
-
# Get specific table schema
|
363
|
-
schema = await handler.get_schema("users")
|
364
|
-
```
|
365
|
-
|
366
|
-
### Error Handling
|
367
|
-
```python
|
368
|
-
try:
|
369
|
-
async with server.get_handler("my_connection") as handler:
|
370
|
-
result = await handler.execute_query("SELECT * FROM users")
|
371
|
-
except ValueError as e:
|
372
|
-
print(f"Configuration error: {e}")
|
373
|
-
except Exception as e:
|
374
|
-
print(f"Query error: {e}")
|
375
|
-
```
|
376
|
-
|
377
|
-
## Security Notes
|
378
|
-
- Supports SELECT queries only to protect database security
|
379
|
-
- Automatically masks sensitive information (like passwords) in logs
|
380
|
-
- Executes queries in read-only transactions
|
381
|
-
|
382
|
-
## API Documentation
|
383
|
-
|
384
|
-
### DatabaseServer
|
385
|
-
Core server class providing:
|
386
|
-
- Resource list retrieval
|
387
|
-
- Tool call handling (list_tables, query)
|
388
|
-
- Database handler management
|
389
|
-
|
390
|
-
### MCP Tools
|
391
|
-
|
392
|
-
#### dbutils-list-tables
|
393
|
-
Lists all tables in the specified database.
|
394
|
-
- Parameters:
|
395
|
-
* connection: Database connection name
|
396
|
-
- Returns: Text content with a list of table names
|
397
|
-
|
398
|
-
#### dbutils-run-query
|
399
|
-
Executes a SQL query on the specified database.
|
400
|
-
- Parameters:
|
401
|
-
* connection: Database connection name
|
402
|
-
* sql: SQL query to execute (SELECT only)
|
403
|
-
- Returns: Query results in a formatted text
|
404
|
-
|
405
|
-
#### dbutils-get-stats
|
406
|
-
Get table statistics information.
|
407
|
-
- Parameters:
|
408
|
-
* connection: Database connection name
|
409
|
-
* table: Table name
|
410
|
-
- Returns: Statistics including row count, size, column stats
|
411
|
-
|
412
|
-
#### dbutils-list-constraints
|
413
|
-
List table constraints (primary key, foreign keys, etc).
|
414
|
-
- Parameters:
|
415
|
-
* connection: Database connection name
|
416
|
-
* table: Table name
|
417
|
-
- Returns: Detailed constraint information
|
418
|
-
|
419
|
-
#### dbutils-explain-query
|
420
|
-
Get query execution plan with cost estimates.
|
421
|
-
- Parameters:
|
422
|
-
* connection: Database connection name
|
423
|
-
* sql: SQL query to explain
|
424
|
-
- Returns: Formatted execution plan
|
425
|
-
|
426
|
-
#### dbutils-get-performance
|
427
|
-
Get database performance statistics.
|
428
|
-
- Parameters:
|
429
|
-
* connection: Database connection name
|
430
|
-
- Returns: Detailed performance statistics including query times, query types, error rates, and resource usage
|
431
|
-
|
432
|
-
#### dbutils-analyze-query
|
433
|
-
Analyze a SQL query for performance and provide optimization suggestions.
|
434
|
-
- Parameters:
|
435
|
-
* connection: Database connection name
|
436
|
-
* sql: SQL query to analyze
|
437
|
-
- Returns: Query analysis with execution plan, timing information, and optimization suggestions
|
438
|
-
|
439
|
-
### DatabaseHandler
|
440
|
-
Abstract base class defining interfaces:
|
441
|
-
- get_tables(): Get table resource list
|
442
|
-
- get_schema(): Get table structure
|
443
|
-
- execute_query(): Execute SQL query
|
444
|
-
- cleanup(): Resource cleanup
|
445
|
-
|
446
|
-
### PostgreSQL Implementation
|
447
|
-
Provides PostgreSQL-specific features:
|
448
|
-
- Remote connection support
|
449
|
-
- Table description information
|
450
|
-
- Constraint queries
|
451
|
-
|
452
|
-
### SQLite Implementation
|
453
|
-
Provides SQLite-specific features:
|
454
|
-
- File path handling
|
455
|
-
- URI scheme support
|
456
|
-
- Password protection support (optional)
|
457
|
-
|
458
|
-
### MySQL Implementation
|
459
|
-
Provides MySQL-specific features:
|
460
|
-
- Remote connection support
|
461
|
-
- Character set configuration
|
462
|
-
- SSL/TLS secure connection
|
463
|
-
- URL and standard connection methods
|
464
|
-
|
465
|
-
## Code Quality
|
466
|
-
|
467
|
-
### Quality Gates
|
468
|
-
We use SonarCloud to maintain high code quality standards. All pull requests must pass the following quality gates:
|
469
|
-
|
470
|
-
- Code Coverage: ≥ 80%
|
471
|
-
- Code Quality:
|
472
|
-
* No blocker or critical issues
|
473
|
-
* Less than 10 major issues
|
474
|
-
* Code duplication < 3%
|
475
|
-
- Security:
|
476
|
-
* No security vulnerabilities
|
477
|
-
* No security hotspots
|
478
|
-
|
479
|
-
### Automated Checks
|
480
|
-
Our CI/CD pipeline automatically performs:
|
481
|
-
1. Full test suite execution
|
482
|
-
2. Code coverage analysis
|
483
|
-
3. SonarCloud static code analysis
|
484
|
-
4. Quality gate validation
|
485
|
-
|
486
|
-
Pull requests that don't meet these standards will be automatically blocked from merging.
|
487
|
-
|
488
|
-
### Code Style
|
489
|
-
We use Ruff for code style checking and formatting:
|
490
|
-
|
491
|
-
[](https://github.com/astral-sh/ruff)
|
492
|
-
|
493
|
-
All code must follow our style guide:
|
494
|
-
- Line length: 88 characters
|
495
|
-
- Indentation: 4 spaces
|
496
|
-
- Quotes: Double quotes
|
497
|
-
- Naming: PEP8 conventions
|
498
|
-
|
499
|
-
For detailed guidelines, see [STYLE_GUIDE.md](docs/STYLE_GUIDE.md).
|
500
|
-
|
501
|
-
### Local Development
|
502
|
-
To check code quality locally:
|
503
|
-
1. Run tests with coverage:
|
504
|
-
```bash
|
505
|
-
pytest --cov=src/mcp_dbutils --cov-report=xml:coverage.xml tests/
|
506
|
-
```
|
507
|
-
2. Use SonarLint in your IDE to catch issues early
|
508
|
-
3. Review SonarCloud analysis results in PR comments
|
509
|
-
4. Run Ruff for code style checking:
|
510
|
-
```bash
|
511
|
-
# Install Ruff
|
512
|
-
uv pip install ruff
|
513
|
-
|
514
|
-
# Check code style
|
515
|
-
ruff check .
|
516
|
-
|
517
|
-
# Format code
|
518
|
-
ruff format .
|
519
|
-
```
|
520
|
-
5. Use pre-commit hooks for automatic checks:
|
521
|
-
```bash
|
522
|
-
# Install pre-commit
|
523
|
-
uv pip install pre-commit
|
524
|
-
pre-commit install
|
525
|
-
|
526
|
-
# Run all checks
|
527
|
-
pre-commit run --all-files
|
528
|
-
```
|
529
|
-
|
530
|
-
### SonarCloud AI Integration
|
531
|
-
We've implemented an AI-assisted workflow for fixing SonarCloud issues:
|
532
|
-
|
533
|
-
1. Our CI/CD pipeline automatically extracts SonarCloud analysis results
|
534
|
-
2. Results are formatted into both JSON and Markdown formats
|
535
|
-
3. These reports can be downloaded using the provided Fish function
|
536
|
-
4. The reports can then be provided to AI tools for analysis and fix suggestions
|
537
|
-
|
538
|
-
For detailed instructions, see [SonarCloud AI Integration Guide](docs/sonarcloud-ai-integration.md).
|
539
|
-
|
540
|
-
```bash
|
541
|
-
# Load the function
|
542
|
-
source scripts/sonar-ai-fix.fish
|
543
|
-
|
544
|
-
# Download the latest SonarCloud analysis reports
|
545
|
-
sonar-ai-fix
|
546
|
-
```
|
547
|
-
|
548
|
-
## Contributing
|
549
|
-
Contributions are welcome! Here's how you can help:
|
550
|
-
|
551
|
-
1. 🐛 Report bugs: Open an issue describing the bug and how to reproduce it
|
552
|
-
2. 💡 Suggest features: Open an issue to propose new features
|
553
|
-
3. 🛠️ Submit PRs: Fork the repo and create a pull request with your changes
|
554
|
-
|
555
|
-
### Development Setup
|
556
|
-
1. Clone the repository
|
557
|
-
2. Create a virtual environment using `uv venv`
|
558
|
-
3. Install dependencies with `uv sync --all-extras`
|
559
|
-
4. Run tests with `pytest`
|
560
|
-
|
561
|
-
For detailed guidelines, see [CONTRIBUTING.md](.github/CONTRIBUTING.md)
|
562
|
-
|
563
|
-
## Acknowledgments
|
564
|
-
- [MCP Servers](https://github.com/modelcontextprotocol/servers) for inspiration and demonstration
|
565
|
-
- AI Editors:
|
566
|
-
* [Claude Desktop](https://claude.ai/download)
|
567
|
-
* [Cline](https://cline.bot)
|
568
|
-
- [Model Context Protocol](https://modelcontextprotocol.io/) for comprehensive interfaces
|
569
|
-
|
570
|
-
## Star History
|
571
|
-
|
572
|
-
[](https://star-history.com/#donghao1393/mcp-dbutils&Date)
|
File without changes
|
File without changes
|
File without changes
|