@conte777/db-view-mcp 1.2.0 → 1.3.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.
Files changed (57) hide show
  1. package/README.md +34 -250
  2. package/config.example.json +3 -1
  3. package/dist/config/types.d.ts +14 -4
  4. package/dist/config/types.js +5 -10
  5. package/dist/config/types.js.map +1 -1
  6. package/dist/connectors/clickhouse.d.ts +1 -1
  7. package/dist/connectors/clickhouse.js +11 -3
  8. package/dist/connectors/clickhouse.js.map +1 -1
  9. package/dist/connectors/manager.d.ts +7 -2
  10. package/dist/connectors/manager.js +38 -35
  11. package/dist/connectors/manager.js.map +1 -1
  12. package/dist/connectors/postgresql.d.ts +1 -1
  13. package/dist/connectors/postgresql.js +61 -13
  14. package/dist/connectors/postgresql.js.map +1 -1
  15. package/dist/index.js +0 -0
  16. package/dist/server.d.ts +1 -1
  17. package/dist/server.js +6 -2
  18. package/dist/server.js.map +1 -1
  19. package/dist/tools/readonly/describe-table.d.ts +1 -3
  20. package/dist/tools/readonly/describe-table.js +5 -5
  21. package/dist/tools/readonly/describe-table.js.map +1 -1
  22. package/dist/tools/readonly/explain.d.ts +1 -3
  23. package/dist/tools/readonly/explain.js +6 -6
  24. package/dist/tools/readonly/explain.js.map +1 -1
  25. package/dist/tools/readonly/list-tables.d.ts +1 -3
  26. package/dist/tools/readonly/list-tables.js +5 -5
  27. package/dist/tools/readonly/list-tables.js.map +1 -1
  28. package/dist/tools/readonly/performance.d.ts +1 -3
  29. package/dist/tools/readonly/performance.js +9 -6
  30. package/dist/tools/readonly/performance.js.map +1 -1
  31. package/dist/tools/readonly/query.d.ts +1 -3
  32. package/dist/tools/readonly/query.js +14 -7
  33. package/dist/tools/readonly/query.js.map +1 -1
  34. package/dist/tools/readonly/schema.d.ts +1 -3
  35. package/dist/tools/readonly/schema.js +5 -5
  36. package/dist/tools/readonly/schema.js.map +1 -1
  37. package/dist/tools/write/execute.d.ts +5 -3
  38. package/dist/tools/write/execute.js +14 -6
  39. package/dist/tools/write/execute.js.map +1 -1
  40. package/dist/tools/write/transaction.d.ts +3 -4
  41. package/dist/tools/write/transaction.js +33 -24
  42. package/dist/tools/write/transaction.js.map +1 -1
  43. package/dist/transport/http.d.ts +2 -2
  44. package/dist/transport/http.js +23 -9
  45. package/dist/transport/http.js.map +1 -1
  46. package/dist/utils/logger.js +1 -1
  47. package/dist/utils/logger.js.map +1 -1
  48. package/dist/utils/resolve-db.d.ts +5 -0
  49. package/dist/utils/resolve-db.js +61 -0
  50. package/dist/utils/resolve-db.js.map +1 -0
  51. package/dist/utils/response.d.ts +12 -0
  52. package/dist/utils/response.js +130 -3
  53. package/dist/utils/response.js.map +1 -1
  54. package/dist/utils/sql-validator.d.ts +16 -0
  55. package/dist/utils/sql-validator.js +157 -4
  56. package/dist/utils/sql-validator.js.map +1 -1
  57. package/package.json +9 -1
@@ -1 +1 @@
1
- {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"AAcA,MAAM,UAAU,aAAa,CAAC,IAAsC;IAClE,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aAC1D;SACF;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,IAAa;IACtD,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAe;gBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;aAC/D;SACF;QACD,OAAO,EAAE,IAAa;KACvB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAA+B,EAAE,QAAgB;IAC1E,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;AAC/D,CAAC"}
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../src/utils/response.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,21 @@
1
1
  export interface ValidationResult {
2
2
  valid: boolean;
3
3
  error?: string;
4
+ /**
5
+ * Present when valid is true: the original SQL with comments and trailing semicolons removed.
6
+ * String literals and quoted identifiers are left byte-for-byte intact — this is NOT the
7
+ * __STR__ placeholder / unquoted-identifier text used internally for keyword matching, which
8
+ * must never reach the database.
9
+ */
10
+ normalizedSql?: string;
4
11
  }
12
+ export type SqlDialect = "postgresql" | "clickhouse";
5
13
  export declare function validateReadonlySql(sql: string): ValidationResult;
14
+ /**
15
+ * Wraps a read-only query in a row-limited subselect. Also strips comments and trailing
16
+ * semicolons (string-literal-aware, same as validateReadonlySql's normalizedSql) as a safety
17
+ * net for callers still passing raw/un-normalized SQL — without this, something like
18
+ * "SELECT 1; -- c" would comment out the wrapper's closing paren. The stripping is idempotent,
19
+ * so passing an already-normalizedSql value is safe and a no-op.
20
+ */
21
+ export declare function wrapReadonlyQuery(sql: string, limit: number, dialect: SqlDialect): string;
@@ -14,11 +14,69 @@ const WRITE_KEYWORDS = [
14
14
  "CALL",
15
15
  ];
16
16
  const WRITE_PATTERN = new RegExp(`\\b(${WRITE_KEYWORDS.join("|")})\\b`, "i");
17
+ // Functions that pass the WRITE_KEYWORDS check but still let a read-only session escape the
18
+ // sandbox: PostgreSQL admin/superuser actions, filesystem/network access, cross-server links,
19
+ // DoS via pg_sleep, or ClickHouse table functions that reach outside the database. The validator
20
+ // doesn't know the dialect, so one combined list is used; the false-positive risk is a table or
21
+ // column literally named e.g. "url" invoked as a function call, which is acceptable.
22
+ const DENIED_FUNCTIONS = [
23
+ // PostgreSQL
24
+ "pg_terminate_backend",
25
+ "pg_cancel_backend",
26
+ "pg_reload_conf",
27
+ "pg_read_file",
28
+ "pg_read_binary_file",
29
+ "pg_ls_dir",
30
+ "pg_ls_logdir",
31
+ "pg_ls_waldir",
32
+ "pg_ls_tmpdir",
33
+ "pg_ls_archive_statusdir",
34
+ "pg_stat_file",
35
+ "pg_file_write",
36
+ "pg_file_rename",
37
+ "pg_file_unlink",
38
+ "lo_import",
39
+ "lo_export",
40
+ "dblink",
41
+ "dblink_exec",
42
+ "dblink_connect",
43
+ "dblink_connect_u",
44
+ "dblink_send_query",
45
+ "dblink_open",
46
+ "dblink_fetch",
47
+ "dblink_close",
48
+ "pg_sleep",
49
+ "pg_logical_emit_message",
50
+ "pg_create_restore_point",
51
+ "pg_switch_wal",
52
+ "pg_promote",
53
+ "set_config",
54
+ // ClickHouse table functions
55
+ "url",
56
+ "file",
57
+ "s3",
58
+ "remote",
59
+ "remoteSecure",
60
+ "mysql",
61
+ "postgresql",
62
+ "jdbc",
63
+ "odbc",
64
+ "hdfs",
65
+ "azureBlobStorage",
66
+ "executable",
67
+ ];
68
+ // Function CALLS only (name directly followed by "("), so column/table names like
69
+ // "file_uploads" or "my_url" are left alone. Matched case-insensitively.
70
+ const DENY_PATTERN = new RegExp(`\\b(${DENIED_FUNCTIONS.join("|")})\\s*\\(`, "i");
17
71
  function stripStringLiterals(sql) {
18
- // Replace single-quoted strings (handling escaped quotes)
72
+ // Replace single-quoted strings (handling escaped quotes) — these are inert data.
19
73
  let result = sql.replace(/'(?:[^'\\]|\\.)*'/g, "__STR__");
20
- // Replace double-quoted identifiers
21
- result = result.replace(/"(?:[^"\\]|\\.)*"/g, "__ID__");
74
+ // Unwrap double-quoted identifiers to their inner text instead of blanking them: in
75
+ // PostgreSQL/ClickHouse `"pg_terminate_backend"(1)` invokes the very same function as the
76
+ // unquoted form, so a quoted name must still be seen by WRITE_PATTERN/DENY_PATTERN. Keeping
77
+ // the content (checked as if unquoted) fails safe — the worst case is rejecting a read query
78
+ // whose column/identifier happens to equal a write keyword or denied function name.
79
+ result = result.replace(/"((?:[^"\\]|\\.)*)"/g, "$1");
22
80
  // Replace dollar-quoted strings (PostgreSQL): $$...$$, $tag$...$tag$
23
81
  result = result.replace(/\$([^$]*)\$[\s\S]*?\$\1\$/g, "__STR__");
24
82
  return result;
@@ -33,6 +91,77 @@ function stripComments(sql) {
33
91
  function normalizeWhitespace(sql) {
34
92
  return sql.replace(/\s+/g, " ").trim();
35
93
  }
94
+ /**
95
+ * Comment stripping for SQL that will actually be sent to the database. Unlike
96
+ * stripComments+stripStringLiterals (placeholder-based, only safe for keyword matching), this
97
+ * tracks quote state in a single pass so string/identifier/dollar-quoted content is copied
98
+ * verbatim — "--" or "/*" inside a literal is never mistaken for a comment.
99
+ */
100
+ function stripCommentsPreserveStrings(sql) {
101
+ let result = "";
102
+ let i = 0;
103
+ const n = sql.length;
104
+ while (i < n) {
105
+ const c = sql[i];
106
+ const c2 = i + 1 < n ? sql[i + 1] : "";
107
+ if (c === "'" || c === '"') {
108
+ const quote = c;
109
+ result += c;
110
+ i++;
111
+ while (i < n) {
112
+ if (sql[i] === "\\" && i + 1 < n) {
113
+ result += sql[i] + sql[i + 1];
114
+ i += 2;
115
+ continue;
116
+ }
117
+ if (sql[i] === quote) {
118
+ result += sql[i];
119
+ i++;
120
+ break;
121
+ }
122
+ result += sql[i];
123
+ i++;
124
+ }
125
+ continue;
126
+ }
127
+ if (c === "$") {
128
+ // Dollar-quoted string ($$...$$ or $tag$...$tag$): [^$]* naturally stops at the next "$".
129
+ const opener = /^\$[^$]*\$/.exec(sql.slice(i));
130
+ if (opener) {
131
+ const delimiter = opener[0];
132
+ const closeIdx = sql.indexOf(delimiter, i + delimiter.length);
133
+ if (closeIdx !== -1) {
134
+ result += sql.slice(i, closeIdx + delimiter.length);
135
+ i = closeIdx + delimiter.length;
136
+ continue;
137
+ }
138
+ }
139
+ result += c;
140
+ i++;
141
+ continue;
142
+ }
143
+ if (c === "-" && c2 === "-") {
144
+ let j = i;
145
+ while (j < n && sql[j] !== "\n")
146
+ j++;
147
+ result += " ";
148
+ i = j;
149
+ continue;
150
+ }
151
+ if (c === "/" && c2 === "*") {
152
+ const end = sql.indexOf("*/", i + 2);
153
+ result += " ";
154
+ i = end === -1 ? n : end + 2;
155
+ continue;
156
+ }
157
+ result += c;
158
+ i++;
159
+ }
160
+ return result;
161
+ }
162
+ function stripTrailingSemicolons(sql) {
163
+ return sql.replace(/;+\s*$/, "").trim();
164
+ }
36
165
  export function validateReadonlySql(sql) {
37
166
  const trimmed = sql.trim();
38
167
  if (!trimmed) {
@@ -60,6 +189,30 @@ export function validateReadonlySql(sql) {
60
189
  error: `Statement '${match[1].toUpperCase()}' is not allowed in read-only mode`,
61
190
  };
62
191
  }
63
- return { valid: true };
192
+ // Check for dangerous function calls (admin/filesystem/network escapes) anywhere in normalized SQL
193
+ const denyMatch = normalized.match(DENY_PATTERN);
194
+ if (denyMatch) {
195
+ return {
196
+ valid: false,
197
+ error: `Function '${denyMatch[1]}' is not allowed in read-only mode`,
198
+ };
199
+ }
200
+ const normalizedSql = stripTrailingSemicolons(stripCommentsPreserveStrings(trimmed));
201
+ return { valid: true, normalizedSql };
202
+ }
203
+ /**
204
+ * Wraps a read-only query in a row-limited subselect. Also strips comments and trailing
205
+ * semicolons (string-literal-aware, same as validateReadonlySql's normalizedSql) as a safety
206
+ * net for callers still passing raw/un-normalized SQL — without this, something like
207
+ * "SELECT 1; -- c" would comment out the wrapper's closing paren. The stripping is idempotent,
208
+ * so passing an already-normalizedSql value is safe and a no-op.
209
+ */
210
+ export function wrapReadonlyQuery(sql, limit, dialect) {
211
+ const inner = stripTrailingSemicolons(stripCommentsPreserveStrings(sql.trim()));
212
+ switch (dialect) {
213
+ case "postgresql":
214
+ case "clickhouse":
215
+ return `SELECT * FROM (${inner}) AS _q LIMIT ${limit}`;
216
+ }
64
217
  }
65
218
  //# sourceMappingURL=sql-validator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sql-validator.js","sourceRoot":"","sources":["../../src/utils/sql-validator.ts"],"names":[],"mappings":"AAAA,MAAM,cAAc,GAAG;IACrB,QAAQ;IACR,QAAQ;IACR,QAAQ;IACR,MAAM;IACN,OAAO;IACP,UAAU;IACV,QAAQ;IACR,OAAO;IACP,QAAQ;IACR,SAAS;IACT,OAAO;IACP,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,aAAa,GAAG,IAAI,MAAM,CAAC,OAAO,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAO7E,SAAS,mBAAmB,CAAC,GAAW;IACtC,0DAA0D;IAC1D,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC;IAC1D,oCAAoC;IACpC,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,oBAAoB,EAAE,QAAQ,CAAC,CAAC;IACxD,qEAAqE;IACrE,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,4BAA4B,EAAE,SAAS,CAAC,CAAC;IACjE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,aAAa,CAAC,GAAW;IAChC,wBAAwB;IACxB,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;IACnD,uBAAuB;IACvB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAC1C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,mBAAmB,CAAC,GAAW;IACtC,OAAO,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,GAAW;IAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE3B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,qBAAqB,EAAE,CAAC;IACxD,CAAC;IAED,iEAAiE;IACjE,MAAM,SAAS,GAAG,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAEnD,iEAAiE;IACjE,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,cAAc,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;QACvE,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,KAAK,EAAE,uDAAuD;aAC/D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IAC9C,IAAI,KAAK,EAAE,CAAC;QACV,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE,cAAc,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,oCAAoC;SAChF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC"}
1
+ {"version":3,"file":"sql-validator.js","sourceRoot":"","sources":["../../src/utils/sql-validator.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conte777/db-view-mcp",
3
- "version": "1.2.0",
3
+ "version": "1.3.0",
4
4
  "description": "MCP server for database access (PostgreSQL + ClickHouse)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,6 +31,14 @@
31
31
  "postgresql",
32
32
  "clickhouse"
33
33
  ],
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/Conte777/db-view-mcp.git"
37
+ },
38
+ "homepage": "https://github.com/Conte777/db-view-mcp#readme",
39
+ "bugs": {
40
+ "url": "https://github.com/Conte777/db-view-mcp/issues"
41
+ },
34
42
  "license": "MIT",
35
43
  "dependencies": {
36
44
  "@clickhouse/client": "^1.17.0",