redash-mcp 2.2.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/sql-guard.js CHANGED
@@ -40,74 +40,71 @@ export function analyzeQuery(sql) {
40
40
  const upper = normalizeForAnalysis(sql);
41
41
  const warnings = [];
42
42
  let modifiedQuery;
43
- // ── Destructive (차단: warn/strict 모두) ────────────────────────────────────
44
43
  if (/\bDROP\s+(TABLE|DATABASE|SCHEMA|VIEW|INDEX|FUNCTION)\b/.test(upper)) {
45
44
  return {
46
45
  blocked: true,
47
46
  warnings: [],
48
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: DROP 문은 데이터/스키마를 영구 삭제합니다.\n규칙: DESTRUCTIVE / DROP\n\n해제가 필요하다면 REDASH_SAFETY_MODE=off 설정하세요.",
47
+ message: "🚫 Query blocked.\n\nReason: DROP statements permanently delete data/schema.\nRule: DESTRUCTIVE / DROP\n\nSet REDASH_SAFETY_MODE=off to disable this check.",
49
48
  };
50
49
  }
51
50
  if (/\bTRUNCATE\b/.test(upper)) {
52
51
  return {
53
52
  blocked: true,
54
53
  warnings: [],
55
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: TRUNCATE 문은 전체 테이블 데이터를 삭제합니다.\n규칙: DESTRUCTIVE / TRUNCATE",
54
+ message: "🚫 Query blocked.\n\nReason: TRUNCATE deletes all data from the table.\nRule: DESTRUCTIVE / TRUNCATE",
56
55
  };
57
56
  }
58
57
  if (/\bALTER\s+TABLE\b/.test(upper)) {
59
58
  return {
60
59
  blocked: true,
61
60
  warnings: [],
62
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: ALTER TABLE 스키마 변경으로 사전 협의가 필요합니다.\n규칙: DESTRUCTIVE / ALTER_TABLE",
61
+ message: "🚫 Query blocked.\n\nReason: ALTER TABLE modifies schema and requires prior coordination.\nRule: DESTRUCTIVE / ALTER_TABLE",
63
62
  };
64
63
  }
65
64
  if (/\b(GRANT|REVOKE)\b/.test(upper)) {
66
65
  return {
67
66
  blocked: true,
68
67
  warnings: [],
69
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: GRANT/REVOKE 권한 변경으로 허용되지 않습니다.\n규칙: DESTRUCTIVE / PRIVILEGE_CHANGE",
68
+ message: "🚫 Query blocked.\n\nReason: GRANT/REVOKE permission changes are not allowed.\nRule: DESTRUCTIVE / PRIVILEGE_CHANGE",
70
69
  };
71
70
  }
72
71
  if (/\bDELETE\s+FROM\b/.test(upper) && !hasWhere(upper)) {
73
72
  return {
74
73
  blocked: true,
75
74
  warnings: [],
76
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: WHERE 조건 없는 DELETE는 전체 데이터를 삭제합니다.\n규칙: DESTRUCTIVE / DELETE_WITHOUT_WHERE\n\n안전한 예시:\n DELETE FROM orders WHERE created_at < '2024-01-01'",
75
+ message: "🚫 Query blocked.\n\nReason: DELETE without WHERE clause will delete all rows.\nRule: DESTRUCTIVE / DELETE_WITHOUT_WHERE\n\nSafe example:\n DELETE FROM orders WHERE created_at < '2024-01-01'",
77
76
  };
78
77
  }
79
78
  if (/\bUPDATE\b/.test(upper) && /\bSET\b/.test(upper) && !hasWhere(upper)) {
80
79
  return {
81
80
  blocked: true,
82
81
  warnings: [],
83
- message: "🚫 쿼리가 차단되었습니다.\n\n사유: WHERE 조건 없는 UPDATE는 전체 데이터를 수정합니다.\n규칙: DESTRUCTIVE / UPDATE_WITHOUT_WHERE\n\n안전한 예시:\n UPDATE orders SET status = 'cancelled' WHERE created_at < '2024-01-01'",
82
+ message: "🚫 Query blocked.\n\nReason: UPDATE without WHERE clause will modify all rows.\nRule: DESTRUCTIVE / UPDATE_WITHOUT_WHERE\n\nSafe example:\n UPDATE orders SET status = 'cancelled' WHERE created_at < '2024-01-01'",
84
83
  };
85
84
  }
86
- // DELETE/UPDATE with WHERE — 경고만
87
85
  if (/\bDELETE\s+FROM\b/.test(upper)) {
88
- warnings.push("[DESTRUCTIVE] DELETE 쿼리입니다. WHERE 조건을 다시 확인하세요.");
86
+ warnings.push("[DESTRUCTIVE] DELETE query detected. Please verify the WHERE clause.");
89
87
  }
90
88
  if (/\bUPDATE\b/.test(upper) && /\bSET\b/.test(upper)) {
91
- warnings.push("[DESTRUCTIVE] UPDATE 쿼리입니다. WHERE 조건을 다시 확인하세요.");
89
+ warnings.push("[DESTRUCTIVE] UPDATE query detected. Please verify the WHERE clause.");
92
90
  }
93
- // ── Cost (warn: 경고 후 실행, strict: 차단) ────────────────────────────────
94
91
  if (!config.disableCost && isSelect(sql)) {
95
92
  const hasSelectStar = /SELECT\s+\*/.test(upper) || /SELECT\s+[\w.]+\.\*/.test(upper);
96
93
  const noWhere = !hasWhere(upper);
97
94
  const noLimit = !hasLimit(upper);
98
95
  if (hasSelectStar) {
99
- warnings.push("[COST] SELECT *를 사용하고 있습니다. 필요한 컬럼만 명시하면 BigQuery 스캔 비용을 줄일 수 있습니다.");
96
+ warnings.push("[COST] SELECT * detected. Specify only needed columns to reduce scan costs.");
100
97
  }
101
98
  if (noWhere) {
102
- warnings.push("[COST] WHERE 조건이 없습니다. 날짜 또는 조건 필터를 추가하는 것을 권장합니다.");
99
+ warnings.push("[COST] No WHERE clause. Consider adding date or condition filters.");
103
100
  }
104
101
  if (noLimit) {
105
102
  if (config.autoLimit > 0) {
106
103
  modifiedQuery = injectLimit(sql, config.autoLimit);
107
- warnings.push(`[COST] LIMIT 없어 자동으로 LIMIT ${config.autoLimit} 추가했습니다. 전체 조회가 필요하면 명시적으로 LIMIT을 지정하세요.`);
104
+ warnings.push(`[COST] No LIMIT clause auto-appended LIMIT ${config.autoLimit}. Specify an explicit LIMIT if you need all rows.`);
108
105
  }
109
106
  else {
110
- warnings.push("[COST] LIMIT 없습니다. 대용량 테이블에서는 전체 데이터가 반환되어 비용이 발생할 있습니다.");
107
+ warnings.push("[COST] No LIMIT clause. Full table scans on large tables may incur significant costs.");
111
108
  }
112
109
  }
113
110
  if (config.mode === "strict") {
@@ -116,12 +113,11 @@ export function analyzeQuery(sql) {
116
113
  return {
117
114
  blocked: true,
118
115
  warnings: [],
119
- message: `🚫 쿼리가 차단되었습니다 (strict 모드).\n\n${costWarnings.join("\n")}\n\nwarn 모드로 변경하려면 REDASH_SAFETY_MODE=warn 으로 설정하세요.`,
116
+ message: `🚫 Query blocked (strict mode).\n\n${costWarnings.join("\n")}\n\nSet REDASH_SAFETY_MODE=warn to allow with warnings.`,
120
117
  };
121
118
  }
122
119
  }
123
120
  }
124
- // ── PII (warn: 경고 후 실행, strict: 차단) ────────────────────────────────
125
121
  if (!config.disablePii) {
126
122
  const piiPatterns = [
127
123
  "EMAIL",
@@ -132,14 +128,10 @@ export function analyzeQuery(sql) {
132
128
  "SOCIAL_SECURITY",
133
129
  "CREDIT_CARD",
134
130
  "CARD_NUMBER",
135
- "주민",
136
- "휴대폰",
137
- "핸드폰",
138
- "생년월일",
139
131
  ];
140
132
  const matched = piiPatterns.filter((k) => upper.includes(k));
141
133
  if (matched.length > 0) {
142
- warnings.push(`[PII] 민감 정보 관련 컬럼이 감지되었습니다: ${matched.join(", ")}. 개인정보 처리 규정을 확인하세요.`);
134
+ warnings.push(`[PII] Sensitive data columns detected: ${matched.join(", ")}. Please verify your data privacy compliance.`);
143
135
  }
144
136
  if (config.mode === "strict") {
145
137
  const piiWarnings = warnings.filter((w) => w.startsWith("[PII]"));
@@ -147,13 +139,13 @@ export function analyzeQuery(sql) {
147
139
  return {
148
140
  blocked: true,
149
141
  warnings: [],
150
- message: `🚫 쿼리가 차단되었습니다 (strict 모드).\n\n${piiWarnings.join("\n")}\n\nwarn 모드로 변경하려면 REDASH_SAFETY_MODE=warn 으로 설정하세요.`,
142
+ message: `🚫 Query blocked (strict mode).\n\n${piiWarnings.join("\n")}\n\nSet REDASH_SAFETY_MODE=warn to allow with warnings.`,
151
143
  };
152
144
  }
153
145
  }
154
146
  }
155
147
  const message = warnings.length > 0
156
- ? `⚠️ 안전 경고 (쿼리는 실행됩니다)\n\n${warnings.join("\n")}\n\n---`
148
+ ? `⚠️ Safety warnings (query will still execute)\n\n${warnings.join("\n")}\n\n---`
157
149
  : "";
158
150
  return { blocked: false, warnings, message, modifiedQuery };
159
151
  }
package/manifest.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "manifest_version": "0.3",
3
+ "name": "redash-mcp",
4
+ "version": "3.0.0",
5
+ "description": "MCP server for Redash -- query data, manage dashboards, and run SQL with natural language. 24 tools including BIRD SQL methodology.",
6
+ "author": {
7
+ "name": "seob717",
8
+ "email": "dev.seob717@gmail.com"
9
+ },
10
+ "license": "MIT",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/seob717/redash-mcp"
14
+ },
15
+ "privacy_policies": [
16
+ "https://github.com/seob717/redash-mcp#privacy-policy"
17
+ ],
18
+ "support": "https://github.com/seob717/redash-mcp/issues",
19
+ "server": {
20
+ "type": "node",
21
+ "entry_point": "dist/index.js",
22
+ "mcp_config": {
23
+ "command": "npx",
24
+ "args": ["-y", "redash-mcp"],
25
+ "env": {
26
+ "REDASH_URL": "${user_config.redash_url}",
27
+ "REDASH_API_KEY": "${user_config.redash_api_key}"
28
+ }
29
+ }
30
+ },
31
+ "user_config": {
32
+ "redash_url": {
33
+ "type": "string",
34
+ "title": "Redash URL",
35
+ "description": "Your Redash instance URL (e.g. https://redash.example.com)",
36
+ "required": true
37
+ },
38
+ "redash_api_key": {
39
+ "type": "string",
40
+ "title": "Redash API Key",
41
+ "description": "Your Redash user API key (found in Settings > Account)",
42
+ "sensitive": true,
43
+ "required": true
44
+ }
45
+ }
46
+ }
package/package.json CHANGED
@@ -1,14 +1,27 @@
1
1
  {
2
2
  "name": "redash-mcp",
3
- "version": "2.2.2",
3
+ "version": "3.0.0",
4
4
  "description": "MCP server for Redash",
5
+ "license": "MIT",
6
+ "author": "seob717",
7
+ "keywords": [
8
+ "mcp",
9
+ "redash",
10
+ "sql",
11
+ "bi",
12
+ "dashboard",
13
+ "model-context-protocol"
14
+ ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
5
18
  "repository": {
6
19
  "type": "git",
7
- "url": "https://github.com/seob717/redash-mcp.git"
20
+ "url": "https://github.com/jiro-developers/redash-mcp.git"
8
21
  },
9
- "homepage": "https://github.com/seob717/redash-mcp#readme",
22
+ "homepage": "https://github.com/jiro-developers/redash-mcp#readme",
10
23
  "bugs": {
11
- "url": "https://github.com/seob717/redash-mcp/issues"
24
+ "url": "https://github.com/jiro-developers/redash-mcp/issues"
12
25
  },
13
26
  "type": "module",
14
27
  "main": "dist/index.js",
@@ -21,6 +34,7 @@
21
34
  "start": "node dist/index.js"
22
35
  },
23
36
  "dependencies": {
37
+ "@anthropic-ai/sdk": "^0.80.0",
24
38
  "@clack/prompts": "^1.1.0",
25
39
  "@modelcontextprotocol/sdk": "^1.0.0",
26
40
  "zod": "^3.0.0"
package/.gitattributes DELETED
@@ -1 +0,0 @@
1
- package-lock.json linguist-generated=true
@@ -1,197 +0,0 @@
1
- # SQL Safety Guard — 설계 문서
2
-
3
- ## 개요
4
-
5
- `redash-mcp`에 SQL 안전 가드 레이어를 추가하여 MCP를 통해 실행되는 쿼리로 인한
6
- 비용 발생, 데이터 손실, 개인정보 노출을 사전에 방지한다.
7
-
8
- ---
9
-
10
- ## 배경 및 목적
11
-
12
- - Redash를 MCP로 연결하면 AI가 자동으로 쿼리를 생성·실행하는 환경이 된다
13
- - 사용자가 SQL을 직접 검토하지 않는 경우가 많아 위험 쿼리가 그대로 실행될 수 있음
14
- - BigQuery는 스캔한 데이터 용량 기준으로 과금되어 예상치 못한 비용 발생 가능
15
- - AI가 생성한 쿼리에 DROP, DELETE 등이 포함될 경우 데이터 손실 위험
16
-
17
- ---
18
-
19
- ## 아키텍처
20
-
21
- ### 위치
22
-
23
- ```
24
- AI (Claude)
25
- ↓ tool call
26
- run_query (MCP 도구)
27
-
28
- [SQL Safety Guard] ← 여기에 삽입
29
- ↓ 통과 시
30
- Redash API
31
-
32
- BigQuery
33
- ```
34
-
35
- ### 패턴
36
-
37
- 미들웨어/인터셉터 패턴. `run_query` 핸들러 내부에서 Redash API 호출 전에 실행.
38
-
39
- ```typescript
40
- // src/sql-guard.ts
41
- export function analyzeQuery(sql: string, mode: SafetyMode): SafetyResult
42
-
43
- // src/index.ts (run_query 핸들러)
44
- const result = analyzeQuery(query, safetyMode);
45
- if (result.blocked) {
46
- return { content: [{ type: "text", text: result.message }] };
47
- }
48
- // ... Redash API 호출
49
- ```
50
-
51
- ---
52
-
53
- ## 감지 규칙
54
-
55
- ### Category 1: 데이터 파괴 (Destructive) — 기본: 차단
56
-
57
- | 규칙 | 패턴 예시 | 기본 동작 |
58
- |---|---|---|
59
- | DDL 변경 | `DROP TABLE`, `TRUNCATE`, `ALTER TABLE` | 차단 |
60
- | 조건 없는 삭제 | `DELETE FROM table` (WHERE 없음) | 차단 |
61
- | 조건 없는 수정 | `UPDATE table SET ...` (WHERE 없음) | 차단 |
62
- | 권한 변경 | `GRANT`, `REVOKE` | 차단 |
63
-
64
- ### Category 2: 비용 위험 (Cost) — 기본: 경고
65
-
66
- | 규칙 | 패턴 예시 | 기본 동작 |
67
- |---|---|---|
68
- | WHERE 없는 SELECT | `SELECT ... FROM table` (WHERE 없음) | 경고 |
69
- | SELECT * | `SELECT * FROM ...` | 경고 |
70
- | 집계 없는 대량 조회 | 조건 없이 raw 데이터 전체 조회 | 경고 |
71
-
72
- ### Category 3: 개인정보 (PII) — 기본: 경고
73
-
74
- | 규칙 | 감지 컬럼명 키워드 | 기본 동작 |
75
- |---|---|---|
76
- | 민감 컬럼 SELECT | `email`, `phone`, `password`, `ssn`, `social`, `주민`, `휴대폰`, `핸드폰` | 경고 |
77
-
78
- > PII 규칙은 컬럼명 기반 휴리스틱이며 오탐이 발생할 수 있다.
79
- > 환경변수로 비활성화 가능.
80
-
81
- ---
82
-
83
- ## 동작 모드
84
-
85
- ```
86
- REDASH_SAFETY_MODE=off|warn|strict
87
- ```
88
-
89
- | 모드 | Destructive | Cost | PII |
90
- |---|---|---|---|
91
- | `off` | 통과 | 통과 | 통과 |
92
- | `warn` (기본) | **차단** | 경고 후 실행 | 경고 후 실행 |
93
- | `strict` | **차단** | **차단** | **차단** |
94
-
95
- - Destructive는 모든 모드에서 `warn` 이상이면 차단 (데이터 손실은 되돌릴 수 없음)
96
- - `off`는 완전히 비활성화가 필요한 경우를 위해 제공 (내부 관리자용 등)
97
-
98
- ---
99
-
100
- ## 환경변수
101
-
102
- | 변수 | 기본값 | 설명 |
103
- |---|---|---|
104
- | `REDASH_SAFETY_MODE` | `warn` | 전체 안전 모드 |
105
- | `REDASH_SAFETY_DISABLE_PII` | `false` | PII 감지 비활성화 |
106
- | `REDASH_SAFETY_DISABLE_COST` | `false` | 비용 경고 비활성화 |
107
-
108
- ---
109
-
110
- ## 응답 포맷
111
-
112
- ### 차단 시
113
-
114
- ```
115
- 🚫 쿼리가 차단되었습니다.
116
-
117
- 사유: WHERE 조건 없이 전체 테이블을 수정하는 쿼리는 실행할 수 없습니다.
118
- 규칙: DESTRUCTIVE / UPDATE_WITHOUT_WHERE
119
-
120
- 안전한 쿼리 예시:
121
- UPDATE orders SET status = 'cancelled' WHERE created_at < '2024-01-01'
122
-
123
- 안전 모드 해제가 필요하다면 REDASH_SAFETY_MODE=off 로 설정하세요.
124
- ```
125
-
126
- ### 경고 시 (warn 모드)
127
-
128
- ```
129
- ⚠️ 안전 경고 (쿼리는 실행됩니다)
130
-
131
- [COST] SELECT *를 사용하고 있습니다. 필요한 컬럼만 명시하면 비용을 줄일 수 있습니다.
132
- [COST] WHERE 조건이 없습니다. 날짜 또는 조건 필터를 추가하는 것을 권장합니다.
133
-
134
- ---
135
- (쿼리 결과)
136
- ```
137
-
138
- ---
139
-
140
- ## 파일 구조
141
-
142
- ```
143
- src/
144
- index.ts # 기존 — run_query에 가드 연결
145
- sql-guard.ts # 신규 — 안전 가드 핵심 로직
146
- setup.ts # 기존 — 설치 마법사에 SAFETY_MODE 설정 추가
147
- ```
148
-
149
- ---
150
-
151
- ## setup 마법사 변경
152
-
153
- ```
154
- ? BigQuery 안전 모드를 선택하세요
155
- ○ off — 제한 없음 (관리자 전용)
156
- ● warn — 위험 패턴 경고 후 실행 (권장)
157
- ○ strict — 위험 쿼리 차단
158
-
159
- ? 개인정보(PII) 컬럼 감지를 활성화하시겠습니까?
160
- ● 예 / ○ 아니오
161
- ```
162
-
163
- ---
164
-
165
- ## 구현 범위 (v2.2.0)
166
-
167
- ### 포함
168
- - [x] Destructive 쿼리 차단 (DDL, DELETE/UPDATE without WHERE)
169
- - [x] Cost 경고/차단 (WHERE 없는 SELECT, SELECT *)
170
- - [x] PII 컬럼 경고 (컬럼명 기반)
171
- - [x] `REDASH_SAFETY_MODE` 환경변수
172
- - [x] setup 마법사 안전 모드 설정 추가
173
- - [x] 단위 테스트 (vitest)
174
-
175
- ### 제외 (추후 검토)
176
- - Cartesian JOIN 감지 (SQL 파서 필요, 복잡도 높음)
177
- - 쿼리 실행 횟수 기반 Rate limiting (상태 관리 필요)
178
- - 실제 BQ 스캔 바이트 추정 (BQ 직접 접근 불가)
179
-
180
- ---
181
-
182
- ## 공식 플러그인 등록
183
-
184
- ### MCP 공식 레지스트리
185
- - `modelcontextprotocol/servers` GitHub 레포에 PR 제출
186
- - 요건: npm 패키지, README, 설치 가이드
187
-
188
- ### Claude Desktop
189
- - 현재 Claude Desktop 플러그인 = MCP 서버
190
- - 공식 디렉토리 등록은 Anthropic 신청 필요 (초대제 운영 중)
191
- - 단기적으로는 MCP 커뮤니티 레지스트리 등록으로 대응
192
-
193
- ### 등록 준비 체크리스트
194
- - [ ] README 영문화 (설치, 환경변수, 도구 목록)
195
- - [ ] 라이선스 명시 (MIT)
196
- - [ ] 버전 관리 전략 (semver)
197
- - [ ] CHANGELOG 작성