db-mcp 1.1.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/.gitleaks.toml +9 -0
  2. package/.trivyignore +8 -0
  3. package/README.md +193 -120
  4. package/dist/{chunk-TVIZ3XJH.js → chunk-5Y42NPBP.js} +4168 -2411
  5. package/dist/{chunk-AOUL5SHS.js → chunk-645ZEFLA.js} +70 -20
  6. package/dist/chunk-OKOVZ5QE.js +28 -0
  7. package/dist/chunk-SFJQCNG7.js +131 -0
  8. package/dist/{chunk-FW7UCRLN.js → chunk-VIDSICEL.js} +3 -0
  9. package/dist/chunk-WBER5YY4.js +2053 -0
  10. package/dist/{chunk-4IA3DB5C.js → chunk-X3MUUOWM.js} +19 -2
  11. package/dist/{chunk-Z2GFQU3G.js → chunk-Z7C2TM4L.js} +114 -21
  12. package/dist/cli.js +79 -5
  13. package/dist/{http-VSB7DBJR.js → http-6KF4ULDI.js} +199 -77
  14. package/dist/index.d.ts +231 -8
  15. package/dist/index.js +6 -5
  16. package/dist/{sqlite-26V3Y4MK.js → sqlite-U5KSYQXK.js} +62 -138
  17. package/dist/{sqlite-native-5O7FZJGB.js → sqlite-native-JXMCFQBA.js} +575 -113
  18. package/dist/worker-script.js +34 -10
  19. package/logs/.gitkeep +1 -0
  20. package/mcp-config-example.json +83 -0
  21. package/package.json +9 -8
  22. package/playwright.config.ts +1 -1
  23. package/scripts/update-badges.ts +99 -0
  24. package/server.json +7 -5
  25. package/test-server/README.md +20 -23
  26. package/test-server/code-map.md +45 -33
  27. package/test-server/reset-database.ps1 +59 -17
  28. package/test-server/scripts/README.md +27 -0
  29. package/test-server/{test-help-resources.mjs → scripts/test-help-resources.mjs} +12 -5
  30. package/test-server/scripts/test-prompts.mjs +251 -0
  31. package/test-server/{test-tool-annotations.mjs → scripts/test-tool-annotations.mjs} +9 -4
  32. package/test-server/test-advanced/README.md +70 -0
  33. package/test-server/test-advanced/test-codemode-advanced-admin.md +174 -0
  34. package/test-server/test-advanced/test-codemode-advanced-core.md +193 -0
  35. package/test-server/test-advanced/test-codemode-advanced-geo.md +157 -0
  36. package/test-server/test-advanced/test-codemode-advanced-introspection.md +171 -0
  37. package/test-server/test-advanced/test-codemode-advanced-json.md +169 -0
  38. package/test-server/test-advanced/test-codemode-advanced-migration.md +160 -0
  39. package/test-server/test-advanced/test-codemode-advanced-stats.md +185 -0
  40. package/test-server/test-advanced/test-codemode-advanced-text.md +183 -0
  41. package/test-server/test-advanced/test-codemode-advanced-transactions.md +136 -0
  42. package/test-server/test-advanced/test-codemode-advanced-vector.md +141 -0
  43. package/test-server/test-codemode/README.md +121 -0
  44. package/test-server/test-codemode/test-codemode-admin.md +223 -0
  45. package/test-server/test-codemode/test-codemode-core.md +286 -0
  46. package/test-server/test-codemode/test-codemode-geo.md +177 -0
  47. package/test-server/test-codemode/test-codemode-introspection.md +190 -0
  48. package/test-server/test-codemode/test-codemode-json.md +237 -0
  49. package/test-server/test-codemode/test-codemode-migration.md +278 -0
  50. package/test-server/test-codemode/test-codemode-sandbox.md +413 -0
  51. package/test-server/test-codemode/test-codemode-stats.md +232 -0
  52. package/test-server/test-codemode/test-codemode-text.md +237 -0
  53. package/test-server/test-codemode/test-codemode-transactions.md +236 -0
  54. package/test-server/test-codemode/test-codemode-vector.md +244 -0
  55. package/test-server/test-codemode/test-codemode-wasm-degradation.md +394 -0
  56. package/test-server/test-database.sql +37 -1
  57. package/test-server/test-resources.md +43 -16
  58. package/test-server/test-tool-groups/README.md +100 -0
  59. package/test-server/test-tool-groups/test-admin-core.md +165 -0
  60. package/test-server/test-tool-groups/test-admin-extensions.md +133 -0
  61. package/test-server/{test-tools.md → test-tool-groups/test-core-data.md} +103 -17
  62. package/test-server/test-tool-groups/test-core-schema.md +240 -0
  63. package/test-server/test-tool-groups/test-geo-haversine.md +130 -0
  64. package/test-server/test-tool-groups/test-geo-spatialite.md +110 -0
  65. package/test-server/test-tool-groups/test-introspection-diagnostics.md +123 -0
  66. package/test-server/test-tool-groups/test-introspection-schema.md +133 -0
  67. package/test-server/test-tool-groups/test-json-read.md +219 -0
  68. package/test-server/test-tool-groups/test-json-write.md +157 -0
  69. package/test-server/test-tool-groups/test-migration.md +193 -0
  70. package/test-server/test-tool-groups/test-stats-advanced.md +118 -0
  71. package/test-server/test-tool-groups/test-stats-basic.md +156 -0
  72. package/test-server/test-tool-groups/test-text-advanced.md +169 -0
  73. package/test-server/test-tool-groups/test-text-basic.md +177 -0
  74. package/test-server/test-tool-groups/test-transactions.md +179 -0
  75. package/test-server/test-tool-groups/test-vector-read.md +130 -0
  76. package/test-server/test-tool-groups/test-vector-write.md +115 -0
  77. package/test-server/tool-reference.md +79 -58
  78. package/tsconfig.build.json +6 -0
  79. package/dist/chunk-RHVEZ42P.js +0 -873
  80. package/test-server/test-agent-experience.md +0 -243
  81. package/test-server/test-group-tools.md +0 -861
  82. package/test-server/test-tools-advanced-1.md +0 -517
  83. package/test-server/test-tools-advanced-2.md +0 -487
  84. package/test-server/test-tools-codemode.md +0 -629
@@ -1,4 +1,4 @@
1
- import { DbMcpError, findSuggestion } from './chunk-AOUL5SHS.js';
1
+ import { DbMcpError, findSuggestion } from './chunk-645ZEFLA.js';
2
2
 
3
3
  // src/utils/errors/classes.ts
4
4
  var ValidationError = class extends DbMcpError {
@@ -67,6 +67,23 @@ var AuthorizationError = class extends DbMcpError {
67
67
  });
68
68
  }
69
69
  };
70
+ var ExtensionNotAvailableError = class extends DbMcpError {
71
+ constructor(extensionName, options) {
72
+ const isWasm = options?.wasmLimitation ?? options?.details?.["wasmLimitation"] ?? false;
73
+ const baseMessage = `Extension '${extensionName}' is not installed or available`;
74
+ const message = isWasm === true ? `${baseMessage} in WASM mode` : baseMessage;
75
+ super(message, "EXTENSION_MISSING", "config" /* CONFIGURATION */, {
76
+ suggestion: options?.suggestion ?? `Install or enable the '${extensionName}' extension. Check environment variable or CLI flag configuration.`,
77
+ details: {
78
+ extension: extensionName,
79
+ ...options?.details,
80
+ ...isWasm === true ? { wasmLimitation: true } : {}
81
+ },
82
+ recoverable: false,
83
+ cause: options?.cause
84
+ });
85
+ }
86
+ };
70
87
 
71
88
  // src/utils/errors/format.ts
72
89
  var CATEGORY_DEFAULT_CODES = {
@@ -132,4 +149,4 @@ function formatHandlerError(error, _context) {
132
149
  };
133
150
  }
134
151
 
135
- export { AuthenticationError, AuthorizationError, ConfigurationError, ConnectionError, QueryError, ResourceNotFoundError, ValidationError, formatHandlerError };
152
+ export { AuthenticationError, AuthorizationError, ConfigurationError, ConnectionError, ExtensionNotAvailableError, QueryError, ResourceNotFoundError, ValidationError, formatHandlerError };
@@ -1,5 +1,5 @@
1
- import { ConnectionError, formatHandlerError, ValidationError } from './chunk-4IA3DB5C.js';
2
- import { isToolEnabled } from './chunk-AOUL5SHS.js';
1
+ import { ConnectionError, formatHandlerError, ValidationError } from './chunk-X3MUUOWM.js';
2
+ import { isToolEnabled } from './chunk-645ZEFLA.js';
3
3
  import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { z } from 'zod';
5
5
 
@@ -65,8 +65,13 @@ function registerToolImpl(adapter, server, tool) {
65
65
  };
66
66
  if (tool.inputSchema !== void 0) {
67
67
  const schema = tool.inputSchema;
68
- if (typeof schema === "object" && schema !== null && "partial" in schema && typeof schema.partial === "function") {
69
- toolOptions["inputSchema"] = schema.partial().passthrough();
68
+ if (typeof schema === "object" && schema !== null && "partial" in schema && typeof schema["partial"] === "function") {
69
+ try {
70
+ toolOptions["inputSchema"] = schema.partial().passthrough();
71
+ } catch (e) {
72
+ console.error(`Error applying .partial() to ${tool.name}:`, e);
73
+ toolOptions["inputSchema"] = schema;
74
+ }
70
75
  } else {
71
76
  toolOptions["inputSchema"] = schema;
72
77
  }
@@ -84,8 +89,10 @@ function registerToolImpl(adapter, server, tool) {
84
89
  server.registerTool(
85
90
  tool.name,
86
91
  toolOptions,
87
- async (args, extra) => {
92
+ async (argsOrExtra, possibleExtra) => {
88
93
  try {
94
+ const extra = possibleExtra !== void 0 ? possibleExtra : argsOrExtra;
95
+ const args = possibleExtra !== void 0 ? argsOrExtra : {};
89
96
  const extraMeta = extra;
90
97
  const progressToken = extraMeta?._meta?.progressToken;
91
98
  const context = adapter.createContext(
@@ -93,45 +100,108 @@ function registerToolImpl(adapter, server, tool) {
93
100
  server.server,
94
101
  progressToken
95
102
  );
96
- const result = await tool.handler(args, context);
97
- if (hasOutputSchema) {
103
+ const execFn = async () => {
104
+ const result = await tool.handler(args, context);
105
+ if (hasOutputSchema) {
106
+ const enriched = JSON.stringify({
107
+ ...result,
108
+ _meta: { tokenEstimate: 0 }
109
+ });
110
+ const tokenEstimate = Math.ceil(
111
+ Buffer.byteLength(enriched, "utf8") / 4
112
+ );
113
+ const finalText = enriched.replace(
114
+ '"tokenEstimate":0',
115
+ `"tokenEstimate":${String(tokenEstimate)}`
116
+ );
117
+ return {
118
+ content: [
119
+ {
120
+ type: "text",
121
+ text: finalText
122
+ }
123
+ ],
124
+ structuredContent: result
125
+ };
126
+ }
127
+ if (typeof result === "object" && result !== null) {
128
+ const withMeta = JSON.stringify(
129
+ { ...result, _meta: { tokenEstimate: 0 } },
130
+ null,
131
+ 2
132
+ );
133
+ const tokenEstimate = Math.ceil(
134
+ Buffer.byteLength(withMeta, "utf8") / 4
135
+ );
136
+ const finalText = withMeta.replace(
137
+ '"tokenEstimate": 0',
138
+ `"tokenEstimate": ${String(tokenEstimate)}`
139
+ );
140
+ return {
141
+ content: [{ type: "text", text: finalText }]
142
+ };
143
+ }
98
144
  return {
99
145
  content: [
100
146
  {
101
147
  type: "text",
102
- text: JSON.stringify(result)
148
+ text: typeof result === "string" ? result : JSON.stringify(result)
103
149
  }
104
- ],
105
- structuredContent: result
150
+ ]
106
151
  };
107
- }
108
- return {
109
- content: [
110
- {
111
- type: "text",
112
- text: typeof result === "string" ? result : JSON.stringify(result)
113
- }
114
- ]
115
152
  };
153
+ const auditInterceptor = adapter.getAuditInterceptor?.();
154
+ if (auditInterceptor) {
155
+ return await auditInterceptor.around(
156
+ tool.name,
157
+ args,
158
+ context.requestId,
159
+ execFn
160
+ );
161
+ }
162
+ return await execFn();
116
163
  } catch (error) {
117
164
  const structured = formatHandlerError(error);
118
165
  if (hasOutputSchema) {
166
+ const enriched = JSON.stringify({
167
+ ...structured,
168
+ _meta: { tokenEstimate: 0 }
169
+ });
170
+ const tokenEstimate2 = Math.ceil(
171
+ Buffer.byteLength(enriched, "utf8") / 4
172
+ );
173
+ const finalText2 = enriched.replace(
174
+ '"tokenEstimate":0',
175
+ `"tokenEstimate":${String(tokenEstimate2)}`
176
+ );
119
177
  return {
120
178
  content: [
121
179
  {
122
180
  type: "text",
123
- text: JSON.stringify(structured, null, 2)
181
+ text: finalText2
124
182
  }
125
183
  ],
126
184
  structuredContent: structured,
127
185
  isError: true
128
186
  };
129
187
  }
188
+ const withMeta = JSON.stringify(
189
+ { ...structured, _meta: { tokenEstimate: 0 } },
190
+ null,
191
+ 2
192
+ );
193
+ const tokenEstimate = Math.ceil(
194
+ Buffer.byteLength(withMeta, "utf8") / 4
195
+ );
196
+ const finalText = withMeta.replace(
197
+ '"tokenEstimate": 0',
198
+ `"tokenEstimate": ${String(tokenEstimate)}`
199
+ );
130
200
  return {
131
201
  content: [
132
202
  {
133
203
  type: "text",
134
- text: JSON.stringify(structured, null, 2)
204
+ text: finalText
135
205
  }
136
206
  ],
137
207
  isError: true
@@ -209,7 +279,7 @@ function registerPromptImpl(adapter, server, prompt) {
209
279
  const context = adapter.createContext();
210
280
  const safeArgs = args ?? {};
211
281
  const result = await prompt.handler(safeArgs, context);
212
- const messages = Array.isArray(result) ? result : [
282
+ const messages = Array.isArray(result) ? result : result !== null && result !== void 0 && typeof result === "object" && "messages" in result && Array.isArray(result.messages) ? result.messages : [
213
283
  {
214
284
  role: "assistant",
215
285
  content: {
@@ -247,6 +317,29 @@ var DatabaseAdapter = class {
247
317
  isConnected() {
248
318
  return this.connected;
249
319
  }
320
+ // ===========================================================================
321
+ // Audit Subsystem
322
+ // ===========================================================================
323
+ auditInterceptor = null;
324
+ backupManager = null;
325
+ /**
326
+ * Inject the audit interceptor.
327
+ */
328
+ setAuditInterceptor(interceptor) {
329
+ this.auditInterceptor = interceptor;
330
+ }
331
+ /**
332
+ * Inject the backup manager for tools to use natively.
333
+ */
334
+ setBackupManager(manager) {
335
+ this.backupManager = manager;
336
+ }
337
+ /**
338
+ * Get the audit interceptor (used by registration layer and Code Mode).
339
+ */
340
+ getAuditInterceptor() {
341
+ return this.auditInterceptor;
342
+ }
250
343
  /**
251
344
  * Register tools with the MCP server
252
345
  * @param server - MCP server instance
package/dist/cli.js CHANGED
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONFIG, createServer } from './chunk-RHVEZ42P.js';
3
- import { VERSION } from './chunk-FW7UCRLN.js';
4
- import './chunk-AOUL5SHS.js';
2
+ import { DEFAULT_CONFIG, createServer } from './chunk-WBER5YY4.js';
3
+ import './chunk-SFJQCNG7.js';
4
+ import { VERSION } from './chunk-VIDSICEL.js';
5
+ import './chunk-645ZEFLA.js';
6
+
7
+ // src/audit/types.ts
8
+ var DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES = 10 * 1024 * 1024;
9
+ var DEFAULT_AUDIT_BACKUP_MAX_DATA_SIZE_BYTES = 50 * 1024 * 1024;
10
+ var DEFAULT_AUDIT_BACKUP_MAX_AGE_DAYS = 30;
11
+ var DEFAULT_AUDIT_BACKUP_MAX_COUNT = 1e3;
5
12
 
6
13
  // src/cli.ts
7
14
  function parseArgs() {
@@ -10,6 +17,11 @@ function parseArgs() {
10
17
  const databases = [];
11
18
  let enableCsv = false;
12
19
  let enableSpatialite = false;
20
+ let auditLogPath;
21
+ let auditRedact = false;
22
+ let auditReads = false;
23
+ let auditBackup = false;
24
+ let auditBackupData = false;
13
25
  for (let i = 0; i < args.length; i++) {
14
26
  const arg = args[i];
15
27
  if (arg === "--transport" || arg === "-t") {
@@ -115,6 +127,19 @@ function parseArgs() {
115
127
  if (lastDb?.options && "backend" in lastDb.options) {
116
128
  lastDb.options["spatialite"] = true;
117
129
  }
130
+ } else if (arg === "--audit-log") {
131
+ const logPath = args[++i];
132
+ if (logPath) {
133
+ auditLogPath = logPath;
134
+ }
135
+ } else if (arg === "--audit-redact") {
136
+ auditRedact = true;
137
+ } else if (arg === "--audit-reads") {
138
+ auditReads = true;
139
+ } else if (arg === "--audit-backup") {
140
+ auditBackup = true;
141
+ } else if (arg === "--audit-backup-data") {
142
+ auditBackupData = true;
118
143
  } else if (arg === "--help" || arg === "-h") {
119
144
  printHelp();
120
145
  process.exit(0);
@@ -123,6 +148,24 @@ function parseArgs() {
123
148
  if (databases.length > 0) {
124
149
  config.databases = databases;
125
150
  }
151
+ if (auditLogPath) {
152
+ config.audit = {
153
+ enabled: true,
154
+ logPath: auditLogPath,
155
+ redact: auditRedact,
156
+ auditReads,
157
+ maxSizeBytes: DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES,
158
+ ...auditBackup && {
159
+ backup: {
160
+ enabled: true,
161
+ includeData: auditBackupData,
162
+ maxAgeDays: DEFAULT_AUDIT_BACKUP_MAX_AGE_DAYS,
163
+ maxCount: DEFAULT_AUDIT_BACKUP_MAX_COUNT,
164
+ maxDataSizeBytes: DEFAULT_AUDIT_BACKUP_MAX_DATA_SIZE_BYTES
165
+ }
166
+ }
167
+ };
168
+ }
126
169
  return config;
127
170
  }
128
171
  function printHelp() {
@@ -156,6 +199,13 @@ Extension Options (Native only):
156
199
  --csv Load CSV extension for CSV virtual tables
157
200
  --spatialite Load SpatiaLite extension for GIS capabilities
158
201
 
202
+ Audit Options:
203
+ --audit-log <path> Enable audit logging (JSONL file path, or "stderr")
204
+ --audit-redact Redact tool arguments from audit entries
205
+ --audit-reads Also log read-scoped tool invocations
206
+ --audit-backup Enable pre-mutation DDL snapshots
207
+ --audit-backup-data Include sample data rows in snapshots
208
+
159
209
  Server Options:
160
210
  --name <name> Server name (default: db-mcp)
161
211
  --version <version> Server version (default: ${VERSION})
@@ -178,6 +228,11 @@ Environment Variables:
178
228
  SQLITE_DATABASE SQLite database path
179
229
  CSV_EXTENSION_PATH Custom path to CSV extension binary
180
230
  SPATIALITE_PATH Custom path to SpatiaLite extension binary
231
+ AUDIT_LOG Audit log file path (or "stderr")
232
+ AUDIT_REDACT Redact arguments (true/false)
233
+ AUDIT_READS Log reads (true/false)
234
+ AUDIT_BACKUP Enable backups (true/false)
235
+ AUDIT_BACKUP_DATA Include data (true/false)
181
236
 
182
237
  Examples:
183
238
  db-mcp --sqlite-native ./data.db
@@ -219,6 +274,25 @@ function loadEnvConfig() {
219
274
  if (toolFilter) {
220
275
  config.toolFilter = toolFilter;
221
276
  }
277
+ const auditLog = process.env["AUDIT_LOG"];
278
+ if (auditLog) {
279
+ config.audit = {
280
+ enabled: true,
281
+ logPath: auditLog,
282
+ redact: process.env["AUDIT_REDACT"] === "true",
283
+ auditReads: process.env["AUDIT_READS"] === "true",
284
+ maxSizeBytes: DEFAULT_AUDIT_LOG_MAX_SIZE_BYTES,
285
+ ...process.env["AUDIT_BACKUP"] === "true" && {
286
+ backup: {
287
+ enabled: true,
288
+ includeData: process.env["AUDIT_BACKUP_DATA"] === "true",
289
+ maxAgeDays: DEFAULT_AUDIT_BACKUP_MAX_AGE_DAYS,
290
+ maxCount: DEFAULT_AUDIT_BACKUP_MAX_COUNT,
291
+ maxDataSizeBytes: DEFAULT_AUDIT_BACKUP_MAX_DATA_SIZE_BYTES
292
+ }
293
+ }
294
+ };
295
+ }
222
296
  const sqliteUri = process.env["SQLITE_DATABASE"] ?? process.env["SQLITE_PATH"];
223
297
  if (sqliteUri) {
224
298
  databases.push({ type: "sqlite", connectionString: sqliteUri });
@@ -256,11 +330,11 @@ async function main() {
256
330
  if (dbConfig.type === "sqlite") {
257
331
  const options = dbConfig.options;
258
332
  if (options?.backend === "better-sqlite3") {
259
- const { NativeSqliteAdapter } = await import('./sqlite-native-5O7FZJGB.js');
333
+ const { NativeSqliteAdapter } = await import('./sqlite-native-JXMCFQBA.js');
260
334
  const adapter = new NativeSqliteAdapter();
261
335
  await server.registerAdapter(adapter, dbConfig);
262
336
  } else {
263
- const { SqliteAdapter } = await import('./sqlite-26V3Y4MK.js');
337
+ const { SqliteAdapter } = await import('./sqlite-U5KSYQXK.js');
264
338
  const adapter = new SqliteAdapter();
265
339
  await server.registerAdapter(adapter, dbConfig);
266
340
  }