@conte777/db-view-mcp 1.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.
Files changed (67) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +341 -0
  3. package/config.example.json +41 -0
  4. package/dist/config/loader.d.ts +6 -0
  5. package/dist/config/loader.js +28 -0
  6. package/dist/config/loader.js.map +1 -0
  7. package/dist/config/types.d.ts +149 -0
  8. package/dist/config/types.js +73 -0
  9. package/dist/config/types.js.map +1 -0
  10. package/dist/connectors/clickhouse.d.ts +20 -0
  11. package/dist/connectors/clickhouse.js +95 -0
  12. package/dist/connectors/clickhouse.js.map +1 -0
  13. package/dist/connectors/interface.d.ts +37 -0
  14. package/dist/connectors/interface.js +2 -0
  15. package/dist/connectors/interface.js.map +1 -0
  16. package/dist/connectors/manager.d.ts +14 -0
  17. package/dist/connectors/manager.js +51 -0
  18. package/dist/connectors/manager.js.map +1 -0
  19. package/dist/connectors/postgresql.d.ts +20 -0
  20. package/dist/connectors/postgresql.js +138 -0
  21. package/dist/connectors/postgresql.js.map +1 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +43 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/server.d.ts +9 -0
  26. package/dist/server.js +23 -0
  27. package/dist/server.js.map +1 -0
  28. package/dist/tools/readonly/describe-table.d.ts +19 -0
  29. package/dist/tools/readonly/describe-table.js +22 -0
  30. package/dist/tools/readonly/describe-table.js.map +1 -0
  31. package/dist/tools/readonly/explain.d.ts +17 -0
  32. package/dist/tools/readonly/explain.js +26 -0
  33. package/dist/tools/readonly/explain.js.map +1 -0
  34. package/dist/tools/readonly/list-databases.d.ts +7 -0
  35. package/dist/tools/readonly/list-databases.js +12 -0
  36. package/dist/tools/readonly/list-databases.js.map +1 -0
  37. package/dist/tools/readonly/list-tables.d.ts +17 -0
  38. package/dist/tools/readonly/list-tables.js +21 -0
  39. package/dist/tools/readonly/list-tables.js.map +1 -0
  40. package/dist/tools/readonly/performance.d.ts +43 -0
  41. package/dist/tools/readonly/performance.js +72 -0
  42. package/dist/tools/readonly/performance.js.map +1 -0
  43. package/dist/tools/readonly/query.d.ts +19 -0
  44. package/dist/tools/readonly/query.js +27 -0
  45. package/dist/tools/readonly/query.js.map +1 -0
  46. package/dist/tools/readonly/schema.d.ts +15 -0
  47. package/dist/tools/readonly/schema.js +20 -0
  48. package/dist/tools/readonly/schema.js.map +1 -0
  49. package/dist/tools/registry.d.ts +4 -0
  50. package/dist/tools/registry.js +56 -0
  51. package/dist/tools/registry.js.map +1 -0
  52. package/dist/tools/write/execute.d.ts +19 -0
  53. package/dist/tools/write/execute.js +26 -0
  54. package/dist/tools/write/execute.js.map +1 -0
  55. package/dist/tools/write/transaction.d.ts +28 -0
  56. package/dist/tools/write/transaction.js +76 -0
  57. package/dist/tools/write/transaction.js.map +1 -0
  58. package/dist/transport/http.d.ts +15 -0
  59. package/dist/transport/http.js +96 -0
  60. package/dist/transport/http.js.map +1 -0
  61. package/dist/utils/response.d.ts +31 -0
  62. package/dist/utils/response.js +25 -0
  63. package/dist/utils/response.js.map +1 -0
  64. package/dist/utils/sql-validator.d.ts +5 -0
  65. package/dist/utils/sql-validator.js +36 -0
  66. package/dist/utils/sql-validator.js.map +1 -0
  67. package/package.json +41 -0
@@ -0,0 +1,20 @@
1
+ import type { Connector, QueryResult, TableInfo, ColumnInfo, ExplainResult, TransactionHandle } from "./interface.js";
2
+ import type { ClickHouseConfig } from "../config/types.js";
3
+ export declare class ClickHouseConnector implements Connector {
4
+ readonly type: "clickhouse";
5
+ private client;
6
+ private config;
7
+ private maxRows;
8
+ private queryTimeout;
9
+ constructor(config: ClickHouseConfig, queryTimeout: number, maxRows: number);
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ private getClient;
13
+ query(sql: string, _params?: string[], maxRows?: number): Promise<QueryResult>;
14
+ execute(sql: string, _params?: string[]): Promise<QueryResult>;
15
+ listTables(_schema?: string): Promise<TableInfo[]>;
16
+ describeTable(table: string, _schema?: string): Promise<ColumnInfo[]>;
17
+ getSchema(): Promise<string>;
18
+ explain(sql: string): Promise<ExplainResult>;
19
+ beginTransaction(): Promise<TransactionHandle>;
20
+ }
@@ -0,0 +1,95 @@
1
+ import { createClient } from "@clickhouse/client";
2
+ export class ClickHouseConnector {
3
+ type = "clickhouse";
4
+ client = null;
5
+ config;
6
+ maxRows;
7
+ queryTimeout;
8
+ constructor(config, queryTimeout, maxRows) {
9
+ this.config = config;
10
+ this.queryTimeout = queryTimeout;
11
+ this.maxRows = maxRows;
12
+ }
13
+ async connect() {
14
+ this.client = createClient({
15
+ url: this.config.url,
16
+ database: this.config.database,
17
+ username: this.config.user,
18
+ password: this.config.password,
19
+ request_timeout: this.queryTimeout,
20
+ });
21
+ await this.client.ping();
22
+ }
23
+ async disconnect() {
24
+ if (this.client) {
25
+ await this.client.close();
26
+ this.client = null;
27
+ }
28
+ }
29
+ getClient() {
30
+ if (!this.client)
31
+ throw new Error("Not connected");
32
+ return this.client;
33
+ }
34
+ async query(sql, _params, maxRows) {
35
+ const limit = maxRows ?? this.maxRows;
36
+ const wrappedSql = `SELECT * FROM (${sql}) AS _q LIMIT ${limit}`;
37
+ const result = await this.getClient().query({ query: wrappedSql, format: "JSONEachRow" });
38
+ const rows = (await result.json());
39
+ return { rows, rowCount: rows.length };
40
+ }
41
+ async execute(sql, _params) {
42
+ await this.getClient().command({ query: sql });
43
+ return { rows: [], rowCount: 0 };
44
+ }
45
+ async listTables(_schema) {
46
+ const result = await this.getClient().query({
47
+ query: `SELECT name, engine FROM system.tables WHERE database = currentDatabase() ORDER BY name`,
48
+ format: "JSONEachRow",
49
+ });
50
+ const rows = (await result.json());
51
+ return rows.map((r) => ({
52
+ schema: this.config.database,
53
+ name: r.name,
54
+ type: r.engine.includes("View") ? "view" : "table",
55
+ }));
56
+ }
57
+ async describeTable(table, _schema) {
58
+ const result = await this.getClient().query({
59
+ query: `SELECT name, type, default_kind, default_expression, is_in_primary_key
60
+ FROM system.columns
61
+ WHERE database = currentDatabase() AND table = {table:String}
62
+ ORDER BY position`,
63
+ format: "JSONEachRow",
64
+ query_params: { table },
65
+ });
66
+ const rows = (await result.json());
67
+ return rows.map((r) => ({
68
+ name: r.name,
69
+ type: r.type,
70
+ nullable: r.type.startsWith("Nullable"),
71
+ defaultValue: r.default_expression || null,
72
+ isPrimaryKey: r.is_in_primary_key === 1,
73
+ }));
74
+ }
75
+ async getSchema() {
76
+ const result = await this.getClient().query({
77
+ query: `SELECT name, create_table_query FROM system.tables WHERE database = currentDatabase()`,
78
+ format: "JSONEachRow",
79
+ });
80
+ const rows = (await result.json());
81
+ return rows.map((r) => r.create_table_query).join(";\n\n");
82
+ }
83
+ async explain(sql) {
84
+ const result = await this.getClient().query({
85
+ query: `EXPLAIN ${sql}`,
86
+ format: "JSONEachRow",
87
+ });
88
+ const rows = (await result.json());
89
+ return { plan: rows.map((r) => r.explain).join("\n") };
90
+ }
91
+ async beginTransaction() {
92
+ throw new Error("Transactions are not supported in ClickHouse");
93
+ }
94
+ }
95
+ //# sourceMappingURL=clickhouse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clickhouse.js","sourceRoot":"","sources":["../../src/connectors/clickhouse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ export interface QueryResult {
2
+ rows: Record<string, unknown>[];
3
+ rowCount: number;
4
+ }
5
+ export interface TableInfo {
6
+ schema: string;
7
+ name: string;
8
+ type: string;
9
+ }
10
+ export interface ColumnInfo {
11
+ name: string;
12
+ type: string;
13
+ nullable: boolean;
14
+ defaultValue: string | null;
15
+ isPrimaryKey: boolean;
16
+ }
17
+ export interface ExplainResult {
18
+ plan: string;
19
+ }
20
+ export interface TransactionHandle {
21
+ id: string;
22
+ execute(sql: string, params?: string[]): Promise<QueryResult>;
23
+ commit(): Promise<void>;
24
+ rollback(): Promise<void>;
25
+ }
26
+ export interface Connector {
27
+ readonly type: "postgresql" | "clickhouse";
28
+ connect(): Promise<void>;
29
+ disconnect(): Promise<void>;
30
+ query(sql: string, params?: string[], maxRows?: number): Promise<QueryResult>;
31
+ execute(sql: string, params?: string[]): Promise<QueryResult>;
32
+ listTables(schema?: string): Promise<TableInfo[]>;
33
+ describeTable(table: string, schema?: string): Promise<ColumnInfo[]>;
34
+ getSchema(): Promise<string>;
35
+ explain(sql: string): Promise<ExplainResult>;
36
+ beginTransaction(): Promise<TransactionHandle>;
37
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/connectors/interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ import type { Connector } from "./interface.js";
2
+ import type { ResolvedDatabaseConfig } from "../config/types.js";
3
+ export declare class ConnectorManager {
4
+ private configs;
5
+ private connectors;
6
+ constructor(databases: ResolvedDatabaseConfig[]);
7
+ getDatabaseIds(): string[];
8
+ getConfig(dbId: string): ResolvedDatabaseConfig | undefined;
9
+ getAllConfigs(): ResolvedDatabaseConfig[];
10
+ getConnector(dbId: string): Promise<Connector>;
11
+ private createConnector;
12
+ connectEager(): Promise<void>;
13
+ disconnectAll(): Promise<void>;
14
+ }
@@ -0,0 +1,51 @@
1
+ import { PostgresConnector } from "./postgresql.js";
2
+ import { ClickHouseConnector } from "./clickhouse.js";
3
+ export class ConnectorManager {
4
+ configs = new Map();
5
+ connectors = new Map();
6
+ constructor(databases) {
7
+ for (const db of databases) {
8
+ this.configs.set(db.id, db);
9
+ }
10
+ }
11
+ getDatabaseIds() {
12
+ return Array.from(this.configs.keys());
13
+ }
14
+ getConfig(dbId) {
15
+ return this.configs.get(dbId);
16
+ }
17
+ getAllConfigs() {
18
+ return Array.from(this.configs.values());
19
+ }
20
+ async getConnector(dbId) {
21
+ const existing = this.connectors.get(dbId);
22
+ if (existing)
23
+ return existing;
24
+ const config = this.configs.get(dbId);
25
+ if (!config)
26
+ throw new Error(`Unknown database: ${dbId}`);
27
+ const connector = this.createConnector(config);
28
+ await connector.connect();
29
+ this.connectors.set(dbId, connector);
30
+ return connector;
31
+ }
32
+ createConnector(config) {
33
+ if (config.type === "postgresql") {
34
+ return new PostgresConnector(config, config.queryTimeout, config.maxRows);
35
+ }
36
+ if (config.type === "clickhouse") {
37
+ return new ClickHouseConnector(config, config.queryTimeout, config.maxRows);
38
+ }
39
+ throw new Error(`Unsupported database type: ${config.type}`);
40
+ }
41
+ async connectEager() {
42
+ const eagerDbs = Array.from(this.configs.values()).filter((c) => !c.lazyConnection);
43
+ await Promise.all(eagerDbs.map((db) => this.getConnector(db.id)));
44
+ }
45
+ async disconnectAll() {
46
+ const tasks = Array.from(this.connectors.values()).map((c) => c.disconnect());
47
+ await Promise.all(tasks);
48
+ this.connectors.clear();
49
+ }
50
+ }
51
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/connectors/manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAEtD,MAAM,OAAO,gBAAgB;IACnB,OAAO,GAAwC,IAAI,GAAG,EAAE,CAAC;IACzD,UAAU,GAA2B,IAAI,GAAG,EAAE,CAAC;IAEvD,YAAY,SAAmC;QAC7C,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,cAAc;QACZ,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,aAAa;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAAY;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAC;QAE9B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,EAAE,CAAC,CAAC;QAE1D,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QAC/C,MAAM,SAAS,CAAC,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACrC,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,eAAe,CAAC,MAA8B;QACpD,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,OAAO,IAAI,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC5E,CAAC;QACD,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,OAAO,IAAI,mBAAmB,CAAC,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QAC9E,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8BAA+B,MAA2B,CAAC,IAAI,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QACpF,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;IAED,KAAK,CAAC,aAAa;QACjB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC;QAC9E,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;IAC1B,CAAC;CACF"}
@@ -0,0 +1,20 @@
1
+ import type { Connector, QueryResult, TableInfo, ColumnInfo, ExplainResult, TransactionHandle } from "./interface.js";
2
+ import type { PostgresConfig } from "../config/types.js";
3
+ export declare class PostgresConnector implements Connector {
4
+ readonly type: "postgresql";
5
+ private pool;
6
+ private config;
7
+ private queryTimeout;
8
+ private maxRows;
9
+ constructor(config: PostgresConfig, queryTimeout: number, maxRows: number);
10
+ connect(): Promise<void>;
11
+ disconnect(): Promise<void>;
12
+ private getPool;
13
+ query(sql: string, params?: string[], maxRows?: number): Promise<QueryResult>;
14
+ execute(sql: string, params?: string[]): Promise<QueryResult>;
15
+ listTables(schema?: string): Promise<TableInfo[]>;
16
+ describeTable(table: string, schema?: string): Promise<ColumnInfo[]>;
17
+ getSchema(): Promise<string>;
18
+ explain(sql: string): Promise<ExplainResult>;
19
+ beginTransaction(): Promise<TransactionHandle>;
20
+ }
@@ -0,0 +1,138 @@
1
+ import pg from "pg";
2
+ import { randomUUID } from "node:crypto";
3
+ export class PostgresConnector {
4
+ type = "postgresql";
5
+ pool = null;
6
+ config;
7
+ queryTimeout;
8
+ maxRows;
9
+ constructor(config, queryTimeout, maxRows) {
10
+ this.config = config;
11
+ this.queryTimeout = queryTimeout;
12
+ this.maxRows = maxRows;
13
+ }
14
+ async connect() {
15
+ this.pool = new pg.Pool({
16
+ host: this.config.host,
17
+ port: this.config.port,
18
+ database: this.config.database,
19
+ user: this.config.user,
20
+ password: this.config.password,
21
+ ssl: this.config.ssl ? { rejectUnauthorized: false } : undefined,
22
+ max: 10,
23
+ });
24
+ // Verify connection
25
+ const client = await this.pool.connect();
26
+ client.release();
27
+ }
28
+ async disconnect() {
29
+ if (this.pool) {
30
+ await this.pool.end();
31
+ this.pool = null;
32
+ }
33
+ }
34
+ getPool() {
35
+ if (!this.pool)
36
+ throw new Error("Not connected");
37
+ return this.pool;
38
+ }
39
+ async query(sql, params, maxRows) {
40
+ const limit = maxRows ?? this.maxRows;
41
+ const wrappedSql = `SELECT * FROM (${sql}) AS _q LIMIT ${limit}`;
42
+ const result = await this.getPool().query(wrappedSql, params);
43
+ return { rows: result.rows, rowCount: result.rows.length };
44
+ }
45
+ async execute(sql, params) {
46
+ const result = await this.getPool().query(sql, params);
47
+ return { rows: result.rows ?? [], rowCount: result.rowCount ?? 0 };
48
+ }
49
+ async listTables(schema) {
50
+ const s = schema ?? "public";
51
+ const result = await this.getPool().query(`SELECT table_schema, table_name, table_type
52
+ FROM information_schema.tables
53
+ WHERE table_schema = $1
54
+ ORDER BY table_name`, [s]);
55
+ return result.rows.map((r) => ({
56
+ schema: r.table_schema,
57
+ name: r.table_name,
58
+ type: r.table_type === "BASE TABLE" ? "table" : "view",
59
+ }));
60
+ }
61
+ async describeTable(table, schema) {
62
+ const s = schema ?? "public";
63
+ const result = await this.getPool().query(`SELECT
64
+ c.column_name,
65
+ c.data_type,
66
+ c.is_nullable,
67
+ c.column_default,
68
+ CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_key
69
+ FROM information_schema.columns c
70
+ LEFT JOIN (
71
+ SELECT ku.column_name
72
+ FROM information_schema.table_constraints tc
73
+ JOIN information_schema.key_column_usage ku
74
+ ON tc.constraint_name = ku.constraint_name
75
+ AND tc.table_schema = ku.table_schema
76
+ WHERE tc.constraint_type = 'PRIMARY KEY'
77
+ AND tc.table_name = $1
78
+ AND tc.table_schema = $2
79
+ ) pk ON c.column_name = pk.column_name
80
+ WHERE c.table_name = $1 AND c.table_schema = $2
81
+ ORDER BY c.ordinal_position`, [table, s]);
82
+ return result.rows.map((r) => ({
83
+ name: r.column_name,
84
+ type: r.data_type,
85
+ nullable: r.is_nullable === "YES",
86
+ defaultValue: r.column_default,
87
+ isPrimaryKey: r.is_primary_key,
88
+ }));
89
+ }
90
+ async getSchema() {
91
+ const result = await this.getPool().query(`SELECT table_name, column_name, data_type, is_nullable, column_default
92
+ FROM information_schema.columns
93
+ WHERE table_schema = 'public'
94
+ ORDER BY table_name, ordinal_position`);
95
+ const tables = new Map();
96
+ for (const row of result.rows) {
97
+ const t = row.table_name;
98
+ if (!tables.has(t))
99
+ tables.set(t, []);
100
+ const nullable = row.is_nullable === "YES" ? " NULL" : " NOT NULL";
101
+ const def = row.column_default ? ` DEFAULT ${row.column_default}` : "";
102
+ tables.get(t).push(` ${row.column_name} ${row.data_type}${nullable}${def}`);
103
+ }
104
+ const lines = [];
105
+ for (const [table, cols] of tables) {
106
+ lines.push(`CREATE TABLE ${table} (`);
107
+ lines.push(cols.join(",\n"));
108
+ lines.push(`);\n`);
109
+ }
110
+ return lines.join("\n");
111
+ }
112
+ async explain(sql) {
113
+ const result = await this.getPool().query(`EXPLAIN ANALYZE ${sql}`);
114
+ const plan = result.rows.map((r) => r["QUERY PLAN"]).join("\n");
115
+ return { plan };
116
+ }
117
+ async beginTransaction() {
118
+ const client = await this.getPool().connect();
119
+ await client.query("BEGIN");
120
+ const id = randomUUID();
121
+ return {
122
+ id,
123
+ async execute(sql, params) {
124
+ const result = await client.query(sql, params);
125
+ return { rows: result.rows ?? [], rowCount: result.rowCount ?? 0 };
126
+ },
127
+ async commit() {
128
+ await client.query("COMMIT");
129
+ client.release();
130
+ },
131
+ async rollback() {
132
+ await client.query("ROLLBACK");
133
+ client.release();
134
+ },
135
+ };
136
+ }
137
+ }
138
+ //# sourceMappingURL=postgresql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgresql.js","sourceRoot":"","sources":["../../src/connectors/postgresql.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { loadConfig, parseCliArgs } from "./config/loader.js";
4
+ import { createServer } from "./server.js";
5
+ import { startHttpTransport } from "./transport/http.js";
6
+ async function main() {
7
+ const { configPath, transport: cliTransport } = parseCliArgs(process.argv.slice(2));
8
+ const config = loadConfig(configPath);
9
+ // CLI --transport overrides config
10
+ const transportType = cliTransport ?? config.transport.type;
11
+ if (transportType === "http") {
12
+ const transportConfig = config.transport.type === "http"
13
+ ? config.transport
14
+ : { type: "http", port: 3000, host: "127.0.0.1", stateless: false };
15
+ const { httpServer, manager } = await startHttpTransport(config, transportConfig);
16
+ const shutdown = async () => {
17
+ console.error("Shutting down HTTP server...");
18
+ httpServer.close();
19
+ await manager.disconnectAll();
20
+ process.exit(0);
21
+ };
22
+ process.on("SIGINT", shutdown);
23
+ process.on("SIGTERM", shutdown);
24
+ }
25
+ else {
26
+ const { server, manager } = await createServer(config);
27
+ const transport = new StdioServerTransport();
28
+ await server.connect(transport);
29
+ process.on("SIGINT", async () => {
30
+ await manager.disconnectAll();
31
+ process.exit(0);
32
+ });
33
+ process.on("SIGTERM", async () => {
34
+ await manager.disconnectAll();
35
+ process.exit(0);
36
+ });
37
+ }
38
+ }
39
+ main().catch((err) => {
40
+ console.error("Failed to start db-view-mcp:", err);
41
+ process.exit(1);
42
+ });
43
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,MAAM,MAAM,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IAEtC,mCAAmC;IACnC,MAAM,aAAa,GAAG,YAAY,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;IAE5D,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;QAC7B,MAAM,eAAe,GACnB,MAAM,CAAC,SAAS,CAAC,IAAI,KAAK,MAAM;YAC9B,CAAC,CAAC,MAAM,CAAC,SAAS;YAClB,CAAC,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;QAEjF,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,kBAAkB,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;QAElF,MAAM,QAAQ,GAAG,KAAK,IAAI,EAAE;YAC1B,OAAO,CAAC,KAAK,CAAC,8BAA8B,CAAC,CAAC;YAC9C,UAAU,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,YAAY,CAAC,MAAM,CAAC,CAAC;QAEvD,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAEhC,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC9B,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;QAEH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;YAC/B,MAAM,OAAO,CAAC,aAAa,EAAE,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { ConnectorManager } from "./connectors/manager.js";
3
+ import { type AppConfig } from "./config/types.js";
4
+ export declare function createConnectorManager(config: AppConfig): ConnectorManager;
5
+ export declare function createMcpServerInstance(manager: ConnectorManager, config: AppConfig): McpServer;
6
+ export declare function createServer(config: AppConfig): Promise<{
7
+ server: McpServer;
8
+ manager: ConnectorManager;
9
+ }>;
package/dist/server.js ADDED
@@ -0,0 +1,23 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { ConnectorManager } from "./connectors/manager.js";
3
+ import { registerTools } from "./tools/registry.js";
4
+ import { resolveDbConfig } from "./config/types.js";
5
+ export function createConnectorManager(config) {
6
+ const resolvedDbs = config.databases.map((db) => resolveDbConfig(db, config.defaults));
7
+ return new ConnectorManager(resolvedDbs);
8
+ }
9
+ export function createMcpServerInstance(manager, config) {
10
+ const server = new McpServer({
11
+ name: "db-view-mcp",
12
+ version: "1.0.0",
13
+ });
14
+ registerTools(server, manager, config.defaults);
15
+ return server;
16
+ }
17
+ export async function createServer(config) {
18
+ const manager = createConnectorManager(config);
19
+ const server = createMcpServerInstance(manager, config);
20
+ await manager.connectEager();
21
+ return { server, manager };
22
+ }
23
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAkB,MAAM,mBAAmB,CAAC;AAEpE,MAAM,UAAU,sBAAsB,CAAC,MAAiB;IACtD,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAC9C,eAAe,CAAC,EAAE,EAAE,MAAM,CAAC,QAAQ,CAAC,CACrC,CAAC;IACF,OAAO,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,OAAyB,EACzB,MAAiB;IAEjB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IACH,aAAa,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAAiB;IAClD,MAAM,OAAO,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAExD,MAAM,OAAO,CAAC,YAAY,EAAE,CAAC;IAE7B,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ import type { ConnectorManager } from "../../connectors/manager.js";
3
+ export declare function createDescribeTableParams(dbIds: string[]): {
4
+ database: z.ZodEnum<{
5
+ [x: string]: string;
6
+ }>;
7
+ table: z.ZodString;
8
+ schema: z.ZodOptional<z.ZodString>;
9
+ };
10
+ export declare function describeTableHandler(manager: ConnectorManager): (params: {
11
+ database: string;
12
+ table: string;
13
+ schema?: string;
14
+ }) => Promise<{
15
+ content: {
16
+ type: "text";
17
+ text: string;
18
+ }[];
19
+ }>;
@@ -0,0 +1,22 @@
1
+ import { z } from "zod";
2
+ import { formatSuccess, formatError } from "../../utils/response.js";
3
+ export function createDescribeTableParams(dbIds) {
4
+ return {
5
+ database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
6
+ table: z.string().describe("Table name"),
7
+ schema: z.string().optional().describe("Schema name (default: public for PostgreSQL)"),
8
+ };
9
+ }
10
+ export function describeTableHandler(manager) {
11
+ return async (params) => {
12
+ try {
13
+ const connector = await manager.getConnector(params.database);
14
+ const columns = await connector.describeTable(params.table, params.schema);
15
+ return formatSuccess({ data: columns, database: params.database });
16
+ }
17
+ catch (err) {
18
+ return formatError(String(err));
19
+ }
20
+ };
21
+ }
22
+ //# sourceMappingURL=describe-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"describe-table.js","sourceRoot":"","sources":["../../../src/tools/readonly/describe-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,UAAU,yBAAyB,CAAC,KAAe;IACvD,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAA8B,CAAC,CAAC,QAAQ,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxG,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC;QACxC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;KACvF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAyB;IAC5D,OAAO,KAAK,EAAE,MAA4D,EAAE,EAAE;QAC5E,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3E,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ import type { ConnectorManager } from "../../connectors/manager.js";
3
+ export declare function createExplainParams(dbIds: string[]): {
4
+ database: z.ZodEnum<{
5
+ [x: string]: string;
6
+ }>;
7
+ sql: z.ZodString;
8
+ };
9
+ export declare function explainHandler(manager: ConnectorManager): (params: {
10
+ database: string;
11
+ sql: string;
12
+ }) => Promise<{
13
+ content: {
14
+ type: "text";
15
+ text: string;
16
+ }[];
17
+ }>;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { formatSuccess, formatError } from "../../utils/response.js";
3
+ import { validateReadonlySql } from "../../utils/sql-validator.js";
4
+ export function createExplainParams(dbIds) {
5
+ return {
6
+ database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
7
+ sql: z.string().describe("SQL query to explain"),
8
+ };
9
+ }
10
+ export function explainHandler(manager) {
11
+ return async (params) => {
12
+ const validation = validateReadonlySql(params.sql);
13
+ if (!validation.valid) {
14
+ return formatError(validation.error, "READONLY_VIOLATION");
15
+ }
16
+ try {
17
+ const connector = await manager.getConnector(params.database);
18
+ const result = await connector.explain(params.sql);
19
+ return formatSuccess({ data: result.plan, database: params.database });
20
+ }
21
+ catch (err) {
22
+ return formatError(String(err));
23
+ }
24
+ };
25
+ }
26
+ //# sourceMappingURL=explain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../../src/tools/readonly/explain.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEnE,MAAM,UAAU,mBAAmB,CAAC,KAAe;IACjD,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAA8B,CAAC,CAAC,QAAQ,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxG,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KACjD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAyB;IACtD,OAAO,KAAK,EAAE,MAAyC,EAAE,EAAE;QACzD,MAAM,UAAU,GAAG,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACnD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,WAAW,CAAC,UAAU,CAAC,KAAM,EAAE,oBAAoB,CAAC,CAAC;QAC9D,CAAC;QACD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACnD,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { ConnectorManager } from "../../connectors/manager.js";
2
+ export declare function listDatabasesHandler(manager: ConnectorManager): () => Promise<{
3
+ content: {
4
+ type: "text";
5
+ text: string;
6
+ }[];
7
+ }>;
@@ -0,0 +1,12 @@
1
+ import { formatSuccess } from "../../utils/response.js";
2
+ export function listDatabasesHandler(manager) {
3
+ return async () => {
4
+ const databases = manager.getAllConfigs().map((c) => ({
5
+ id: c.id,
6
+ type: c.type,
7
+ description: c.description ?? "",
8
+ }));
9
+ return formatSuccess({ data: databases });
10
+ };
11
+ }
12
+ //# sourceMappingURL=list-databases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list-databases.js","sourceRoot":"","sources":["../../../src/tools/readonly/list-databases.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAExD,MAAM,UAAU,oBAAoB,CAAC,OAAyB;IAC5D,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACpD,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;SACjC,CAAC,CAAC,CAAC;QACJ,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { z } from "zod";
2
+ import type { ConnectorManager } from "../../connectors/manager.js";
3
+ export declare function createListTablesParams(dbIds: string[]): {
4
+ database: z.ZodEnum<{
5
+ [x: string]: string;
6
+ }>;
7
+ schema: z.ZodOptional<z.ZodString>;
8
+ };
9
+ export declare function listTablesHandler(manager: ConnectorManager): (params: {
10
+ database: string;
11
+ schema?: string;
12
+ }) => Promise<{
13
+ content: {
14
+ type: "text";
15
+ text: string;
16
+ }[];
17
+ }>;