@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,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Adapter Interfaces
|
|
3
|
+
*
|
|
4
|
+
* Core abstractions for multi-database support.
|
|
5
|
+
*/
|
|
6
|
+
import type { ParsedQuery, TableInfo, TableDescription, DefaultsConfig, DatabaseConfig } from '../types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Result from a raw query execution
|
|
9
|
+
* Normalized format across all database drivers
|
|
10
|
+
*/
|
|
11
|
+
export interface RawQueryResult {
|
|
12
|
+
/** Column metadata */
|
|
13
|
+
fields: Array<{
|
|
14
|
+
name: string;
|
|
15
|
+
}>;
|
|
16
|
+
/** Row data as arrays (positional, not named) */
|
|
17
|
+
rows: unknown[][];
|
|
18
|
+
/** Number of rows returned or affected */
|
|
19
|
+
rowCount: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Database adapter interface - implemented by each database driver
|
|
23
|
+
*
|
|
24
|
+
* Combines connection management with SQL dialect operations.
|
|
25
|
+
*/
|
|
26
|
+
export interface DatabaseAdapter {
|
|
27
|
+
/** Unique identifier for this adapter type */
|
|
28
|
+
readonly type: 'postgresql' | 'mysql' | 'sqlite';
|
|
29
|
+
/**
|
|
30
|
+
* Execute a function with a managed connection.
|
|
31
|
+
* Connection is created at start and destroyed at end.
|
|
32
|
+
*/
|
|
33
|
+
withConnection<T>(fn: (conn: AdapterConnection) => Promise<T>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* Get the default schema name for this database type
|
|
36
|
+
*
|
|
37
|
+
* PostgreSQL: "public"
|
|
38
|
+
* MySQL: database name from connection URL
|
|
39
|
+
* SQLite: "main"
|
|
40
|
+
*/
|
|
41
|
+
getDefaultSchema(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Clean up any resources (called on server shutdown)
|
|
44
|
+
*/
|
|
45
|
+
dispose(): Promise<void>;
|
|
46
|
+
/**
|
|
47
|
+
* Parse a SQL statement and validate it
|
|
48
|
+
*
|
|
49
|
+
* SECURITY: This validates:
|
|
50
|
+
* - Single statement only (no multi-statement attacks)
|
|
51
|
+
* - No dangerous operations (DROP, TRUNCATE, etc.)
|
|
52
|
+
*
|
|
53
|
+
* @param sql - Raw SQL to parse
|
|
54
|
+
* @throws DbMcpError if SQL is invalid or multi-statement
|
|
55
|
+
*/
|
|
56
|
+
parseQuery(sql: string): ParsedQuery;
|
|
57
|
+
/**
|
|
58
|
+
* Inject LIMIT clause if query doesn't have one
|
|
59
|
+
*
|
|
60
|
+
* Used to enforce maxRows limit on SELECT queries.
|
|
61
|
+
*
|
|
62
|
+
* @param sql - Original SQL
|
|
63
|
+
* @param limit - Limit value to inject
|
|
64
|
+
* @returns Modified SQL with LIMIT, or original if already has LIMIT
|
|
65
|
+
*/
|
|
66
|
+
injectLimit(sql: string, limit: number): string;
|
|
67
|
+
/**
|
|
68
|
+
* Validate that a SQL query is appropriate for a specific tool
|
|
69
|
+
*
|
|
70
|
+
* @param sql - The SQL query string
|
|
71
|
+
* @param tool - Either 'query' (SELECT only) or 'execute' (INSERT/UPDATE/DELETE)
|
|
72
|
+
* @throws DbMcpError with QUERY_BLOCKED if query type is not allowed
|
|
73
|
+
*/
|
|
74
|
+
validateQueryForTool(sql: string, tool: 'query' | 'execute'): void;
|
|
75
|
+
/**
|
|
76
|
+
* Get the EXPLAIN prefix for this dialect
|
|
77
|
+
*
|
|
78
|
+
* @param analyze - Whether to include ANALYZE
|
|
79
|
+
* @returns Prefix to prepend to SQL for EXPLAIN
|
|
80
|
+
*
|
|
81
|
+
* PostgreSQL: "EXPLAIN " or "EXPLAIN ANALYZE "
|
|
82
|
+
* MySQL: "EXPLAIN " or "EXPLAIN ANALYZE "
|
|
83
|
+
* SQLite: "EXPLAIN QUERY PLAN "
|
|
84
|
+
*/
|
|
85
|
+
getExplainPrefix(analyze: boolean): string;
|
|
86
|
+
/**
|
|
87
|
+
* Convert parameter placeholders to dialect-specific format
|
|
88
|
+
*
|
|
89
|
+
* PostgreSQL uses $1, $2, $3 (no conversion needed)
|
|
90
|
+
* MySQL/SQLite use ? placeholders (convert $1 -> ?)
|
|
91
|
+
*
|
|
92
|
+
* @param sql - SQL with placeholders
|
|
93
|
+
* @returns SQL with converted placeholders
|
|
94
|
+
*/
|
|
95
|
+
convertPlaceholders(sql: string): string;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Active connection handle - passed to tool implementations
|
|
99
|
+
*
|
|
100
|
+
* Provides database operations during a single request lifecycle.
|
|
101
|
+
* Connection is automatically recycled after the request completes.
|
|
102
|
+
*/
|
|
103
|
+
export interface AdapterConnection {
|
|
104
|
+
/**
|
|
105
|
+
* Execute a parameterized query
|
|
106
|
+
*
|
|
107
|
+
* SECURITY: All user SQL MUST go through this method with parameters
|
|
108
|
+
*
|
|
109
|
+
* @param sql - SQL with placeholders ($1, $2 for PG; ? for MySQL/SQLite)
|
|
110
|
+
* @param params - Parameter values (type-safe, prevents injection)
|
|
111
|
+
*/
|
|
112
|
+
query(sql: string, params?: unknown[]): Promise<RawQueryResult>;
|
|
113
|
+
/**
|
|
114
|
+
* Execute a raw SQL statement (for SET, BEGIN, etc.)
|
|
115
|
+
*
|
|
116
|
+
* Only use for validated internal commands.
|
|
117
|
+
* Never pass user-provided values through this method.
|
|
118
|
+
*/
|
|
119
|
+
execute(sql: string): Promise<void>;
|
|
120
|
+
/**
|
|
121
|
+
* List tables in a schema (adapter-specific implementation)
|
|
122
|
+
*
|
|
123
|
+
* @param schema - Schema name (ignored for SQLite)
|
|
124
|
+
* @param maxTables - Maximum number of tables to return
|
|
125
|
+
*/
|
|
126
|
+
listTables(schema: string, maxTables: number): Promise<ListTablesInternalResult>;
|
|
127
|
+
/**
|
|
128
|
+
* Describe a table structure (adapter-specific implementation)
|
|
129
|
+
*
|
|
130
|
+
* @param table - Table name
|
|
131
|
+
* @param schema - Schema name (ignored for SQLite)
|
|
132
|
+
* @param limits - Limits for columns and indexes
|
|
133
|
+
*/
|
|
134
|
+
describeTable(table: string, schema: string, limits: {
|
|
135
|
+
maxColumns: number;
|
|
136
|
+
maxIndexes: number;
|
|
137
|
+
}): Promise<TableDescription>;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Internal result from listTables before tool formatting
|
|
141
|
+
*/
|
|
142
|
+
export interface ListTablesInternalResult {
|
|
143
|
+
tables: TableInfo[];
|
|
144
|
+
totalAvailable: number;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Configuration passed to adapter constructors
|
|
148
|
+
*/
|
|
149
|
+
export interface AdapterConfig {
|
|
150
|
+
/** Database configuration (url, readonly, etc.) */
|
|
151
|
+
database: DatabaseConfig;
|
|
152
|
+
/** Default settings (timeout, limits) */
|
|
153
|
+
defaults: DefaultsConfig;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,cAAc,EACf,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,sBAAsB;IACtB,MAAM,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChC,iDAAiD;IACjD,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC;IAClB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,YAAY,GAAG,OAAO,GAAG,QAAQ,CAAC;IAEjD;;;OAGG;IACH,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,iBAAiB,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAE3E;;;;;;OAMG;IACH,gBAAgB,IAAI,MAAM,CAAC;IAE3B;;OAEG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAMzB;;;;;;;;;OASG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,WAAW,CAAC;IAErC;;;;;;;;OAQG;IACH,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAEhD;;;;;;OAMG;IACH,oBAAoB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAEnE;;;;;;;;;OASG;IACH,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC;IAE3C;;;;;;;;OAQG;IACH,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;;;;;OAOG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEhE;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;;;;OAKG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAEjF;;;;;;OAMG;IACH,aAAa,CACX,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,MAAM,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GACjD,OAAO,CAAC,gBAAgB,CAAC,CAAC;CAC9B;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,mDAAmD;IACnD,QAAQ,EAAE,cAAc,CAAC;IACzB,yCAAyC;IACzC,QAAQ,EAAE,cAAc,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/adapters/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Config } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load configuration with resolution priority:
|
|
4
|
+
* 1. CLI argument: --config ./path/to/config.json
|
|
5
|
+
* 2. Environment variable: DB_MCP_CONFIG
|
|
6
|
+
* 3. Current directory: ./databases.json
|
|
7
|
+
* 4. Home directory: ~/.config/db-mcp/databases.json
|
|
8
|
+
* 5. ENV-only mode: DB_MCP_{NAME}_URL variables
|
|
9
|
+
*/
|
|
10
|
+
export declare function loadConfig(cliConfigPath?: string): Promise<Config>;
|
|
11
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAA6C,MAAM,aAAa,CAAC;AAqErF;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA8ExE"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readFile } from 'fs/promises';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { resolve, join } from 'path';
|
|
4
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
5
|
+
const DEFAULT_CONFIG = {
|
|
6
|
+
maxRows: 100,
|
|
7
|
+
maxCellLength: 500,
|
|
8
|
+
maxTotalSize: 65536, // 64KB
|
|
9
|
+
maxColumns: 50,
|
|
10
|
+
maxTables: 200,
|
|
11
|
+
maxIndexes: 20,
|
|
12
|
+
timeout: 30000,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Try to read and parse a JSON config file.
|
|
16
|
+
* Returns null if file doesn't exist.
|
|
17
|
+
*/
|
|
18
|
+
async function tryReadConfigFile(path) {
|
|
19
|
+
try {
|
|
20
|
+
const content = await readFile(path, 'utf-8');
|
|
21
|
+
return JSON.parse(content);
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
if (err.code === 'ENOENT') {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
throw new DbMcpError(ErrorCode.CONFIG_INVALID, `Failed to parse config file ${path}: ${err.message}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Resolve ${ENV_VAR} placeholders in a string.
|
|
32
|
+
*/
|
|
33
|
+
function resolveEnvPlaceholders(value) {
|
|
34
|
+
return value.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
|
|
35
|
+
const envValue = process.env[envVar];
|
|
36
|
+
if (envValue === undefined) {
|
|
37
|
+
throw new DbMcpError(ErrorCode.CONFIG_INVALID, `Environment variable ${envVar} is not defined`);
|
|
38
|
+
}
|
|
39
|
+
return envValue;
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Extract databases from DB_MCP_{NAME}_URL environment variables.
|
|
44
|
+
*/
|
|
45
|
+
function getDatabasesFromEnv() {
|
|
46
|
+
const databases = {};
|
|
47
|
+
const pattern = /^DB_MCP_([A-Z0-9_]+)_URL$/;
|
|
48
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
49
|
+
const match = key.match(pattern);
|
|
50
|
+
if (match && value) {
|
|
51
|
+
const name = match[1].toLowerCase();
|
|
52
|
+
databases[name] = {
|
|
53
|
+
url: value,
|
|
54
|
+
readonly: false,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return databases;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Load configuration with resolution priority:
|
|
62
|
+
* 1. CLI argument: --config ./path/to/config.json
|
|
63
|
+
* 2. Environment variable: DB_MCP_CONFIG
|
|
64
|
+
* 3. Current directory: ./databases.json
|
|
65
|
+
* 4. Home directory: ~/.config/db-mcp/databases.json
|
|
66
|
+
* 5. ENV-only mode: DB_MCP_{NAME}_URL variables
|
|
67
|
+
*/
|
|
68
|
+
export async function loadConfig(cliConfigPath) {
|
|
69
|
+
let rawConfig = null;
|
|
70
|
+
// 1. CLI argument
|
|
71
|
+
if (cliConfigPath) {
|
|
72
|
+
const resolvedPath = resolve(cliConfigPath);
|
|
73
|
+
rawConfig = await tryReadConfigFile(resolvedPath);
|
|
74
|
+
if (!rawConfig) {
|
|
75
|
+
throw new DbMcpError(ErrorCode.CONFIG_NOT_FOUND, `Config file not found: ${resolvedPath}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// 2. Environment variable
|
|
79
|
+
if (!rawConfig && process.env.DB_MCP_CONFIG) {
|
|
80
|
+
const envPath = resolve(process.env.DB_MCP_CONFIG);
|
|
81
|
+
rawConfig = await tryReadConfigFile(envPath);
|
|
82
|
+
if (!rawConfig) {
|
|
83
|
+
throw new DbMcpError(ErrorCode.CONFIG_NOT_FOUND, `Config file not found: ${envPath}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// 3. Current directory
|
|
87
|
+
if (!rawConfig) {
|
|
88
|
+
rawConfig = await tryReadConfigFile(resolve('./databases.json'));
|
|
89
|
+
}
|
|
90
|
+
// 4. Home directory
|
|
91
|
+
if (!rawConfig) {
|
|
92
|
+
const homePath = join(homedir(), '.config', 'db-mcp', 'databases.json');
|
|
93
|
+
rawConfig = await tryReadConfigFile(homePath);
|
|
94
|
+
}
|
|
95
|
+
// 5. ENV-only mode
|
|
96
|
+
const envDatabases = getDatabasesFromEnv();
|
|
97
|
+
// Build final config
|
|
98
|
+
const databases = {};
|
|
99
|
+
// Add databases from config file (with env placeholder resolution)
|
|
100
|
+
if (rawConfig?.databases) {
|
|
101
|
+
for (const [name, dbConfig] of Object.entries(rawConfig.databases)) {
|
|
102
|
+
databases[name] = {
|
|
103
|
+
url: resolveEnvPlaceholders(dbConfig.url),
|
|
104
|
+
readonly: dbConfig.readonly ?? false,
|
|
105
|
+
maxRows: dbConfig.maxRows,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
// Add databases from environment (ENV-only mode)
|
|
110
|
+
// These don't override config file databases
|
|
111
|
+
for (const [name, dbConfig] of Object.entries(envDatabases)) {
|
|
112
|
+
if (!(name in databases)) {
|
|
113
|
+
databases[name] = dbConfig;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
// Validate at least one database is configured
|
|
117
|
+
if (Object.keys(databases).length === 0) {
|
|
118
|
+
throw new DbMcpError(ErrorCode.CONFIG_NOT_FOUND, 'No databases configured. Provide a config file or set DB_MCP_{NAME}_URL environment variables.');
|
|
119
|
+
}
|
|
120
|
+
// Merge defaults
|
|
121
|
+
const defaults = {
|
|
122
|
+
...DEFAULT_CONFIG,
|
|
123
|
+
...rawConfig?.defaults,
|
|
124
|
+
};
|
|
125
|
+
return { databases, defaults };
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;GAIG"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Entry point for mcp-datalink server
|
|
4
|
+
*
|
|
5
|
+
* Parses CLI arguments and starts the MCP server.
|
|
6
|
+
*/
|
|
7
|
+
import { parseArgs } from 'node:util';
|
|
8
|
+
import { loadConfig } from './config/loader.js';
|
|
9
|
+
import { runServer } from './server.js';
|
|
10
|
+
async function main() {
|
|
11
|
+
const { values } = parseArgs({
|
|
12
|
+
options: {
|
|
13
|
+
config: { type: 'string', short: 'c' },
|
|
14
|
+
help: { type: 'boolean', short: 'h' },
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
if (values.help) {
|
|
18
|
+
console.log(`
|
|
19
|
+
mcp-datalink - MCP server for secure database access
|
|
20
|
+
|
|
21
|
+
Usage: mcp-datalink [options]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
-c, --config <path> Path to config file (default: databases.json)
|
|
25
|
+
-h, --help Show this help message
|
|
26
|
+
|
|
27
|
+
Supported databases: PostgreSQL (MySQL, SQLite coming soon)
|
|
28
|
+
`);
|
|
29
|
+
process.exit(0);
|
|
30
|
+
}
|
|
31
|
+
const config = await loadConfig(values.config);
|
|
32
|
+
await runServer(config);
|
|
33
|
+
}
|
|
34
|
+
main().catch((error) => {
|
|
35
|
+
console.error('Fatal error:', error.message);
|
|
36
|
+
process.exit(1);
|
|
37
|
+
});
|
|
38
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA;;;;GAIG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,KAAK,UAAU,IAAI;IACjB,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC3B,OAAO,EAAE;YACP,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE;YACtC,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;SACtC;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;CAUf,CAAC,CAAC;QACC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server setup for db-mcp
|
|
3
|
+
*
|
|
4
|
+
* Creates and configures the MCP server with all database tools.
|
|
5
|
+
*/
|
|
6
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
7
|
+
import type { Config } from './types.js';
|
|
8
|
+
/**
|
|
9
|
+
* Creates an MCP server configured with all db-mcp tools.
|
|
10
|
+
*
|
|
11
|
+
* @param config - Application configuration with database connections and defaults
|
|
12
|
+
* @returns Configured MCP Server instance
|
|
13
|
+
*/
|
|
14
|
+
export declare function createServer(config: Config): Server;
|
|
15
|
+
/**
|
|
16
|
+
* Starts the MCP server with stdio transport.
|
|
17
|
+
*
|
|
18
|
+
* @param config - Application configuration
|
|
19
|
+
*/
|
|
20
|
+
export declare function runServer(config: Config): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAMnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AASzC;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAoLnD;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI7D"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server setup for db-mcp
|
|
3
|
+
*
|
|
4
|
+
* Creates and configures the MCP server with all database tools.
|
|
5
|
+
*/
|
|
6
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
7
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
8
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
9
|
+
import { listDatabases } from './tools/list-databases.js';
|
|
10
|
+
import { listTables } from './tools/list-tables.js';
|
|
11
|
+
import { describeTable } from './tools/describe-table.js';
|
|
12
|
+
import { query, formatQueryResultAsMarkdown } from './tools/query.js';
|
|
13
|
+
import { execute } from './tools/execute.js';
|
|
14
|
+
import { explain } from './tools/explain.js';
|
|
15
|
+
import { DbMcpError } from './utils/errors.js';
|
|
16
|
+
/**
|
|
17
|
+
* Creates an MCP server configured with all db-mcp tools.
|
|
18
|
+
*
|
|
19
|
+
* @param config - Application configuration with database connections and defaults
|
|
20
|
+
* @returns Configured MCP Server instance
|
|
21
|
+
*/
|
|
22
|
+
export function createServer(config) {
|
|
23
|
+
const server = new Server({
|
|
24
|
+
name: 'mcp-datalink',
|
|
25
|
+
version: '1.0.0',
|
|
26
|
+
}, {
|
|
27
|
+
capabilities: {
|
|
28
|
+
tools: {},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
// Register list tools handler
|
|
32
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
33
|
+
tools: [
|
|
34
|
+
{
|
|
35
|
+
name: 'list_databases',
|
|
36
|
+
description: 'List all configured database connections',
|
|
37
|
+
inputSchema: {
|
|
38
|
+
type: 'object',
|
|
39
|
+
properties: {},
|
|
40
|
+
required: [],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'list_tables',
|
|
45
|
+
description: 'List tables in a database schema',
|
|
46
|
+
inputSchema: {
|
|
47
|
+
type: 'object',
|
|
48
|
+
properties: {
|
|
49
|
+
database: { type: 'string', description: 'Database connection name' },
|
|
50
|
+
schema: { type: 'string', description: 'Schema name (default: public)' },
|
|
51
|
+
},
|
|
52
|
+
required: ['database'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: 'describe_table',
|
|
57
|
+
description: 'Get table structure including columns, indexes, and foreign keys',
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: 'object',
|
|
60
|
+
properties: {
|
|
61
|
+
database: { type: 'string', description: 'Database connection name' },
|
|
62
|
+
table: { type: 'string', description: 'Table name' },
|
|
63
|
+
schema: { type: 'string', description: 'Schema name (default: public)' },
|
|
64
|
+
},
|
|
65
|
+
required: ['database', 'table'],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: 'query',
|
|
70
|
+
description: 'Execute a read-only SELECT query. Use $1, $2, ... placeholders for parameters.',
|
|
71
|
+
inputSchema: {
|
|
72
|
+
type: 'object',
|
|
73
|
+
properties: {
|
|
74
|
+
database: { type: 'string', description: 'Database connection name' },
|
|
75
|
+
sql: { type: 'string', description: 'SQL SELECT query. Use $1, $2, ... for parameter placeholders' },
|
|
76
|
+
params: { type: 'array', description: 'Parameter values in order ($1, $2, ...). Always use params instead of interpolating values into SQL.' },
|
|
77
|
+
},
|
|
78
|
+
required: ['database', 'sql'],
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: 'execute',
|
|
83
|
+
description: 'Execute INSERT/UPDATE/DELETE query. Use $1, $2, ... placeholders for parameters.',
|
|
84
|
+
inputSchema: {
|
|
85
|
+
type: 'object',
|
|
86
|
+
properties: {
|
|
87
|
+
database: { type: 'string', description: 'Database connection name' },
|
|
88
|
+
sql: { type: 'string', description: 'SQL INSERT/UPDATE/DELETE query. Use $1, $2, ... for parameter placeholders' },
|
|
89
|
+
params: { type: 'array', description: 'Parameter values in order ($1, $2, ...). Always use params instead of interpolating values into SQL.' },
|
|
90
|
+
},
|
|
91
|
+
required: ['database', 'sql'],
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'explain',
|
|
96
|
+
description: 'Show query execution plan',
|
|
97
|
+
inputSchema: {
|
|
98
|
+
type: 'object',
|
|
99
|
+
properties: {
|
|
100
|
+
database: { type: 'string', description: 'Database connection name' },
|
|
101
|
+
sql: { type: 'string', description: 'SQL query to explain' },
|
|
102
|
+
analyze: { type: 'boolean', description: 'Run EXPLAIN ANALYZE (default: false)' },
|
|
103
|
+
},
|
|
104
|
+
required: ['database', 'sql'],
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
],
|
|
108
|
+
}));
|
|
109
|
+
// Register call tool handler
|
|
110
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
111
|
+
const { name, arguments: args } = request.params;
|
|
112
|
+
try {
|
|
113
|
+
switch (name) {
|
|
114
|
+
case 'list_databases':
|
|
115
|
+
return {
|
|
116
|
+
content: [{ type: 'text', text: JSON.stringify(listDatabases(config), null, 2) }],
|
|
117
|
+
};
|
|
118
|
+
case 'list_tables':
|
|
119
|
+
return {
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: 'text',
|
|
123
|
+
text: JSON.stringify(await listTables(args, config), null, 2),
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
case 'describe_table':
|
|
128
|
+
return {
|
|
129
|
+
content: [
|
|
130
|
+
{
|
|
131
|
+
type: 'text',
|
|
132
|
+
text: JSON.stringify(await describeTable(args, config), null, 2),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
};
|
|
136
|
+
case 'query': {
|
|
137
|
+
const result = await query(args, config);
|
|
138
|
+
return {
|
|
139
|
+
content: [
|
|
140
|
+
{
|
|
141
|
+
type: 'text',
|
|
142
|
+
text: formatQueryResultAsMarkdown(result),
|
|
143
|
+
},
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
case 'execute':
|
|
148
|
+
return {
|
|
149
|
+
content: [
|
|
150
|
+
{
|
|
151
|
+
type: 'text',
|
|
152
|
+
text: JSON.stringify(await execute(args, config), null, 2),
|
|
153
|
+
},
|
|
154
|
+
],
|
|
155
|
+
};
|
|
156
|
+
case 'explain':
|
|
157
|
+
return {
|
|
158
|
+
content: [
|
|
159
|
+
{
|
|
160
|
+
type: 'text',
|
|
161
|
+
text: JSON.stringify(await explain(args, config), null, 2),
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
default:
|
|
166
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
if (error instanceof DbMcpError) {
|
|
171
|
+
return {
|
|
172
|
+
content: [{ type: 'text', text: JSON.stringify(error.toJSON(), null, 2) }],
|
|
173
|
+
isError: true,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
throw error;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
return server;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Starts the MCP server with stdio transport.
|
|
183
|
+
*
|
|
184
|
+
* @param config - Application configuration
|
|
185
|
+
*/
|
|
186
|
+
export async function runServer(config) {
|
|
187
|
+
const server = createServer(config);
|
|
188
|
+
const transport = new StdioServerTransport();
|
|
189
|
+
await server.connect(transport);
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* describe_table tool - Returns table structure including columns, indexes, and foreign keys
|
|
3
|
+
*/
|
|
4
|
+
import type { Config, TableDescription } from '../types.js';
|
|
5
|
+
export interface DescribeTableParams {
|
|
6
|
+
database: string;
|
|
7
|
+
table: string;
|
|
8
|
+
schema?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function describeTable(params: DescribeTableParams, config: Config): Promise<TableDescription>;
|
|
11
|
+
//# sourceMappingURL=describe-table.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-table.d.ts","sourceRoot":"","sources":["../../src/tools/describe-table.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAI5D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,mBAAmB,EAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAwB3B"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* describe_table tool - Returns table structure including columns, indexes, and foreign keys
|
|
3
|
+
*/
|
|
4
|
+
import { createAdapter } from '../adapters/index.js';
|
|
5
|
+
import { DbMcpError, ErrorCode } from '../utils/errors.js';
|
|
6
|
+
export async function describeTable(params, config) {
|
|
7
|
+
const { table, database } = params;
|
|
8
|
+
const { maxColumns, maxIndexes } = config.defaults;
|
|
9
|
+
// Get database config
|
|
10
|
+
const dbConfig = config.databases[database];
|
|
11
|
+
if (!dbConfig) {
|
|
12
|
+
throw new DbMcpError(ErrorCode.DATABASE_NOT_FOUND, `Database "${database}" not found in configuration`, { database, available: Object.keys(config.databases) });
|
|
13
|
+
}
|
|
14
|
+
// Create adapter for this database
|
|
15
|
+
const adapter = createAdapter(dbConfig, config.defaults);
|
|
16
|
+
// Use provided schema or adapter's default schema
|
|
17
|
+
// PostgreSQL: "public", MySQL: database name, SQLite: "main"
|
|
18
|
+
const schema = params.schema ?? adapter.getDefaultSchema();
|
|
19
|
+
return adapter.withConnection(async (conn) => {
|
|
20
|
+
return conn.describeTable(table, schema, { maxColumns, maxIndexes });
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=describe-table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"describe-table.js","sourceRoot":"","sources":["../../src/tools/describe-table.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAQ3D,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA2B,EAC3B,MAAc;IAEd,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IACnC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC;IAEnD,sBAAsB;IACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAClB,SAAS,CAAC,kBAAkB,EAC5B,aAAa,QAAQ,8BAA8B,EACnD,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CACvD,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,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC"}
|