db-mcp 4.0.0 → 5.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.
Files changed (138) hide show
  1. package/README.md +30 -25
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/adapters/database-adapter.d.ts +9 -0
  4. package/dist/adapters/database-adapter.d.ts.map +1 -1
  5. package/dist/adapters/sqlite/query-executor.d.ts.map +1 -1
  6. package/dist/adapters/sqlite/read-write-lock.d.ts +49 -0
  7. package/dist/adapters/sqlite/read-write-lock.d.ts.map +1 -0
  8. package/dist/adapters/sqlite/schemas/admin.d.ts +5 -5
  9. package/dist/adapters/sqlite/schemas/admin.d.ts.map +1 -1
  10. package/dist/adapters/sqlite/schemas/core.d.ts +94 -0
  11. package/dist/adapters/sqlite/schemas/core.d.ts.map +1 -1
  12. package/dist/adapters/sqlite/schemas/introspection.d.ts +8 -7
  13. package/dist/adapters/sqlite/schemas/introspection.d.ts.map +1 -1
  14. package/dist/adapters/sqlite/schemas/migration.d.ts +2 -2
  15. package/dist/adapters/sqlite/schemas/migration.d.ts.map +1 -1
  16. package/dist/adapters/sqlite/sqlite-adapter.d.ts +6 -0
  17. package/dist/adapters/sqlite/sqlite-adapter.d.ts.map +1 -1
  18. package/dist/adapters/sqlite/tools/admin/backup/create.d.ts.map +1 -1
  19. package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts.map +1 -1
  20. package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts.map +1 -1
  21. package/dist/adapters/sqlite/tools/admin/pragma.d.ts.map +1 -1
  22. package/dist/adapters/sqlite/tools/admin/verify.d.ts.map +1 -1
  23. package/dist/adapters/sqlite/tools/codemode.d.ts.map +1 -1
  24. package/dist/adapters/sqlite/tools/core/convenience.d.ts.map +1 -1
  25. package/dist/adapters/sqlite/tools/core/index.d.ts.map +1 -1
  26. package/dist/adapters/sqlite/tools/core/queries.d.ts.map +1 -1
  27. package/dist/adapters/sqlite/tools/core/versioning.d.ts +19 -0
  28. package/dist/adapters/sqlite/tools/core/versioning.d.ts.map +1 -0
  29. package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts.map +1 -1
  30. package/dist/adapters/sqlite/tools/json-operations/crud.d.ts.map +1 -1
  31. package/dist/adapters/sqlite/tools/migration/helpers.d.ts.map +1 -1
  32. package/dist/adapters/sqlite/tools/vector/metadata.d.ts.map +1 -1
  33. package/dist/adapters/sqlite/tools/vector/search.d.ts.map +1 -1
  34. package/dist/adapters/sqlite/tools/vector/storage.d.ts.map +1 -1
  35. package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts.map +1 -1
  36. package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts.map +1 -1
  37. package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts.map +1 -1
  38. package/dist/adapters/sqlite/types.d.ts +1 -1
  39. package/dist/adapters/sqlite/types.d.ts.map +1 -1
  40. package/dist/adapters/sqlite-native/index.d.ts +1 -1
  41. package/dist/adapters/sqlite-native/index.d.ts.map +1 -1
  42. package/dist/adapters/sqlite-native/tools/window/helpers.d.ts +52 -0
  43. package/dist/adapters/sqlite-native/tools/window/helpers.d.ts.map +1 -0
  44. package/dist/adapters/sqlite-native/tools/window/index.d.ts +7 -0
  45. package/dist/adapters/sqlite-native/tools/window/index.d.ts.map +1 -0
  46. package/dist/adapters/sqlite-native/tools/window/lag-lead.d.ts +7 -0
  47. package/dist/adapters/sqlite-native/tools/window/lag-lead.d.ts.map +1 -0
  48. package/dist/adapters/sqlite-native/tools/window/moving-average.d.ts +7 -0
  49. package/dist/adapters/sqlite-native/tools/window/moving-average.d.ts.map +1 -0
  50. package/dist/adapters/sqlite-native/tools/window/ntile.d.ts +7 -0
  51. package/dist/adapters/sqlite-native/tools/window/ntile.d.ts.map +1 -0
  52. package/dist/adapters/sqlite-native/tools/window/rank.d.ts +7 -0
  53. package/dist/adapters/sqlite-native/tools/window/rank.d.ts.map +1 -0
  54. package/dist/adapters/sqlite-native/tools/window/row-number.d.ts +7 -0
  55. package/dist/adapters/sqlite-native/tools/window/row-number.d.ts.map +1 -0
  56. package/dist/adapters/sqlite-native/tools/window/running-total.d.ts +7 -0
  57. package/dist/adapters/sqlite-native/tools/window/running-total.d.ts.map +1 -0
  58. package/dist/adapters/sqlite-native/tools/window/schemas.d.ts +159 -0
  59. package/dist/adapters/sqlite-native/tools/window/schemas.d.ts.map +1 -0
  60. package/dist/adapters/sqlite-native/transaction-methods.d.ts.map +1 -1
  61. package/dist/audit/logger.d.ts.map +1 -1
  62. package/dist/auth/authorization-server-discovery.d.ts.map +1 -1
  63. package/dist/auth/scopes/mapping.d.ts.map +1 -1
  64. package/dist/auth/token-validator.d.ts.map +1 -1
  65. package/dist/{chunk-EQF3WZHX.js → chunk-27C5EE6U.js} +15 -2
  66. package/dist/{chunk-R5M4WKDM.js → chunk-2TYICG7B.js} +381 -185
  67. package/dist/{chunk-TGE7LFAR.js → chunk-UE7GVOBV.js} +1069 -355
  68. package/dist/{chunk-NIC5Z2CA.js → chunk-WYBUO4FL.js} +394 -381
  69. package/dist/{chunk-Y57WFKAP.js → chunk-XLIYO3YA.js} +178 -72
  70. package/dist/cli.js +18 -6
  71. package/dist/codemode/api-constants.d.ts.map +1 -1
  72. package/dist/codemode/api.d.ts.map +1 -1
  73. package/dist/codemode/sandbox-factory.d.ts.map +1 -1
  74. package/dist/codemode/sandbox.d.ts +0 -3
  75. package/dist/codemode/sandbox.d.ts.map +1 -1
  76. package/dist/codemode/security.d.ts.map +1 -1
  77. package/dist/codemode/types.d.ts +2 -0
  78. package/dist/codemode/types.d.ts.map +1 -1
  79. package/dist/constants/server-instructions.d.ts.map +1 -1
  80. package/dist/filtering/tool-constants.d.ts +5 -5
  81. package/dist/filtering/tool-constants.d.ts.map +1 -1
  82. package/dist/{http-2WGR3E5K.js → http-2XDGZF4F.js} +177 -32
  83. package/dist/index.js +4 -4
  84. package/dist/observability/system-db.d.ts.map +1 -1
  85. package/dist/server/mcp-server.d.ts.map +1 -1
  86. package/dist/server/registration/admin-tools.d.ts.map +1 -1
  87. package/dist/server/registration/audit-tools/backup.d.ts +8 -0
  88. package/dist/server/registration/audit-tools/backup.d.ts.map +1 -0
  89. package/dist/server/registration/audit-tools/helpers.d.ts +11 -0
  90. package/dist/server/registration/audit-tools/helpers.d.ts.map +1 -0
  91. package/dist/server/registration/audit-tools/index.d.ts +4 -0
  92. package/dist/server/registration/audit-tools/index.d.ts.map +1 -0
  93. package/dist/server/registration/audit-tools/resource.d.ts +8 -0
  94. package/dist/server/registration/audit-tools/resource.d.ts.map +1 -0
  95. package/dist/server/registration/audit-tools/search.d.ts +7 -0
  96. package/dist/server/registration/audit-tools/search.d.ts.map +1 -0
  97. package/dist/server/registration/index.d.ts +1 -1
  98. package/dist/server/registration/index.d.ts.map +1 -1
  99. package/dist/{sqlite-D4WCNPU4.js → sqlite-XWZPEZJO.js} +192 -19
  100. package/dist/{sqlite-native-DLVS2T52.js → sqlite-native-5GQ3WKCZ.js} +156 -117
  101. package/dist/transports/http/middleware.d.ts.map +1 -1
  102. package/dist/transports/http/oauth.d.ts.map +1 -1
  103. package/dist/transports/http/sessions/legacy-sse.d.ts.map +1 -1
  104. package/dist/transports/http/sessions/stateful.d.ts +5 -1
  105. package/dist/transports/http/sessions/stateful.d.ts.map +1 -1
  106. package/dist/transports/http/transport.d.ts +2 -0
  107. package/dist/transports/http/transport.d.ts.map +1 -1
  108. package/dist/transports/http/types.d.ts +9 -0
  109. package/dist/transports/http/types.d.ts.map +1 -1
  110. package/dist/types/auth.d.ts +4 -0
  111. package/dist/types/auth.d.ts.map +1 -1
  112. package/dist/types/server.d.ts +3 -0
  113. package/dist/types/server.d.ts.map +1 -1
  114. package/dist/utils/annotations.d.ts +8 -0
  115. package/dist/utils/annotations.d.ts.map +1 -1
  116. package/dist/utils/errors/categories.d.ts +16 -11
  117. package/dist/utils/errors/categories.d.ts.map +1 -1
  118. package/dist/utils/errors/classes.d.ts +37 -0
  119. package/dist/utils/errors/classes.d.ts.map +1 -1
  120. package/dist/utils/errors/format.d.ts +2 -2
  121. package/dist/utils/errors/format.d.ts.map +1 -1
  122. package/dist/utils/errors/index.d.ts +1 -1
  123. package/dist/utils/errors/index.d.ts.map +1 -1
  124. package/dist/utils/errors/suggestions.d.ts +1 -0
  125. package/dist/utils/errors/suggestions.d.ts.map +1 -1
  126. package/dist/utils/index.d.ts +2 -0
  127. package/dist/utils/index.d.ts.map +1 -1
  128. package/dist/utils/security-utils.d.ts +29 -0
  129. package/dist/utils/security-utils.d.ts.map +1 -0
  130. package/dist/utils/stream-utils.d.ts +14 -0
  131. package/dist/utils/stream-utils.d.ts.map +1 -0
  132. package/dist/utils/where-clause.d.ts +0 -13
  133. package/dist/utils/where-clause.d.ts.map +1 -1
  134. package/package.json +36 -39
  135. package/dist/adapters/sqlite-native/tools/window.d.ts +0 -7
  136. package/dist/adapters/sqlite-native/tools/window.d.ts.map +0 -1
  137. package/dist/server/registration/audit-tools.d.ts +0 -17
  138. package/dist/server/registration/audit-tools.d.ts.map +0 -1
@@ -1,5 +1,5 @@
1
- import { VERSION, NAME, READ_ONLY, SERVER_ICONS, ASSISTANT_FOCUSED, redactObject, getRequiredScope, estimateTokens, AuditListBackupsOutputSchema, AuditListBackupsSchema, AuditGetBackupOutputSchema, AuditCleanupOutputSchema, AuditDiffBackupOutputSchema, AuditRestoreBackupOutputSchema, AuditSearchOutputSchema, AuditSearchSchema } from './chunk-R5M4WKDM.js';
2
- import { parseToolFilter, getToolFilterFromEnv, logger, getFilterSummary, DbMcpError, getAuthContext, scopesGrantToolAccess, registerToolScopes, metrics, InsufficientScopeError, sanitizeErrorMessage, formatHandlerError } from './chunk-Y57WFKAP.js';
1
+ import { VERSION, NAME, READ_ONLY, SERVER_ICONS, ASSISTANT_FOCUSED, toSDK, redactObject, getRequiredScope, estimateTokens, AuditListBackupsOutputSchema, AuditListBackupsSchema, AuditGetBackupOutputSchema, AuditCleanupOutputSchema, AuditDiffBackupOutputSchema, AuditRestoreBackupOutputSchema, AuditSearchOutputSchema, AuditSearchSchema } from './chunk-2TYICG7B.js';
2
+ import { ErrorCategory, logger, parseToolFilter, getToolFilterFromEnv, ValidationError, getFilterSummary, DbMcpError, getAuthContext, scopesGrantToolAccess, registerToolScopes, metrics, InsufficientScopeError, formatHandlerError, InternalError, sanitizeErrorMessage } from './chunk-XLIYO3YA.js';
3
3
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
4
4
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
5
  import { dirname, join, basename, sep } from 'path';
@@ -34,9 +34,7 @@ Read \`sqlite://help\` for gotchas and critical usage patterns.
34
34
  Read \`sqlite://help/{group}\` for group-specific tool reference (core, json, text, stats, vector, geo, admin, transactions, introspection, migration).
35
35
  Only help resources for your enabled tool groups are registered.`;
36
36
  var HELP_CONTENT = /* @__PURE__ */ new Map([
37
- [
38
- "admin",
39
- `# db-mcp Help \u2014 Database Administration (31N/30W tools) + Server Audit (7 tools)
37
+ ["admin", `# db-mcp Help \u2014 Database Administration (31N/30W tools) + Server Audit (7 tools)
40
38
 
41
39
  ## Maintenance
42
40
 
@@ -45,7 +43,7 @@ sqlite_integrity_check({ maxErrors: 10 }); // check for corruption
45
43
  sqlite_optimize({ analyze: true, reindex: true }); // optimize performance
46
44
  sqlite_vacuum(); // reclaim space
47
45
  sqlite_analyze({ table: "orders" }); // update statistics for query planner
48
- sqlite_dbstat({ summarize: true }); // storage stats (\u26A0\uFE0F summarize native-only; WASM returns counts only)
46
+ sqlite_dbstat(); // storage stats (\u26A0\uFE0F summarize native-only; WASM returns counts only)
49
47
  sqlite_reindex(); // rebuild all indexes
50
48
  sqlite_reindex({ target: "idx_users_email" }); // rebuild specific index
51
49
  sqlite_reindex({ target: "orders" }); // rebuild all indexes for a table
@@ -53,6 +51,8 @@ sqlite_reindex({ target: "orders" }); // rebuild all indexes for a table
53
51
 
54
52
  ## Backup/Restore (Native only)
55
53
 
54
+ \u26A0\uFE0F Paths must be absolute and within explicitly authorized \`ALLOWED_IO_ROOTS\`.
55
+
56
56
  \`\`\`javascript
57
57
  sqlite_backup({ targetPath: "/path/to/backup.db" });
58
58
  sqlite_vacuum_into({ outputPath: "/path/to/compact.db" }); // create defragmented copy
@@ -70,7 +70,7 @@ sqlite_audit_get_backup({ filename: "snapshot_123.json" }); // retrieve specific
70
70
  sqlite_audit_diff_backup({ filename: "snapshot_123.json" }); // compare snapshot against live schema
71
71
  sqlite_audit_restore_backup({ filename: "snapshot_123.json", dryRun: true }); // restore schema from snapshot
72
72
  sqlite_audit_cleanup(); // apply retention policy and delete old snapshots
73
- sqlite_audit_search({ query: "DROP TABLE", limit: 50 }); // search and filter structured audit logs
73
+ sqlite_audit_search({ tool: "sqlite_drop_table", limit: 10 }); // search and filter structured audit logs
74
74
  \`\`\`
75
75
 
76
76
  ## PRAGMA
@@ -81,7 +81,7 @@ sqlite_pragma_settings({ pragma: "cache_size", value: 10000 }); // set value
81
81
  sqlite_pragma_table_info({ table: "users" }); // column details
82
82
  sqlite_pragma_compile_options({ filter: "FTS" }); // \u26A0\uFE0F WASM may show FTS3, not FTS5
83
83
  sqlite_pragma_database_list(); // list attached databases
84
- sqlite_attach_database({ filepath: "/path/to/other.db", alias: "archive" }); // attach external DB
84
+ sqlite_attach_database({ filepath: "/path/to/other.db", alias: "archive" }); // attach external DB (\u26A0\uFE0F subject to ALLOWED_IO_ROOTS)
85
85
  sqlite_detach_database({ alias: "archive" }); // detach DB
86
86
  sqlite_pragma_optimize(); // run PRAGMA optimize
87
87
  \`\`\`
@@ -137,7 +137,7 @@ sqlite_create_rtree_table({ tableName: "locations_idx", dimensions: 2 }); // 2D:
137
137
 
138
138
  ## CSV Virtual Tables (Native only)
139
139
 
140
- \u26A0\uFE0F Requires ABSOLUTE file paths
140
+ \u26A0\uFE0F Requires ABSOLUTE file paths that must fall within explicitly authorized \`ALLOWED_IO_ROOTS\`.
141
141
 
142
142
  \`\`\`javascript
143
143
  sqlite_analyze_csv_schema({ filePath: "/absolute/path/to/data.csv" }); // analyze CSV structure
@@ -145,16 +145,13 @@ sqlite_create_csv_table({
145
145
  tableName: "csv_data",
146
146
  filePath: "/absolute/path/to/data.csv",
147
147
  });
148
- \`\`\``
149
- ],
150
- [
151
- "core",
152
- `# db-mcp Help \u2014 Core Operations (21 tools)
148
+ \`\`\``],
149
+ ["core", `# db-mcp Help \u2014 Core Operations (25 tools)
153
150
 
154
151
  ## Basic Queries
155
152
 
156
- - \`sqlite_read_query({ query: "SELECT * FROM users LIMIT 10", cursor: "..." })\` \u2014 execute SELECT, PRAGMA, EXPLAIN, or WITH statements. Supports \`cursor\` for offset-based pagination (returns \`nextCursor\`). **Agent Tip:** Avoid \`SELECT *\` on wide tables with large text/JSON columns to conserve token context; use \`sqlite_describe_table\` first and select specific columns.
157
- - \`sqlite_write_query({ query: "INSERT INTO users (name) VALUES ('Alice')" })\` \u2014 execute INSERT, UPDATE, DELETE, REPLACE, or trigger DDL (CREATE/DROP TRIGGER)
153
+ - \`sqlite_read_query({ query: "SELECT * FROM users LIMIT 10", cursor: "...", stream: true, chunkSize: 10 })\` \u2014 execute SELECT, PRAGMA, EXPLAIN, or WITH statements. Supports \`cursor\` for offset-based pagination (returns \`nextCursor\`). Set \`stream: true\` to return row-by-row chunks via progress notifications instead of full response buffering (requires client progressToken support; gracefully falls back if unavailable). **Agent Tip:** Avoid \`SELECT *\` on wide tables with large text/JSON columns to conserve token context; use \`sqlite_describe_table\` first and select specific columns.
154
+ - \`sqlite_write_query({ query: "INSERT INTO users (name) VALUES ('Alice')" })\` \u2014 execute INSERT, UPDATE, DELETE, REPLACE, or trigger DDL (CREATE/DROP TRIGGER). Supports \`expectedVersion\` for OCC.
158
155
 
159
156
  ## Tables & Schema
160
157
 
@@ -174,19 +171,30 @@ sqlite_create_csv_table({
174
171
  - \`sqlite_create_index({ indexName: "idx_users_email", table: "users", columns: ["email"], unique?: true })\` \u2014 create a new index
175
172
  - \`sqlite_drop_index({ indexName: "idx_users_email", ifExists?: true })\` \u2014 drop an existing index
176
173
 
174
+ ## Versioning & Concurrency (OCC)
175
+
176
+ - \`sqlite_enable_versioning({ table: "users" })\` \u2014 add a \`_version\` column and a BEFORE UPDATE trigger to enforce optimistic concurrency control on a table
177
+ - \`sqlite_disable_versioning({ table: "users" })\` \u2014 remove the \`_version\` column and concurrency trigger
178
+ - \`sqlite_check_version({ table: "users", rowId: 1 })\` \u2014 get the current \`_version\` of a row
179
+ - \`sqlite_conditional_update({ table: "users", conditions: [{ column: "id", operator: "=", value: 1 }], expectedVersion: 2, data: { name: "Bob" } })\` \u2014 safely update a row, incrementing \`_version\` atomically. Will fail if \`expectedVersion\` does not match
180
+
177
181
  ## Convenience Tools (High-Level Data Operations)
178
182
 
179
- - \`sqlite_upsert({ table: "users", data: { id: 1, name: "Alice" }, conflictColumns: ["id"], updateColumns: ["name"], returning: true })\` \u2014 insert or update a row using \`ON CONFLICT\` (or \`REPLACE\` fallback). Supports \`returning: true\` or array of columns.
183
+ - \`sqlite_upsert({ table: "users", data: { id: 1, name: "Alice" }, conflictColumns: ["id"], updateColumns: ["name"], returning: true })\` \u2014 insert or update a row using \`ON CONFLICT\` (or \`REPLACE\` fallback). Supports \`returning: true\` or array of columns, and \`expectedVersion\` for OCC.
180
184
  - \`sqlite_batch_insert({ table: "users", rows: [{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }], returning: true })\` \u2014 insert multiple rows in a single batch. Supports \`returning: true\` or array of columns.
181
185
  - \`sqlite_count({ table: "users", where?: "status = 'active'" })\` \u2014 count rows in a table (faster than a full query)
182
186
  - \`sqlite_exists({ table: "users", where: "email = 'test@example.com'" })\` \u2014 check if a row exists (stops at first match)
183
187
  - \`sqlite_truncate({ table: "users" })\` \u2014 quickly delete all rows from a table (executes \`DELETE FROM table\`)
184
188
  - \`sqlite_date_add({ table: "users", column: "created_at", amount: 7, unit: "days", whereClause: "id = 1" })\` \u2014 add or subtract time intervals from a date column. By default returns only the computed column; use \`selectColumns\` to return additional context.
185
- - \`sqlite_date_diff({ table: "users", column1: "ended_at", column2: "started_at", unit: "days", whereClause: "id = 1" })\` \u2014 calculate the difference between two date columns. By default returns only the computed column; use \`selectColumns\` to return additional context.`
186
- ],
187
- [
188
- "geo",
189
- `# db-mcp Help \u2014 Geospatial Operations (11N/4W: 4 basic + 7 SpatiaLite [NATIVE ONLY])
189
+ - \`sqlite_date_diff({ table: "users", column1: "ended_at", column2: "started_at", unit: "days", whereClause: "id = 1" })\` \u2014 calculate the difference between two date columns. By default returns only the computed column; use \`selectColumns\` to return additional context.
190
+
191
+ ## \u26A0\uFE0F Core Gotchas
192
+
193
+ 1. **sqlite_write_query**: DML only (INSERT/UPDATE/DELETE/REPLACE) \u2014 use \`sqlite_read_query\` for SELECT, and dedicated DDL tools for schema modifications.
194
+ 2. **sqlite_upsert**: Always specify \`conflictColumns\` \u2014 without it, falls back to \`REPLACE\` which deletes and re-inserts the row, potentially losing columns not included in \`data\`.
195
+ 3. **Optimistic Concurrency Control (OCC)**: When a table is versioned (\`sqlite_enable_versioning\`), you MUST supply \`expectedVersion\` to \`sqlite_write_query\`, \`sqlite_upsert\`, and \`sqlite_conditional_update\`. Omitting it will result in a \`ConflictError\` to strictly prevent lost updates.
196
+ 4. **sqlite_batch_insert**: All rows must have the same keys \u2014 inconsistent column sets across rows will cause errors or unexpected NULLs.`],
197
+ ["geo", `# db-mcp Help \u2014 Geospatial Operations (11N/4W: 4 basic + 7 SpatiaLite [NATIVE ONLY])
190
198
 
191
199
  ## Basic Geo (always available \u2014 Haversine formula)
192
200
 
@@ -291,36 +299,15 @@ sqlite_spatialite_index({
291
299
  geometryColumn: "geom",
292
300
  action: "create",
293
301
  }); // create, drop, or check
294
- \`\`\``
295
- ],
296
- [
297
- "gotchas",
298
- `# db-mcp Help \u2014 Gotchas & Code Mode
299
-
300
- ## \u26A0\uFE0F Critical Gotchas
301
-
302
- 1. **sqlite_write_query**: DML only (INSERT/UPDATE/DELETE/REPLACE) \u2014 use \`sqlite_read_query\` for SELECT, and dedicated DDL tools like \`sqlite_create_table\`, \`sqlite_create_trigger\`, and \`sqlite_drop_trigger\` for schema modifications.
303
- 2. **Regex patterns**: Double-escape backslashes (\`\\\\\\\\\`) when passing through JSON/MCP
304
- 3. **FTS5 virtual tables**: \`*_fts\` and shadow tables \`*_fts_*\` are hidden from \`sqlite_list_tables\` for cleaner output
305
- 4. **FTS5 boolean logic**: Uses AND by default \u2014 \`"machine learning"\` = rows with BOTH words. Use OR explicitly: \`"machine OR learning"\`
306
- 5. **json_each row multiplication**: Expands arrays to rows \u2014 use \`limit\` param for large arrays
307
- 6. **json_group_object without groupByColumn**: Each row creates a key-value pair; duplicate keys result if key values aren't unique
308
- 7. **allowExpressions**: For column extraction ONLY (e.g., \`json_extract\`), NOT aggregate functions \u2014 use \`aggregateFunction\` param instead
309
- 8. **sqlite_json_normalize_column**: Defaults to \`preserve\` (maintains original format); use \`outputFormat: 'text'\` to force text
310
- 9. **Fuzzy matching tokenization**: Matches WORD TOKENS by default \u2014 \`"laptop"\` matches \`"Laptop Pro 15"\` (distance 0 on first token). Use \`tokenize: false\` for full-string matching
311
- 10. **SpatiaLite distances**: \`nearest_neighbor\`/\`distance_matrix\` return CARTESIAN distance (degrees), not geodetic (km/miles)
312
- 11. **SpatiaLite buffer**: Auto-simplifies output by default (tolerance=0.0001). Use \`simplifyTolerance: 0\` to disable
313
- 12. **sqlite_stats_top_n**: Returns all columns by default which creates large payloads for wide tables \u2014 always pass \`selectColumns\` to control output size
314
- 13. **CSV virtual tables**: Require ABSOLUTE file paths
315
- 14. **sqlite_create_series_table**: Creates a REGULAR table (not virtual) \u2014 use \`sqlite_drop_table\` to remove
316
- 15. **sqlite_dbstat**: \`summarize\` only works in native; WASM returns counts only
317
- 16. **PRAGMA compile options**: WASM may show FTS3, not FTS5
318
- 17. **Vector tool schemas**: Vector tools use distinct schemas for specific operations. E.g., \`sqlite.vector.dimensions\` requires \`vectorColumn\`. Additionally, \`sqlite.vector.get\` wraps metadata inside a \`metadata\` object (e.g., \`metadata.content\`), and \`sqlite.vector.stats\` returns \`sampleSize\` and \`magnitudeStats\` (not \`count\` and \`stats\`).
319
- 18. **FTS5 trigger cleanup**: Dropping an FTS5 table with \`sqlite_drop_table\` automatically finds and removes the associated \`_ai\`, \`_ad\`, and \`_au\` sync triggers from the source table.
320
- 19. **sqlite_batch_insert**: All rows must have the same keys \u2014 inconsistent column sets across rows will cause errors or unexpected NULLs
321
- 20. **sqlite_schema_diff**: \`baseline\` and \`target\` accept either the string \`"current"\` (queries live DB) or an inline snapshot object from a prior \`sqlite_schema_snapshot\` call. At least one side must be \`"current"\` unless doing an offline comparison
322
- 21. **sqlite_upsert**: Always specify \`conflictColumns\` \u2014 without it, falls back to \`REPLACE\` which deletes and re-inserts the row, potentially losing columns not included in \`data\`
323
- 22. **Resource Subscriptions**: The \`sqlite://schema\` and \`sqlite://health\` resources support MCP subscriptions, allowing the client to receive real-time push notifications when DDL changes occur or health metrics update without needing to poll.
302
+ \`\`\``],
303
+ ["gotchas", `# db-mcp Help \u2014 Gotchas & Code Mode
304
+
305
+ ## Server-Level Rules
306
+
307
+ 1. **CSV virtual tables & Backups**: Require ABSOLUTE file paths. Operations will be strictly blocked if paths do not fall within the explicitly authorized \`ALLOWED_IO_ROOTS\` directory list. Unconfigured stdio transports default to no filesystem access.
308
+ 2. **Resource Subscriptions**: The \`sqlite://schema\` and \`sqlite://health\` resources support MCP subscriptions, allowing the client to receive real-time push notifications when DDL changes occur or health metrics update without needing to poll.
309
+ 3. **HTTP Session Timeouts**: Stateful HTTP sessions automatically expire after 30 minutes of inactivity, or 24 hours total. Sessions are swept automatically; ensure client workflows re-authenticate or handle broken sessions gracefully.
310
+ 4. **Structured Errors**: The server returns strongly-typed JSON errors instead of generic stack traces. Execution timeouts surface as recoverable \`TimeoutError\` (category: \`timeout\`). Rate limit violations surface as \`RateLimitError\` (category: \`rate_limit\`). Input/schema rejections surface as \`ValidationError\` (category: \`validation\`). Use this metadata (\`code\`, \`category\`, \`recoverable\`) to programmatically retry or backoff.
324
311
 
325
312
  ## WASM vs Native
326
313
 
@@ -347,22 +334,19 @@ sqlite_spatialite_index({
347
334
  **Usage**: \`sqlite_execute_code({ code: "const tables = await sqlite.core.listTables(); return tables;" })\`
348
335
  **Discover**: \`sqlite.help()\` for all groups, \`sqlite.<group>.help()\` for methods.
349
336
  **Progress**: Use \`await sqlite.reportProgress(current, total, "Message")\` for custom long-running tasks.
350
- **Groups**: \`sqlite.core\`, \`sqlite.json\`, \`sqlite.text\`, \`sqlite.stats\`, \`sqlite.vector\`, \`sqlite.admin\`, \`sqlite.transactions\` (Native-only), \`sqlite.geo\`, \`sqlite.introspection\`, \`sqlite.migration\`
337
+ **Groups**: \`sqlite.core\`, \`sqlite.json\`, \`sqlite.text\`, \`sqlite.stats\`, \`sqlite.vector\`, \`sqlite.admin\`, \`sqlite.transactions\` (Native-only), \`sqlite.geo\`, \`sqlite.introspection\`, \`sqlite.migration\` (opt-in)
351
338
 
352
339
  > **Note**: Code Mode dynamically filters capabilities. In WASM environments, \`sqlite.help()\` will omit unsupported groups (e.g., \`transactions\`) and tools (e.g., FTS5) to accurately reflect the active runtime.
353
340
 
354
341
  ## Code Mode API Mapping
355
342
 
356
- \`sqlite_group_action\` \u2192 \`sqlite.group.action()\` (group prefixes dropped: \`sqlite_json_insert\` \u2192 \`sqlite.json.insert()\`)
357
- **Exception**: \`stats\` and \`migration\` keep their prefix: \`sqlite_stats_basic\` \u2192 \`sqlite.stats.statsBasic()\`, \`sqlite_migration_apply\` \u2192 \`sqlite.migration.migrationApply()\`
343
+ Code Mode maps standard tools to an object-oriented sandbox API (\`sqlite_group_action\` \u2192 \`sqlite.group.action()\`).
358
344
 
359
- **Positional args work**: \`sqlite.core.readQuery("SELECT...")\`, \`sqlite.json.insert("docs", "data", {...})\`
360
-
361
- **Discovery**: \`sqlite.help()\` returns all groups and methods. \`sqlite.core.help()\`, \`sqlite.json.help()\` for group-specific methods.`
362
- ],
363
- [
364
- "introspection",
365
- `# db-mcp Help \u2014 Schema Introspection (10 tools)
345
+ - **Flexible Parameters**: Parameters are forgiven for casing discrepancies (e.g. \`conflict_columns\` vs \`conflictColumns\`).
346
+ - **Flexible Methods**: Methods mapped into the Code Mode proxy forgive casing discrepancies (e.g. \`sqlite.core.read_query\` executes \`sqlite.core.readQuery()\`).
347
+ - Methods support both an options object and **positional arguments** (e.g. \`sqlite.core.readQuery("SELECT...")\`, \`sqlite.json.insert("docs", "data", {...})\`).
348
+ - **Discovery**: Call \`sqlite.help()\` or \`sqlite.core.help()\` to see available methods directly within the sandbox.`],
349
+ ["introspection", `# db-mcp Help \u2014 Schema Introspection (10 tools)
366
350
 
367
351
  All introspection tools are **read-only** \u2014 they query PRAGMAs and sqlite_master, never modify data.
368
352
 
@@ -450,11 +434,9 @@ sqlite_query_plan({ sql: "SELECT * FROM orders WHERE status = 'active'" });
450
434
  ## \u26A0\uFE0F Gotchas
451
435
 
452
436
  - \`excludeSystemTables\` defaults to \`true\` \u2014 SpatiaLite system tables are hidden for cleaner output. Pass \`false\` to include them
453
- - \`sqlite_migration_risks\` analyzes DDL text statically \u2014 it does NOT execute the statements`
454
- ],
455
- [
456
- "json",
457
- `# db-mcp Help \u2014 JSON Operations (25 tools)
437
+ - \`sqlite_migration_risks\` analyzes DDL text statically \u2014 it does NOT execute the statements
438
+ - \`sqlite_schema_diff\`: \`baseline\` and \`target\` accept either the string \`"current"\` (queries live DB) or an inline snapshot object from a prior \`sqlite_schema_snapshot\` call. At least one side must be \`"current"\` unless doing an offline comparison.`],
439
+ ["json", `# db-mcp Help \u2014 JSON Operations (25 tools)
458
440
 
459
441
  ## Collection & CRUD
460
442
 
@@ -528,11 +510,8 @@ sqlite_json_group_object({
528
510
 
529
511
  - \`sqlite_json_storage_info({ table, column })\` \u2014 check text vs JSONB format
530
512
  - \`sqlite_jsonb_convert({ table, column })\` \u2014 convert to JSONB for faster queries
531
- - \`sqlite_json_normalize_column({ table, column, outputFormat? })\` \u2014 normalize JSON (sort keys, compact). \u26A0\uFE0F Defaults to \`"preserve"\` (maintains original format); use \`outputFormat: "text"\` to force text output`
532
- ],
533
- [
534
- "migration",
535
- `# db-mcp Help \u2014 Migration Tracking (6 tools)
513
+ - \`sqlite_json_normalize_column({ table, column, outputFormat? })\` \u2014 normalize JSON (sort keys, compact). \u26A0\uFE0F Defaults to \`"preserve"\` (maintains original format); use \`outputFormat: "text"\` to force text output`],
514
+ ["migration", `# db-mcp Help \u2014 Migration Tracking (6 tools)
536
515
 
537
516
  \u26A0\uFE0F Must call \`sqlite_migration_init()\` before using any other migration tool \u2014 it creates the tracking table.
538
517
 
@@ -574,11 +553,8 @@ sqlite_migration_status();
574
553
  ## \u26A0\uFE0F Gotchas
575
554
 
576
555
  - Rollback requires \`rollbackSql\` to have been provided when the migration was recorded/applied
577
- - Migration group is **opt-in** \u2014 not included by default. Enable via \`--tool-filter\` flag: use \`dev-schema\` (core+introspection+migration+codemode) or \`full\` (all groups)`
578
- ],
579
- [
580
- "stats",
581
- `# db-mcp Help \u2014 Statistical Analysis (23N/17W: 17 core + 6 window [NATIVE ONLY])
556
+ - Migration group is **opt-in** \u2014 not included by default. Enable via \`--tool-filter\` flag: use \`dev-schema\` (core+introspection+migration+codemode) or \`full\` (all groups)`],
557
+ ["stats", `# db-mcp Help \u2014 Statistical Analysis (23N/17W: 17 core + 6 window [NATIVE ONLY])
582
558
 
583
559
  ## Core Statistics (always available)
584
560
 
@@ -697,11 +673,8 @@ sqlite_window_moving_avg({
697
673
  windowSize: 7,
698
674
  selectColumns: ["date"],
699
675
  });
700
- \`\`\``
701
- ],
702
- [
703
- "text",
704
- `# db-mcp Help \u2014 Text Processing & FTS5 (20N/15W: 15 text + 5 FTS5 [NATIVE ONLY])
676
+ \`\`\``],
677
+ ["text", `# db-mcp Help \u2014 Text Processing & FTS5 (20N/15W: 15 text + 5 FTS5 [NATIVE ONLY])
705
678
 
706
679
  ## Full-Text Search / FTS5 (5 tools, Native only)
707
680
 
@@ -840,6 +813,7 @@ sqlite_hybrid_search({
840
813
  metric: "cosine",
841
814
  limit: 10,
842
815
  });
816
+ // \u26A0\uFE0F Requires an FTS5 table (Native only) and a vector column in the source table
843
817
 
844
818
  // Sentiment analysis \u2014 text analysis (can analyze raw text or database columns)
845
819
  sqlite_text_sentiment({ text: "This product is amazing and wonderful!" });
@@ -852,11 +826,8 @@ sqlite_text_sentiment({
852
826
  returnWords: true,
853
827
  });
854
828
  // \u2192 { sentiment: "neutral", score: 0, matchedPositive: ["great"], matchedNegative: ["slow"] }
855
- \`\`\``
856
- ],
857
- [
858
- "transactions",
859
- `# db-mcp Help \u2014 Transactions (8 tools, Native only)
829
+ \`\`\``],
830
+ ["transactions", `# db-mcp Help \u2014 Transactions (8 tools, Native only)
860
831
 
861
832
  ## Atomic Execution (preferred for simple cases)
862
833
 
@@ -887,11 +858,8 @@ sqlite_transaction_status(); // \u2192 { status: "active" | "none", active: true
887
858
 
888
859
  - Transaction tools are **Native only** \u2014 WASM adapter does not support transactions
889
860
  - Use \`sqlite_transaction_execute\` for simple multi-statement operations; manual \`begin\`/\`commit\` for complex flows with savepoints
890
- - \`sqlite_transaction_status\` is read-only and requires only \`read\` scope; all other transaction tools require \`write\` scope`
891
- ],
892
- [
893
- "vector",
894
- `# db-mcp Help \u2014 Vector/Semantic Search (11 tools)
861
+ - \`sqlite_transaction_status\` is read-only and requires only \`read\` scope; all other transaction tools require \`write\` scope`],
862
+ ["vector", `# db-mcp Help \u2014 Vector/Semantic Search (11 tools)
895
863
 
896
864
  \`\`\`javascript
897
865
  // Create vector table with metadata columns
@@ -917,8 +885,11 @@ sqlite_vector_stats({ table: "docs", vectorColumn: "emb" }); // returns sampleSi
917
885
  // Utility tools for preprocessing
918
886
  sqlite_vector_normalize({ vector: [3, 4, 0, 0] }); // returns unit vector [0.6, 0.8, 0, 0]
919
887
  sqlite_vector_distance({ vector1: [...], vector2: [...], metric: "cosine" }); // returns { value: <number> }
920
- \`\`\``
921
- ]
888
+ \`\`\`
889
+
890
+ ## \u26A0\uFE0F Vector Gotchas
891
+
892
+ - **Vector tool schemas**: Vector tools use distinct schemas for specific operations. E.g., \`sqlite.vector.dimensions\` requires \`vectorColumn\`. Additionally, \`sqlite_vector_get\` wraps metadata inside a \`metadata\` object (e.g., \`metadata.content\`), and \`sqlite_vector_stats\` returns \`sampleSize\` and \`magnitudeStats\` (not \`count\` and \`stats\`).`]
922
893
  ]);
923
894
 
924
895
  // src/audit/logger.ts
@@ -948,9 +919,9 @@ var AuditLogger = class {
948
919
  /**
949
920
  * Initialization is handled externally by SystemDb.
950
921
  */
951
- // eslint-disable-next-line @typescript-eslint/require-await
952
- async init() {
953
- if (this.stderrMode || !this.config.enabled) return;
922
+ init() {
923
+ if (this.stderrMode || !this.config.enabled) return Promise.resolve();
924
+ return Promise.resolve();
954
925
  }
955
926
  /**
956
927
  * Append an audit entry to the buffer.
@@ -1219,7 +1190,7 @@ var SystemDb = class {
1219
1190
  }
1220
1191
  getDb() {
1221
1192
  if (!this.db) {
1222
- throw new Error("SystemDb not initialized");
1193
+ throw new InternalError("SystemDb not initialized");
1223
1194
  }
1224
1195
  return this.db;
1225
1196
  }
@@ -1757,202 +1728,7 @@ function createAuditInterceptor(auditLogger, backupManager) {
1757
1728
  };
1758
1729
  }
1759
1730
 
1760
- // src/server/registration/built-in-tools.ts
1761
- function registerBuiltInTools(server, adaptersMap, config, toolFilter) {
1762
- const serverInfoOpts = {
1763
- title: "Server Info",
1764
- description: "Get information about the db-mcp server and registered adapters",
1765
- icons: SERVER_ICONS,
1766
- annotations: READ_ONLY
1767
- };
1768
- server.registerTool("server_info", serverInfoOpts, () => {
1769
- const authCtx = getAuthContext();
1770
- if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "server_info")) {
1771
- throw new InsufficientScopeError(["read"], authCtx.scopes);
1772
- }
1773
- const adapterInfo = [];
1774
- for (const [id, adapter] of adaptersMap) {
1775
- adapterInfo.push({
1776
- id,
1777
- ...adapter.getInfo()
1778
- });
1779
- }
1780
- return {
1781
- content: [
1782
- {
1783
- type: "text",
1784
- text: JSON.stringify(
1785
- {
1786
- name: config.name,
1787
- version: config.version,
1788
- transport: config.transport,
1789
- adapters: adapterInfo,
1790
- toolFilter: {
1791
- raw: toolFilter.raw,
1792
- enabledGroups: [...toolFilter.enabledGroups]
1793
- }
1794
- },
1795
- null,
1796
- 2
1797
- )
1798
- }
1799
- ]
1800
- };
1801
- });
1802
- const healthOpts = {
1803
- title: "Server Health",
1804
- description: "Check health status of all database connections",
1805
- icons: SERVER_ICONS,
1806
- annotations: READ_ONLY
1807
- };
1808
- server.registerTool("server_health", healthOpts, async () => {
1809
- const authCtx = getAuthContext();
1810
- if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "server_health")) {
1811
- throw new InsufficientScopeError(["read"], authCtx.scopes);
1812
- }
1813
- const health = {
1814
- server: "healthy",
1815
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1816
- adapters: {}
1817
- };
1818
- for (const [id, adapter] of adaptersMap) {
1819
- try {
1820
- const adapterHealth = await adapter.getHealth();
1821
- health["adapters"][id] = adapterHealth;
1822
- } catch (error) {
1823
- let errorMsg = error instanceof Error ? error.message : "Unknown error";
1824
- errorMsg = errorMsg.replace(/(:[^:@/]+@)/g, ":***@");
1825
- health["adapters"][id] = {
1826
- connected: false,
1827
- error: errorMsg
1828
- };
1829
- }
1830
- }
1831
- return {
1832
- content: [
1833
- {
1834
- type: "text",
1835
- text: JSON.stringify(health, null, 2)
1836
- }
1837
- ]
1838
- };
1839
- });
1840
- const listAdaptersOpts = {
1841
- title: "List Adapters",
1842
- description: "List all registered database adapters",
1843
- icons: SERVER_ICONS,
1844
- annotations: READ_ONLY
1845
- };
1846
- server.registerTool("list_adapters", listAdaptersOpts, () => {
1847
- const authCtx = getAuthContext();
1848
- if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "list_adapters")) {
1849
- throw new InsufficientScopeError(["read"], authCtx.scopes);
1850
- }
1851
- const adapters = [];
1852
- for (const [, adapter] of adaptersMap) {
1853
- adapters.push({
1854
- id: `${adapter.type}:default`,
1855
- type: adapter.type,
1856
- name: adapter.name,
1857
- version: adapter.version,
1858
- connected: adapter.isConnected()
1859
- });
1860
- }
1861
- return {
1862
- content: [
1863
- {
1864
- type: "text",
1865
- text: JSON.stringify(adapters, null, 2)
1866
- }
1867
- ]
1868
- };
1869
- });
1870
- registerToolScopes(
1871
- /* @__PURE__ */ new Map([
1872
- ["server_info", ["read"]],
1873
- ["server_health", ["read"]],
1874
- ["list_adapters", ["read"]]
1875
- ])
1876
- );
1877
- }
1878
-
1879
- // src/server/registration/help-resources.ts
1880
- function registerHelpResources(server, toolFilter) {
1881
- const gotchasContent = HELP_CONTENT.get("gotchas");
1882
- if (gotchasContent) {
1883
- server.registerResource(
1884
- "sqlite_help",
1885
- "sqlite://help",
1886
- {
1887
- description: "Critical gotchas, WASM vs Native comparison, and Code Mode API reference",
1888
- mimeType: "text/markdown",
1889
- annotations: ASSISTANT_FOCUSED
1890
- },
1891
- () => {
1892
- metrics.recordResourceRead("sqlite://help");
1893
- return {
1894
- contents: [
1895
- {
1896
- uri: "sqlite://help",
1897
- mimeType: "text/markdown",
1898
- text: gotchasContent
1899
- }
1900
- ]
1901
- };
1902
- }
1903
- );
1904
- }
1905
- const groupHelpKeys = [
1906
- { group: "core", key: "core" },
1907
- { group: "json", key: "json" },
1908
- { group: "text", key: "text" },
1909
- { group: "stats", key: "stats" },
1910
- { group: "vector", key: "vector" },
1911
- { group: "geo", key: "geo" },
1912
- { group: "admin", key: "admin" },
1913
- { group: "transactions", key: "transactions" },
1914
- { group: "introspection", key: "introspection" },
1915
- { group: "migration", key: "migration" }
1916
- ];
1917
- for (const { group, key } of groupHelpKeys) {
1918
- const isCodemodeOnly = toolFilter.enabledGroups.size === 1 && toolFilter.enabledGroups.has("codemode");
1919
- if (!toolFilter.enabledGroups.has(group) && !isCodemodeOnly) {
1920
- continue;
1921
- }
1922
- const content = HELP_CONTENT.get(key);
1923
- if (!content) continue;
1924
- server.registerResource(
1925
- `sqlite_help_${key}`,
1926
- `sqlite://help/${key}`,
1927
- {
1928
- description: `Tool reference for the ${group} tool group`,
1929
- mimeType: "text/markdown",
1930
- annotations: ASSISTANT_FOCUSED
1931
- },
1932
- () => {
1933
- metrics.recordResourceRead(`sqlite://help/${key}`);
1934
- return {
1935
- contents: [
1936
- {
1937
- uri: `sqlite://help/${key}`,
1938
- mimeType: "text/markdown",
1939
- text: content
1940
- }
1941
- ]
1942
- };
1943
- }
1944
- );
1945
- }
1946
- const registeredHelp = ["sqlite://help"];
1947
- for (const { group, key } of groupHelpKeys) {
1948
- if (toolFilter.enabledGroups.has(group)) {
1949
- registeredHelp.push(`sqlite://help/${key}`);
1950
- }
1951
- }
1952
- logger.info(`Help resources: ${registeredHelp.join(", ")}`, {
1953
- module: "SERVER"
1954
- });
1955
- }
1731
+ // src/server/registration/audit-tools/helpers.ts
1956
1732
  function redactSqlLiterals(text) {
1957
1733
  return text.replace(/'(?:''|[^'])*'/g, "'***'");
1958
1734
  }
@@ -1960,16 +1736,18 @@ function validateDdl(sql) {
1960
1736
  const cleanSql = sql.replace(/\/\*[\s\S]*?\*\//g, "").replace(/--.*$/gm, "");
1961
1737
  const upperSql = cleanSql.toUpperCase();
1962
1738
  if (upperSql.includes("ATTACH ") || upperSql.includes("DETACH ") || upperSql.includes("PRAGMA ") || upperSql.includes("LOAD_EXTENSION(")) {
1963
- throw new Error(
1739
+ throw new ValidationError(
1964
1740
  `DDL validation failed: unauthorized command or function call`
1965
1741
  );
1966
1742
  }
1967
1743
  if (upperSql.includes(" ON MAIN.") || upperSql.includes(" ON TEMP.")) {
1968
- throw new Error(
1744
+ throw new ValidationError(
1969
1745
  `DDL validation failed: trigger attempts to target a specific database`
1970
1746
  );
1971
1747
  }
1972
1748
  }
1749
+
1750
+ // src/server/registration/audit-tools/resource.ts
1973
1751
  function registerAuditResource(server, auditLogger, backupManager) {
1974
1752
  if (!auditLogger) return;
1975
1753
  server.registerResource(
@@ -2012,12 +1790,13 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2012
1790
  description: "List pre-mutation DDL snapshots captured before destructive operations. Returns metadata for each snapshot including timestamp, tool, target, and size.",
2013
1791
  inputSchema: AuditListBackupsSchema,
2014
1792
  outputSchema: AuditListBackupsOutputSchema,
2015
- annotations: {
1793
+ annotations: toSDK({
2016
1794
  readOnlyHint: true,
2017
1795
  destructiveHint: false,
2018
1796
  idempotentHint: true,
2019
- openWorldHint: false
2020
- }
1797
+ openWorldHint: false,
1798
+ sensitiveHint: true
1799
+ })
2021
1800
  },
2022
1801
  async (args) => {
2023
1802
  const authCtx = getAuthContext();
@@ -2079,12 +1858,13 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2079
1858
  filename: z.string().default("").describe("Snapshot filename from sqlite_audit_list_backups results")
2080
1859
  }),
2081
1860
  outputSchema: AuditGetBackupOutputSchema,
2082
- annotations: {
1861
+ annotations: toSDK({
2083
1862
  readOnlyHint: true,
2084
1863
  destructiveHint: false,
2085
1864
  idempotentHint: true,
2086
- openWorldHint: false
2087
- }
1865
+ openWorldHint: false,
1866
+ sensitiveHint: true
1867
+ })
2088
1868
  },
2089
1869
  async (args) => {
2090
1870
  const authCtx = getAuthContext();
@@ -2112,7 +1892,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2112
1892
  if (!snapshot) {
2113
1893
  const errRes = {
2114
1894
  success: false,
2115
- error: `Snapshot not found: ${filename}`
1895
+ error: `Snapshot not found: ${filename}`,
1896
+ code: "NOT_FOUND",
1897
+ category: "not_found"
2116
1898
  };
2117
1899
  return {
2118
1900
  content: [
@@ -2144,12 +1926,13 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2144
1926
  title: "Cleanup Audit Backups",
2145
1927
  description: "Apply retention policy to audit backup snapshots. Deletes snapshots exceeding age or count limits.",
2146
1928
  outputSchema: AuditCleanupOutputSchema,
2147
- annotations: {
1929
+ annotations: toSDK({
2148
1930
  readOnlyHint: false,
2149
1931
  destructiveHint: true,
2150
1932
  idempotentHint: true,
2151
- openWorldHint: false
2152
- }
1933
+ openWorldHint: false,
1934
+ sensitiveHint: true
1935
+ })
2153
1936
  },
2154
1937
  async () => {
2155
1938
  const authCtx = getAuthContext();
@@ -2184,12 +1967,13 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2184
1967
  )
2185
1968
  }),
2186
1969
  outputSchema: AuditDiffBackupOutputSchema,
2187
- annotations: {
1970
+ annotations: toSDK({
2188
1971
  readOnlyHint: true,
2189
1972
  destructiveHint: false,
2190
1973
  idempotentHint: true,
2191
- openWorldHint: false
2192
- }
1974
+ openWorldHint: false,
1975
+ sensitiveHint: true
1976
+ })
2193
1977
  },
2194
1978
  async (args) => {
2195
1979
  const authCtx = getAuthContext();
@@ -2217,7 +2001,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2217
2001
  if (!snapshot) {
2218
2002
  const errRes = {
2219
2003
  success: false,
2220
- error: `Snapshot not found: ${filename}`
2004
+ error: `Snapshot not found: ${filename}`,
2005
+ code: "NOT_FOUND",
2006
+ category: "not_found"
2221
2007
  };
2222
2008
  return {
2223
2009
  content: [
@@ -2234,7 +2020,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2234
2020
  if (!adapter) {
2235
2021
  const errRes = {
2236
2022
  success: false,
2237
- error: "No connected adapter available"
2023
+ error: "No connected adapter available",
2024
+ code: "INTERNAL_ERROR",
2025
+ category: "internal"
2238
2026
  };
2239
2027
  return {
2240
2028
  content: [
@@ -2323,19 +2111,16 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2323
2111
  structuredContent: result
2324
2112
  };
2325
2113
  } catch (error) {
2326
- const errRes = {
2327
- success: false,
2328
- error: error instanceof Error ? error.message : String(error)
2329
- };
2114
+ const structured = formatHandlerError(error);
2330
2115
  return {
2331
2116
  content: [
2332
2117
  {
2333
2118
  type: "text",
2334
- text: JSON.stringify(errRes, null, 2)
2119
+ text: JSON.stringify(structured, null, 2)
2335
2120
  }
2336
2121
  ],
2337
2122
  isError: true,
2338
- structuredContent: errRes
2123
+ structuredContent: structured
2339
2124
  };
2340
2125
  }
2341
2126
  }
@@ -2350,12 +2135,13 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2350
2135
  dryRun: z.unknown().optional().describe("If true, returns the DDL without executing it (boolean)")
2351
2136
  }),
2352
2137
  outputSchema: AuditRestoreBackupOutputSchema,
2353
- annotations: {
2138
+ annotations: toSDK({
2354
2139
  readOnlyHint: false,
2355
2140
  destructiveHint: true,
2356
2141
  idempotentHint: false,
2357
- openWorldHint: false
2358
- }
2142
+ openWorldHint: false,
2143
+ sensitiveHint: true
2144
+ })
2359
2145
  },
2360
2146
  async (args) => {
2361
2147
  const authCtx = getAuthContext();
@@ -2388,7 +2174,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2388
2174
  if (!snapshot) {
2389
2175
  const errRes = {
2390
2176
  success: false,
2391
- error: `Snapshot not found: ${filename}`
2177
+ error: `Snapshot not found: ${filename}`,
2178
+ code: "NOT_FOUND",
2179
+ category: "not_found"
2392
2180
  };
2393
2181
  return {
2394
2182
  content: [
@@ -2405,7 +2193,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2405
2193
  if (!ddl.trim()) {
2406
2194
  const errRes = {
2407
2195
  success: false,
2408
- error: "Snapshot contains no DDL statements"
2196
+ error: "Snapshot contains no DDL statements",
2197
+ code: "VALIDATION_ERROR",
2198
+ category: "validation"
2409
2199
  };
2410
2200
  return {
2411
2201
  content: [
@@ -2422,7 +2212,9 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2422
2212
  if (!adapter) {
2423
2213
  const errRes = {
2424
2214
  success: false,
2425
- error: "No connected adapter available"
2215
+ error: "No connected adapter available",
2216
+ code: "INTERNAL_ERROR",
2217
+ category: "internal"
2426
2218
  };
2427
2219
  return {
2428
2220
  content: [
@@ -2499,19 +2291,16 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2499
2291
  structuredContent: result
2500
2292
  };
2501
2293
  } catch (error) {
2502
- const errRes = {
2503
- success: false,
2504
- error: error instanceof Error ? error.message : String(error)
2505
- };
2294
+ const structured = formatHandlerError(error);
2506
2295
  return {
2507
2296
  content: [
2508
2297
  {
2509
2298
  type: "text",
2510
- text: JSON.stringify(errRes, null, 2)
2299
+ text: JSON.stringify(structured, null, 2)
2511
2300
  }
2512
2301
  ],
2513
2302
  isError: true,
2514
- structuredContent: errRes
2303
+ structuredContent: structured
2515
2304
  };
2516
2305
  }
2517
2306
  }
@@ -2530,6 +2319,8 @@ function registerAuditBackupTools(server, backupManager, adaptersMap) {
2530
2319
  { module: "AUDIT" }
2531
2320
  );
2532
2321
  }
2322
+
2323
+ // src/server/registration/audit-tools/search.ts
2533
2324
  function registerAuditSearchTool(server, auditLogger) {
2534
2325
  if (!auditLogger) return;
2535
2326
  server.registerTool(
@@ -2539,21 +2330,44 @@ function registerAuditSearchTool(server, auditLogger) {
2539
2330
  description: "Search and filter structured audit logs from the System Database. Returns recent tool invocations, outcomes, token estimates, and parameters.",
2540
2331
  inputSchema: AuditSearchSchema,
2541
2332
  outputSchema: AuditSearchOutputSchema,
2542
- annotations: {
2333
+ annotations: toSDK({
2543
2334
  readOnlyHint: true,
2544
2335
  destructiveHint: false,
2545
2336
  idempotentHint: true,
2546
- openWorldHint: false
2547
- }
2337
+ openWorldHint: false,
2338
+ sensitiveHint: true
2339
+ })
2548
2340
  },
2549
2341
  async (args) => {
2550
- const authCtx = getAuthContext();
2551
- if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "sqlite_audit_search")) {
2552
- throw new InsufficientScopeError(["admin", "full"], authCtx.scopes);
2553
- }
2554
- let parsed;
2555
2342
  try {
2556
- parsed = AuditSearchSchema.parse(args ?? {});
2343
+ const authCtx = getAuthContext();
2344
+ if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "sqlite_audit_search")) {
2345
+ throw new InsufficientScopeError(["admin", "full"], authCtx.scopes);
2346
+ }
2347
+ const parsed = AuditSearchSchema.parse(args ?? {});
2348
+ const { entries, totalCount } = await auditLogger.search(parsed);
2349
+ const result = {
2350
+ success: true,
2351
+ entries,
2352
+ count: entries.length,
2353
+ totalCount
2354
+ };
2355
+ const tokenEstimate = Math.ceil(
2356
+ Buffer.byteLength(JSON.stringify(result), "utf8") / 4
2357
+ );
2358
+ return {
2359
+ content: [
2360
+ {
2361
+ type: "text",
2362
+ text: JSON.stringify(
2363
+ { ...result, _meta: { tokenEstimate } },
2364
+ null,
2365
+ 2
2366
+ )
2367
+ }
2368
+ ],
2369
+ structuredContent: result
2370
+ };
2557
2371
  } catch (error) {
2558
2372
  const structured = formatHandlerError(error);
2559
2373
  return {
@@ -2567,29 +2381,6 @@ function registerAuditSearchTool(server, auditLogger) {
2567
2381
  structuredContent: structured
2568
2382
  };
2569
2383
  }
2570
- const { entries, totalCount } = await auditLogger.search(parsed);
2571
- const result = {
2572
- success: true,
2573
- entries,
2574
- count: entries.length,
2575
- totalCount
2576
- };
2577
- const tokenEstimate = Math.ceil(
2578
- Buffer.byteLength(JSON.stringify(result), "utf8") / 4
2579
- );
2580
- return {
2581
- content: [
2582
- {
2583
- type: "text",
2584
- text: JSON.stringify(
2585
- { ...result, _meta: { tokenEstimate } },
2586
- null,
2587
- 2
2588
- )
2589
- }
2590
- ],
2591
- structuredContent: result
2592
- };
2593
2384
  }
2594
2385
  );
2595
2386
  registerToolScopes(/* @__PURE__ */ new Map([["sqlite_audit_search", ["admin", "full"]]]));
@@ -2598,6 +2389,203 @@ function registerAuditSearchTool(server, auditLogger) {
2598
2389
  });
2599
2390
  }
2600
2391
 
2392
+ // src/server/registration/built-in-tools.ts
2393
+ function registerBuiltInTools(server, adaptersMap, config, toolFilter) {
2394
+ const serverInfoOpts = {
2395
+ title: "Server Info",
2396
+ description: "Get information about the db-mcp server and registered adapters",
2397
+ icons: SERVER_ICONS,
2398
+ annotations: READ_ONLY
2399
+ };
2400
+ server.registerTool("server_info", serverInfoOpts, () => {
2401
+ const authCtx = getAuthContext();
2402
+ if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "server_info")) {
2403
+ throw new InsufficientScopeError(["read"], authCtx.scopes);
2404
+ }
2405
+ const adapterInfo = [];
2406
+ for (const [id, adapter] of adaptersMap) {
2407
+ adapterInfo.push({
2408
+ id,
2409
+ ...adapter.getInfo()
2410
+ });
2411
+ }
2412
+ return {
2413
+ content: [
2414
+ {
2415
+ type: "text",
2416
+ text: JSON.stringify(
2417
+ {
2418
+ name: config.name,
2419
+ version: config.version,
2420
+ transport: config.transport,
2421
+ adapters: adapterInfo,
2422
+ toolFilter: {
2423
+ raw: toolFilter.raw,
2424
+ enabledGroups: [...toolFilter.enabledGroups]
2425
+ }
2426
+ },
2427
+ null,
2428
+ 2
2429
+ )
2430
+ }
2431
+ ]
2432
+ };
2433
+ });
2434
+ const healthOpts = {
2435
+ title: "Server Health",
2436
+ description: "Check health status of all database connections",
2437
+ icons: SERVER_ICONS,
2438
+ annotations: READ_ONLY
2439
+ };
2440
+ server.registerTool("server_health", healthOpts, async () => {
2441
+ const authCtx = getAuthContext();
2442
+ if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "server_health")) {
2443
+ throw new InsufficientScopeError(["read"], authCtx.scopes);
2444
+ }
2445
+ const health = {
2446
+ server: "healthy",
2447
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
2448
+ adapters: {}
2449
+ };
2450
+ for (const [id, adapter] of adaptersMap) {
2451
+ try {
2452
+ const adapterHealth = await adapter.getHealth();
2453
+ health["adapters"][id] = adapterHealth;
2454
+ } catch (error) {
2455
+ let errorMsg = error instanceof Error ? error.message : "Unknown error";
2456
+ errorMsg = errorMsg.replace(/(:[^:@/]+@)/g, ":***@");
2457
+ health["adapters"][id] = {
2458
+ connected: false,
2459
+ error: errorMsg
2460
+ };
2461
+ }
2462
+ }
2463
+ return {
2464
+ content: [
2465
+ {
2466
+ type: "text",
2467
+ text: JSON.stringify(health, null, 2)
2468
+ }
2469
+ ]
2470
+ };
2471
+ });
2472
+ const listAdaptersOpts = {
2473
+ title: "List Adapters",
2474
+ description: "List all registered database adapters",
2475
+ icons: SERVER_ICONS,
2476
+ annotations: READ_ONLY
2477
+ };
2478
+ server.registerTool("list_adapters", listAdaptersOpts, () => {
2479
+ const authCtx = getAuthContext();
2480
+ if (authCtx && !scopesGrantToolAccess(authCtx.scopes, "list_adapters")) {
2481
+ throw new InsufficientScopeError(["read"], authCtx.scopes);
2482
+ }
2483
+ const adapters = [];
2484
+ for (const [, adapter] of adaptersMap) {
2485
+ adapters.push({
2486
+ id: `${adapter.type}:default`,
2487
+ type: adapter.type,
2488
+ name: adapter.name,
2489
+ version: adapter.version,
2490
+ connected: adapter.isConnected()
2491
+ });
2492
+ }
2493
+ return {
2494
+ content: [
2495
+ {
2496
+ type: "text",
2497
+ text: JSON.stringify(adapters, null, 2)
2498
+ }
2499
+ ]
2500
+ };
2501
+ });
2502
+ registerToolScopes(
2503
+ /* @__PURE__ */ new Map([
2504
+ ["server_info", ["read"]],
2505
+ ["server_health", ["read"]],
2506
+ ["list_adapters", ["read"]]
2507
+ ])
2508
+ );
2509
+ }
2510
+
2511
+ // src/server/registration/help-resources.ts
2512
+ function registerHelpResources(server, toolFilter) {
2513
+ const gotchasContent = HELP_CONTENT.get("gotchas");
2514
+ if (gotchasContent) {
2515
+ server.registerResource(
2516
+ "sqlite_help",
2517
+ "sqlite://help",
2518
+ {
2519
+ description: "Critical gotchas, WASM vs Native comparison, and Code Mode API reference",
2520
+ mimeType: "text/markdown",
2521
+ annotations: ASSISTANT_FOCUSED
2522
+ },
2523
+ () => {
2524
+ metrics.recordResourceRead("sqlite://help");
2525
+ return {
2526
+ contents: [
2527
+ {
2528
+ uri: "sqlite://help",
2529
+ mimeType: "text/markdown",
2530
+ text: gotchasContent
2531
+ }
2532
+ ]
2533
+ };
2534
+ }
2535
+ );
2536
+ }
2537
+ const groupHelpKeys = [
2538
+ { group: "core", key: "core" },
2539
+ { group: "json", key: "json" },
2540
+ { group: "text", key: "text" },
2541
+ { group: "stats", key: "stats" },
2542
+ { group: "vector", key: "vector" },
2543
+ { group: "geo", key: "geo" },
2544
+ { group: "admin", key: "admin" },
2545
+ { group: "transactions", key: "transactions" },
2546
+ { group: "introspection", key: "introspection" },
2547
+ { group: "migration", key: "migration" }
2548
+ ];
2549
+ for (const { group, key } of groupHelpKeys) {
2550
+ const isCodemodeOnly = toolFilter.enabledGroups.size === 1 && toolFilter.enabledGroups.has("codemode");
2551
+ if (!toolFilter.enabledGroups.has(group) && !isCodemodeOnly) {
2552
+ continue;
2553
+ }
2554
+ const content = HELP_CONTENT.get(key);
2555
+ if (!content) continue;
2556
+ server.registerResource(
2557
+ `sqlite_help_${key}`,
2558
+ `sqlite://help/${key}`,
2559
+ {
2560
+ description: `Tool reference for the ${group} tool group`,
2561
+ mimeType: "text/markdown",
2562
+ annotations: ASSISTANT_FOCUSED
2563
+ },
2564
+ () => {
2565
+ metrics.recordResourceRead(`sqlite://help/${key}`);
2566
+ return {
2567
+ contents: [
2568
+ {
2569
+ uri: `sqlite://help/${key}`,
2570
+ mimeType: "text/markdown",
2571
+ text: content
2572
+ }
2573
+ ]
2574
+ };
2575
+ }
2576
+ );
2577
+ }
2578
+ const registeredHelp = ["sqlite://help"];
2579
+ for (const { group, key } of groupHelpKeys) {
2580
+ if (toolFilter.enabledGroups.has(group)) {
2581
+ registeredHelp.push(`sqlite://help/${key}`);
2582
+ }
2583
+ }
2584
+ logger.info(`Help resources: ${registeredHelp.join(", ")}`, {
2585
+ module: "SERVER"
2586
+ });
2587
+ }
2588
+
2601
2589
  // src/server/registration/observability-resources.ts
2602
2590
  function registerObservabilityResources(server) {
2603
2591
  server.registerResource(
@@ -2634,12 +2622,13 @@ function registerAdminTools(server) {
2634
2622
  "The new value for the setting (e.g., 'debug', 'info', 'warning')"
2635
2623
  )
2636
2624
  }),
2637
- annotations: {
2625
+ annotations: toSDK({
2638
2626
  readOnlyHint: false,
2639
2627
  destructiveHint: false,
2640
2628
  idempotentHint: false,
2641
- openWorldHint: false
2642
- }
2629
+ openWorldHint: false,
2630
+ sensitiveHint: true
2631
+ })
2643
2632
  },
2644
2633
  (args) => {
2645
2634
  const authCtx = getAuthContext();
@@ -2693,7 +2682,8 @@ function registerAdminTools(server) {
2693
2682
  {
2694
2683
  success: false,
2695
2684
  error: `Invalid log level: ${value}. Must be one of: ${validLevels.join(", ")}`,
2696
- code: "INVALID_CONFIG"
2685
+ code: "INVALID_CONFIG",
2686
+ category: "validation"
2697
2687
  },
2698
2688
  null,
2699
2689
  2
@@ -2734,7 +2724,8 @@ function registerAdminTools(server) {
2734
2724
  {
2735
2725
  success: false,
2736
2726
  error: "Missing setting or value for set action",
2737
- code: "INVALID_CONFIG"
2727
+ code: "INVALID_CONFIG",
2728
+ category: "validation"
2738
2729
  },
2739
2730
  null,
2740
2731
  2
@@ -2748,27 +2739,27 @@ function registerAdminTools(server) {
2748
2739
  content: [
2749
2740
  {
2750
2741
  type: "text",
2751
- text: JSON.stringify({ success: false, error: "Invalid action" })
2742
+ text: JSON.stringify({
2743
+ success: false,
2744
+ error: "Invalid action",
2745
+ code: "INVALID_CONFIG",
2746
+ category: "validation"
2747
+ })
2752
2748
  }
2753
2749
  ],
2754
2750
  isError: true
2755
2751
  };
2756
2752
  } catch (error) {
2753
+ const structured = formatHandlerError(error);
2757
2754
  return {
2758
2755
  content: [
2759
2756
  {
2760
2757
  type: "text",
2761
- text: JSON.stringify(
2762
- {
2763
- success: false,
2764
- error: error instanceof Error ? error.message : String(error)
2765
- },
2766
- null,
2767
- 2
2768
- )
2758
+ text: JSON.stringify(structured, null, 2)
2769
2759
  }
2770
2760
  ],
2771
- isError: true
2761
+ isError: true,
2762
+ structuredContent: structured
2772
2763
  };
2773
2764
  }
2774
2765
  }
@@ -2908,7 +2899,7 @@ if (typeof proto["createToolError"] === "function") {
2908
2899
  success: false,
2909
2900
  error: cleanError,
2910
2901
  code: "VALIDATION_ERROR",
2911
- category: "validation" /* VALIDATION */
2902
+ category: ErrorCategory.VALIDATION
2912
2903
  };
2913
2904
  result.content[0].text = JSON.stringify(structured, null, 2);
2914
2905
  result.isError = true;
@@ -2930,6 +2921,25 @@ var DbMcpServer = class {
2930
2921
  subscriptionManager;
2931
2922
  constructor(config) {
2932
2923
  this.config = config;
2924
+ let allowedIoRoots = config.allowedIoRoots;
2925
+ if (!allowedIoRoots) {
2926
+ if (config.transport === "http") {
2927
+ const errorMsg = `FATAL: Refusing to bind HTTP transport without explicit ALLOWED_IO_ROOTS. You MUST specify --allowed-io-roots (or ALLOWED_IO_ROOTS env var) to prevent ambient filesystem authority.`;
2928
+ logger.error(errorMsg, { module: "SERVER" });
2929
+ process.exit(1);
2930
+ }
2931
+ allowedIoRoots = [];
2932
+ logger.warning(
2933
+ "\u26A0\uFE0F SECURITY WARNING: ALLOWED_IO_ROOTS not explicitly provided. Defaulting to empty array (NO filesystem access). You MUST specify --allowed-io-roots (or ALLOWED_IO_ROOTS env var) to enable filesystem tools.",
2934
+ { module: "SERVER" }
2935
+ );
2936
+ } else {
2937
+ logger.info("IO sandbox configured", {
2938
+ module: "SERVER",
2939
+ allowedRoots: allowedIoRoots
2940
+ });
2941
+ }
2942
+ this.config.allowedIoRoots = allowedIoRoots;
2933
2943
  this.toolFilter = config.toolFilter ? parseToolFilter(config.toolFilter) : getToolFilterFromEnv();
2934
2944
  this.server = new McpServer(
2935
2945
  {
@@ -2961,7 +2971,7 @@ var DbMcpServer = class {
2961
2971
  if (!["sqlite://schema", "sqlite://tables", "sqlite://health"].includes(
2962
2972
  uri
2963
2973
  ) && !uri.startsWith("sqlite://table/")) {
2964
- throw new Error(`Resource ${uri} is not subscribable`);
2974
+ throw new ValidationError(`Resource ${uri} is not subscribable`);
2965
2975
  }
2966
2976
  this.subscriptionManager.subscribe(
2967
2977
  uri,
@@ -3010,7 +3020,7 @@ var DbMcpServer = class {
3010
3020
  throw new DbMcpError(
3011
3021
  "Security: SDK _requestHandlers monkey-patch failed. Scope filtering is disabled.",
3012
3022
  "SERVER_START_FAILED",
3013
- "internal" /* INTERNAL */
3023
+ ErrorCategory.INTERNAL
3014
3024
  );
3015
3025
  }
3016
3026
  const originalListToolsHandler = handlers.get("tools/list");
@@ -3045,6 +3055,9 @@ var DbMcpServer = class {
3045
3055
  }
3046
3056
  await adapter.connect(config);
3047
3057
  this.adapters.set(adapterId, adapter);
3058
+ if ("setAllowedIoRoots" in adapter) {
3059
+ adapter.setAllowedIoRoots(this.config.allowedIoRoots);
3060
+ }
3048
3061
  if (this.auditInterceptor && "setAuditInterceptor" in adapter) {
3049
3062
  adapter.setAuditInterceptor(this.auditInterceptor);
3050
3063
  this.auditInterceptor.setQueryAdapter({
@@ -3100,7 +3113,7 @@ var DbMcpServer = class {
3100
3113
  throw new DbMcpError(
3101
3114
  `Unsupported transport: ${this.config.transport}`,
3102
3115
  "SERVER_START_FAILED",
3103
- "config" /* CONFIGURATION */
3116
+ ErrorCategory.CONFIGURATION
3104
3117
  );
3105
3118
  }
3106
3119
  }
@@ -3122,7 +3135,7 @@ var DbMcpServer = class {
3122
3135
  * Start server with HTTP transport (Streamable HTTP with SSE support)
3123
3136
  */
3124
3137
  async startHttp() {
3125
- const { HttpTransport } = await import('./http-2WGR3E5K.js');
3138
+ const { HttpTransport } = await import('./http-2XDGZF4F.js');
3126
3139
  const oauthConfig = {
3127
3140
  enabled: this.config.oauth?.enabled ?? false,
3128
3141
  authorizationServerUrl: this.config.oauth?.authorizationServerUrl ?? "",