@pilat/mcp-datalink 1.0.1
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/README.md +442 -0
- package/databases.example.json +18 -0
- package/dist/__integration__/global-setup.d.ts +8 -0
- package/dist/__integration__/global-setup.d.ts.map +1 -0
- package/dist/__integration__/global-setup.js +34 -0
- package/dist/__integration__/global-setup.js.map +1 -0
- package/dist/__integration__/global-teardown.d.ts +8 -0
- package/dist/__integration__/global-teardown.d.ts.map +1 -0
- package/dist/__integration__/global-teardown.js +17 -0
- package/dist/__integration__/global-teardown.js.map +1 -0
- package/dist/__integration__/helpers.d.ts +58 -0
- package/dist/__integration__/helpers.d.ts.map +1 -0
- package/dist/__integration__/helpers.js +568 -0
- package/dist/__integration__/helpers.js.map +1 -0
- package/dist/__integration__/setup.d.ts +79 -0
- package/dist/__integration__/setup.d.ts.map +1 -0
- package/dist/__integration__/setup.js +230 -0
- package/dist/__integration__/setup.js.map +1 -0
- package/dist/adapters/factory.d.ts +40 -0
- package/dist/adapters/factory.d.ts.map +1 -0
- package/dist/adapters/factory.js +114 -0
- package/dist/adapters/factory.js.map +1 -0
- package/dist/adapters/index.d.ts +31 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +34 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/mysql/adapter.d.ts +61 -0
- package/dist/adapters/mysql/adapter.d.ts.map +1 -0
- package/dist/adapters/mysql/adapter.js +567 -0
- package/dist/adapters/mysql/adapter.js.map +1 -0
- package/dist/adapters/postgresql/adapter.d.ts +52 -0
- package/dist/adapters/postgresql/adapter.d.ts.map +1 -0
- package/dist/adapters/postgresql/adapter.js +429 -0
- package/dist/adapters/postgresql/adapter.js.map +1 -0
- package/dist/adapters/sqlite/adapter.d.ts +56 -0
- package/dist/adapters/sqlite/adapter.d.ts.map +1 -0
- package/dist/adapters/sqlite/adapter.js +582 -0
- package/dist/adapters/sqlite/adapter.js.map +1 -0
- package/dist/adapters/types.d.ts +155 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +7 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/config/loader.d.ts +11 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +127 -0
- package/dist/config/loader.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +21 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +191 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/describe-table.d.ts +11 -0
- package/dist/tools/describe-table.d.ts.map +1 -0
- package/dist/tools/describe-table.js +23 -0
- package/dist/tools/describe-table.js.map +1 -0
- package/dist/tools/execute.d.ts +22 -0
- package/dist/tools/execute.d.ts.map +1 -0
- package/dist/tools/execute.js +48 -0
- package/dist/tools/execute.js.map +1 -0
- package/dist/tools/explain.d.ts +25 -0
- package/dist/tools/explain.d.ts.map +1 -0
- package/dist/tools/explain.js +81 -0
- package/dist/tools/explain.js.map +1 -0
- package/dist/tools/list-databases.d.ts +18 -0
- package/dist/tools/list-databases.d.ts.map +1 -0
- package/dist/tools/list-databases.js +17 -0
- package/dist/tools/list-databases.js.map +1 -0
- package/dist/tools/list-tables.d.ts +22 -0
- package/dist/tools/list-tables.d.ts.map +1 -0
- package/dist/tools/list-tables.js +43 -0
- package/dist/tools/list-tables.js.map +1 -0
- package/dist/tools/query.d.ts +25 -0
- package/dist/tools/query.d.ts.map +1 -0
- package/dist/tools/query.js +109 -0
- package/dist/tools/query.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/errors.d.ts +22 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +41 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/formatter.d.ts +13 -0
- package/dist/utils/formatter.d.ts.map +1 -0
- package/dist/utils/formatter.js +56 -0
- package/dist/utils/formatter.js.map +1 -0
- package/dist/utils/truncate.d.ts +37 -0
- package/dist/utils/truncate.d.ts.map +1 -0
- package/dist/utils/truncate.js +91 -0
- package/dist/utils/truncate.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute tool for INSERT/UPDATE/DELETE statements
|
|
3
|
+
*/
|
|
4
|
+
import type { Config, ExecuteResult } from '../types.js';
|
|
5
|
+
export interface ExecuteParams {
|
|
6
|
+
database: string;
|
|
7
|
+
sql: string;
|
|
8
|
+
params?: unknown[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Execute an INSERT/UPDATE/DELETE statement
|
|
12
|
+
*
|
|
13
|
+
* @param params - Execute parameters including database name, SQL, and optional params
|
|
14
|
+
* @param config - Application configuration
|
|
15
|
+
* @returns ExecuteResult with command type and rows affected
|
|
16
|
+
* @throws DbMcpError with READONLY_VIOLATION if database is readonly
|
|
17
|
+
* @throws DbMcpError with QUERY_BLOCKED if SELECT or dangerous DDL
|
|
18
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
19
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
20
|
+
*/
|
|
21
|
+
export declare function execute(params: ExecuteParams, config: Config): Promise<ExecuteResult>;
|
|
22
|
+
//# sourceMappingURL=execute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.d.ts","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIzD,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CA+CxB"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Execute tool for INSERT/UPDATE/DELETE statements
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Execute an INSERT/UPDATE/DELETE statement
|
|
8
|
+
*
|
|
9
|
+
* @param params - Execute parameters including database name, SQL, and optional params
|
|
10
|
+
* @param config - Application configuration
|
|
11
|
+
* @returns ExecuteResult with command type and rows affected
|
|
12
|
+
* @throws DbMcpError with READONLY_VIOLATION if database is readonly
|
|
13
|
+
* @throws DbMcpError with QUERY_BLOCKED if SELECT or dangerous DDL
|
|
14
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
15
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
16
|
+
*/
|
|
17
|
+
export async function execute(params, config) {
|
|
18
|
+
const startTime = Date.now();
|
|
19
|
+
// Get database config
|
|
20
|
+
const dbConfig = config.databases[params.database];
|
|
21
|
+
if (!dbConfig) {
|
|
22
|
+
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
23
|
+
}
|
|
24
|
+
// Step 1: Check if database is readonly
|
|
25
|
+
if (dbConfig.readonly) {
|
|
26
|
+
throw new DbMcpError(ErrorCode.READONLY_VIOLATION, `Database "${params.database}" is configured as readonly. INSERT/UPDATE/DELETE operations are not allowed.`, { database: params.database });
|
|
27
|
+
}
|
|
28
|
+
// Create adapter for this database
|
|
29
|
+
const adapter = createAdapter(dbConfig, config.defaults);
|
|
30
|
+
// Step 2: Validate query type - blocks SELECT and dangerous DDL
|
|
31
|
+
adapter.validateQueryForTool(params.sql, 'execute');
|
|
32
|
+
// Step 3: Get the command type from parsed query
|
|
33
|
+
const parsed = adapter.parseQuery(params.sql);
|
|
34
|
+
const command = parsed.type.toUpperCase();
|
|
35
|
+
// Step 4: Convert placeholders for non-PostgreSQL dialects
|
|
36
|
+
// PostgreSQL uses $1, $2; MySQL/SQLite use ?
|
|
37
|
+
const sql = adapter.convertPlaceholders(params.sql);
|
|
38
|
+
const result = await adapter.withConnection(async (conn) => {
|
|
39
|
+
return conn.query(sql, params.params ?? []);
|
|
40
|
+
});
|
|
41
|
+
const executionTime = Date.now() - startTime;
|
|
42
|
+
return {
|
|
43
|
+
command,
|
|
44
|
+
rowsAffected: result.rowCount,
|
|
45
|
+
executionTime,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=execute.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute.js","sourceRoot":"","sources":["../../src/tools/execute.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQ3D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,MAAqB,EACrB,MAAc;IAEd,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,sBAAsB;IACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,kBAAkB,EAC5B,aAAa,MAAM,CAAC,QAAQ,8BAA8B,EAC1D,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CACxE,CAAC;IACJ,CAAC;IAED,wCAAwC;IACxC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,kBAAkB,EAC5B,aAAa,MAAM,CAAC,QAAQ,+EAA+E,EAC3G,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,CAC9B,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEzD,gEAAgE;IAChE,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAEpD,iDAAiD;IACjD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC9C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAE1C,2DAA2D;IAC3D,6CAA6C;IAC7C,MAAM,GAAG,GAAG,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAEpD,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QACzD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAE7C,OAAO;QACL,OAAO;QACP,YAAY,EAAE,MAAM,CAAC,QAAQ;QAC7B,aAAa;KACd,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explain tool for showing query execution plans
|
|
3
|
+
*/
|
|
4
|
+
import type { Config } from '../types.js';
|
|
5
|
+
export interface ExplainParams {
|
|
6
|
+
database: string;
|
|
7
|
+
sql: string;
|
|
8
|
+
analyze?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface ExplainResult {
|
|
11
|
+
plan: string;
|
|
12
|
+
executionTime: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get the execution plan for a SQL query
|
|
16
|
+
*
|
|
17
|
+
* @param params - Explain parameters including database name, SQL, and optional analyze flag
|
|
18
|
+
* @param config - Application configuration
|
|
19
|
+
* @returns ExplainResult with plan text and execution time
|
|
20
|
+
* @throws DbMcpError with QUERY_BLOCKED if query is dangerous (DROP, TRUNCATE, etc.)
|
|
21
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
22
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
23
|
+
*/
|
|
24
|
+
export declare function explain(params: ExplainParams, config: Config): Promise<ExplainResult>;
|
|
25
|
+
//# sourceMappingURL=explain.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAI1C,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAC3B,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,aAAa,CAAC,CAmFxB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explain tool for showing query execution plans
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Get the execution plan for a SQL query
|
|
8
|
+
*
|
|
9
|
+
* @param params - Explain parameters including database name, SQL, and optional analyze flag
|
|
10
|
+
* @param config - Application configuration
|
|
11
|
+
* @returns ExplainResult with plan text and execution time
|
|
12
|
+
* @throws DbMcpError with QUERY_BLOCKED if query is dangerous (DROP, TRUNCATE, etc.)
|
|
13
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
14
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
15
|
+
*/
|
|
16
|
+
export async function explain(params, config) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
// Get database config
|
|
19
|
+
const dbConfig = config.databases[params.database];
|
|
20
|
+
if (!dbConfig) {
|
|
21
|
+
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
22
|
+
}
|
|
23
|
+
// Create adapter for this database
|
|
24
|
+
const adapter = createAdapter(dbConfig, config.defaults);
|
|
25
|
+
// Step 1: Parse query and check for dangerous operations
|
|
26
|
+
const parsed = adapter.parseQuery(params.sql);
|
|
27
|
+
if (parsed.isDangerous) {
|
|
28
|
+
throw new DbMcpError(ErrorCode.QUERY_BLOCKED, parsed.dangerousReason ?? 'This operation is not allowed', { sql: params.sql, queryType: parsed.type });
|
|
29
|
+
}
|
|
30
|
+
const result = await adapter.withConnection(async (conn) => {
|
|
31
|
+
// Build EXPLAIN query using adapter-specific prefix
|
|
32
|
+
const explainPrefix = adapter.getExplainPrefix(params.analyze ?? false);
|
|
33
|
+
// SQLite and MySQL don't need READ ONLY transactions for EXPLAIN:
|
|
34
|
+
// - SQLite: Doesn't support READ ONLY transactions
|
|
35
|
+
// - MySQL: EXPLAIN doesn't execute the query, and READ ONLY tx blocks
|
|
36
|
+
// EXPLAIN on UPDATE/DELETE even though they're safe
|
|
37
|
+
//
|
|
38
|
+
// Defense in depth is still provided by:
|
|
39
|
+
// 1. SQL parser blocking dangerous operations (DROP, TRUNCATE, etc.)
|
|
40
|
+
// 2. EXPLAIN not executing the query (MySQL) / EXPLAIN QUERY PLAN (SQLite)
|
|
41
|
+
// 3. Database adapter opening in readonly mode when configured
|
|
42
|
+
if (adapter.type === 'sqlite' || adapter.type === 'mysql') {
|
|
43
|
+
return await conn.query(explainPrefix + params.sql);
|
|
44
|
+
}
|
|
45
|
+
// PostgreSQL: Use READ ONLY transaction since EXPLAIN ANALYZE executes the query
|
|
46
|
+
await conn.execute('BEGIN TRANSACTION READ ONLY');
|
|
47
|
+
try {
|
|
48
|
+
const queryResult = await conn.query(explainPrefix + params.sql);
|
|
49
|
+
await conn.execute('COMMIT');
|
|
50
|
+
return queryResult;
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
await conn.execute('ROLLBACK');
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// Step 3: Format plan as text (join rows with newlines)
|
|
58
|
+
// Different databases have different EXPLAIN output formats:
|
|
59
|
+
// - PostgreSQL: Single column with plan text
|
|
60
|
+
// - MySQL: Multiple columns (id, select_type, table, type, key, rows, Extra, etc.)
|
|
61
|
+
// - SQLite: 4 columns (id, parent, notused, detail)
|
|
62
|
+
const planLines = result.rows.map((row) => {
|
|
63
|
+
if (adapter.type === 'sqlite' && row.length >= 4) {
|
|
64
|
+
// SQLite: extract the 'detail' column (4th column, index 3)
|
|
65
|
+
return String(row[3]);
|
|
66
|
+
}
|
|
67
|
+
if (adapter.type === 'mysql' && row.length > 1) {
|
|
68
|
+
// MySQL: Join all columns with tabs for tabular output
|
|
69
|
+
// Columns: id, select_type, table, partitions, type, possible_keys, key, key_len, ref, rows, filtered, Extra
|
|
70
|
+
return row.map((col) => (col === null ? 'NULL' : String(col))).join('\t');
|
|
71
|
+
}
|
|
72
|
+
// PostgreSQL: first column is the plan line
|
|
73
|
+
return row[0];
|
|
74
|
+
});
|
|
75
|
+
const executionTime = Date.now() - startTime;
|
|
76
|
+
return {
|
|
77
|
+
plan: planLines.join('\n'),
|
|
78
|
+
executionTime,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=explain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/tools/explain.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_databases tool - returns configured databases from config
|
|
3
|
+
*/
|
|
4
|
+
import type { Config } from '../types.js';
|
|
5
|
+
export interface ListDatabasesResult {
|
|
6
|
+
databases: Array<{
|
|
7
|
+
name: string;
|
|
8
|
+
readonly: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Returns all configured databases with their readonly flags.
|
|
13
|
+
*
|
|
14
|
+
* @param config - The application config containing database configurations
|
|
15
|
+
* @returns List of databases with name and readonly status
|
|
16
|
+
*/
|
|
17
|
+
export declare function listDatabases(config: Config): ListDatabasesResult;
|
|
18
|
+
//# sourceMappingURL=list-databases.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-databases.d.ts","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC;KACnB,CAAC,CAAC;CACJ;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,mBAAmB,CAOjE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_databases tool - returns configured databases from config
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Returns all configured databases with their readonly flags.
|
|
6
|
+
*
|
|
7
|
+
* @param config - The application config containing database configurations
|
|
8
|
+
* @returns List of databases with name and readonly status
|
|
9
|
+
*/
|
|
10
|
+
export function listDatabases(config) {
|
|
11
|
+
const databases = Object.entries(config.databases).map(([name, dbConfig]) => ({
|
|
12
|
+
name,
|
|
13
|
+
readonly: dbConfig.readonly,
|
|
14
|
+
}));
|
|
15
|
+
return { databases };
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=list-databases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-databases.js","sourceRoot":"","sources":["../../src/tools/list-databases.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,SAAS,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5E,IAAI;QACJ,QAAQ,EAAE,QAAQ,CAAC,QAAQ;KAC5B,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,SAAS,EAAE,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_tables tool - lists tables in a database schema
|
|
3
|
+
*/
|
|
4
|
+
import type { Config, TableInfo } from '../types.js';
|
|
5
|
+
export interface ListTablesParams {
|
|
6
|
+
database: string;
|
|
7
|
+
schema?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ListTablesResult {
|
|
10
|
+
tables: TableInfo[];
|
|
11
|
+
truncated: boolean;
|
|
12
|
+
totalAvailable?: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Lists tables and views in a database schema.
|
|
16
|
+
*
|
|
17
|
+
* @param params - Database name and optional schema (defaults to "public")
|
|
18
|
+
* @param config - The application config
|
|
19
|
+
* @returns List of tables with truncation info if over maxTables limit
|
|
20
|
+
*/
|
|
21
|
+
export declare function listTables(params: ListTablesParams, config: Config): Promise<ListTablesResult>;
|
|
22
|
+
//# sourceMappingURL=list-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-tables.d.ts","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAIrD,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAuC3B"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* list_tables tool - lists tables in a database schema
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
+
/**
|
|
7
|
+
* Lists tables and views in a database schema.
|
|
8
|
+
*
|
|
9
|
+
* @param params - Database name and optional schema (defaults to "public")
|
|
10
|
+
* @param config - The application config
|
|
11
|
+
* @returns List of tables with truncation info if over maxTables limit
|
|
12
|
+
*/
|
|
13
|
+
export async function listTables(params, config) {
|
|
14
|
+
const maxTables = config.defaults.maxTables;
|
|
15
|
+
// Get database config
|
|
16
|
+
const dbConfig = config.databases[params.database];
|
|
17
|
+
if (!dbConfig) {
|
|
18
|
+
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
19
|
+
}
|
|
20
|
+
// Create adapter for this database
|
|
21
|
+
const adapter = createAdapter(dbConfig, config.defaults);
|
|
22
|
+
// Use provided schema or adapter's default schema
|
|
23
|
+
// PostgreSQL: "public", MySQL: database name, SQLite: "main"
|
|
24
|
+
const schema = params.schema ?? adapter.getDefaultSchema();
|
|
25
|
+
return adapter.withConnection(async (conn) => {
|
|
26
|
+
const result = await conn.listTables(schema, maxTables);
|
|
27
|
+
const allTables = result.tables;
|
|
28
|
+
const totalAvailable = result.totalAvailable;
|
|
29
|
+
const truncated = totalAvailable > maxTables;
|
|
30
|
+
if (truncated) {
|
|
31
|
+
return {
|
|
32
|
+
tables: allTables.slice(0, maxTables),
|
|
33
|
+
truncated: true,
|
|
34
|
+
totalAvailable,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
tables: allTables,
|
|
39
|
+
truncated: false,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=list-tables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list-tables.js","sourceRoot":"","sources":["../../src/tools/list-tables.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAa3D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAwB,EACxB,MAAc;IAEd,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;IAE5C,sBAAsB;IACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,kBAAkB,EAC5B,aAAa,MAAM,CAAC,QAAQ,8BAA8B,EAC1D,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CACxE,CAAC;IACJ,CAAC;IAED,mCAAmC;IACnC,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IAEzD,kDAAkD;IAClD,6DAA6D;IAC7D,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAE3D,OAAO,OAAO,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3C,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACxD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC;QAChC,MAAM,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC;QAC7C,MAAM,SAAS,GAAG,cAAc,GAAG,SAAS,CAAC;QAE7C,IAAI,SAAS,EAAE,CAAC;YACd,OAAO;gBACL,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;gBACrC,SAAS,EAAE,IAAI;gBACf,cAAc;aACf,CAAC;QACJ,CAAC;QAED,OAAO;YACL,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,KAAK;SACjB,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query tool for executing SELECT statements
|
|
3
|
+
*/
|
|
4
|
+
import type { Config, QueryResult } from '../types.js';
|
|
5
|
+
export interface QueryParams {
|
|
6
|
+
database: string;
|
|
7
|
+
sql: string;
|
|
8
|
+
params?: unknown[];
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Format QueryResult as Markdown table followed by metadata
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatQueryResultAsMarkdown(result: QueryResult): string;
|
|
14
|
+
/**
|
|
15
|
+
* Execute a SELECT query and return formatted results
|
|
16
|
+
*
|
|
17
|
+
* @param params - Query parameters including database name, SQL, and optional params
|
|
18
|
+
* @param config - Application configuration
|
|
19
|
+
* @returns QueryResult with columns, rows, and metadata
|
|
20
|
+
* @throws DbMcpError with QUERY_BLOCKED if not a SELECT query
|
|
21
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
22
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
23
|
+
*/
|
|
24
|
+
export declare function query(params: QueryParams, config: Config): Promise<QueryResult>;
|
|
25
|
+
//# sourceMappingURL=query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAMvD,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAqBvE;AAED;;;;;;;;;GASG;AACH,wBAAsB,KAAK,CACzB,MAAM,EAAE,WAAW,EACnB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,WAAW,CAAC,CA6FtB"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query tool for executing SELECT statements
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
+
import { truncateRows, truncateCell, checkTotalSize } from '../utils/truncate.js';
|
|
7
|
+
import { formatAsMarkdownTable, formatValue } from '../utils/formatter.js';
|
|
8
|
+
/**
|
|
9
|
+
* Format QueryResult as Markdown table followed by metadata
|
|
10
|
+
*/
|
|
11
|
+
export function formatQueryResultAsMarkdown(result) {
|
|
12
|
+
const parts = [];
|
|
13
|
+
// Data as Markdown table
|
|
14
|
+
const table = formatAsMarkdownTable(result.columns, result.rows);
|
|
15
|
+
if (table) {
|
|
16
|
+
parts.push(table);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
parts.push('_No results_');
|
|
20
|
+
}
|
|
21
|
+
// Metadata section
|
|
22
|
+
parts.push('');
|
|
23
|
+
parts.push(`**Rows:** ${result.rowCount}${result.truncated ? ` (truncated from ${result.totalAvailable ?? 'unknown'})` : ''}`);
|
|
24
|
+
parts.push(`**Execution time:** ${result.executionTime}ms`);
|
|
25
|
+
if (result.truncated && result.hint) {
|
|
26
|
+
parts.push(`**Hint:** ${result.hint}`);
|
|
27
|
+
}
|
|
28
|
+
return parts.join('\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Execute a SELECT query and return formatted results
|
|
32
|
+
*
|
|
33
|
+
* @param params - Query parameters including database name, SQL, and optional params
|
|
34
|
+
* @param config - Application configuration
|
|
35
|
+
* @returns QueryResult with columns, rows, and metadata
|
|
36
|
+
* @throws DbMcpError with QUERY_BLOCKED if not a SELECT query
|
|
37
|
+
* @throws DbMcpError with DATABASE_NOT_FOUND if database not configured
|
|
38
|
+
* @throws DbMcpError with CONNECTION_FAILED if connection fails
|
|
39
|
+
*/
|
|
40
|
+
export async function query(params, config) {
|
|
41
|
+
const startTime = Date.now();
|
|
42
|
+
// Get database config
|
|
43
|
+
const dbConfig = config.databases[params.database];
|
|
44
|
+
if (!dbConfig) {
|
|
45
|
+
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${params.database}" not found in configuration`, { database: params.database, available: Object.keys(config.databases) });
|
|
46
|
+
}
|
|
47
|
+
// Create adapter for this database
|
|
48
|
+
const adapter = createAdapter(dbConfig, config.defaults);
|
|
49
|
+
// Step 1: Validate that this is a SELECT query
|
|
50
|
+
adapter.validateQueryForTool(params.sql, 'query');
|
|
51
|
+
// Step 2: Parse query and inject LIMIT if missing
|
|
52
|
+
const parsed = adapter.parseQuery(params.sql);
|
|
53
|
+
let sql = params.sql;
|
|
54
|
+
if (!parsed.hasLimit) {
|
|
55
|
+
// Get maxRows from database config or defaults
|
|
56
|
+
const maxRows = dbConfig?.maxRows ?? config.defaults.maxRows;
|
|
57
|
+
sql = adapter.injectLimit(params.sql, maxRows);
|
|
58
|
+
}
|
|
59
|
+
// Step 3: Convert placeholders for non-PostgreSQL dialects
|
|
60
|
+
// PostgreSQL uses $1, $2; MySQL/SQLite use ?
|
|
61
|
+
sql = adapter.convertPlaceholders(sql);
|
|
62
|
+
const result = await adapter.withConnection(async (conn) => {
|
|
63
|
+
return conn.query(sql, params.params ?? []);
|
|
64
|
+
});
|
|
65
|
+
const columns = result.fields.map((field) => field.name);
|
|
66
|
+
const rawRows = result.rows;
|
|
67
|
+
// Step 4: Format each cell value
|
|
68
|
+
let formattedRows = rawRows.map((row) => row.map((cell) => formatValue(cell)));
|
|
69
|
+
// Step 5: Truncate individual cells if over maxCellLength
|
|
70
|
+
let anyCellTruncated = false;
|
|
71
|
+
formattedRows = formattedRows.map((row) => row.map((cell) => {
|
|
72
|
+
const truncated = truncateCell(cell, config.defaults.maxCellLength);
|
|
73
|
+
if (truncated.truncated) {
|
|
74
|
+
anyCellTruncated = true;
|
|
75
|
+
}
|
|
76
|
+
return truncated.value;
|
|
77
|
+
}));
|
|
78
|
+
// Step 6: Truncate rows if over maxRows
|
|
79
|
+
const { rows: truncatedRows, info: rowTruncationInfo } = truncateRows(formattedRows, config.defaults.maxRows);
|
|
80
|
+
// Step 7: Check total size
|
|
81
|
+
const tableOutput = formatAsMarkdownTable(columns, truncatedRows);
|
|
82
|
+
const sizeInfo = checkTotalSize(tableOutput, config.defaults.maxTotalSize);
|
|
83
|
+
// Determine final truncation state
|
|
84
|
+
const truncated = rowTruncationInfo.truncated || anyCellTruncated || sizeInfo.truncated;
|
|
85
|
+
// Determine truncation reason (priority: maxTotalSize > maxRows > maxCellLength)
|
|
86
|
+
let truncationReason;
|
|
87
|
+
if (sizeInfo.truncated) {
|
|
88
|
+
truncationReason = sizeInfo.truncationReason;
|
|
89
|
+
}
|
|
90
|
+
else if (rowTruncationInfo.truncated) {
|
|
91
|
+
truncationReason = rowTruncationInfo.truncationReason;
|
|
92
|
+
}
|
|
93
|
+
else if (anyCellTruncated) {
|
|
94
|
+
truncationReason = 'maxCellLength';
|
|
95
|
+
}
|
|
96
|
+
const executionTime = Date.now() - startTime;
|
|
97
|
+
return {
|
|
98
|
+
columns,
|
|
99
|
+
rows: truncatedRows,
|
|
100
|
+
rowCount: truncatedRows.length,
|
|
101
|
+
truncated,
|
|
102
|
+
truncationReason,
|
|
103
|
+
totalAvailable: rowTruncationInfo.totalAvailable,
|
|
104
|
+
returned: rowTruncationInfo.returned,
|
|
105
|
+
hint: rowTruncationInfo.hint ?? sizeInfo.hint,
|
|
106
|
+
executionTime,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types for db-mcp server
|
|
3
|
+
*/
|
|
4
|
+
export type QueryType = 'select' | 'insert' | 'update' | 'delete' | 'other';
|
|
5
|
+
export interface ParsedQuery {
|
|
6
|
+
/** The type of SQL query */
|
|
7
|
+
type: QueryType;
|
|
8
|
+
/** Whether the query has a LIMIT clause (for SELECT queries) */
|
|
9
|
+
hasLimit: boolean;
|
|
10
|
+
/** Whether the query is dangerous (DROP, TRUNCATE, ALTER, etc.) */
|
|
11
|
+
isDangerous: boolean;
|
|
12
|
+
/** Reason why query is considered dangerous */
|
|
13
|
+
dangerousReason?: string;
|
|
14
|
+
/** The original SQL string */
|
|
15
|
+
sql: string;
|
|
16
|
+
}
|
|
17
|
+
export interface DatabaseConfig {
|
|
18
|
+
url: string;
|
|
19
|
+
readonly: boolean;
|
|
20
|
+
maxRows?: number;
|
|
21
|
+
}
|
|
22
|
+
export interface DefaultsConfig {
|
|
23
|
+
maxRows: number;
|
|
24
|
+
maxCellLength: number;
|
|
25
|
+
maxTotalSize: number;
|
|
26
|
+
maxColumns: number;
|
|
27
|
+
maxTables: number;
|
|
28
|
+
maxIndexes: number;
|
|
29
|
+
timeout: number;
|
|
30
|
+
}
|
|
31
|
+
export interface Config {
|
|
32
|
+
databases: Record<string, DatabaseConfig>;
|
|
33
|
+
defaults: DefaultsConfig;
|
|
34
|
+
}
|
|
35
|
+
/** Raw config shape before defaults are applied */
|
|
36
|
+
export interface RawConfig {
|
|
37
|
+
databases?: Record<string, Partial<DatabaseConfig> & {
|
|
38
|
+
url: string;
|
|
39
|
+
}>;
|
|
40
|
+
defaults?: Partial<DefaultsConfig>;
|
|
41
|
+
}
|
|
42
|
+
export interface QueryResult {
|
|
43
|
+
columns: string[];
|
|
44
|
+
rows: unknown[][];
|
|
45
|
+
rowCount: number;
|
|
46
|
+
truncated: boolean;
|
|
47
|
+
truncationReason?: string;
|
|
48
|
+
totalAvailable?: number;
|
|
49
|
+
returned?: number;
|
|
50
|
+
hint?: string;
|
|
51
|
+
executionTime: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ExecuteResult {
|
|
54
|
+
command: string;
|
|
55
|
+
rowsAffected: number;
|
|
56
|
+
executionTime: number;
|
|
57
|
+
}
|
|
58
|
+
export interface ColumnInfo {
|
|
59
|
+
name: string;
|
|
60
|
+
type: string;
|
|
61
|
+
nullable: boolean;
|
|
62
|
+
default: string | null;
|
|
63
|
+
primaryKey: boolean;
|
|
64
|
+
}
|
|
65
|
+
export interface IndexInfo {
|
|
66
|
+
name: string;
|
|
67
|
+
columns: string[];
|
|
68
|
+
unique: boolean;
|
|
69
|
+
primary: boolean;
|
|
70
|
+
}
|
|
71
|
+
export interface ForeignKeyInfo {
|
|
72
|
+
column: string;
|
|
73
|
+
references: {
|
|
74
|
+
table: string;
|
|
75
|
+
column: string;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export interface TableDescription {
|
|
79
|
+
table: string;
|
|
80
|
+
schema: string;
|
|
81
|
+
columns: ColumnInfo[];
|
|
82
|
+
indexes: IndexInfo[];
|
|
83
|
+
foreignKeys: ForeignKeyInfo[];
|
|
84
|
+
truncated: boolean;
|
|
85
|
+
truncationReason?: string;
|
|
86
|
+
}
|
|
87
|
+
export interface TableInfo {
|
|
88
|
+
name: string;
|
|
89
|
+
schema: string;
|
|
90
|
+
type: 'table' | 'view';
|
|
91
|
+
rows_estimate: number | null;
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types and handling for db-mcp server
|
|
3
|
+
*/
|
|
4
|
+
export declare const ErrorCode: {
|
|
5
|
+
readonly INVALID_SQL: "INVALID_SQL";
|
|
6
|
+
readonly MULTI_STATEMENT: "MULTI_STATEMENT";
|
|
7
|
+
readonly QUERY_BLOCKED: "QUERY_BLOCKED";
|
|
8
|
+
readonly CONNECTION_FAILED: "CONNECTION_FAILED";
|
|
9
|
+
readonly QUERY_TIMEOUT: "QUERY_TIMEOUT";
|
|
10
|
+
readonly DATABASE_NOT_FOUND: "DATABASE_NOT_FOUND";
|
|
11
|
+
readonly CONFIG_NOT_FOUND: "CONFIG_NOT_FOUND";
|
|
12
|
+
readonly CONFIG_INVALID: "CONFIG_INVALID";
|
|
13
|
+
readonly READONLY_VIOLATION: "READONLY_VIOLATION";
|
|
14
|
+
};
|
|
15
|
+
export type ErrorCodeType = typeof ErrorCode[keyof typeof ErrorCode];
|
|
16
|
+
export declare class DbMcpError extends Error {
|
|
17
|
+
readonly code: ErrorCodeType;
|
|
18
|
+
readonly details?: Record<string, unknown>;
|
|
19
|
+
constructor(code: ErrorCodeType, message: string, details?: Record<string, unknown>);
|
|
20
|
+
toJSON(): Record<string, unknown>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/utils/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,SAAS;;;;;;;;;;CAiBZ,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,OAAO,SAAS,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC;AAErE,qBAAa,UAAW,SAAQ,KAAK;IACnC,SAAgB,IAAI,EAAE,aAAa,CAAC;IACpC,SAAgB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;gBAEtC,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAYnF,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAQlC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error types and handling for db-mcp server
|
|
3
|
+
*/
|
|
4
|
+
export const ErrorCode = {
|
|
5
|
+
// SQL validation errors
|
|
6
|
+
INVALID_SQL: 'INVALID_SQL',
|
|
7
|
+
MULTI_STATEMENT: 'MULTI_STATEMENT',
|
|
8
|
+
QUERY_BLOCKED: 'QUERY_BLOCKED',
|
|
9
|
+
// Database errors
|
|
10
|
+
CONNECTION_FAILED: 'CONNECTION_FAILED',
|
|
11
|
+
QUERY_TIMEOUT: 'QUERY_TIMEOUT',
|
|
12
|
+
DATABASE_NOT_FOUND: 'DATABASE_NOT_FOUND',
|
|
13
|
+
// Configuration errors
|
|
14
|
+
CONFIG_NOT_FOUND: 'CONFIG_NOT_FOUND',
|
|
15
|
+
CONFIG_INVALID: 'CONFIG_INVALID',
|
|
16
|
+
// Access errors
|
|
17
|
+
READONLY_VIOLATION: 'READONLY_VIOLATION',
|
|
18
|
+
};
|
|
19
|
+
export class DbMcpError extends Error {
|
|
20
|
+
code;
|
|
21
|
+
details;
|
|
22
|
+
constructor(code, message, details) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = 'DbMcpError';
|
|
25
|
+
this.code = code;
|
|
26
|
+
this.details = details;
|
|
27
|
+
// Maintain proper stack trace in V8
|
|
28
|
+
if (Error.captureStackTrace) {
|
|
29
|
+
Error.captureStackTrace(this, DbMcpError);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
toJSON() {
|
|
33
|
+
return {
|
|
34
|
+
name: this.name,
|
|
35
|
+
code: this.code,
|
|
36
|
+
message: this.message,
|
|
37
|
+
details: this.details,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=errors.js.map
|