@cano721/mysql-mcp-server 0.9.2 → 0.9.3
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 +9 -17
- package/build/index.js +44 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
## 보안 기능
|
|
25
25
|
|
|
26
26
|
- **읽기 전용 접근**: SELECT, SHOW, DESCRIBE 문 항상 허용
|
|
27
|
-
- **분석 도구**: EXPLAIN, ANALYZE 기본 허용 (읽기 전용 분석)
|
|
27
|
+
- **분석 도구**: EXPLAIN, EXPLAIN ANALYZE 기본 허용 (읽기 전용 분석)
|
|
28
28
|
- **쿼리 검증**: SQL 인젝션 방지 및 데이터 수정 시도 차단
|
|
29
29
|
- **쿼리 타임아웃**: 장시간 실행되는 쿼리로부터 리소스 보호
|
|
30
30
|
- **행 제한**: 과도한 데이터 반환 방지 (최대 1000행)
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
- `SELECT` - 데이터 조회 및 분석 (항상 허용)
|
|
35
35
|
- `SHOW` - 데이터베이스/테이블/인덱스 정보 조회 (항상 허용)
|
|
36
36
|
- `DESCRIBE` / `DESC` - 테이블 구조 및 컬럼 정보 (항상 허용)
|
|
37
|
-
- `EXPLAIN` - 쿼리 실행 계획
|
|
38
|
-
- `ANALYZE` -
|
|
37
|
+
- `EXPLAIN` - 쿼리 실행 계획 분석 (기본 허용, 읽기 전용)
|
|
38
|
+
- `EXPLAIN ANALYZE` - 쿼리 실제 실행 및 성능 분석 (기본 허용, 읽기 전용)
|
|
39
39
|
|
|
40
40
|
## 요구사항
|
|
41
41
|
|
|
@@ -281,18 +281,6 @@ MySQL 서버에서 접근 가능한 모든 데이터베이스를 나열합니다
|
|
|
281
281
|
}
|
|
282
282
|
```
|
|
283
283
|
|
|
284
|
-
**ANALYZE 사용 예제**:
|
|
285
|
-
```json
|
|
286
|
-
{
|
|
287
|
-
"server_name": "mysql",
|
|
288
|
-
"tool_name": "execute_query",
|
|
289
|
-
"arguments": {
|
|
290
|
-
"database": "my_database",
|
|
291
|
-
"query": "ANALYZE TABLE my_table"
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
284
|
### explain_query
|
|
297
285
|
|
|
298
286
|
쿼리 실행 계획을 분석합니다 (MYSQL_ALLOW_EXPLAIN=true 필요).
|
|
@@ -317,12 +305,16 @@ MySQL 서버에서 접근 가능한 모든 데이터베이스를 나열합니다
|
|
|
317
305
|
|
|
318
306
|
### analyze_query
|
|
319
307
|
|
|
320
|
-
|
|
308
|
+
쿼리를 실제로 실행하면서 성능 통계를 분석합니다 (MYSQL_ALLOW_ANALYZE=true 필요).
|
|
309
|
+
|
|
310
|
+
`EXPLAIN ANALYZE` 구문을 사용하여 쿼리를 실제로 실행하고, 각 단계별 실행 시간과 행 수 등의 상세한 성능 정보를 제공합니다.
|
|
321
311
|
|
|
322
312
|
**매개변수**:
|
|
323
|
-
- `query` (필수): 분석할 SQL 쿼리
|
|
313
|
+
- `query` (필수): 분석할 SQL 쿼리 (SELECT 문)
|
|
324
314
|
- `database` (선택사항): 데이터베이스명
|
|
325
315
|
|
|
316
|
+
**주의**: 이 도구는 쿼리를 실제로 실행하므로, 대용량 데이터 조회 시 시간이 오래 걸릴 수 있습니다.
|
|
317
|
+
|
|
326
318
|
**예제**:
|
|
327
319
|
```json
|
|
328
320
|
{
|
package/build/index.js
CHANGED
|
@@ -63,7 +63,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
63
63
|
const tools = [
|
|
64
64
|
{
|
|
65
65
|
name: "list_databases",
|
|
66
|
-
description: "List all accessible databases on the MySQL server",
|
|
66
|
+
description: "List all accessible databases on the MySQL server. 한글: 데이터베이스 목록, DB 목록, 데이터베이스 조회",
|
|
67
67
|
inputSchema: {
|
|
68
68
|
type: "object",
|
|
69
69
|
properties: {},
|
|
@@ -72,7 +72,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
74
|
name: "list_tables",
|
|
75
|
-
description: "List all tables in a specified database",
|
|
75
|
+
description: "List all tables in a specified database. 한글: 테이블 목록, 테이블 조회, 테이블 리스트",
|
|
76
76
|
inputSchema: {
|
|
77
77
|
type: "object",
|
|
78
78
|
properties: {
|
|
@@ -86,7 +86,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
name: "describe_table",
|
|
89
|
-
description: "Show the schema for a specific table",
|
|
89
|
+
description: "Show the schema for a specific table. 한글: 테이블 스키마, 테이블 구조, 컬럼 정보, 테이블 설명",
|
|
90
90
|
inputSchema: {
|
|
91
91
|
type: "object",
|
|
92
92
|
properties: {
|
|
@@ -104,7 +104,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
name: "execute_query",
|
|
107
|
-
description: "Execute a read-only SQL query",
|
|
107
|
+
description: "Execute a read-only SQL query. 한글: 쿼리 실행, SQL 실행, 조회 쿼리",
|
|
108
108
|
inputSchema: {
|
|
109
109
|
type: "object",
|
|
110
110
|
properties: {
|
|
@@ -122,7 +122,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
name: "get_related_tables",
|
|
125
|
-
description: "Find all related/connected/associated tables linked to a specific table through foreign keys. Discovers table relationships and dependencies with depth traversal. Use this when asked to find related tables, connected tables, associated tables, or table relationships.",
|
|
125
|
+
description: "Find all related/connected/associated tables linked to a specific table through foreign keys. Discovers table relationships and dependencies with depth traversal. Use this when asked to find related tables, connected tables, associated tables, or table relationships. 한글: 연관 테이블, 관련 테이블, 연결된 테이블, 테이블 관계, 참조 테이블, FK 관계",
|
|
126
126
|
inputSchema: {
|
|
127
127
|
type: "object",
|
|
128
128
|
properties: {
|
|
@@ -151,7 +151,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
151
151
|
if (allowExplain) {
|
|
152
152
|
tools.push({
|
|
153
153
|
name: "explain_query",
|
|
154
|
-
description: "Analyze query execution plan using EXPLAIN",
|
|
154
|
+
description: "Analyze query execution plan using EXPLAIN. 한글: 쿼리 실행 계획, 쿼리 분석, EXPLAIN",
|
|
155
155
|
inputSchema: {
|
|
156
156
|
type: "object",
|
|
157
157
|
properties: {
|
|
@@ -177,7 +177,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
177
177
|
if (allowAnalyze) {
|
|
178
178
|
tools.push({
|
|
179
179
|
name: "analyze_query",
|
|
180
|
-
description: "Analyze query performance and statistics using ANALYZE",
|
|
180
|
+
description: "Analyze query performance and statistics using ANALYZE. 한글: 쿼리 성능 분석, 쿼리 통계, ANALYZE",
|
|
181
181
|
inputSchema: {
|
|
182
182
|
type: "object",
|
|
183
183
|
properties: {
|
|
@@ -320,7 +320,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
320
320
|
}
|
|
321
321
|
const results = [];
|
|
322
322
|
const visited = new Set();
|
|
323
|
-
const
|
|
323
|
+
const circularReferences = [];
|
|
324
|
+
const queue = [
|
|
325
|
+
{ tableName: table, depth: 0, path: [table] }
|
|
326
|
+
];
|
|
324
327
|
visited.add(table);
|
|
325
328
|
while (queue.length > 0) {
|
|
326
329
|
const current = queue.shift();
|
|
@@ -348,7 +351,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
348
351
|
});
|
|
349
352
|
if (!visited.has(row.child_table)) {
|
|
350
353
|
visited.add(row.child_table);
|
|
351
|
-
queue.push({
|
|
354
|
+
queue.push({
|
|
355
|
+
tableName: row.child_table,
|
|
356
|
+
depth: current.depth + 1,
|
|
357
|
+
path: [...current.path, row.child_table]
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
else if (current.path.includes(row.child_table)) {
|
|
361
|
+
// 순환 참조 감지
|
|
362
|
+
const cycleStart = current.path.indexOf(row.child_table);
|
|
363
|
+
const cyclePath = [...current.path.slice(cycleStart), row.child_table];
|
|
364
|
+
circularReferences.push({
|
|
365
|
+
path: cyclePath,
|
|
366
|
+
description: `${cyclePath.join(' → ')}`
|
|
367
|
+
});
|
|
352
368
|
}
|
|
353
369
|
}
|
|
354
370
|
// Find parent tables (tables that the current table references)
|
|
@@ -379,7 +395,20 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
379
395
|
}
|
|
380
396
|
if (!visited.has(row.parent_table)) {
|
|
381
397
|
visited.add(row.parent_table);
|
|
382
|
-
queue.push({
|
|
398
|
+
queue.push({
|
|
399
|
+
tableName: row.parent_table,
|
|
400
|
+
depth: current.depth + 1,
|
|
401
|
+
path: [...current.path, row.parent_table]
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
else if (current.path.includes(row.parent_table)) {
|
|
405
|
+
// 순환 참조 감지
|
|
406
|
+
const cycleStart = current.path.indexOf(row.parent_table);
|
|
407
|
+
const cyclePath = [...current.path.slice(cycleStart), row.parent_table];
|
|
408
|
+
circularReferences.push({
|
|
409
|
+
path: cyclePath,
|
|
410
|
+
description: `${cyclePath.join(' → ')}`
|
|
411
|
+
});
|
|
383
412
|
}
|
|
384
413
|
}
|
|
385
414
|
}
|
|
@@ -432,6 +461,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
432
461
|
fk_relations_count: results.length,
|
|
433
462
|
pattern_match_count: patternMatchResults.length,
|
|
434
463
|
total_relations: results.length + patternMatchResults.length,
|
|
464
|
+
circular_references_detected: circularReferences.length > 0,
|
|
465
|
+
circular_references: circularReferences.length > 0 ? circularReferences : undefined,
|
|
435
466
|
fk_relations: results,
|
|
436
467
|
pattern_match_relations: includePatternMatch ? patternMatchResults : undefined,
|
|
437
468
|
note: includePatternMatch
|
|
@@ -441,6 +472,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
441
472
|
if (warning) {
|
|
442
473
|
response.warning = warning;
|
|
443
474
|
}
|
|
475
|
+
if (circularReferences.length > 0) {
|
|
476
|
+
response.circular_reference_note = `⚠️ 순환참조가 감지되었습니다 (${circularReferences.length}개). 이미 방문한 테이블은 재탐색하지 않았습니다.`;
|
|
477
|
+
}
|
|
444
478
|
return {
|
|
445
479
|
content: [{
|
|
446
480
|
type: "text",
|