@conte777/db-view-mcp 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config/loader.d.ts +1 -0
- package/dist/config/loader.js +25 -1
- package/dist/config/loader.js.map +1 -1
- package/dist/config/types.d.ts +20 -0
- package/dist/config/types.js +5 -0
- package/dist/config/types.js.map +1 -1
- package/dist/connectors/clickhouse.d.ts +2 -2
- package/dist/connectors/clickhouse.js +4 -3
- package/dist/connectors/clickhouse.js.map +1 -1
- package/dist/connectors/instrumented.d.ts +18 -0
- package/dist/connectors/instrumented.js +52 -0
- package/dist/connectors/instrumented.js.map +1 -0
- package/dist/connectors/interface.d.ts +2 -2
- package/dist/connectors/manager.d.ts +6 -0
- package/dist/connectors/manager.js +58 -5
- package/dist/connectors/manager.js.map +1 -1
- package/dist/connectors/postgresql.d.ts +2 -2
- package/dist/connectors/postgresql.js +29 -11
- package/dist/connectors/postgresql.js.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/tools/readonly/explain.d.ts +2 -0
- package/dist/tools/readonly/explain.js +2 -1
- package/dist/tools/readonly/explain.js.map +1 -1
- package/dist/tools/readonly/performance.d.ts +1 -2
- package/dist/tools/readonly/performance.js +6 -6
- package/dist/tools/readonly/performance.js.map +1 -1
- package/dist/tools/readonly/schema.d.ts +2 -0
- package/dist/tools/readonly/schema.js +2 -1
- package/dist/tools/readonly/schema.js.map +1 -1
- package/dist/tools/registry.js +2 -2
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/write/transaction.d.ts +18 -0
- package/dist/tools/write/transaction.js +70 -13
- package/dist/tools/write/transaction.js.map +1 -1
- package/dist/transport/http.d.ts +1 -0
- package/dist/transport/http.js +26 -13
- package/dist/transport/http.js.map +1 -1
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.js +52 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/sql-validator.js +41 -21
- package/dist/utils/sql-validator.js.map +1 -1
- package/package.json +5 -2
|
@@ -5,10 +5,12 @@ export declare function createExplainParams(dbIds: string[]): {
|
|
|
5
5
|
[x: string]: string;
|
|
6
6
|
}>;
|
|
7
7
|
sql: z.ZodString;
|
|
8
|
+
analyze: z.ZodOptional<z.ZodBoolean>;
|
|
8
9
|
};
|
|
9
10
|
export declare function explainHandler(manager: ConnectorManager): (params: {
|
|
10
11
|
database: string;
|
|
11
12
|
sql: string;
|
|
13
|
+
analyze?: boolean;
|
|
12
14
|
}) => Promise<{
|
|
13
15
|
content: {
|
|
14
16
|
type: "text";
|
|
@@ -5,6 +5,7 @@ export function createExplainParams(dbIds) {
|
|
|
5
5
|
return {
|
|
6
6
|
database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
|
|
7
7
|
sql: z.string().describe("SQL query to explain"),
|
|
8
|
+
analyze: z.boolean().optional().describe("Run EXPLAIN ANALYZE (actually executes the query). Default: false"),
|
|
8
9
|
};
|
|
9
10
|
}
|
|
10
11
|
export function explainHandler(manager) {
|
|
@@ -15,7 +16,7 @@ export function explainHandler(manager) {
|
|
|
15
16
|
}
|
|
16
17
|
try {
|
|
17
18
|
const connector = await manager.getConnector(params.database);
|
|
18
|
-
const result = await connector.explain(params.sql);
|
|
19
|
+
const result = await connector.explain(params.sql, params.analyze ?? false);
|
|
19
20
|
return formatSuccess({ data: result.plan, database: params.database });
|
|
20
21
|
}
|
|
21
22
|
catch (err) {
|
|
@@ -1 +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;
|
|
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;QAChD,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mEAAmE,CAAC;KAC9G,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAyB;IACtD,OAAO,KAAK,EAAE,MAA4D,EAAE,EAAE;QAC5E,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,EAAE,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC,CAAC;YAC5E,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"}
|
|
@@ -6,7 +6,7 @@ interface SlowQuery {
|
|
|
6
6
|
timestamp: Date;
|
|
7
7
|
database: string;
|
|
8
8
|
}
|
|
9
|
-
declare class PerformanceTracker {
|
|
9
|
+
export declare class PerformanceTracker {
|
|
10
10
|
private slowQueries;
|
|
11
11
|
private threshold;
|
|
12
12
|
recordQuery(sql: string, duration: number, database: string): void;
|
|
@@ -15,7 +15,6 @@ declare class PerformanceTracker {
|
|
|
15
15
|
getThreshold(): number;
|
|
16
16
|
reset(): void;
|
|
17
17
|
}
|
|
18
|
-
export declare const performanceTracker: PerformanceTracker;
|
|
19
18
|
export declare function createPerformanceParams(dbIds: string[]): {
|
|
20
19
|
database: z.ZodEnum<{
|
|
21
20
|
[x: string]: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatSuccess, formatError } from "../../utils/response.js";
|
|
3
|
-
class PerformanceTracker {
|
|
3
|
+
export class PerformanceTracker {
|
|
4
4
|
slowQueries = [];
|
|
5
5
|
threshold = 1000; // ms
|
|
6
6
|
recordQuery(sql, duration, database) {
|
|
@@ -26,7 +26,6 @@ class PerformanceTracker {
|
|
|
26
26
|
this.slowQueries = [];
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
|
-
export const performanceTracker = new PerformanceTracker();
|
|
30
29
|
export function createPerformanceParams(dbIds) {
|
|
31
30
|
return {
|
|
32
31
|
database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
|
|
@@ -36,29 +35,30 @@ export function createPerformanceParams(dbIds) {
|
|
|
36
35
|
};
|
|
37
36
|
}
|
|
38
37
|
export function performanceHandler(manager) {
|
|
38
|
+
const tracker = manager.getPerformanceTracker();
|
|
39
39
|
return async (params) => {
|
|
40
40
|
try {
|
|
41
41
|
switch (params.action) {
|
|
42
42
|
case "getSlowQueries":
|
|
43
43
|
return formatSuccess({
|
|
44
|
-
data:
|
|
44
|
+
data: tracker.getSlowQueries(params.database, params.limit),
|
|
45
45
|
database: params.database,
|
|
46
46
|
});
|
|
47
47
|
case "getMetrics":
|
|
48
48
|
return formatSuccess({
|
|
49
49
|
data: {
|
|
50
|
-
slowQueryThreshold:
|
|
50
|
+
slowQueryThreshold: tracker.getThreshold(),
|
|
51
51
|
connectedDatabases: manager.getDatabaseIds(),
|
|
52
52
|
},
|
|
53
53
|
database: params.database,
|
|
54
54
|
});
|
|
55
55
|
case "reset":
|
|
56
|
-
|
|
56
|
+
tracker.reset();
|
|
57
57
|
return formatSuccess({ data: "Performance metrics reset" });
|
|
58
58
|
case "setThreshold":
|
|
59
59
|
if (!params.threshold)
|
|
60
60
|
return formatError("threshold is required for setThreshold");
|
|
61
|
-
|
|
61
|
+
tracker.setThreshold(params.threshold);
|
|
62
62
|
return formatSuccess({ data: `Threshold set to ${params.threshold}ms` });
|
|
63
63
|
default:
|
|
64
64
|
return formatError(`Unknown action: ${params.action}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"performance.js","sourceRoot":"","sources":["../../../src/tools/readonly/performance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AASrE,MAAM,kBAAkB;
|
|
1
|
+
{"version":3,"file":"performance.js","sourceRoot":"","sources":["../../../src/tools/readonly/performance.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,9 +4,11 @@ export declare function createSchemaParams(dbIds: string[]): {
|
|
|
4
4
|
database: z.ZodEnum<{
|
|
5
5
|
[x: string]: string;
|
|
6
6
|
}>;
|
|
7
|
+
schema: z.ZodOptional<z.ZodString>;
|
|
7
8
|
};
|
|
8
9
|
export declare function schemaHandler(manager: ConnectorManager): (params: {
|
|
9
10
|
database: string;
|
|
11
|
+
schema?: string;
|
|
10
12
|
}) => Promise<{
|
|
11
13
|
content: {
|
|
12
14
|
type: "text";
|
|
@@ -3,13 +3,14 @@ import { formatSuccess, formatError } from "../../utils/response.js";
|
|
|
3
3
|
export function createSchemaParams(dbIds) {
|
|
4
4
|
return {
|
|
5
5
|
database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
|
|
6
|
+
schema: z.string().optional().describe("Schema name (default: 'public' for PostgreSQL, ignored for ClickHouse)"),
|
|
6
7
|
};
|
|
7
8
|
}
|
|
8
9
|
export function schemaHandler(manager) {
|
|
9
10
|
return async (params) => {
|
|
10
11
|
try {
|
|
11
12
|
const connector = await manager.getConnector(params.database);
|
|
12
|
-
const ddl = await connector.getSchema();
|
|
13
|
+
const ddl = await connector.getSchema(params.schema);
|
|
13
14
|
return formatSuccess({ data: ddl, database: params.database });
|
|
14
15
|
}
|
|
15
16
|
catch (err) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/tools/readonly/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,UAAU,kBAAkB,CAAC,KAAe;IAChD,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAA8B,CAAC,CAAC,QAAQ,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/tools/readonly/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAErE,MAAM,UAAU,kBAAkB,CAAC,KAAe;IAChD,OAAO;QACL,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,KAA8B,CAAC,CAAC,QAAQ,CAAC,2BAA2B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACxG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,wEAAwE,CAAC;KACjH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAyB;IACrD,OAAO,KAAK,EAAE,MAA6C,EAAE,EAAE;QAC7D,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC9D,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YACrD,OAAO,aAAa,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACjE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
package/dist/tools/registry.js
CHANGED
|
@@ -35,8 +35,8 @@ function registerPerDatabaseTools(server, manager, dbIds) {
|
|
|
35
35
|
server.tool(`query_${dbId}`, `Execute a read-only SQL query on ${dbId}${desc}`, { sql: createQueryToolParams(singleDbIds).sql, maxRows: createQueryToolParams(singleDbIds).maxRows }, async (params) => queryToolHandler(manager)({ database: dbId, ...params }));
|
|
36
36
|
server.tool(`list_tables_${dbId}`, `List tables on ${dbId}${desc}`, { schema: createListTablesParams(singleDbIds).schema }, async (params) => listTablesHandler(manager)({ database: dbId, ...params }));
|
|
37
37
|
server.tool(`describe_table_${dbId}`, `Describe table structure on ${dbId}${desc}`, { table: createDescribeTableParams(singleDbIds).table, schema: createDescribeTableParams(singleDbIds).schema }, async (params) => describeTableHandler(manager)({ database: dbId, ...params }));
|
|
38
|
-
server.tool(`schema_${dbId}`, `Get full schema of ${dbId}${desc}`, {}, async () => schemaHandler(manager)({ database: dbId }));
|
|
39
|
-
server.tool(`explain_query_${dbId}`, `Run EXPLAIN on ${dbId}${desc}`, { sql: createExplainParams(singleDbIds).sql }, async (params) => explainHandler(manager)({ database: dbId, ...params }));
|
|
38
|
+
server.tool(`schema_${dbId}`, `Get full schema of ${dbId}${desc}`, { schema: createSchemaParams(singleDbIds).schema }, async (params) => schemaHandler(manager)({ database: dbId, ...params }));
|
|
39
|
+
server.tool(`explain_query_${dbId}`, `Run EXPLAIN on ${dbId}${desc}`, { sql: createExplainParams(singleDbIds).sql, analyze: createExplainParams(singleDbIds).analyze }, async (params) => explainHandler(manager)({ database: dbId, ...params }));
|
|
40
40
|
server.tool(`performance_${dbId}`, `Performance metrics for ${dbId}${desc}`, {
|
|
41
41
|
action: createPerformanceParams(singleDbIds).action,
|
|
42
42
|
threshold: createPerformanceParams(singleDbIds).threshold,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import type { ConnectorManager } from "../../connectors/manager.js";
|
|
3
|
+
import type { TransactionHandle } from "../../connectors/interface.js";
|
|
4
|
+
interface TransactionEntry {
|
|
5
|
+
handle: TransactionHandle;
|
|
6
|
+
database: string;
|
|
7
|
+
timer: ReturnType<typeof setTimeout>;
|
|
8
|
+
}
|
|
9
|
+
export declare class TransactionStore {
|
|
10
|
+
private entries;
|
|
11
|
+
private ttlMs;
|
|
12
|
+
constructor(ttlMs?: number);
|
|
13
|
+
add(handle: TransactionHandle, database: string): void;
|
|
14
|
+
get(id: string): TransactionEntry | undefined;
|
|
15
|
+
remove(id: string): void;
|
|
16
|
+
cleanupAll(): Promise<void>;
|
|
17
|
+
private autoRollback;
|
|
18
|
+
}
|
|
19
|
+
export declare const transactionStore: TransactionStore;
|
|
3
20
|
export declare function createTransactionParams(dbIds: string[]): {
|
|
4
21
|
database: z.ZodEnum<{
|
|
5
22
|
[x: string]: string;
|
|
@@ -26,3 +43,4 @@ export declare function transactionHandler(manager: ConnectorManager): (params:
|
|
|
26
43
|
text: string;
|
|
27
44
|
}[];
|
|
28
45
|
}>;
|
|
46
|
+
export {};
|
|
@@ -1,6 +1,63 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { formatSuccess, formatError } from "../../utils/response.js";
|
|
3
|
-
|
|
3
|
+
import { getLogger } from "../../utils/logger.js";
|
|
4
|
+
const DEFAULT_TX_TTL_MS = 5 * 60 * 1000; // 5 minutes
|
|
5
|
+
export class TransactionStore {
|
|
6
|
+
entries = new Map();
|
|
7
|
+
ttlMs;
|
|
8
|
+
constructor(ttlMs = DEFAULT_TX_TTL_MS) {
|
|
9
|
+
this.ttlMs = ttlMs;
|
|
10
|
+
}
|
|
11
|
+
add(handle, database) {
|
|
12
|
+
const timer = setTimeout(() => {
|
|
13
|
+
this.autoRollback(handle.id);
|
|
14
|
+
}, this.ttlMs);
|
|
15
|
+
timer.unref();
|
|
16
|
+
this.entries.set(handle.id, { handle, database, timer });
|
|
17
|
+
}
|
|
18
|
+
get(id) {
|
|
19
|
+
return this.entries.get(id);
|
|
20
|
+
}
|
|
21
|
+
remove(id) {
|
|
22
|
+
const entry = this.entries.get(id);
|
|
23
|
+
if (entry) {
|
|
24
|
+
clearTimeout(entry.timer);
|
|
25
|
+
this.entries.delete(id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async cleanupAll() {
|
|
29
|
+
const logger = getLogger();
|
|
30
|
+
const ids = Array.from(this.entries.keys());
|
|
31
|
+
for (const id of ids) {
|
|
32
|
+
await this.autoRollback(id);
|
|
33
|
+
}
|
|
34
|
+
logger.info("All transactions cleaned up", { count: ids.length });
|
|
35
|
+
}
|
|
36
|
+
async autoRollback(id) {
|
|
37
|
+
const entry = this.entries.get(id);
|
|
38
|
+
if (!entry)
|
|
39
|
+
return;
|
|
40
|
+
const logger = getLogger();
|
|
41
|
+
try {
|
|
42
|
+
await entry.handle.rollback();
|
|
43
|
+
logger.warn("Transaction auto-rolled back due to TTL expiry", {
|
|
44
|
+
transactionId: id,
|
|
45
|
+
database: entry.database,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
logger.error("Failed to auto-rollback transaction", {
|
|
50
|
+
transactionId: id,
|
|
51
|
+
error: String(err),
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
finally {
|
|
55
|
+
clearTimeout(entry.timer);
|
|
56
|
+
this.entries.delete(id);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export const transactionStore = new TransactionStore();
|
|
4
61
|
export function createTransactionParams(dbIds) {
|
|
5
62
|
return {
|
|
6
63
|
database: z.enum(dbIds).describe(`Database ID. Available: ${dbIds.join(", ")}`),
|
|
@@ -17,7 +74,7 @@ export function transactionHandler(manager) {
|
|
|
17
74
|
case "begin": {
|
|
18
75
|
const connector = await manager.getConnector(params.database);
|
|
19
76
|
const tx = await connector.beginTransaction();
|
|
20
|
-
|
|
77
|
+
transactionStore.add(tx, params.database);
|
|
21
78
|
return formatSuccess({
|
|
22
79
|
data: { transactionId: tx.id, message: "Transaction started" },
|
|
23
80
|
database: params.database,
|
|
@@ -28,10 +85,10 @@ export function transactionHandler(manager) {
|
|
|
28
85
|
return formatError("transactionId is required for execute");
|
|
29
86
|
if (!params.statement)
|
|
30
87
|
return formatError("statement is required for execute");
|
|
31
|
-
const
|
|
32
|
-
if (!
|
|
88
|
+
const entry = transactionStore.get(params.transactionId);
|
|
89
|
+
if (!entry)
|
|
33
90
|
return formatError(`Transaction not found: ${params.transactionId}`, "TX_NOT_FOUND");
|
|
34
|
-
const result = await
|
|
91
|
+
const result = await entry.handle.execute(params.statement, params.params);
|
|
35
92
|
return formatSuccess({
|
|
36
93
|
rows: result.rows,
|
|
37
94
|
count: result.rowCount,
|
|
@@ -41,11 +98,11 @@ export function transactionHandler(manager) {
|
|
|
41
98
|
case "commit": {
|
|
42
99
|
if (!params.transactionId)
|
|
43
100
|
return formatError("transactionId is required for commit");
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
101
|
+
const entry = transactionStore.get(params.transactionId);
|
|
102
|
+
if (!entry)
|
|
46
103
|
return formatError(`Transaction not found: ${params.transactionId}`, "TX_NOT_FOUND");
|
|
47
|
-
await
|
|
48
|
-
|
|
104
|
+
await entry.handle.commit();
|
|
105
|
+
transactionStore.remove(params.transactionId);
|
|
49
106
|
return formatSuccess({
|
|
50
107
|
data: { message: "Transaction committed" },
|
|
51
108
|
database: params.database,
|
|
@@ -54,11 +111,11 @@ export function transactionHandler(manager) {
|
|
|
54
111
|
case "rollback": {
|
|
55
112
|
if (!params.transactionId)
|
|
56
113
|
return formatError("transactionId is required for rollback");
|
|
57
|
-
const
|
|
58
|
-
if (!
|
|
114
|
+
const entry = transactionStore.get(params.transactionId);
|
|
115
|
+
if (!entry)
|
|
59
116
|
return formatError(`Transaction not found: ${params.transactionId}`, "TX_NOT_FOUND");
|
|
60
|
-
await
|
|
61
|
-
|
|
117
|
+
await entry.handle.rollback();
|
|
118
|
+
transactionStore.remove(params.transactionId);
|
|
62
119
|
return formatSuccess({
|
|
63
120
|
data: { message: "Transaction rolled back" },
|
|
64
121
|
database: params.database,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/tools/write/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../../../src/tools/write/transaction.ts"],"names":[],"mappings":"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"}
|
package/dist/transport/http.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { AppConfig, HttpTransportConfig } from "../config/types.js";
|
|
|
6
6
|
interface SessionEntry {
|
|
7
7
|
transport: StreamableHTTPServerTransport;
|
|
8
8
|
server: McpServer;
|
|
9
|
+
lastAccessedAt: number;
|
|
9
10
|
}
|
|
10
11
|
export declare function startHttpTransport(config: AppConfig, transportConfig: HttpTransportConfig): Promise<{
|
|
11
12
|
httpServer: Server<typeof import("node:http").IncomingMessage, typeof import("node:http").ServerResponse>;
|
package/dist/transport/http.js
CHANGED
|
@@ -1,18 +1,22 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
1
|
+
import { randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
2
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
3
3
|
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
4
4
|
import { createConnectorManager, createMcpServerInstance } from "../server.js";
|
|
5
|
+
import { getLogger } from "../utils/logger.js";
|
|
5
6
|
export async function startHttpTransport(config, transportConfig) {
|
|
7
|
+
const logger = getLogger();
|
|
6
8
|
const manager = createConnectorManager(config);
|
|
7
9
|
await manager.connectEager();
|
|
8
10
|
const sessions = new Map();
|
|
9
11
|
const { host, port } = transportConfig;
|
|
10
12
|
const app = createMcpExpressApp({ host });
|
|
11
13
|
if (transportConfig.auth) {
|
|
12
|
-
const
|
|
14
|
+
const expectedValue = `Bearer ${transportConfig.auth.token}`;
|
|
15
|
+
const expectedBuf = Buffer.from(expectedValue);
|
|
13
16
|
app.use("/mcp", (req, res, next) => {
|
|
14
|
-
const authHeader = req.headers.authorization;
|
|
15
|
-
|
|
17
|
+
const authHeader = req.headers.authorization ?? "";
|
|
18
|
+
const actualBuf = Buffer.from(authHeader);
|
|
19
|
+
if (actualBuf.length !== expectedBuf.length || !timingSafeEqual(actualBuf, expectedBuf)) {
|
|
16
20
|
res.status(401).json({ error: "Unauthorized" });
|
|
17
21
|
return;
|
|
18
22
|
}
|
|
@@ -24,6 +28,19 @@ export async function startHttpTransport(config, transportConfig) {
|
|
|
24
28
|
}
|
|
25
29
|
else {
|
|
26
30
|
setupStatefulRoutes(app, manager, config, sessions);
|
|
31
|
+
const sessionTimeout = transportConfig.sessionTimeout;
|
|
32
|
+
const cleanupInterval = setInterval(() => {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
for (const [sid, entry] of sessions) {
|
|
35
|
+
if (now - entry.lastAccessedAt > sessionTimeout) {
|
|
36
|
+
logger.info("Cleaning up expired session", { sessionId: sid });
|
|
37
|
+
entry.transport.close().catch(() => { });
|
|
38
|
+
entry.server.close().catch(() => { });
|
|
39
|
+
sessions.delete(sid);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}, 60_000);
|
|
43
|
+
cleanupInterval.unref();
|
|
27
44
|
}
|
|
28
45
|
setupHealthEndpoint(app, manager, sessions);
|
|
29
46
|
const httpServer = await new Promise((resolve) => {
|
|
@@ -31,14 +48,9 @@ export async function startHttpTransport(config, transportConfig) {
|
|
|
31
48
|
resolve(server);
|
|
32
49
|
});
|
|
33
50
|
});
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
console.error("Mode: stateless");
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.error("Mode: stateful (session-based)");
|
|
41
|
-
}
|
|
51
|
+
logger.info(`HTTP server listening on http://${host}:${port}/mcp`);
|
|
52
|
+
logger.info(`Health check: http://${host}:${port}/health`);
|
|
53
|
+
logger.info(`Mode: ${transportConfig.stateless ? "stateless" : "stateful (session-based)"}`);
|
|
42
54
|
return { httpServer, manager, sessions };
|
|
43
55
|
}
|
|
44
56
|
function setupStatelessRoutes(app, manager, config) {
|
|
@@ -59,6 +71,7 @@ function setupStatefulRoutes(app, manager, config, sessions) {
|
|
|
59
71
|
const sessionId = req.headers["mcp-session-id"];
|
|
60
72
|
if (sessionId && sessions.has(sessionId)) {
|
|
61
73
|
const session = sessions.get(sessionId);
|
|
74
|
+
session.lastAccessedAt = Date.now();
|
|
62
75
|
await session.transport.handleRequest(req, res, req.body);
|
|
63
76
|
return;
|
|
64
77
|
}
|
|
@@ -71,7 +84,7 @@ function setupStatefulRoutes(app, manager, config, sessions) {
|
|
|
71
84
|
const transport = new StreamableHTTPServerTransport({
|
|
72
85
|
sessionIdGenerator: () => randomUUID(),
|
|
73
86
|
onsessioninitialized: (newSessionId) => {
|
|
74
|
-
sessions.set(newSessionId, { transport, server });
|
|
87
|
+
sessions.set(newSessionId, { transport, server, lastAccessedAt: Date.now() });
|
|
75
88
|
},
|
|
76
89
|
});
|
|
77
90
|
transport.onclose = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type LogLevel = "debug" | "info" | "warn" | "error";
|
|
2
|
+
export declare class Logger {
|
|
3
|
+
private level;
|
|
4
|
+
private context;
|
|
5
|
+
constructor(level?: LogLevel, context?: Record<string, unknown>);
|
|
6
|
+
child(context: Record<string, unknown>): Logger;
|
|
7
|
+
debug(message: string, data?: Record<string, unknown>): void;
|
|
8
|
+
info(message: string, data?: Record<string, unknown>): void;
|
|
9
|
+
warn(message: string, data?: Record<string, unknown>): void;
|
|
10
|
+
error(message: string, data?: Record<string, unknown>): void;
|
|
11
|
+
private log;
|
|
12
|
+
}
|
|
13
|
+
export declare function initLogger(level: LogLevel): Logger;
|
|
14
|
+
export declare function getLogger(): Logger;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
const LOG_LEVELS = {
|
|
2
|
+
debug: 0,
|
|
3
|
+
info: 1,
|
|
4
|
+
warn: 2,
|
|
5
|
+
error: 3,
|
|
6
|
+
};
|
|
7
|
+
export class Logger {
|
|
8
|
+
level;
|
|
9
|
+
context;
|
|
10
|
+
constructor(level = "info", context = {}) {
|
|
11
|
+
this.level = LOG_LEVELS[level];
|
|
12
|
+
this.context = context;
|
|
13
|
+
}
|
|
14
|
+
child(context) {
|
|
15
|
+
const child = new Logger("debug", { ...this.context, ...context });
|
|
16
|
+
child.level = this.level;
|
|
17
|
+
return child;
|
|
18
|
+
}
|
|
19
|
+
debug(message, data) {
|
|
20
|
+
this.log("debug", message, data);
|
|
21
|
+
}
|
|
22
|
+
info(message, data) {
|
|
23
|
+
this.log("info", message, data);
|
|
24
|
+
}
|
|
25
|
+
warn(message, data) {
|
|
26
|
+
this.log("warn", message, data);
|
|
27
|
+
}
|
|
28
|
+
error(message, data) {
|
|
29
|
+
this.log("error", message, data);
|
|
30
|
+
}
|
|
31
|
+
log(level, message, data) {
|
|
32
|
+
if (LOG_LEVELS[level] < this.level)
|
|
33
|
+
return;
|
|
34
|
+
const entry = {
|
|
35
|
+
level,
|
|
36
|
+
message,
|
|
37
|
+
timestamp: new Date().toISOString(),
|
|
38
|
+
...this.context,
|
|
39
|
+
...data,
|
|
40
|
+
};
|
|
41
|
+
process.stderr.write(JSON.stringify(entry) + "\n");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let globalLogger = new Logger("info");
|
|
45
|
+
export function initLogger(level) {
|
|
46
|
+
globalLogger = new Logger(level);
|
|
47
|
+
return globalLogger;
|
|
48
|
+
}
|
|
49
|
+
export function getLogger() {
|
|
50
|
+
return globalLogger;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,GAA6B;IAC3C,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;IACP,KAAK,EAAE,CAAC;CACT,CAAC;AASF,MAAM,OAAO,MAAM;IACT,KAAK,CAAS;IACd,OAAO,CAA0B;IAEzC,YAAY,QAAkB,MAAM,EAAE,UAAmC,EAAE;QACzE,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,OAAgC;QACpC,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,OAAO,EAAE,CAAC,CAAC;QACnE,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,IAAI,CAAC,OAAe,EAAE,IAA8B;QAClD,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IAClC,CAAC;IAED,KAAK,CAAC,OAAe,EAAE,IAA8B;QACnD,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAEO,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,IAA8B;QAC1E,IAAI,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK;YAAE,OAAO;QAE3C,MAAM,KAAK,GAAa;YACtB,KAAK;YACL,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,IAAI,CAAC,OAAO;YACf,GAAG,IAAI;SACR,CAAC;QAEF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAC;IACrD,CAAC;CACF;AAED,IAAI,YAAY,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;AAEtC,MAAM,UAAU,UAAU,CAAC,KAAe;IACxC,YAAY,GAAG,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IACjC,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -1,34 +1,54 @@
|
|
|
1
1
|
const WRITE_KEYWORDS = [
|
|
2
|
-
"INSERT",
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"ALTER",
|
|
7
|
-
"TRUNCATE",
|
|
8
|
-
"CREATE",
|
|
9
|
-
"GRANT",
|
|
10
|
-
"REVOKE",
|
|
11
|
-
"REPLACE",
|
|
12
|
-
"MERGE",
|
|
2
|
+
"INSERT", "UPDATE", "DELETE", "DROP",
|
|
3
|
+
"ALTER", "TRUNCATE", "CREATE",
|
|
4
|
+
"GRANT", "REVOKE", "REPLACE", "MERGE",
|
|
5
|
+
"COPY", "CALL",
|
|
13
6
|
];
|
|
14
|
-
const WRITE_PATTERN = new RegExp(
|
|
15
|
-
|
|
7
|
+
const WRITE_PATTERN = new RegExp(`\\b(${WRITE_KEYWORDS.join("|")})\\b`, "i");
|
|
8
|
+
function stripStringLiterals(sql) {
|
|
9
|
+
// Replace single-quoted strings (handling escaped quotes)
|
|
10
|
+
let result = sql.replace(/'(?:[^'\\]|\\.)*'/g, "__STR__");
|
|
11
|
+
// Replace double-quoted identifiers
|
|
12
|
+
result = result.replace(/"(?:[^"\\]|\\.)*"/g, "__ID__");
|
|
13
|
+
// Replace dollar-quoted strings (PostgreSQL): $$...$$, $tag$...$tag$
|
|
14
|
+
result = result.replace(/\$([^$]*)\$[\s\S]*?\$\1\$/g, "__STR__");
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
function stripComments(sql) {
|
|
18
|
+
// Remove block comments
|
|
19
|
+
let result = sql.replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
20
|
+
// Remove line comments
|
|
21
|
+
result = result.replace(/--[^\n]*/g, " ");
|
|
22
|
+
return result;
|
|
23
|
+
}
|
|
24
|
+
function normalizeWhitespace(sql) {
|
|
25
|
+
return sql.replace(/\s+/g, " ").trim();
|
|
26
|
+
}
|
|
16
27
|
export function validateReadonlySql(sql) {
|
|
17
28
|
const trimmed = sql.trim();
|
|
18
29
|
if (!trimmed) {
|
|
19
30
|
return { valid: false, error: "Empty SQL statement" };
|
|
20
31
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
32
|
+
// Normalize: strip strings first, then comments, then whitespace
|
|
33
|
+
const noStrings = stripStringLiterals(trimmed);
|
|
34
|
+
const noComments = stripComments(noStrings);
|
|
35
|
+
const normalized = normalizeWhitespace(noComments);
|
|
36
|
+
// Check for multiple statements (after removing string literals)
|
|
37
|
+
if (normalized.includes(";")) {
|
|
38
|
+
const afterSemicolon = normalized.split(";").slice(1).join(";").trim();
|
|
39
|
+
if (afterSemicolon.length > 0) {
|
|
40
|
+
return {
|
|
41
|
+
valid: false,
|
|
42
|
+
error: "Multiple statements are not allowed in read-only mode",
|
|
43
|
+
};
|
|
44
|
+
}
|
|
26
45
|
}
|
|
27
|
-
|
|
28
|
-
|
|
46
|
+
// Check for write keywords anywhere in normalized SQL
|
|
47
|
+
const match = normalized.match(WRITE_PATTERN);
|
|
48
|
+
if (match) {
|
|
29
49
|
return {
|
|
30
50
|
valid: false,
|
|
31
|
-
error: `Statement '${match
|
|
51
|
+
error: `Statement '${match[1].toUpperCase()}' is not allowed in read-only mode`,
|
|
32
52
|
};
|
|
33
53
|
}
|
|
34
54
|
return { valid: true };
|