@parseable/parseable-mcp-server
Advanced tools
| export interface ClientTarget { | ||
| id: string; | ||
| name: string; | ||
| configPath: string; | ||
| } | ||
| export interface InitArgs { | ||
| url?: string; | ||
| username?: string; | ||
| password?: string; | ||
| client?: string; | ||
| } | ||
| export declare function getClientTargets(home?: string, plat?: string): ClientTarget[]; | ||
| export declare function parseInitArgs(argv: string[]): InitArgs; | ||
| export declare function mergeConfig(existing: Record<string, unknown>, creds: { | ||
| url: string; | ||
| username: string; | ||
| password: string; | ||
| }): Record<string, unknown>; | ||
| export declare function runInit(argv?: string[]): Promise<void>; |
+140
| import { existsSync } from "node:fs"; | ||
| import { mkdir, readFile, writeFile } from "node:fs/promises"; | ||
| import { homedir, platform } from "node:os"; | ||
| import { dirname, join } from "node:path"; | ||
| import { createInterface } from "node:readline/promises"; | ||
| export function getClientTargets(home = homedir(), plat = platform()) { | ||
| const targets = []; | ||
| let claudePath; | ||
| if (plat === "darwin") { | ||
| claudePath = join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"); | ||
| } | ||
| else if (plat === "win32") { | ||
| claudePath = join(process.env.APPDATA ?? home, "Claude", "claude_desktop_config.json"); | ||
| } | ||
| else { | ||
| claudePath = join(home, ".config", "Claude", "claude_desktop_config.json"); | ||
| } | ||
| targets.push({ id: "claude-desktop", name: "Claude Desktop", configPath: claudePath }); | ||
| targets.push({ id: "cursor", name: "Cursor", configPath: join(home, ".cursor", "mcp.json") }); | ||
| return targets; | ||
| } | ||
| export function parseInitArgs(argv) { | ||
| const args = {}; | ||
| for (let i = 0; i < argv.length; i++) { | ||
| const a = argv[i]; | ||
| if (a === "--url" && argv[i + 1]) | ||
| args.url = argv[++i]; | ||
| else if (a === "--username" && argv[i + 1]) | ||
| args.username = argv[++i]; | ||
| else if (a === "--password" && argv[i + 1]) | ||
| args.password = argv[++i]; | ||
| else if (a === "--client" && argv[i + 1]) | ||
| args.client = argv[++i]; | ||
| } | ||
| return args; | ||
| } | ||
| export function mergeConfig(existing, creds) { | ||
| const entry = { | ||
| command: "npx", | ||
| args: ["-y", "@parseable/parseable-mcp-server"], | ||
| env: { | ||
| PARSEABLE_URL: creds.url, | ||
| PARSEABLE_USERNAME: creds.username, | ||
| PARSEABLE_PASSWORD: creds.password, | ||
| }, | ||
| }; | ||
| const servers = existing.mcpServers ?? {}; | ||
| servers.parseable = entry; | ||
| return { ...existing, mcpServers: servers }; | ||
| } | ||
| async function writeClientConfig(target, creds) { | ||
| let existing = {}; | ||
| if (existsSync(target.configPath)) { | ||
| const raw = await readFile(target.configPath, "utf8"); | ||
| if (raw.trim()) { | ||
| try { | ||
| existing = JSON.parse(raw); | ||
| } | ||
| catch { | ||
| throw new Error(`Existing config at ${target.configPath} is not valid JSON. Refusing to overwrite.`); | ||
| } | ||
| } | ||
| await writeFile(`${target.configPath}.bak`, raw, "utf8"); | ||
| } | ||
| else { | ||
| await mkdir(dirname(target.configPath), { recursive: true }); | ||
| } | ||
| const merged = mergeConfig(existing, creds); | ||
| await writeFile(target.configPath, `${JSON.stringify(merged, null, 2)}\n`, "utf8"); | ||
| } | ||
| async function ask(rl, question, fallback) { | ||
| const q = fallback ? `${question} [${fallback}]: ` : `${question}: `; | ||
| const answer = (await rl.question(q)).trim(); | ||
| return answer || fallback || ""; | ||
| } | ||
| export async function runInit(argv = process.argv.slice(3)) { | ||
| const args = parseInitArgs(argv); | ||
| console.log("Parseable MCP server — interactive setup\n"); | ||
| const all = getClientTargets(); | ||
| const detected = all.filter((t) => existsSync(t.configPath)); | ||
| if (detected.length === 0) { | ||
| console.log("No MCP clients detected yet. Creating config files for both Claude Desktop and Cursor."); | ||
| console.log("If you only use one, you can delete the other later.\n"); | ||
| } | ||
| else { | ||
| console.log("Detected MCP clients:"); | ||
| for (const [i, t] of detected.entries()) { | ||
| console.log(` ${i + 1}. ${t.name} (${t.configPath})`); | ||
| } | ||
| console.log(); | ||
| } | ||
| const rl = createInterface({ input: process.stdin, output: process.stdout }); | ||
| let chosen; | ||
| if (args.client) { | ||
| const match = all.find((t) => t.id === args.client); | ||
| if (!match) { | ||
| rl.close(); | ||
| console.error(`Unknown client "${args.client}". Use one of: ${all.map((t) => t.id).join(", ")}`); | ||
| process.exit(1); | ||
| } | ||
| chosen = [match]; | ||
| } | ||
| else if (detected.length === 0) { | ||
| chosen = all; | ||
| } | ||
| else { | ||
| const pick = await ask(rl, "Configure which? (comma-separated numbers, or 'all')", "all"); | ||
| if (pick === "all") { | ||
| chosen = detected; | ||
| } | ||
| else { | ||
| const indices = pick.split(",").map((s) => Number.parseInt(s.trim(), 10) - 1); | ||
| chosen = indices.map((i) => detected[i]).filter(Boolean); | ||
| } | ||
| } | ||
| if (chosen.length === 0) { | ||
| rl.close(); | ||
| console.error("No clients selected. Aborting."); | ||
| process.exit(1); | ||
| } | ||
| const url = args.url || (await ask(rl, "Parseable URL")); | ||
| const username = args.username || (await ask(rl, "Username", "admin")); | ||
| const password = args.password || (await ask(rl, "Password")); | ||
| rl.close(); | ||
| if (!url || !username || !password) { | ||
| console.error("URL, username, and password are all required."); | ||
| process.exit(1); | ||
| } | ||
| for (const target of chosen) { | ||
| try { | ||
| await writeClientConfig(target, { url, username, password }); | ||
| console.log(`✓ Configured ${target.name}: ${target.configPath}`); | ||
| } | ||
| catch (err) { | ||
| console.error(`✗ Failed to configure ${target.name}: ${err.message}`); | ||
| } | ||
| } | ||
| console.log(`\nRestart ${chosen.map((t) => t.name).join(" / ")} to load 27 Parseable tools.`); | ||
| } | ||
| //# sourceMappingURL=init.js.map |
| {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAkB,MAAM,wBAAwB,CAAC;AAezE,MAAM,UAAU,gBAAgB,CAC9B,OAAe,OAAO,EAAE,EACxB,OAAe,QAAQ,EAAE;IAEzB,MAAM,OAAO,GAAmB,EAAE,CAAC;IAEnC,IAAI,UAAkB,CAAC;IACvB,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtB,UAAU,GAAG,IAAI,CACf,IAAI,EACJ,SAAS,EACT,qBAAqB,EACrB,QAAQ,EACR,4BAA4B,CAC7B,CAAC;IACJ,CAAC;SAAM,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC;QAC5B,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IACzF,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,4BAA4B,CAAC,CAAC;IAC7E,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,IAAI,EAAE,gBAAgB,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IAEvF,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,CAAC,IAAI,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IAE9F,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc;IAC1C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,OAAO,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aAClD,IAAI,CAAC,KAAK,YAAY,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACjE,IAAI,CAAC,KAAK,YAAY,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;aACjE,IAAI,CAAC,KAAK,UAAU,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;YAAE,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,QAAiC,EACjC,KAA0D;IAE1D,MAAM,KAAK,GAAG;QACZ,OAAO,EAAE,KAAK;QACd,IAAI,EAAE,CAAC,IAAI,EAAE,iCAAiC,CAAC;QAC/C,GAAG,EAAE;YACH,aAAa,EAAE,KAAK,CAAC,GAAG;YACxB,kBAAkB,EAAE,KAAK,CAAC,QAAQ;YAClC,kBAAkB,EAAE,KAAK,CAAC,QAAQ;SACnC;KACF,CAAC;IAEF,MAAM,OAAO,GAAI,QAAQ,CAAC,UAAsC,IAAI,EAAE,CAAC;IACvE,OAAO,CAAC,SAAS,GAAG,KAAK,CAAC;IAC1B,OAAO,EAAE,GAAG,QAAQ,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AAC9C,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,MAAoB,EACpB,KAA0D;IAE1D,IAAI,QAAQ,GAA4B,EAAE,CAAC;IAC3C,IAAI,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;YACf,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC7B,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACb,sBAAsB,MAAM,CAAC,UAAU,4CAA4C,CACpF,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,SAAS,CAAC,GAAG,MAAM,CAAC,UAAU,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC5C,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AACrF,CAAC;AAED,KAAK,UAAU,GAAG,CAAC,EAAa,EAAE,QAAgB,EAAE,QAAiB;IACnE,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,QAAQ,KAAK,QAAQ,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,CAAC;IACrE,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAC7C,OAAO,MAAM,IAAI,QAAQ,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IAEjC,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAE1D,MAAM,GAAG,GAAG,gBAAgB,EAAE,CAAC;IAC/B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAE7D,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CACT,wFAAwF,CACzF,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,wDAAwD,CAAC,CAAC;IACxE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACxC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,CAAC,GAAG,EAAE,CAAC;IAChB,CAAC;IAED,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAE7E,IAAI,MAAsB,CAAC;IAC3B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,CAAC,KAAK,CACX,mBAAmB,IAAI,CAAC,MAAM,kBAAkB,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClF,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC;IACnB,CAAC;SAAM,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,EAAE,EAAE,sDAAsD,EAAE,KAAK,CAAC,CAAC;QAC1F,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACnB,MAAM,GAAG,QAAQ,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC9E,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC,CAAC;IACzD,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC,CAAC;IAE9D,EAAE,CAAC,KAAK,EAAE,CAAC;IAEX,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,MAAM,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,iBAAiB,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;YAC7D,OAAO,CAAC,GAAG,CAAC,gBAAgB,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,MAAM,CAAC,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,aAAa,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;AAChG,CAAC"} |
+5
-0
@@ -9,2 +9,7 @@ #!/usr/bin/env node | ||
| async function main() { | ||
| if (process.argv[2] === "init") { | ||
| const { runInit } = await import("./init.js"); | ||
| await runInit(); | ||
| return; | ||
| } | ||
| const config = loadConfig(); | ||
@@ -11,0 +16,0 @@ const client = new ParseableClient(config); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,KAAK,UAAU,IAAI;IACjB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,EAAE,IAA6B,EAAE,EAAE;YACtD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC3C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;oBAClC,OAAO,WAAW,CAAC,GAAG,GAAG,CAAC,OAAO,uBAAuB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtE,CAAC;gBACD,OAAO,WAAW,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC;QAEF,uEAAuE;QAErE,MAAM,CAAC,YAKR,CACC,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CACX,mCAAmC,KAAK,CAAC,MAAM,8BAA8B,MAAM,CAAC,GAAG,EAAE,CAC1F,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"} | ||
| {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE3D,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QAC/B,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAC9C,MAAM,OAAO,EAAE,CAAC;QAChB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,GAAG,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IAE/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,KAAK,EAAE,IAA6B,EAAE,EAAE;YACtD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC3C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;oBAClC,OAAO,WAAW,CAAC,GAAG,GAAG,CAAC,OAAO,uBAAuB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;gBACtE,CAAC;gBACD,OAAO,WAAW,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACvE,CAAC;QACH,CAAC,CAAC;QAEF,uEAAuE;QAErE,MAAM,CAAC,YAKR,CACC,IAAI,CAAC,IAAI,EACT;YACE,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,EACD,OAAO,CACR,CAAC;IACJ,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CACX,mCAAmC,KAAK,CAAC,MAAM,8BAA8B,MAAM,CAAC,GAAG,EAAE,CAC1F,CAAC;AACJ,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"} |
+1
-1
| { | ||
| "name": "@parseable/parseable-mcp-server", | ||
| "version": "0.1.1", | ||
| "version": "0.2.0", | ||
| "description": "Model Context Protocol server for Parseable. Lets LLMs discover and query Parseable datasets.", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
+88
-63
@@ -5,57 +5,85 @@ # Parseable MCP Server | ||
| > **Status:** v0.4 — 27 tools across discovery, query (SQL + PromQL), alerts, alert targets, diagnostics, RBAC (read-only), and admin (read-only). Tools-only over stdio for maximum cross-client compatibility. | ||
| > **Status:** v0.2 — 27 tools across discovery, query (SQL + PromQL), alerts, alert targets, diagnostics, RBAC (read-only), and admin (read-only). Tools-only over stdio for maximum cross-client compatibility. | ||
| ## Quickstart | ||
| One command, interactive setup — detects Claude Desktop / Cursor, asks for your Parseable URL + credentials, writes their config files: | ||
| ```bash | ||
| npx -y @parseable/parseable-mcp-server init | ||
| ``` | ||
| Restart your MCP client. Tools appear. Skip the rest of this README unless you want to configure manually. | ||
| For scripted / non-interactive setup: | ||
| ```bash | ||
| npx -y @parseable/parseable-mcp-server init \ | ||
| --client claude-desktop \ | ||
| --url https://your-parseable.example.com \ | ||
| --username admin \ | ||
| --password "$PARSEABLE_PASSWORD" | ||
| ``` | ||
| Supported `--client` values: `claude-desktop`, `cursor`. Existing config files are backed up as `<config>.bak` before being modified. Other `mcpServers` entries are preserved. | ||
| ## Tools | ||
| ### Discovery | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `list_datasets` | List all log datasets on the server. | | ||
| | `get_dataset_schema` | Get column names + types for a dataset. | | ||
| | `get_dataset_info` | Get dataset metadata (created_at, retention, owner, time window). | | ||
| | `get_dataset_stats` | Get event count and storage bytes for a dataset. | | ||
| | `sample_events` | Return the most recent N events from a dataset (time-bounded, row-capped). | | ||
| | Tool | Purpose | | ||
| | -------------------- | -------------------------------------------------------------------------- | | ||
| | `list_datasets` | List all log datasets on the server. | | ||
| | `get_dataset_schema` | Get column names + types for a dataset. | | ||
| | `get_dataset_info` | Get dataset metadata (created_at, retention, owner, time window). | | ||
| | `get_dataset_stats` | Get event count and storage bytes for a dataset. | | ||
| | `sample_events` | Return the most recent N events from a dataset (time-bounded, row-capped). | | ||
| ### Query | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `query_sql` | Run a SQL `SELECT` over a time window. DDL/DML blocked. Auto-injects `LIMIT`. | | ||
| | Tool | Purpose | | ||
| | -------------- | ------------------------------------------------------------------------------------------ | | ||
| | `query_sql` | Run a SQL `SELECT` over a time window. DDL/DML blocked. Auto-injects `LIMIT`. | | ||
| | `query_promql` | Run PromQL instant or range query against a metrics dataset. Auto-routes by `start`+`end`. | | ||
| ### Alerts | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `list_alerts` | List all alerts with state, severity, tags. | | ||
| | `get_alert` | Get full config for one alert. | | ||
| | `list_alert_tags` | List all alert tags in use. | | ||
| | `enable_alert` | Enable an alert. | | ||
| | `disable_alert` | Disable an alert. | | ||
| | `evaluate_alert` | Force-evaluate an alert now. **May fire real notifications.** | | ||
| | `create_alert` | Create a new alert. Walks user through 8 questions (title, dataset, condition, window, frequency, severity, tags, targets), confirms assembled spec before submitting. | | ||
| | Tool | Purpose | | ||
| | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `list_alerts` | List all alerts with state, severity, tags. | | ||
| | `get_alert` | Get full config for one alert. | | ||
| | `list_alert_tags` | List all alert tags in use. | | ||
| | `enable_alert` | Enable an alert. | | ||
| | `disable_alert` | Disable an alert. | | ||
| | `evaluate_alert` | Force-evaluate an alert now. **May fire real notifications.** | | ||
| | `create_alert` | Create a new alert. Walks user through 8 questions (title, dataset, condition, window, frequency, severity, tags, targets), confirms assembled spec before submitting. | | ||
| ### Alert targets | ||
| Notification destinations referenced by alerts. Three supported types: **Slack**, **generic webhook**, **Alertmanager**. | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `list_alert_targets` | List all configured targets with ID, name, type. Called automatically by `create_alert` so the user picks targets by name instead of typing UUIDs. | | ||
| | `get_alert_target` | Get full config for one target (endpoint, headers, auth, notification interval). | | ||
| | `create_alert_target` | Create a new Slack/webhook/Alertmanager target. | | ||
| | Tool | Purpose | | ||
| | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `list_alert_targets` | List all configured targets with ID, name, type. Called automatically by `create_alert` so the user picks targets by name instead of typing UUIDs. | | ||
| | `get_alert_target` | Get full config for one target (endpoint, headers, auth, notification interval). | | ||
| | `create_alert_target` | Create a new Slack/webhook/Alertmanager target. | | ||
| ### Diagnostics | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `ping` | Check server connectivity and return version/build info (`/about`), `/liveness`, `/readiness`. Use to debug MCP-server → Parseable connection issues. | | ||
| | `explain_query` | Run `EXPLAIN` on a SQL query without executing it. Returns DataFusion plan for debugging slow queries, predicate pushdown, partition pruning. | | ||
| | Tool | Purpose | | ||
| | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| | `ping` | Check server connectivity and return version/build info (`/about`), `/liveness`, `/readiness`. Use to debug MCP-server → Parseable connection issues. | | ||
| | `explain_query` | Run `EXPLAIN` on a SQL query without executing it. Returns DataFusion plan for debugging slow queries, predicate pushdown, partition pruning. | | ||
| ### RBAC (read-only) | ||
| Inspect users, roles, and effective access. **No tools for creating, modifying, or deleting users/roles** — RBAC mutation stays in the Parseable UI/CLI by design. | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `list_users` | List all registered users. | | ||
| | `get_user_roles` | Get the roles assigned to a specific user. | | ||
| | `list_roles` | List all role names defined on the server. | | ||
| | `get_role` | Get the privilege definition for a role (actions + datasets). | | ||
| | `get_default_role` | Get the default role assigned to new users. | | ||
| | Tool | Purpose | | ||
| | ------------------ | ------------------------------------------------------------- | | ||
| | `list_users` | List all registered users. | | ||
| | `get_user_roles` | Get the roles assigned to a specific user. | | ||
| | `list_roles` | List all role names defined on the server. | | ||
| | `get_role` | Get the privilege definition for a role (actions + datasets). | | ||
| | `get_default_role` | Get the default role assigned to new users. | | ||
@@ -65,9 +93,10 @@ These compose for permission audits: "Does user X have write access to dataset Y?" → call `get_user_roles(X)` → for each role call `get_role` → check if `Ingest` or `PutAlert` privilege covers Y. | ||
| ### Admin (read-only) | ||
| Inspect cluster health and dataset lifecycle. **No tools for mutating cluster state or retention** — keep changes in UI/CLI by design. | ||
| | Tool | Purpose | | ||
| |---|---| | ||
| | `get_cluster_status` | List all nodes (Prism, Querier, Ingestor, Indexer) with status. Distributed mode only. | | ||
| | Tool | Purpose | | ||
| | --------------------- | ------------------------------------------------------------------------------------------------- | | ||
| | `get_cluster_status` | List all nodes (Prism, Querier, Ingestor, Indexer) with status. Distributed mode only. | | ||
| | `get_cluster_metrics` | Aggregated metrics across all nodes (ingest rate, query latency, storage). Distributed mode only. | | ||
| | `get_retention` | Get retention policy for a dataset. | | ||
| | `get_retention` | Get retention policy for a dataset. | | ||
@@ -81,8 +110,4 @@ ## Prerequisites | ||
| No install step — every MCP client invokes the server via `npx`, which fetches it on demand: | ||
| No install step — every MCP client invokes the server via `npx`, which fetches it on demand. The [Quickstart](#quickstart) above wires it into Claude Desktop / Cursor automatically. Skip ahead to **Client setup** below if you prefer manual config. | ||
| ``` | ||
| npx -y @parseable/parseable-mcp-server | ||
| ``` | ||
| For local development (hacking on the server itself): | ||
@@ -102,14 +127,14 @@ | ||
| | Var | Required | Default | Purpose | | ||
| |---|---|---|---| | ||
| | `PARSEABLE_URL` | ✅ | — | Parseable server base URL, no trailing slash | | ||
| | `PARSEABLE_USERNAME` | ✅ | — | Basic auth username | | ||
| | `PARSEABLE_PASSWORD` | ✅ | — | Basic auth password | | ||
| | `PARSEABLE_DEFAULT_DATASET` | | — | Scope a tool prompt to one dataset (advisory) | | ||
| | `PARSEABLE_MAX_ROWS` | | 1000 | Hard cap on query result rows | | ||
| | `PARSEABLE_QUERY_TIMEOUT_MS` | | 30000 | HTTP request timeout | | ||
| | Var | Required | Default | Purpose | | ||
| | ---------------------------- | -------- | ------- | --------------------------------------------- | | ||
| | `PARSEABLE_URL` | ✅ | — | Parseable server base URL, no trailing slash | | ||
| | `PARSEABLE_USERNAME` | ✅ | — | Basic auth username | | ||
| | `PARSEABLE_PASSWORD` | ✅ | — | Basic auth password | | ||
| | `PARSEABLE_DEFAULT_DATASET` | | — | Scope a tool prompt to one dataset (advisory) | | ||
| | `PARSEABLE_MAX_ROWS` | | 1000 | Hard cap on query result rows | | ||
| | `PARSEABLE_QUERY_TIMEOUT_MS` | | 30000 | HTTP request timeout | | ||
| ## Client setup | ||
| The command and args are the same for every client — only the config file location and syntax differ. | ||
| Manual config — only needed if [Quickstart](#quickstart) doesn't cover your client (Claude Code, Codex, VS Code, Windsurf, Continue, Cline, Zed). The command and args are the same for every client — only the config file location and syntax differ. | ||
@@ -216,11 +241,11 @@ ### Claude Desktop | ||
| - *"What datasets do I have in Parseable?"* | ||
| - *"Show schema for `nginx_access`."* | ||
| - *"Run SQL: count events per status code in `nginx_access` over the last hour."* | ||
| - *"Plot rate(http_requests_total[5m]) from `otel_metrics` over last 30 min, step 1m."* | ||
| - *"List my alerts and which ones are disabled."* | ||
| - *"Disable alert `<id>`, too noisy."* | ||
| - *"Create an alert that fires when 5xx count in `nginx_access` > 50 over 5 min, severity high, notify the ops Slack channel."* — the client walks the 8-step Q&A, calls `list_alert_targets` to pick "ops Slack" by name, then submits. | ||
| - *"What notification targets are configured?"* — calls `list_alert_targets`. | ||
| - *"Add a Slack target pointing at `https://hooks.slack.com/services/...` named ops-alerts."* — calls `create_alert_target`. | ||
| - _"What datasets do I have in Parseable?"_ | ||
| - _"Show schema for `nginx_access`."_ | ||
| - _"Run SQL: count events per status code in `nginx_access` over the last hour."_ | ||
| - _"Plot rate(http_requests_total[5m]) from `otel_metrics` over last 30 min, step 1m."_ | ||
| - _"List my alerts and which ones are disabled."_ | ||
| - _"Disable alert `<id>`, too noisy."_ | ||
| - _"Create an alert that fires when 5xx count in `nginx_access` > 50 over 5 min, severity high, notify the ops Slack channel."_ — the client walks the 8-step Q&A, calls `list_alert_targets` to pick "ops Slack" by name, then submits. | ||
| - _"What notification targets are configured?"_ — calls `list_alert_targets`. | ||
| - _"Add a Slack target pointing at `https://hooks.slack.com/services/...` named ops-alerts."_ — calls `create_alert_target`. | ||
@@ -227,0 +252,0 @@ ## Security notes |
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 2 instances
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
113857
17.56%102
3.03%1291
14.45%301
9.06%10
42.86%