@rmwxxwmr/mcp-database-service 0.1.2
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/LICENSE +21 -0
- package/README.md +236 -0
- package/README.zh-CN.md +236 -0
- package/config/databases.example.json +48 -0
- package/dist/config/configSummary.d.ts +4 -0
- package/dist/config/configSummary.js +117 -0
- package/dist/config/configSummary.js.map +1 -0
- package/dist/config/configTypes.d.ts +81 -0
- package/dist/config/configTypes.js +2 -0
- package/dist/config/configTypes.js.map +1 -0
- package/dist/config/configValidation.d.ts +6 -0
- package/dist/config/configValidation.js +142 -0
- package/dist/config/configValidation.js.map +1 -0
- package/dist/config/loadConfig.d.ts +8 -0
- package/dist/config/loadConfig.js +85 -0
- package/dist/config/loadConfig.js.map +1 -0
- package/dist/core/errors.d.ts +15 -0
- package/dist/core/errors.js +28 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/logger.d.ts +7 -0
- package/dist/core/logger.js +68 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/resultTypes.d.ts +49 -0
- package/dist/core/resultTypes.js +2 -0
- package/dist/core/resultTypes.js.map +1 -0
- package/dist/db/clientFactory.d.ts +9 -0
- package/dist/db/clientFactory.js +27 -0
- package/dist/db/clientFactory.js.map +1 -0
- package/dist/db/readonlyGuard.d.ts +14 -0
- package/dist/db/readonlyGuard.js +253 -0
- package/dist/db/readonlyGuard.js.map +1 -0
- package/dist/db/redis/redisClient.d.ts +16 -0
- package/dist/db/redis/redisClient.js +106 -0
- package/dist/db/redis/redisClient.js.map +1 -0
- package/dist/db/sql/baseSqlAdapter.d.ts +52 -0
- package/dist/db/sql/baseSqlAdapter.js +310 -0
- package/dist/db/sql/baseSqlAdapter.js.map +1 -0
- package/dist/db/sql/mysqlClient.d.ts +33 -0
- package/dist/db/sql/mysqlClient.js +150 -0
- package/dist/db/sql/mysqlClient.js.map +1 -0
- package/dist/db/sql/openGaussClient.d.ts +9 -0
- package/dist/db/sql/openGaussClient.js +11 -0
- package/dist/db/sql/openGaussClient.js.map +1 -0
- package/dist/db/sql/oracleClient.d.ts +33 -0
- package/dist/db/sql/oracleClient.js +203 -0
- package/dist/db/sql/oracleClient.js.map +1 -0
- package/dist/db/sql/postgresClient.d.ts +33 -0
- package/dist/db/sql/postgresClient.js +160 -0
- package/dist/db/sql/postgresClient.js.map +1 -0
- package/dist/db/types.d.ts +24 -0
- package/dist/db/types.js +2 -0
- package/dist/db/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +21 -0
- package/dist/server/createServer.d.ts +46 -0
- package/dist/server/createServer.js +441 -0
- package/dist/server/createServer.js.map +1 -0
- package/dist/server/toolRegistry.d.ts +36 -0
- package/dist/server/toolRegistry.js +927 -0
- package/dist/server/toolRegistry.js.map +1 -0
- package/dist/utils/normalize.d.ts +6 -0
- package/dist/utils/normalize.js +29 -0
- package/dist/utils/normalize.js.map +1 -0
- package/package.json +62 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { ApplicationError, toApplicationError } from "../../core/errors.js";
|
|
2
|
+
import { BaseSqlAdapter } from "./baseSqlAdapter.js";
|
|
3
|
+
export class OracleAdapter extends BaseSqlAdapter {
|
|
4
|
+
oracleConfig;
|
|
5
|
+
connection = null;
|
|
6
|
+
constructor(oracleConfig, queryTimeoutMs) {
|
|
7
|
+
super(oracleConfig, queryTimeoutMs);
|
|
8
|
+
this.oracleConfig = oracleConfig;
|
|
9
|
+
}
|
|
10
|
+
async connect() {
|
|
11
|
+
try {
|
|
12
|
+
const oracledb = await loadOracleDb(this.oracleConfig);
|
|
13
|
+
const connectString = this.oracleConfig.connection.serviceName
|
|
14
|
+
? `${this.oracleConfig.connection.host}:${this.oracleConfig.connection.port ?? 1521}/${this.oracleConfig.connection.serviceName}`
|
|
15
|
+
: `${this.oracleConfig.connection.host}:${this.oracleConfig.connection.port ?? 1521}:${this.oracleConfig.connection.sid}`;
|
|
16
|
+
this.connection = await oracledb.getConnection({
|
|
17
|
+
user: this.oracleConfig.connection.user,
|
|
18
|
+
password: this.oracleConfig.connection.password,
|
|
19
|
+
connectString
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
catch (error) {
|
|
23
|
+
throw toApplicationError(error, "CONNECTION_ERROR");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async close() {
|
|
27
|
+
if (!this.connection) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
await this.connection.close();
|
|
31
|
+
this.connection = null;
|
|
32
|
+
}
|
|
33
|
+
async executeRaw(sql, params) {
|
|
34
|
+
if (!this.connection) {
|
|
35
|
+
throw new ApplicationError("CONNECTION_ERROR", "Oracle connection is not open");
|
|
36
|
+
}
|
|
37
|
+
const oracledb = await loadOracleDb(this.oracleConfig);
|
|
38
|
+
const result = await this.connection.execute(sql, params ?? [], {
|
|
39
|
+
outFormat: oracledb.OUT_FORMAT_OBJECT
|
|
40
|
+
});
|
|
41
|
+
return (result.rows ?? []);
|
|
42
|
+
}
|
|
43
|
+
async executeStatementRaw(sql, params) {
|
|
44
|
+
if (!this.connection) {
|
|
45
|
+
throw new ApplicationError("CONNECTION_ERROR", "Oracle connection is not open");
|
|
46
|
+
}
|
|
47
|
+
const result = await this.connection.execute(sql, params ?? []);
|
|
48
|
+
const affectedRows = typeof result === "object" && result !== null && "rowsAffected" in result
|
|
49
|
+
? Number(result.rowsAffected ?? 0)
|
|
50
|
+
: null;
|
|
51
|
+
return { affectedRows };
|
|
52
|
+
}
|
|
53
|
+
async explainQueryRows(sql, params) {
|
|
54
|
+
await this.executeStatementRaw(`EXPLAIN PLAN FOR ${sql}`, params);
|
|
55
|
+
return this.executeRaw(`
|
|
56
|
+
SELECT plan_table_output AS planLine
|
|
57
|
+
FROM TABLE(DBMS_XPLAN.DISPLAY())
|
|
58
|
+
`);
|
|
59
|
+
}
|
|
60
|
+
async analyzeQueryRows(_sql, _params) {
|
|
61
|
+
throw new ApplicationError("NOT_SUPPORTED", "analyze_query is not supported for Oracle in the current implementation");
|
|
62
|
+
}
|
|
63
|
+
pingSql() {
|
|
64
|
+
return "SELECT 1 AS ok FROM dual";
|
|
65
|
+
}
|
|
66
|
+
listSchemasSql() {
|
|
67
|
+
return "SELECT username AS schema FROM all_users ORDER BY username";
|
|
68
|
+
}
|
|
69
|
+
listTablesSql(schema) {
|
|
70
|
+
return {
|
|
71
|
+
sql: `
|
|
72
|
+
SELECT owner AS schema_name, table_name AS name, 'TABLE' AS type
|
|
73
|
+
FROM all_tables
|
|
74
|
+
WHERE owner = COALESCE(:schema, SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'))
|
|
75
|
+
UNION ALL
|
|
76
|
+
SELECT owner AS schema_name, view_name AS name, 'VIEW' AS type
|
|
77
|
+
FROM all_views
|
|
78
|
+
WHERE owner = COALESCE(:schema, SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'))
|
|
79
|
+
ORDER BY name
|
|
80
|
+
`,
|
|
81
|
+
params: { schema: schema?.toUpperCase() ?? null }
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
describeTableSql(schema, table) {
|
|
85
|
+
return {
|
|
86
|
+
sql: `
|
|
87
|
+
SELECT
|
|
88
|
+
c.column_name AS name,
|
|
89
|
+
c.data_type AS datatype,
|
|
90
|
+
c.nullable AS nullable,
|
|
91
|
+
c.data_default AS defaultValue,
|
|
92
|
+
com.comments AS comment_text,
|
|
93
|
+
CASE
|
|
94
|
+
WHEN EXISTS (
|
|
95
|
+
SELECT 1
|
|
96
|
+
FROM all_constraints cons
|
|
97
|
+
JOIN all_cons_columns cols
|
|
98
|
+
ON cons.owner = cols.owner
|
|
99
|
+
AND cons.constraint_name = cols.constraint_name
|
|
100
|
+
WHERE cons.constraint_type = 'P'
|
|
101
|
+
AND cons.owner = c.owner
|
|
102
|
+
AND cons.table_name = c.table_name
|
|
103
|
+
AND cols.column_name = c.column_name
|
|
104
|
+
) THEN 1 ELSE 0
|
|
105
|
+
END AS primary_key
|
|
106
|
+
FROM all_tab_columns c
|
|
107
|
+
LEFT JOIN all_col_comments com
|
|
108
|
+
ON com.owner = c.owner
|
|
109
|
+
AND com.table_name = c.table_name
|
|
110
|
+
AND com.column_name = c.column_name
|
|
111
|
+
WHERE c.owner = COALESCE(:schema, SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'))
|
|
112
|
+
AND c.table_name = :tableName
|
|
113
|
+
ORDER BY c.column_id
|
|
114
|
+
`,
|
|
115
|
+
params: {
|
|
116
|
+
schema: schema?.toUpperCase() ?? null,
|
|
117
|
+
tableName: table.toUpperCase()
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
listIndexesSql(schema, table) {
|
|
122
|
+
return {
|
|
123
|
+
sql: `
|
|
124
|
+
SELECT
|
|
125
|
+
idx.table_owner AS schema_name,
|
|
126
|
+
idx.table_name AS table_name,
|
|
127
|
+
idx.index_name AS index_name,
|
|
128
|
+
col.column_name AS column_name,
|
|
129
|
+
CASE WHEN idx.uniqueness = 'UNIQUE' THEN 1 ELSE 0 END AS is_unique,
|
|
130
|
+
col.column_position AS column_position,
|
|
131
|
+
col.descend AS sort_order,
|
|
132
|
+
idx.index_type AS index_type
|
|
133
|
+
FROM all_indexes idx
|
|
134
|
+
LEFT JOIN all_ind_columns col
|
|
135
|
+
ON idx.owner = col.index_owner
|
|
136
|
+
AND idx.index_name = col.index_name
|
|
137
|
+
AND idx.table_owner = col.table_owner
|
|
138
|
+
AND idx.table_name = col.table_name
|
|
139
|
+
WHERE idx.table_owner = COALESCE(:schema, SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'))
|
|
140
|
+
AND idx.table_name = :tableName
|
|
141
|
+
ORDER BY idx.index_name, col.column_position
|
|
142
|
+
`,
|
|
143
|
+
params: {
|
|
144
|
+
schema: schema?.toUpperCase() ?? null,
|
|
145
|
+
tableName: table.toUpperCase()
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
tableStatisticsSql(schema, table) {
|
|
150
|
+
return {
|
|
151
|
+
sql: `
|
|
152
|
+
SELECT
|
|
153
|
+
owner AS schema_name,
|
|
154
|
+
table_name AS table_name,
|
|
155
|
+
num_rows AS approximateRowCount,
|
|
156
|
+
blocks,
|
|
157
|
+
avg_row_len AS averageRowLength,
|
|
158
|
+
sample_size AS sampleSize,
|
|
159
|
+
last_analyzed AS lastAnalyzed,
|
|
160
|
+
temporary AS isTemporary,
|
|
161
|
+
partitioned AS isPartitioned
|
|
162
|
+
FROM all_tables
|
|
163
|
+
WHERE owner = COALESCE(:schema, SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA'))
|
|
164
|
+
AND table_name = :tableName
|
|
165
|
+
`,
|
|
166
|
+
params: {
|
|
167
|
+
schema: schema?.toUpperCase() ?? null,
|
|
168
|
+
tableName: table.toUpperCase()
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
let initializedOracleClient = null;
|
|
174
|
+
async function loadOracleDb(config) {
|
|
175
|
+
const module = await import("oracledb");
|
|
176
|
+
const oracledb = (module.default ?? module);
|
|
177
|
+
initializeOracleClientIfNeeded(oracledb, config);
|
|
178
|
+
return oracledb;
|
|
179
|
+
}
|
|
180
|
+
function initializeOracleClientIfNeeded(oracledb, config) {
|
|
181
|
+
const desiredMode = config.connection.clientMode ?? (config.connection.clientLibDir ? "thick" : "thin");
|
|
182
|
+
const desiredLibDir = config.connection.clientLibDir;
|
|
183
|
+
if (!initializedOracleClient) {
|
|
184
|
+
if (desiredMode === "thick") {
|
|
185
|
+
oracledb.initOracleClient?.({ libDir: desiredLibDir });
|
|
186
|
+
}
|
|
187
|
+
initializedOracleClient = {
|
|
188
|
+
mode: desiredMode,
|
|
189
|
+
clientLibDir: desiredLibDir
|
|
190
|
+
};
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
if (initializedOracleClient.mode !== desiredMode) {
|
|
194
|
+
throw new ApplicationError("CONFIG_ERROR", `Oracle client mode conflict: already initialized as ${initializedOracleClient.mode}, requested ${desiredMode}`);
|
|
195
|
+
}
|
|
196
|
+
if (desiredMode === "thick" && initializedOracleClient.clientLibDir !== desiredLibDir) {
|
|
197
|
+
throw new ApplicationError("CONFIG_ERROR", "Oracle thick mode already initialized with a different clientLibDir", {
|
|
198
|
+
currentLibDir: initializedOracleClient.clientLibDir ?? null,
|
|
199
|
+
requestedLibDir: desiredLibDir ?? null
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=oracleClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oracleClient.js","sourceRoot":"","sources":["../../../src/db/sql/oracleClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { PostgresDatabaseConfig } from "../../config/configTypes.js";
|
|
2
|
+
import { BaseSqlAdapter } from "./baseSqlAdapter.js";
|
|
3
|
+
export declare class PostgresAdapter extends BaseSqlAdapter {
|
|
4
|
+
private readonly postgresConfig;
|
|
5
|
+
private client;
|
|
6
|
+
constructor(postgresConfig: PostgresDatabaseConfig, queryTimeoutMs: number | null);
|
|
7
|
+
connect(): Promise<void>;
|
|
8
|
+
close(): Promise<void>;
|
|
9
|
+
protected executeRaw(sql: string, params?: unknown[] | Record<string, unknown>): Promise<Record<string, unknown>[]>;
|
|
10
|
+
protected executeStatementRaw(sql: string, params?: unknown[] | Record<string, unknown>): Promise<{
|
|
11
|
+
affectedRows: number | null;
|
|
12
|
+
}>;
|
|
13
|
+
protected explainQueryRows(sql: string, params?: unknown[] | Record<string, unknown>): Promise<Record<string, unknown>[]>;
|
|
14
|
+
protected analyzeQueryRows(sql: string, params?: unknown[] | Record<string, unknown>): Promise<Record<string, unknown>[]>;
|
|
15
|
+
protected pingSql(): string;
|
|
16
|
+
protected listSchemasSql(): string;
|
|
17
|
+
protected listTablesSql(schema?: string): {
|
|
18
|
+
sql: string;
|
|
19
|
+
params?: unknown[];
|
|
20
|
+
};
|
|
21
|
+
protected describeTableSql(schema: string | undefined, table: string): {
|
|
22
|
+
sql: string;
|
|
23
|
+
params?: unknown[];
|
|
24
|
+
};
|
|
25
|
+
protected listIndexesSql(schema: string | undefined, table: string): {
|
|
26
|
+
sql: string;
|
|
27
|
+
params?: unknown[];
|
|
28
|
+
};
|
|
29
|
+
protected tableStatisticsSql(schema: string | undefined, table: string): {
|
|
30
|
+
sql: string;
|
|
31
|
+
params?: unknown[];
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { ApplicationError, toApplicationError } from "../../core/errors.js";
|
|
2
|
+
import { BaseSqlAdapter } from "./baseSqlAdapter.js";
|
|
3
|
+
export class PostgresAdapter extends BaseSqlAdapter {
|
|
4
|
+
postgresConfig;
|
|
5
|
+
client = null;
|
|
6
|
+
constructor(postgresConfig, queryTimeoutMs) {
|
|
7
|
+
super(postgresConfig, queryTimeoutMs);
|
|
8
|
+
this.postgresConfig = postgresConfig;
|
|
9
|
+
}
|
|
10
|
+
async connect() {
|
|
11
|
+
try {
|
|
12
|
+
const { Client: PgClient } = await import("pg");
|
|
13
|
+
this.client = new PgClient({
|
|
14
|
+
host: this.postgresConfig.connection.host,
|
|
15
|
+
port: this.postgresConfig.connection.port ?? 5432,
|
|
16
|
+
database: this.postgresConfig.connection.databaseName,
|
|
17
|
+
user: this.postgresConfig.connection.user,
|
|
18
|
+
password: this.postgresConfig.connection.password,
|
|
19
|
+
connectionTimeoutMillis: this.postgresConfig.connection.connectTimeoutMs,
|
|
20
|
+
ssl: this.postgresConfig.connection.ssl
|
|
21
|
+
});
|
|
22
|
+
await this.client.connect();
|
|
23
|
+
if (this.postgresConfig.readonly) {
|
|
24
|
+
await this.client.query("SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY");
|
|
25
|
+
}
|
|
26
|
+
if (this.queryTimeoutMs) {
|
|
27
|
+
await this.client.query(`SET statement_timeout = ${this.queryTimeoutMs}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
throw toApplicationError(error, "CONNECTION_ERROR");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async close() {
|
|
35
|
+
if (!this.client) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await this.client.end();
|
|
39
|
+
this.client = null;
|
|
40
|
+
}
|
|
41
|
+
async executeRaw(sql, params) {
|
|
42
|
+
if (!this.client) {
|
|
43
|
+
throw new ApplicationError("CONNECTION_ERROR", "PostgreSQL connection is not open");
|
|
44
|
+
}
|
|
45
|
+
const result = await this.client.query(sql, Array.isArray(params) ? params : []);
|
|
46
|
+
return result.rows;
|
|
47
|
+
}
|
|
48
|
+
async executeStatementRaw(sql, params) {
|
|
49
|
+
if (!this.client) {
|
|
50
|
+
throw new ApplicationError("CONNECTION_ERROR", "PostgreSQL connection is not open");
|
|
51
|
+
}
|
|
52
|
+
const result = await this.client.query(sql, Array.isArray(params) ? params : []);
|
|
53
|
+
return {
|
|
54
|
+
affectedRows: typeof result.rowCount === "number" ? result.rowCount : null
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
async explainQueryRows(sql, params) {
|
|
58
|
+
return this.executeRaw(`EXPLAIN ${sql}`, params);
|
|
59
|
+
}
|
|
60
|
+
async analyzeQueryRows(sql, params) {
|
|
61
|
+
return this.executeRaw(`EXPLAIN (ANALYZE, BUFFERS, VERBOSE) ${sql}`, params);
|
|
62
|
+
}
|
|
63
|
+
pingSql() {
|
|
64
|
+
return "SELECT 1 AS ok";
|
|
65
|
+
}
|
|
66
|
+
listSchemasSql() {
|
|
67
|
+
return `
|
|
68
|
+
SELECT schema_name AS schema
|
|
69
|
+
FROM information_schema.schemata
|
|
70
|
+
WHERE schema_name NOT IN ('information_schema', 'pg_catalog')
|
|
71
|
+
ORDER BY schema_name
|
|
72
|
+
`;
|
|
73
|
+
}
|
|
74
|
+
listTablesSql(schema) {
|
|
75
|
+
return {
|
|
76
|
+
sql: `
|
|
77
|
+
SELECT table_schema AS schema, table_name AS name, table_type AS type
|
|
78
|
+
FROM information_schema.tables
|
|
79
|
+
WHERE table_schema = COALESCE($1, current_schema())
|
|
80
|
+
ORDER BY table_name
|
|
81
|
+
`,
|
|
82
|
+
params: [schema ?? null]
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
describeTableSql(schema, table) {
|
|
86
|
+
return {
|
|
87
|
+
sql: `
|
|
88
|
+
SELECT
|
|
89
|
+
c.column_name AS name,
|
|
90
|
+
c.data_type AS dataType,
|
|
91
|
+
c.is_nullable AS nullable,
|
|
92
|
+
c.column_default AS defaultValue,
|
|
93
|
+
pgd.description AS comment,
|
|
94
|
+
EXISTS (
|
|
95
|
+
SELECT 1
|
|
96
|
+
FROM information_schema.table_constraints tc
|
|
97
|
+
JOIN information_schema.key_column_usage kcu
|
|
98
|
+
ON tc.constraint_name = kcu.constraint_name
|
|
99
|
+
AND tc.table_schema = kcu.table_schema
|
|
100
|
+
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
101
|
+
AND tc.table_schema = c.table_schema
|
|
102
|
+
AND tc.table_name = c.table_name
|
|
103
|
+
AND kcu.column_name = c.column_name
|
|
104
|
+
) AS primaryKey
|
|
105
|
+
FROM information_schema.columns c
|
|
106
|
+
LEFT JOIN pg_catalog.pg_statio_all_tables st
|
|
107
|
+
ON st.relname = c.table_name
|
|
108
|
+
AND st.schemaname = c.table_schema
|
|
109
|
+
LEFT JOIN pg_catalog.pg_description pgd
|
|
110
|
+
ON pgd.objoid = st.relid
|
|
111
|
+
AND pgd.objsubid = c.ordinal_position
|
|
112
|
+
WHERE c.table_schema = COALESCE($1, current_schema())
|
|
113
|
+
AND c.table_name = $2
|
|
114
|
+
ORDER BY c.ordinal_position
|
|
115
|
+
`,
|
|
116
|
+
params: [schema ?? null, table]
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
listIndexesSql(schema, table) {
|
|
120
|
+
return {
|
|
121
|
+
sql: `
|
|
122
|
+
SELECT
|
|
123
|
+
schemaname AS schema_name,
|
|
124
|
+
tablename AS table_name,
|
|
125
|
+
indexname AS index_name,
|
|
126
|
+
indexdef AS definition
|
|
127
|
+
FROM pg_indexes
|
|
128
|
+
WHERE schemaname = COALESCE($1, current_schema())
|
|
129
|
+
AND tablename = $2
|
|
130
|
+
ORDER BY indexname
|
|
131
|
+
`,
|
|
132
|
+
params: [schema ?? null, table]
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
tableStatisticsSql(schema, table) {
|
|
136
|
+
return {
|
|
137
|
+
sql: `
|
|
138
|
+
SELECT
|
|
139
|
+
schemaname AS schema_name,
|
|
140
|
+
relname AS table_name,
|
|
141
|
+
n_live_tup AS approximateRowCount,
|
|
142
|
+
n_dead_tup AS deadRowCount,
|
|
143
|
+
seq_scan AS sequentialScans,
|
|
144
|
+
idx_scan AS indexScans,
|
|
145
|
+
pg_total_relation_size(relid) AS totalBytes,
|
|
146
|
+
pg_relation_size(relid) AS tableBytes,
|
|
147
|
+
pg_indexes_size(relid) AS indexBytes,
|
|
148
|
+
last_analyze AS lastAnalyze,
|
|
149
|
+
last_autoanalyze AS lastAutoAnalyze,
|
|
150
|
+
last_vacuum AS lastVacuum,
|
|
151
|
+
last_autovacuum AS lastAutoVacuum
|
|
152
|
+
FROM pg_stat_user_tables
|
|
153
|
+
WHERE schemaname = COALESCE($1, current_schema())
|
|
154
|
+
AND relname = $2
|
|
155
|
+
`,
|
|
156
|
+
params: [schema ?? null, table]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=postgresClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"postgresClient.js","sourceRoot":"","sources":["../../../src/db/sql/postgresClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { DatabaseConfig } from "../config/configTypes.js";
|
|
2
|
+
import type { ColumnInfo, IndexInfo, PingResult, QueryResult, RedisScanResult, SchemaInfo, StatementResult, TableStatistics, TableInfo } from "../core/resultTypes.js";
|
|
3
|
+
export interface DatabaseAdapter {
|
|
4
|
+
readonly config: DatabaseConfig;
|
|
5
|
+
connect(): Promise<void>;
|
|
6
|
+
close(): Promise<void>;
|
|
7
|
+
ping(): Promise<PingResult>;
|
|
8
|
+
}
|
|
9
|
+
export interface SqlDatabaseAdapter extends DatabaseAdapter {
|
|
10
|
+
listSchemas(): Promise<SchemaInfo[]>;
|
|
11
|
+
listTables(schema?: string): Promise<TableInfo[]>;
|
|
12
|
+
describeTable(schema: string | undefined, table: string): Promise<ColumnInfo[]>;
|
|
13
|
+
listIndexes(schema: string | undefined, table: string): Promise<IndexInfo[]>;
|
|
14
|
+
getTableStatistics(schema: string | undefined, table: string): Promise<TableStatistics | null>;
|
|
15
|
+
explainQuery(sql: string, params: unknown[] | undefined, maxRows: number): Promise<QueryResult>;
|
|
16
|
+
analyzeQuery(sql: string, params: unknown[] | undefined, maxRows: number): Promise<QueryResult>;
|
|
17
|
+
executeQuery(sql: string, params: unknown[] | undefined, maxRows: number): Promise<QueryResult>;
|
|
18
|
+
executeStatement(sql: string, params?: unknown[]): Promise<StatementResult>;
|
|
19
|
+
}
|
|
20
|
+
export interface RedisDatabaseAdapter extends DatabaseAdapter {
|
|
21
|
+
get(key: string): Promise<string | null>;
|
|
22
|
+
hgetall(key: string): Promise<Record<string, string>>;
|
|
23
|
+
scan(cursor: string, pattern: string | undefined, count: number): Promise<RedisScanResult>;
|
|
24
|
+
}
|
package/dist/db/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/db/types.ts"],"names":[],"mappings":""}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { loadConfig } from "./config/loadConfig.js";
|
|
3
|
+
import { log } from "./core/logger.js";
|
|
4
|
+
import { createServer } from "./server/createServer.js";
|
|
5
|
+
/**
|
|
6
|
+
* Main entrypoint: load validated config, start the MCP server, and leave all
|
|
7
|
+
* actual database work to per-request lazy adapters.
|
|
8
|
+
*/
|
|
9
|
+
async function main() {
|
|
10
|
+
const config = await loadConfig(process.argv.slice(2), process.env);
|
|
11
|
+
await createServer(config);
|
|
12
|
+
log("info", "MCP database server started", {
|
|
13
|
+
databaseCount: config.databases.length
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
main().catch((error) => {
|
|
17
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
18
|
+
log("error", "Failed to start MCP database server", { message });
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
});
|
|
21
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
2
|
+
import type { LoadedConfig } from "../config/configTypes.js";
|
|
3
|
+
interface PendingStatementConfirmation {
|
|
4
|
+
databaseKey: string;
|
|
5
|
+
sql: string;
|
|
6
|
+
params?: unknown[];
|
|
7
|
+
expiresAt: number;
|
|
8
|
+
}
|
|
9
|
+
interface StatementConfirmationInput {
|
|
10
|
+
databaseKey: string;
|
|
11
|
+
sql: string;
|
|
12
|
+
params?: unknown[];
|
|
13
|
+
confirmationId?: string;
|
|
14
|
+
confirmExecution?: boolean;
|
|
15
|
+
}
|
|
16
|
+
interface StatementConfirmationContext {
|
|
17
|
+
database: LoadedConfig["databases"][number];
|
|
18
|
+
input: StatementConfirmationInput;
|
|
19
|
+
pendingConfirmations: Map<string, PendingStatementConfirmation>;
|
|
20
|
+
supportsInteractiveConfirmation: boolean;
|
|
21
|
+
elicitConfirmation?: (message: string) => Promise<boolean>;
|
|
22
|
+
now?: () => number;
|
|
23
|
+
createId?: () => string;
|
|
24
|
+
maxPendingConfirmations?: number;
|
|
25
|
+
}
|
|
26
|
+
type StatementConfirmationResult = {
|
|
27
|
+
status: "confirmed";
|
|
28
|
+
} | {
|
|
29
|
+
status: "pending";
|
|
30
|
+
confirmationId: string;
|
|
31
|
+
confirmationMode: "two_step";
|
|
32
|
+
message: string;
|
|
33
|
+
statement: string;
|
|
34
|
+
targetObject: string;
|
|
35
|
+
riskLevel: "normal" | "high" | "critical";
|
|
36
|
+
riskDetails: string;
|
|
37
|
+
sqlPreview: string;
|
|
38
|
+
paramsPreview: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* The MCP layer is intentionally thin: validate input, route to the correct
|
|
42
|
+
* adapter, and return normalized JSON text for clients.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createServer(config: LoadedConfig): Promise<Server>;
|
|
45
|
+
export declare function confirmStatementExecutionWithFallback(context: StatementConfirmationContext): Promise<StatementConfirmationResult>;
|
|
46
|
+
export {};
|