redash-mcp 2.0.3 → 2.1.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/.omc/project-memory.json +101 -0
- package/.omc/sessions/0450b0c4-f994-42f3-afd3-8f1b23f25ad6.json +8 -0
- package/.omc/sessions/0cb3ce10-4e01-4426-8d8f-e76668bcf8eb.json +8 -0
- package/.omc/sessions/1eaa9d6f-a106-4c32-aad1-96ea536bbc23.json +8 -0
- package/.omc/sessions/3a248a8e-825c-4cb7-980b-8b6ef4c75fb6.json +8 -0
- package/.omc/sessions/42043e3e-2800-407f-b1ab-e17206a826e2.json +8 -0
- package/.omc/sessions/441cb2ce-7778-43b1-aad0-6f528ce067f5.json +8 -0
- package/.omc/sessions/4a7d0bb3-4702-49c3-ad7d-3a0936365e46.json +8 -0
- package/.omc/sessions/51fddb19-06a4-4491-b751-e46b5d7e04c4.json +8 -0
- package/.omc/sessions/85f46695-2555-4c3d-9b7b-8ed9ab03083a.json +8 -0
- package/.omc/sessions/bce5f4fd-c242-4074-b005-37abb59f88d8.json +8 -0
- package/.omc/state/agent-replay-0cb3ce10-4e01-4426-8d8f-e76668bcf8eb.jsonl +11 -0
- package/.omc/state/agent-replay-4a7d0bb3-4702-49c3-ad7d-3a0936365e46.jsonl +1 -0
- package/.omc/state/hud-state.json +6 -0
- package/.omc/state/hud-stdin-cache.json +1 -0
- package/.omc/state/idle-notif-cooldown.json +3 -0
- package/.omc/state/last-tool-error.json +7 -0
- package/.omc/state/sessions/0cb3ce10-4e01-4426-8d8f-e76668bcf8eb/cancel-signal-state.json +7 -0
- package/dist/index.js +33 -18
- package/dist/setup.js +53 -35
- package/package.json +2 -1
- package/.claude/settings.local.json +0 -18
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"lastScanned": 1772697803610,
|
|
4
|
+
"projectRoot": "/Users/jiro/WebstormProjects/jiro-tools/redash-mcp",
|
|
5
|
+
"techStack": {
|
|
6
|
+
"languages": [
|
|
7
|
+
{
|
|
8
|
+
"name": "JavaScript/TypeScript",
|
|
9
|
+
"version": null,
|
|
10
|
+
"confidence": "high",
|
|
11
|
+
"markers": [
|
|
12
|
+
"package.json"
|
|
13
|
+
]
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "TypeScript",
|
|
17
|
+
"version": null,
|
|
18
|
+
"confidence": "high",
|
|
19
|
+
"markers": [
|
|
20
|
+
"tsconfig.json"
|
|
21
|
+
]
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"frameworks": [],
|
|
25
|
+
"packageManager": "npm",
|
|
26
|
+
"runtime": null
|
|
27
|
+
},
|
|
28
|
+
"build": {
|
|
29
|
+
"buildCommand": "npm run build",
|
|
30
|
+
"testCommand": null,
|
|
31
|
+
"lintCommand": null,
|
|
32
|
+
"devCommand": "npm run dev",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsc",
|
|
35
|
+
"dev": "tsx src/index.ts",
|
|
36
|
+
"start": "node dist/index.js"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"conventions": {
|
|
40
|
+
"namingStyle": "camelCase",
|
|
41
|
+
"importStyle": "ES modules",
|
|
42
|
+
"testPattern": null,
|
|
43
|
+
"fileOrganization": null
|
|
44
|
+
},
|
|
45
|
+
"structure": {
|
|
46
|
+
"isMonorepo": false,
|
|
47
|
+
"workspaces": [],
|
|
48
|
+
"mainDirectories": [
|
|
49
|
+
"src"
|
|
50
|
+
],
|
|
51
|
+
"gitBranches": null
|
|
52
|
+
},
|
|
53
|
+
"customNotes": [],
|
|
54
|
+
"directoryMap": {
|
|
55
|
+
"dist": {
|
|
56
|
+
"path": "dist",
|
|
57
|
+
"purpose": "Distribution/build output",
|
|
58
|
+
"fileCount": 1,
|
|
59
|
+
"lastAccessed": 1772697803604,
|
|
60
|
+
"keyFiles": [
|
|
61
|
+
"index.js"
|
|
62
|
+
]
|
|
63
|
+
},
|
|
64
|
+
"src": {
|
|
65
|
+
"path": "src",
|
|
66
|
+
"purpose": "Source code",
|
|
67
|
+
"fileCount": 1,
|
|
68
|
+
"lastAccessed": 1772697803604,
|
|
69
|
+
"keyFiles": [
|
|
70
|
+
"index.ts"
|
|
71
|
+
]
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
"hotPaths": [
|
|
75
|
+
{
|
|
76
|
+
"path": "src/index.ts",
|
|
77
|
+
"accessCount": 23,
|
|
78
|
+
"lastAccessed": 1772762087285,
|
|
79
|
+
"type": "file"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"path": "package.json",
|
|
83
|
+
"accessCount": 18,
|
|
84
|
+
"lastAccessed": 1772761975801,
|
|
85
|
+
"type": "file"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"path": "src/setup.ts",
|
|
89
|
+
"accessCount": 9,
|
|
90
|
+
"lastAccessed": 1772763077204,
|
|
91
|
+
"type": "file"
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"path": "",
|
|
95
|
+
"accessCount": 8,
|
|
96
|
+
"lastAccessed": 1772760488146,
|
|
97
|
+
"type": "directory"
|
|
98
|
+
}
|
|
99
|
+
],
|
|
100
|
+
"userDirectives": []
|
|
101
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
{"t":0,"agent":"system","event":"keyword_detected","keyword":"ultrawork"}
|
|
2
|
+
{"t":0,"agent":"system","event":"mode_change","mode_from":"none","mode_to":"ultrawork"}
|
|
3
|
+
{"t":0,"agent":"af83682","agent_type":"executor","event":"agent_start","parent_mode":"none"}
|
|
4
|
+
{"t":0,"agent":"a5125cc","agent_type":"executor","event":"agent_start","parent_mode":"none"}
|
|
5
|
+
{"t":0,"agent":"a5d466c","agent_type":"executor","event":"agent_start","parent_mode":"none"}
|
|
6
|
+
{"t":0,"agent":"a5125cc","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":19049}
|
|
7
|
+
{"t":0,"agent":"ae89220","agent_type":"executor","event":"agent_start","parent_mode":"none"}
|
|
8
|
+
{"t":0,"agent":"af83682","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":53629}
|
|
9
|
+
{"t":0,"agent":"ae89220","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":29751}
|
|
10
|
+
{"t":0,"agent":"a5d466c","agent_type":"executor","event":"agent_stop","success":true,"duration_ms":43278}
|
|
11
|
+
{"t":0,"agent":"system","event":"skill_invoked","skill_name":"oh-my-claudecode:cancel"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"t":0,"agent":"system","event":"skill_invoked","skill_name":"oh-my-claudecode:skill"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"session_id":"af950aa1-02a2-433d-bf22-7ae432356e6a","transcript_path":"/Users/jiro/.claude/projects/-Users-jiro-WebstormProjects-jiro-tools-redash-mcp/af950aa1-02a2-433d-bf22-7ae432356e6a.jsonl","cwd":"/Users/jiro/WebstormProjects/jiro-tools/redash-mcp","model":{"id":"claude-sonnet-4-6","display_name":"Sonnet 4.6"},"workspace":{"current_dir":"/Users/jiro/WebstormProjects/jiro-tools/redash-mcp","project_dir":"/Users/jiro/WebstormProjects/jiro-tools/redash-mcp","added_dirs":["/Users/jiro/.claude/skills/omc-learned"]},"version":"2.1.69","output_style":{"name":"default"},"cost":{"total_cost_usd":3.3345675000000017,"total_duration_ms":3892454,"total_api_duration_ms":594144,"total_lines_added":271,"total_lines_removed":22},"context_window":{"total_input_tokens":71068,"total_output_tokens":28846,"context_window_size":200000,"current_usage":{"input_tokens":1,"output_tokens":139,"cache_creation_input_tokens":157,"cache_read_input_tokens":52142},"used_percentage":26,"remaining_percentage":74},"exceeds_200k_tokens":false}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"tool_name": "Bash",
|
|
3
|
+
"tool_input_preview": "{\"command\":\"NPM_TOKEN=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 npm whoami --registry=https://registry.npmjs.org/ 2>&1\",\"description\":\"토큰으로 npm 인증 확인\"}",
|
|
4
|
+
"error": "Exit code 1\nnpm error code E401\nnpm error 401 Unauthorized - GET https://registry.npmjs.org/-/whoami\nnpm error A complete log of this run can be found in: /Users/jiro/.npm/_logs/2026-03-06T02_18_25_687Z-debug-0.log\n\nnpm error code E401\nnpm error 401 Unauthorized - GET https://registry.npmjs.org/-/whoami\nnpm error A complete log of this run can be found in: /Users/jiro/.npm/_logs/2026-03-06T02_18_25_687Z-debug-0.log",
|
|
5
|
+
"timestamp": "2026-03-06T02:18:26.057Z",
|
|
6
|
+
"retry_count": 1
|
|
7
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -23,17 +23,27 @@ async function redashFetch(path, options) {
|
|
|
23
23
|
},
|
|
24
24
|
});
|
|
25
25
|
if (!res.ok) {
|
|
26
|
-
|
|
26
|
+
let hint = "";
|
|
27
|
+
if (res.status === 401)
|
|
28
|
+
hint = " (REDASH_API_KEY를 확인하세요)";
|
|
29
|
+
else if (res.status === 403)
|
|
30
|
+
hint = " (해당 리소스에 대한 접근 권한이 없습니다)";
|
|
31
|
+
else if (res.status === 404)
|
|
32
|
+
hint = " (리소스를 찾을 수 없습니다. ID를 확인하세요)";
|
|
33
|
+
throw new Error(`Redash API error: ${res.status} ${res.statusText}${hint}`);
|
|
34
|
+
}
|
|
35
|
+
if (res.status === 204 || res.headers.get("content-length") === "0") {
|
|
36
|
+
return null;
|
|
27
37
|
}
|
|
28
38
|
return res.json();
|
|
29
39
|
}
|
|
30
40
|
async function pollQueryResult(jobId, timeoutSecs = 30) {
|
|
31
41
|
for (let i = 0; i < timeoutSecs; i++) {
|
|
32
42
|
const job = await redashFetch(`/jobs/${jobId}`);
|
|
33
|
-
if (job.job.status === 3) {
|
|
43
|
+
if (job.job.status === 3) { // 3 = success
|
|
34
44
|
return await redashFetch(`/query_results/${job.job.query_result_id}`);
|
|
35
45
|
}
|
|
36
|
-
if (job.job.status === 4) {
|
|
46
|
+
if (job.job.status === 4) { // 4 = failure
|
|
37
47
|
throw new Error(`Query failed: ${job.job.error}`);
|
|
38
48
|
}
|
|
39
49
|
await new Promise((r) => setTimeout(r, 1000));
|
|
@@ -41,10 +51,11 @@ async function pollQueryResult(jobId, timeoutSecs = 30) {
|
|
|
41
51
|
throw new Error(`Query timed out after ${timeoutSecs}s`);
|
|
42
52
|
}
|
|
43
53
|
function formatAsMarkdownTable(columns, rows) {
|
|
44
|
-
const
|
|
54
|
+
const escape = (s) => s.replace(/\|/g, "\\|");
|
|
55
|
+
const header = `| ${columns.map(escape).join(" | ")} |`;
|
|
45
56
|
const separator = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
46
57
|
const body = rows
|
|
47
|
-
.map((row) => `| ${columns.map((c) => String(row[c] ?? "")).join(" | ")} |`)
|
|
58
|
+
.map((row) => `| ${columns.map((c) => escape(String(row[c] ?? ""))).join(" | ")} |`)
|
|
48
59
|
.join("\n");
|
|
49
60
|
return `${header}\n${separator}\n${body}`;
|
|
50
61
|
}
|
|
@@ -63,7 +74,7 @@ async function fetchSchema(dataSourceId) {
|
|
|
63
74
|
}
|
|
64
75
|
const server = new McpServer({
|
|
65
76
|
name: "redash-mcp",
|
|
66
|
-
version: "2.0.
|
|
77
|
+
version: "2.0.2",
|
|
67
78
|
});
|
|
68
79
|
// ─── Data Sources ────────────────────────────────────────────────────────────
|
|
69
80
|
server.tool("list_data_sources", "Redash에 연결된 데이터소스 목록(id, name, type)을 반환합니다. 항상 이 툴을 먼저 호출해 data_source_id를 확인하세요.", {}, async () => {
|
|
@@ -183,7 +194,9 @@ server.tool("list_queries", "Redash에 저장된 쿼리 목록을 조회합니
|
|
|
183
194
|
});
|
|
184
195
|
server.tool("get_query_result", "저장된 Redash 쿼리를 ID로 실행하고 결과를 반환합니다.", {
|
|
185
196
|
query_id: z.number().describe("저장된 쿼리 ID (list_queries로 확인)"),
|
|
186
|
-
|
|
197
|
+
max_rows: z.number().optional().default(100).describe("반환할 최대 행 수 (기본 100)"),
|
|
198
|
+
format: z.enum(["table", "json"]).optional().default("table").describe("결과 포맷: table(마크다운) 또는 json"),
|
|
199
|
+
}, async ({ query_id, max_rows, format }) => {
|
|
187
200
|
const res = await redashFetch(`/queries/${query_id}/results`, {
|
|
188
201
|
method: "POST",
|
|
189
202
|
body: JSON.stringify({}),
|
|
@@ -198,11 +211,22 @@ server.tool("get_query_result", "저장된 Redash 쿼리를 ID로 실행하고
|
|
|
198
211
|
const qr = result.query_result;
|
|
199
212
|
const rows = qr.data.rows;
|
|
200
213
|
const columns = qr.data.columns.map((c) => c.name);
|
|
214
|
+
const displayRows = rows.slice(0, max_rows);
|
|
215
|
+
const truncated = rows.length > max_rows
|
|
216
|
+
? `\n⚠️ 전체 ${rows.length}행 중 ${max_rows}행만 표시합니다.`
|
|
217
|
+
: "";
|
|
218
|
+
let body;
|
|
219
|
+
if (format === "json") {
|
|
220
|
+
body = JSON.stringify(displayRows, null, 2);
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
body = formatAsMarkdownTable(columns, displayRows);
|
|
224
|
+
}
|
|
201
225
|
return {
|
|
202
226
|
content: [
|
|
203
227
|
{
|
|
204
228
|
type: "text",
|
|
205
|
-
text: `쿼리 ID: ${query_id}\n총 ${rows.length}
|
|
229
|
+
text: `쿼리 ID: ${query_id}\n총 ${rows.length}행 | 컬럼: ${columns.join(", ")}${truncated}\n\n${body}`,
|
|
206
230
|
},
|
|
207
231
|
],
|
|
208
232
|
};
|
|
@@ -302,16 +326,7 @@ server.tool("fork_query", "기존 쿼리를 복제(fork)합니다.", {
|
|
|
302
326
|
server.tool("archive_query", "쿼리를 아카이브(삭제)합니다. 복구 불가합니다.", {
|
|
303
327
|
query_id: z.number().describe("아카이브할 쿼리 ID"),
|
|
304
328
|
}, async ({ query_id }) => {
|
|
305
|
-
|
|
306
|
-
method: "DELETE",
|
|
307
|
-
headers: {
|
|
308
|
-
"Authorization": `Key ${REDASH_API_KEY}`,
|
|
309
|
-
"Content-Type": "application/json",
|
|
310
|
-
},
|
|
311
|
-
});
|
|
312
|
-
if (!res.ok) {
|
|
313
|
-
throw new Error(`Redash API error: ${res.status} ${res.statusText}`);
|
|
314
|
-
}
|
|
329
|
+
await redashFetch(`/queries/${query_id}`, { method: "DELETE" });
|
|
315
330
|
return {
|
|
316
331
|
content: [{ type: "text", text: `쿼리 ${query_id}가 아카이브되었습니다.` }],
|
|
317
332
|
};
|
package/dist/setup.js
CHANGED
|
@@ -2,10 +2,8 @@
|
|
|
2
2
|
import * as fs from "fs";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import * as os from "os";
|
|
5
|
-
import * as readline from "readline";
|
|
6
5
|
import { execSync } from "child_process";
|
|
7
|
-
|
|
8
|
-
const ask = (q) => new Promise((res) => rl.question(q, res));
|
|
6
|
+
import * as p from "@clack/prompts";
|
|
9
7
|
function findNpxPath() {
|
|
10
8
|
try {
|
|
11
9
|
const result = execSync("which npx", { encoding: "utf8" }).trim();
|
|
@@ -18,9 +16,9 @@ function findNpxPath() {
|
|
|
18
16
|
"/opt/homebrew/bin/npx",
|
|
19
17
|
"/usr/bin/npx",
|
|
20
18
|
];
|
|
21
|
-
for (const
|
|
22
|
-
if (fs.existsSync(
|
|
23
|
-
return
|
|
19
|
+
for (const c of candidates) {
|
|
20
|
+
if (fs.existsSync(c))
|
|
21
|
+
return c;
|
|
24
22
|
}
|
|
25
23
|
return "npx";
|
|
26
24
|
}
|
|
@@ -40,38 +38,66 @@ function getClaudeCodeConfigPath() {
|
|
|
40
38
|
return path.join(os.homedir(), ".claude", "settings.json");
|
|
41
39
|
}
|
|
42
40
|
export async function main() {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
53
|
-
|
|
54
|
-
process.exit(
|
|
41
|
+
p.intro("redash-mcp 설치 마법사");
|
|
42
|
+
const targets = await p.multiselect({
|
|
43
|
+
message: "설치 대상을 선택하세요 (스페이스바로 선택, 엔터로 확인)",
|
|
44
|
+
options: [
|
|
45
|
+
{ value: "desktop", label: "Claude Desktop" },
|
|
46
|
+
{ value: "cli", label: "Claude Code (CLI)" },
|
|
47
|
+
],
|
|
48
|
+
required: true,
|
|
49
|
+
});
|
|
50
|
+
if (p.isCancel(targets)) {
|
|
51
|
+
p.cancel("설치가 취소되었습니다.");
|
|
52
|
+
process.exit(0);
|
|
55
53
|
}
|
|
54
|
+
const redashUrl = await p.text({
|
|
55
|
+
message: "Redash URL을 입력하세요",
|
|
56
|
+
placeholder: "https://redash.example.com",
|
|
57
|
+
validate(value) {
|
|
58
|
+
if (!value)
|
|
59
|
+
return "URL을 입력해주세요.";
|
|
60
|
+
if (!value.startsWith("http://") && !value.startsWith("https://"))
|
|
61
|
+
return "http:// 또는 https://로 시작해야 합니다.";
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
if (p.isCancel(redashUrl)) {
|
|
65
|
+
p.cancel("설치가 취소되었습니다.");
|
|
66
|
+
process.exit(0);
|
|
67
|
+
}
|
|
68
|
+
const apiKey = await p.text({
|
|
69
|
+
message: "Redash API 키를 입력하세요",
|
|
70
|
+
validate(value) {
|
|
71
|
+
if (!value)
|
|
72
|
+
return "API 키를 입력해주세요.";
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
if (p.isCancel(apiKey)) {
|
|
76
|
+
p.cancel("설치가 취소되었습니다.");
|
|
77
|
+
process.exit(0);
|
|
78
|
+
}
|
|
79
|
+
const url = redashUrl.replace(/\/$/, "");
|
|
56
80
|
const npxPath = findNpxPath();
|
|
57
81
|
const mcpEntry = {
|
|
58
82
|
command: npxPath,
|
|
59
83
|
args: ["-y", "redash-mcp"],
|
|
60
84
|
env: {
|
|
61
|
-
REDASH_URL:
|
|
85
|
+
REDASH_URL: url,
|
|
62
86
|
REDASH_API_KEY: apiKey,
|
|
63
87
|
},
|
|
64
88
|
};
|
|
65
|
-
|
|
89
|
+
const s = p.spinner();
|
|
90
|
+
if (targets.includes("desktop")) {
|
|
91
|
+
s.start("Claude Desktop 설정 중...");
|
|
66
92
|
setupDesktop(mcpEntry);
|
|
93
|
+
s.stop("Claude Desktop 설정 완료");
|
|
67
94
|
}
|
|
68
|
-
if (
|
|
95
|
+
if (targets.includes("cli")) {
|
|
96
|
+
s.start("Claude Code (CLI) 설정 중...");
|
|
69
97
|
setupClaudeCode(mcpEntry);
|
|
98
|
+
s.stop("Claude Code (CLI) 설정 완료");
|
|
70
99
|
}
|
|
71
|
-
|
|
72
|
-
console.error("\n❌ 잘못된 선택입니다. 1, 2, 3 중 하나를 입력하세요.");
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
100
|
+
p.outro("설치가 완료되었습니다. 재시작 후 사용할 수 있습니다.");
|
|
75
101
|
}
|
|
76
102
|
function setupDesktop(mcpEntry) {
|
|
77
103
|
const configPath = getDesktopConfigPath();
|
|
@@ -82,8 +108,7 @@ function setupDesktop(mcpEntry) {
|
|
|
82
108
|
config.mcpServers ??= {};
|
|
83
109
|
}
|
|
84
110
|
catch {
|
|
85
|
-
|
|
86
|
-
process.exit(1);
|
|
111
|
+
throw new Error(`claude_desktop_config.json 파일을 읽을 수 없습니다: ${configPath}`);
|
|
87
112
|
}
|
|
88
113
|
}
|
|
89
114
|
else {
|
|
@@ -91,9 +116,6 @@ function setupDesktop(mcpEntry) {
|
|
|
91
116
|
}
|
|
92
117
|
config.mcpServers["redash-mcp"] = mcpEntry;
|
|
93
118
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
94
|
-
console.log("\n✅ Claude Desktop 설정 완료!");
|
|
95
|
-
console.log(` 설정 파일: ${configPath}`);
|
|
96
|
-
console.log(" 👉 Claude Desktop을 재시작하면 활성화됩니다.");
|
|
97
119
|
}
|
|
98
120
|
function setupClaudeCode(mcpEntry) {
|
|
99
121
|
const configPath = getClaudeCodeConfigPath();
|
|
@@ -103,8 +125,7 @@ function setupClaudeCode(mcpEntry) {
|
|
|
103
125
|
config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
104
126
|
}
|
|
105
127
|
catch {
|
|
106
|
-
|
|
107
|
-
process.exit(1);
|
|
128
|
+
throw new Error(`Claude Code settings.json 파일을 읽을 수 없습니다: ${configPath}`);
|
|
108
129
|
}
|
|
109
130
|
}
|
|
110
131
|
else {
|
|
@@ -113,7 +134,4 @@ function setupClaudeCode(mcpEntry) {
|
|
|
113
134
|
config.mcpServers ??= {};
|
|
114
135
|
config.mcpServers["redash-mcp"] = mcpEntry;
|
|
115
136
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
116
|
-
console.log("\n✅ Claude Code (CLI) 설정 완료!");
|
|
117
|
-
console.log(` 설정 파일: ${configPath}`);
|
|
118
|
-
console.log(" 👉 새 Claude Code 세션에서 바로 사용할 수 있습니다.");
|
|
119
137
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "redash-mcp",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "MCP server for Redash",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"start": "node dist/index.js"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
+
"@clack/prompts": "^1.1.0",
|
|
16
17
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
17
18
|
"zod": "^3.0.0"
|
|
18
19
|
},
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(git clone:*)",
|
|
5
|
-
"Bash(npm:*)",
|
|
6
|
-
"Bash(git push:*)"
|
|
7
|
-
]
|
|
8
|
-
},
|
|
9
|
-
"enabledMcpjsonServers": [
|
|
10
|
-
"context7",
|
|
11
|
-
"filesystem",
|
|
12
|
-
"github"
|
|
13
|
-
],
|
|
14
|
-
"sandbox": {
|
|
15
|
-
"enabled": true,
|
|
16
|
-
"autoAllowBashIfSandboxed": true
|
|
17
|
-
}
|
|
18
|
-
}
|