mcp-dbutils 0.17.0__py3-none-any.whl → 0.19.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/base.py +364 -178
- mcp_dbutils/mysql/handler.py +52 -32
- mcp_dbutils/postgres/handler.py +50 -30
- mcp_dbutils/sqlite/handler.py +68 -53
- mcp_dbutils-0.19.0.dist-info/METADATA +145 -0
- {mcp_dbutils-0.17.0.dist-info → mcp_dbutils-0.19.0.dist-info}/RECORD +9 -9
- mcp_dbutils-0.17.0.dist-info/METADATA +0 -308
- {mcp_dbutils-0.17.0.dist-info → mcp_dbutils-0.19.0.dist-info}/WHEEL +0 -0
- {mcp_dbutils-0.17.0.dist-info → mcp_dbutils-0.19.0.dist-info}/entry_points.txt +0 -0
- {mcp_dbutils-0.17.0.dist-info → mcp_dbutils-0.19.0.dist-info}/licenses/LICENSE +0 -0
mcp_dbutils/sqlite/handler.py
CHANGED
@@ -98,7 +98,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
98
98
|
end_time = time.time()
|
99
99
|
elapsed_ms = (end_time - start_time) * 1000
|
100
100
|
self.log("debug", f"Query executed in {elapsed_ms:.2f}ms")
|
101
|
-
|
101
|
+
|
102
102
|
if is_select:
|
103
103
|
# Get column names
|
104
104
|
columns = [description[0] for description in cur.description]
|
@@ -110,7 +110,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
110
110
|
for i, col_name in enumerate(columns):
|
111
111
|
row_dict[col_name] = row[i]
|
112
112
|
results.append(row_dict)
|
113
|
-
|
113
|
+
|
114
114
|
return str({
|
115
115
|
"columns": columns,
|
116
116
|
"rows": results
|
@@ -136,13 +136,13 @@ class SQLiteHandler(ConnectionHandler):
|
|
136
136
|
# 获取表信息
|
137
137
|
cur.execute(f"PRAGMA table_info({table_name})")
|
138
138
|
columns = cur.fetchall()
|
139
|
-
|
139
|
+
|
140
140
|
# SQLite不支持表级注释,但我们可以获取表的详细信息
|
141
141
|
description = [
|
142
142
|
f"Table: {table_name}\n",
|
143
143
|
COLUMNS_HEADER
|
144
144
|
]
|
145
|
-
|
145
|
+
|
146
146
|
for col in columns:
|
147
147
|
col_info = [
|
148
148
|
f" {col[1]} ({col[2]})",
|
@@ -152,9 +152,9 @@ class SQLiteHandler(ConnectionHandler):
|
|
152
152
|
]
|
153
153
|
description.extend(col_info)
|
154
154
|
description.append("") # Empty line between columns
|
155
|
-
|
155
|
+
|
156
156
|
return "\n".join(description)
|
157
|
-
|
157
|
+
|
158
158
|
except sqlite3.Error as e:
|
159
159
|
error_msg = f"Failed to get table description: {str(e)}"
|
160
160
|
self.stats.record_error(e.__class__.__name__)
|
@@ -168,25 +168,25 @@ class SQLiteHandler(ConnectionHandler):
|
|
168
168
|
# SQLite provides the complete CREATE statement
|
169
169
|
cur.execute("SELECT sql FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
170
170
|
result = cur.fetchone()
|
171
|
-
|
171
|
+
|
172
172
|
if not result:
|
173
173
|
return f"Table {table_name} not found"
|
174
|
-
|
174
|
+
|
175
175
|
ddl = result[0]
|
176
|
-
|
176
|
+
|
177
177
|
# Get indexes
|
178
178
|
cur.execute("SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name=?", (table_name,))
|
179
179
|
indexes = cur.fetchall()
|
180
|
-
|
180
|
+
|
181
181
|
# Add index definitions
|
182
182
|
if indexes:
|
183
183
|
ddl = ddl + "\n\n-- Indexes:"
|
184
184
|
for idx in indexes:
|
185
185
|
if idx[0]: # Some internal indexes might have NULL sql
|
186
186
|
ddl = ddl + "\n" + idx[0] + ";"
|
187
|
-
|
187
|
+
|
188
188
|
return ddl
|
189
|
-
|
189
|
+
|
190
190
|
except sqlite3.Error as e:
|
191
191
|
error_msg = f"Failed to get table DDL: {str(e)}"
|
192
192
|
self.stats.record_error(e.__class__.__name__)
|
@@ -197,49 +197,49 @@ class SQLiteHandler(ConnectionHandler):
|
|
197
197
|
try:
|
198
198
|
with sqlite3.connect(self.config.path) as conn:
|
199
199
|
cur = conn.cursor()
|
200
|
-
|
200
|
+
|
201
201
|
# Check if table exists
|
202
202
|
cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
203
203
|
if not cur.fetchone():
|
204
204
|
raise ConnectionHandlerError(f"Table '{table_name}' doesn't exist")
|
205
|
-
|
205
|
+
|
206
206
|
# 获取索引列表
|
207
207
|
cur.execute(f"PRAGMA index_list({table_name})")
|
208
208
|
indexes = cur.fetchall()
|
209
|
-
|
209
|
+
|
210
210
|
if not indexes:
|
211
211
|
return f"No indexes found on table {table_name}"
|
212
|
-
|
212
|
+
|
213
213
|
formatted_indexes = [f"Indexes for {table_name}:"]
|
214
|
-
|
214
|
+
|
215
215
|
for idx in indexes:
|
216
216
|
# 获取索引详细信息
|
217
217
|
cur.execute(f"PRAGMA index_info({idx[1]})")
|
218
218
|
index_info = cur.fetchall()
|
219
|
-
|
219
|
+
|
220
220
|
# 获取索引的SQL定义
|
221
221
|
cur.execute("SELECT sql FROM sqlite_master WHERE type='index' AND name=?", (idx[1],))
|
222
222
|
sql = cur.fetchone()
|
223
|
-
|
223
|
+
|
224
224
|
index_details = [
|
225
225
|
f"\nIndex: {idx[1]}",
|
226
226
|
f"Type: {'UNIQUE' if idx[2] else 'INDEX'}",
|
227
227
|
COLUMNS_HEADER
|
228
228
|
]
|
229
|
-
|
229
|
+
|
230
230
|
for col in index_info:
|
231
231
|
index_details.append(f" - {col[2]}")
|
232
|
-
|
232
|
+
|
233
233
|
if sql and sql[0]:
|
234
234
|
index_details.extend([
|
235
235
|
"Definition:",
|
236
236
|
f" {sql[0]}"
|
237
237
|
])
|
238
|
-
|
238
|
+
|
239
239
|
formatted_indexes.extend(index_details)
|
240
|
-
|
240
|
+
|
241
241
|
return "\n".join(formatted_indexes)
|
242
|
-
|
242
|
+
|
243
243
|
except sqlite3.Error as e:
|
244
244
|
error_msg = f"Failed to get index information: {str(e)}"
|
245
245
|
self.stats.record_error(e.__class__.__name__)
|
@@ -250,33 +250,33 @@ class SQLiteHandler(ConnectionHandler):
|
|
250
250
|
try:
|
251
251
|
with sqlite3.connect(self.config.path) as conn:
|
252
252
|
cur = conn.cursor()
|
253
|
-
|
253
|
+
|
254
254
|
# Check if table exists
|
255
255
|
cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", (table_name,))
|
256
256
|
if not cur.fetchone():
|
257
257
|
raise ConnectionHandlerError(f"Table '{table_name}' doesn't exist")
|
258
|
-
|
258
|
+
|
259
259
|
# Get basic table information
|
260
260
|
cur.execute(f"PRAGMA table_info({table_name})")
|
261
261
|
columns = cur.fetchall()
|
262
|
-
|
262
|
+
|
263
263
|
# Count rows
|
264
264
|
cur.execute(f"SELECT COUNT(*) FROM {table_name}")
|
265
265
|
row_count = cur.fetchone()[0]
|
266
|
-
|
266
|
+
|
267
267
|
# Get index information
|
268
268
|
cur.execute(f"PRAGMA index_list({table_name})")
|
269
269
|
indexes = cur.fetchall()
|
270
|
-
|
270
|
+
|
271
271
|
# Get page count and size
|
272
272
|
cur.execute("PRAGMA page_count")
|
273
273
|
page_count = cur.fetchone()[0]
|
274
274
|
cur.execute("PRAGMA page_size")
|
275
275
|
page_size = cur.fetchone()[0]
|
276
|
-
|
276
|
+
|
277
277
|
# Calculate total size
|
278
278
|
total_size = page_count * page_size
|
279
|
-
|
279
|
+
|
280
280
|
# Format size in human readable format
|
281
281
|
def format_size(size):
|
282
282
|
for unit in ['B', 'KB', 'MB', 'GB']:
|
@@ -284,7 +284,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
284
284
|
return f"{size:.2f} {unit}"
|
285
285
|
size /= 1024
|
286
286
|
return f"{size:.2f} TB"
|
287
|
-
|
287
|
+
|
288
288
|
# Get column statistics
|
289
289
|
column_stats = []
|
290
290
|
for col in columns:
|
@@ -295,7 +295,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
295
295
|
# Get distinct value count
|
296
296
|
cur.execute(f"SELECT COUNT(DISTINCT {col_name}) FROM {table_name}")
|
297
297
|
distinct_count = cur.fetchone()[0]
|
298
|
-
|
298
|
+
|
299
299
|
column_stats.append({
|
300
300
|
'name': col_name,
|
301
301
|
'type': col[2],
|
@@ -303,7 +303,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
303
303
|
'null_percent': (null_count / row_count * 100) if row_count > 0 else 0,
|
304
304
|
'distinct_count': distinct_count
|
305
305
|
})
|
306
|
-
|
306
|
+
|
307
307
|
# Format output
|
308
308
|
output = [
|
309
309
|
f"Table Statistics for {table_name}:",
|
@@ -314,7 +314,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
314
314
|
f" Index Count: {len(indexes)}\n",
|
315
315
|
"Column Statistics:"
|
316
316
|
]
|
317
|
-
|
317
|
+
|
318
318
|
for stat in column_stats:
|
319
319
|
col_info = [
|
320
320
|
f" {stat['name']} ({stat['type']}):",
|
@@ -323,7 +323,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
323
323
|
]
|
324
324
|
output.extend(col_info)
|
325
325
|
output.append("") # Empty line between columns
|
326
|
-
|
326
|
+
|
327
327
|
return "\n".join(output)
|
328
328
|
|
329
329
|
except sqlite3.Error as e:
|
@@ -336,21 +336,21 @@ class SQLiteHandler(ConnectionHandler):
|
|
336
336
|
try:
|
337
337
|
with sqlite3.connect(self.config.path) as conn:
|
338
338
|
cur = conn.cursor()
|
339
|
-
|
339
|
+
|
340
340
|
# Get table info (includes PRIMARY KEY)
|
341
341
|
cur.execute(f"PRAGMA table_info({table_name})")
|
342
342
|
columns = cur.fetchall()
|
343
|
-
|
343
|
+
|
344
344
|
# Get foreign keys
|
345
345
|
cur.execute(f"PRAGMA foreign_key_list({table_name})")
|
346
346
|
foreign_keys = cur.fetchall()
|
347
|
-
|
347
|
+
|
348
348
|
# Get indexes (for UNIQUE constraints)
|
349
349
|
cur.execute(f"PRAGMA index_list({table_name})")
|
350
350
|
indexes = cur.fetchall()
|
351
|
-
|
351
|
+
|
352
352
|
output = [f"Constraints for {table_name}:"]
|
353
|
-
|
353
|
+
|
354
354
|
# Primary Key constraints
|
355
355
|
pk_columns = [col[1] for col in columns if col[5]] # col[5] is pk flag
|
356
356
|
if pk_columns:
|
@@ -358,13 +358,13 @@ class SQLiteHandler(ConnectionHandler):
|
|
358
358
|
"\nPrimary Key Constraints:",
|
359
359
|
f" PRIMARY KEY ({', '.join(pk_columns)})"
|
360
360
|
])
|
361
|
-
|
361
|
+
|
362
362
|
# Foreign Key constraints
|
363
363
|
if foreign_keys:
|
364
364
|
output.append("\nForeign Key Constraints:")
|
365
365
|
current_fk = None
|
366
366
|
fk_columns = []
|
367
|
-
|
367
|
+
|
368
368
|
for fk in foreign_keys:
|
369
369
|
# SQLite foreign_key_list format:
|
370
370
|
# id, seq, table, from, to, on_update, on_delete, match
|
@@ -380,10 +380,10 @@ class SQLiteHandler(ConnectionHandler):
|
|
380
380
|
output.append(f" ON UPDATE: {fk[5]}")
|
381
381
|
if fk[6]: # on_delete
|
382
382
|
output.append(f" ON DELETE: {fk[6]}")
|
383
|
-
|
383
|
+
|
384
384
|
if fk_columns:
|
385
385
|
output.append(f" ({', '.join(fk_columns)})")
|
386
|
-
|
386
|
+
|
387
387
|
# Unique constraints (from indexes)
|
388
388
|
unique_indexes = [idx for idx in indexes if idx[2]] # idx[2] is unique flag
|
389
389
|
if unique_indexes:
|
@@ -394,7 +394,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
394
394
|
index_info = cur.fetchall()
|
395
395
|
columns = [info[2] for info in index_info] # info[2] is column name
|
396
396
|
output.append(f" UNIQUE ({', '.join(columns)})")
|
397
|
-
|
397
|
+
|
398
398
|
# Check constraints
|
399
399
|
# Note: SQLite doesn't provide direct access to CHECK constraints through PRAGMA
|
400
400
|
# We need to parse the table creation SQL
|
@@ -403,7 +403,7 @@ class SQLiteHandler(ConnectionHandler):
|
|
403
403
|
if "CHECK" in create_sql.upper():
|
404
404
|
output.append("\nCheck Constraints:")
|
405
405
|
output.append(" See table DDL for CHECK constraints")
|
406
|
-
|
406
|
+
|
407
407
|
return "\n".join(output)
|
408
408
|
|
409
409
|
except sqlite3.Error as e:
|
@@ -416,18 +416,18 @@ class SQLiteHandler(ConnectionHandler):
|
|
416
416
|
try:
|
417
417
|
with sqlite3.connect(self.config.path) as conn:
|
418
418
|
cur = conn.cursor()
|
419
|
-
|
419
|
+
|
420
420
|
# Check if the query is valid by preparing it
|
421
421
|
try:
|
422
422
|
# Use prepare to validate the query without executing it
|
423
423
|
conn.execute(f"EXPLAIN {sql}")
|
424
424
|
except sqlite3.Error as e:
|
425
425
|
raise ConnectionHandlerError(f"Failed to explain query: {str(e)}")
|
426
|
-
|
426
|
+
|
427
427
|
# Get EXPLAIN output
|
428
428
|
cur.execute(f"EXPLAIN QUERY PLAN {sql}")
|
429
429
|
plan = cur.fetchall()
|
430
|
-
|
430
|
+
|
431
431
|
# Format the output
|
432
432
|
output = [
|
433
433
|
"Query Execution Plan:",
|
@@ -435,20 +435,20 @@ class SQLiteHandler(ConnectionHandler):
|
|
435
435
|
"Details:",
|
436
436
|
"--------"
|
437
437
|
]
|
438
|
-
|
438
|
+
|
439
439
|
for step in plan:
|
440
440
|
# EXPLAIN QUERY PLAN format:
|
441
441
|
# id | parent | notused | detail
|
442
442
|
indent = " " * (step[0] - step[1] if step[1] >= 0 else step[0])
|
443
443
|
output.append(f"{indent}{step[3]}")
|
444
|
-
|
444
|
+
|
445
445
|
# Add query statistics
|
446
446
|
output.extend([
|
447
447
|
"\nNote: SQLite's EXPLAIN QUERY PLAN provides a high-level overview.",
|
448
448
|
"For detailed execution statistics, consider using EXPLAIN (not QUERY PLAN)",
|
449
449
|
"which shows the virtual machine instructions."
|
450
450
|
])
|
451
|
-
|
451
|
+
|
452
452
|
return "\n".join(output)
|
453
453
|
|
454
454
|
except sqlite3.Error as e:
|
@@ -456,6 +456,21 @@ class SQLiteHandler(ConnectionHandler):
|
|
456
456
|
self.stats.record_error(e.__class__.__name__)
|
457
457
|
raise ConnectionHandlerError(error_msg)
|
458
458
|
|
459
|
+
async def test_connection(self) -> bool:
|
460
|
+
"""Test database connection
|
461
|
+
|
462
|
+
Returns:
|
463
|
+
bool: True if connection is successful, False otherwise
|
464
|
+
"""
|
465
|
+
try:
|
466
|
+
with sqlite3.connect(self.config.path) as conn:
|
467
|
+
cur = conn.cursor()
|
468
|
+
cur.execute("SELECT 1")
|
469
|
+
return True
|
470
|
+
except sqlite3.Error as e:
|
471
|
+
self.log("error", f"Connection test failed: {str(e)}")
|
472
|
+
return False
|
473
|
+
|
459
474
|
async def cleanup(self):
|
460
475
|
"""Cleanup resources"""
|
461
476
|
# Log final stats
|
@@ -0,0 +1,145 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: mcp-dbutils
|
3
|
+
Version: 0.19.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 数据库工具
|
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
|
+
[English](README_EN.md) | [Français](README_FR.md) | [Español](README_ES.md) | [العربية](README_AR.md) | [Русский](README_RU.md) | [文档导航](#文档导航)
|
44
|
+
|
45
|
+

|
46
|
+
|
47
|
+
## 简介
|
48
|
+
|
49
|
+
MCP Database Utilities 是一个多功能的 MCP 服务,它使您的 AI 能够通过统一的连接配置安全地访问各种类型的数据库(SQLite、MySQL、PostgreSQL 等)进行数据分析。
|
50
|
+
|
51
|
+
您可以将其视为 AI 系统和数据库之间的安全桥梁,允许 AI 在不直接访问数据库或冒数据修改风险的情况下读取和分析您的数据。
|
52
|
+
|
53
|
+
### 核心特性
|
54
|
+
|
55
|
+
- **安全优先**:严格只读操作,无直接数据库访问,隔离连接,按需连接,自动超时
|
56
|
+
- **隐私保障**:本地处理,最小数据暴露,凭证保护,敏感数据屏蔽
|
57
|
+
- **多数据库支持**:使用相同的接口连接 SQLite、MySQL、PostgreSQL
|
58
|
+
- **简单配置**:所有数据库连接使用单个 YAML 文件
|
59
|
+
- **高级功能**:表格浏览、架构分析和查询执行
|
60
|
+
|
61
|
+
> 🔒 **安全说明**:MCP 数据库工具采用安全优先的架构设计,非常适合注重数据保护的企业、初创公司和个人用户。详细了解我们的[安全架构](docs/zh/technical/security.md)。
|
62
|
+
|
63
|
+
## 快速入门
|
64
|
+
|
65
|
+
我们提供了多种安装方式,包括 uvx、Docker 和 Smithery。详细的安装和配置步骤请参阅[安装指南](docs/zh/installation.md)。
|
66
|
+
|
67
|
+
### 基本步骤
|
68
|
+
|
69
|
+
1. **安装**:选择适合您的安装方式([详细说明](docs/zh/installation.md))
|
70
|
+
2. **配置**:创建包含数据库连接信息的 YAML 文件([配置指南](docs/zh/configuration.md))
|
71
|
+
3. **连接**:将配置添加到您的 AI 客户端
|
72
|
+
4. **使用**:开始与您的数据库交互([使用指南](docs/zh/usage.md))
|
73
|
+
|
74
|
+
### 示例交互
|
75
|
+
|
76
|
+
**您**:"能否列出我的数据库中的所有表?"
|
77
|
+
|
78
|
+
**AI**:"以下是您的数据库中的表:
|
79
|
+
- customers(客户)
|
80
|
+
- products(产品)
|
81
|
+
- orders(订单)
|
82
|
+
- inventory(库存)"
|
83
|
+
|
84
|
+
**您**:"customers 表的结构是什么样的?"
|
85
|
+
|
86
|
+
**AI**:"customers 表有以下结构:
|
87
|
+
- id(整数,主键)
|
88
|
+
- name(文本)
|
89
|
+
- email(文本)
|
90
|
+
- registration_date(日期)"
|
91
|
+
|
92
|
+
## 文档导航
|
93
|
+
|
94
|
+
### 入门指南
|
95
|
+
- [安装指南](docs/zh/installation.md) - 详细的安装步骤和配置说明
|
96
|
+
- [平台特定安装指南](docs/zh/installation-platform-specific.md) - 针对不同操作系统的安装说明
|
97
|
+
- [配置指南](docs/zh/configuration.md) - 数据库连接配置示例和最佳实践
|
98
|
+
- [使用指南](docs/zh/usage.md) - 基本操作流程和常见使用场景
|
99
|
+
|
100
|
+
### 技术文档
|
101
|
+
- [架构设计](docs/zh/technical/architecture.md) - 系统架构和组件说明
|
102
|
+
- [安全架构](docs/zh/technical/security.md) - 安全特性和保护机制
|
103
|
+
- [开发指南](docs/zh/technical/development.md) - 代码质量和开发流程
|
104
|
+
- [测试指南](docs/zh/technical/testing.md) - 测试框架和最佳实践
|
105
|
+
- [SonarCloud 集成](docs/zh/technical/sonarcloud-integration.md) - SonarCloud 与 AI 集成指南
|
106
|
+
|
107
|
+
### 示例文档
|
108
|
+
- [SQLite 示例](docs/zh/examples/sqlite-examples.md) - SQLite 数据库操作示例
|
109
|
+
- [PostgreSQL 示例](docs/zh/examples/postgresql-examples.md) - PostgreSQL 数据库操作示例
|
110
|
+
- [MySQL 示例](docs/zh/examples/mysql-examples.md) - MySQL 数据库操作示例
|
111
|
+
- [高级 LLM 交互示例](docs/zh/examples/advanced-llm-interactions.md) - 与各类 LLM 的高级交互示例
|
112
|
+
|
113
|
+
### 多语言文档
|
114
|
+
- **英语** - [English Documentation](docs/en/)
|
115
|
+
- **法语** - [Documentation Française](docs/fr/)
|
116
|
+
- **西班牙语** - [Documentación en Español](docs/es/)
|
117
|
+
- **阿拉伯语** - [التوثيق باللغة العربية](docs/ar/)
|
118
|
+
- **俄语** - [Документация на русском](docs/ru/)
|
119
|
+
|
120
|
+
### 支持与反馈
|
121
|
+
- [GitHub Issues](https://github.com/donghao1393/mcp-dbutils/issues) - 报告问题或请求功能
|
122
|
+
- [Smithery](https://smithery.ai/server/@donghao1393/mcp-dbutils) - 简化安装和更新
|
123
|
+
|
124
|
+
## 可用工具
|
125
|
+
|
126
|
+
MCP 数据库工具提供了多种工具,使 AI 能够与您的数据库交互:
|
127
|
+
|
128
|
+
- **dbutils-list-connections**:列出配置中的所有可用数据库连接
|
129
|
+
- **dbutils-list-tables**:列出数据库中的所有表
|
130
|
+
- **dbutils-run-query**:执行 SQL 查询(仅 SELECT)
|
131
|
+
- **dbutils-get-stats**:获取表统计信息
|
132
|
+
- **dbutils-list-constraints**:列出表约束
|
133
|
+
- **dbutils-explain-query**:获取查询执行计划
|
134
|
+
- **dbutils-get-performance**:获取数据库性能指标
|
135
|
+
- **dbutils-analyze-query**:分析查询以进行优化
|
136
|
+
|
137
|
+
有关这些工具的详细说明和使用示例,请参阅[使用指南](docs/zh/usage.md)。
|
138
|
+
|
139
|
+
## 星标历史
|
140
|
+
|
141
|
+
[](https://starchart.cc/donghao1393/mcp-dbutils)
|
142
|
+
|
143
|
+
## 许可证
|
144
|
+
|
145
|
+
本项目采用 MIT 许可证 - 有关详细信息,请参阅 [LICENSE](LICENSE) 文件。
|
@@ -1,22 +1,22 @@
|
|
1
1
|
mcp_dbutils/__init__.py,sha256=6LLccQv7je2L4IpY_I3OzSJZcK32VUDJv2IY31y6eYg,1900
|
2
|
-
mcp_dbutils/base.py,sha256=
|
2
|
+
mcp_dbutils/base.py,sha256=ptQfJwzYKteGokOrrkIcG3QIlz-f1Afk_XxyEHYcFLI,35957
|
3
3
|
mcp_dbutils/config.py,sha256=bmXpOd1fyYfoyUS75I035ChT6t3wP5AyEnJ06e2ZS2o,1848
|
4
4
|
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=L2COmWts8WNQaI7wZSPtQ-BqKnpYL7DRnNk7Yw3UsxU,22285
|
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
|
12
|
-
mcp_dbutils/postgres/handler.py,sha256=
|
12
|
+
mcp_dbutils/postgres/handler.py,sha256=JKnh3QsF5oQ4nS-OdhMC1nWtTp235PArFncFN4pmDZ8,24670
|
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=nCgBeBp3zjpE2HNohMbh3Jpz5tNeMczt5K87JOhVWzY,19320
|
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.19.0.dist-info/METADATA,sha256=xOY0fVqaZ6XzrOmt2fQghZfEncZ8dXB8QN8fXaTaKKc,7146
|
19
|
+
mcp_dbutils-0.19.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
20
|
+
mcp_dbutils-0.19.0.dist-info/entry_points.txt,sha256=XTjt0QmYRgKOJQT6skR9bp1EMUfIrgpHeZJPZ3CJffs,49
|
21
|
+
mcp_dbutils-0.19.0.dist-info/licenses/LICENSE,sha256=1A_CwpWVlbjrKdVEYO77vYfnXlW7oxcilZ8FpA_BzCI,1065
|
22
|
+
mcp_dbutils-0.19.0.dist-info/RECORD,,
|