db-mcp 3.0.2 → 5.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 (183) hide show
  1. package/README.md +112 -75
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/adapters/database-adapter.d.ts +11 -1
  4. package/dist/adapters/database-adapter.d.ts.map +1 -1
  5. package/dist/adapters/registration/resources.d.ts.map +1 -1
  6. package/dist/adapters/registration/tools.d.ts.map +1 -1
  7. package/dist/adapters/sqlite/prompts/analysis.d.ts.map +1 -1
  8. package/dist/adapters/sqlite/query-executor.d.ts.map +1 -1
  9. package/dist/adapters/sqlite/read-write-lock.d.ts +49 -0
  10. package/dist/adapters/sqlite/read-write-lock.d.ts.map +1 -0
  11. package/dist/adapters/sqlite/resources.d.ts +1 -1
  12. package/dist/adapters/sqlite/resources.d.ts.map +1 -1
  13. package/dist/adapters/sqlite/schemas/admin.d.ts +33 -19
  14. package/dist/adapters/sqlite/schemas/admin.d.ts.map +1 -1
  15. package/dist/adapters/sqlite/schemas/core.d.ts +96 -0
  16. package/dist/adapters/sqlite/schemas/core.d.ts.map +1 -1
  17. package/dist/adapters/sqlite/schemas/fts.d.ts +4 -0
  18. package/dist/adapters/sqlite/schemas/fts.d.ts.map +1 -1
  19. package/dist/adapters/sqlite/schemas/introspection.d.ts +25 -15
  20. package/dist/adapters/sqlite/schemas/introspection.d.ts.map +1 -1
  21. package/dist/adapters/sqlite/schemas/migration.d.ts +2 -2
  22. package/dist/adapters/sqlite/schemas/migration.d.ts.map +1 -1
  23. package/dist/adapters/sqlite/schemas/spatialite.d.ts +1 -0
  24. package/dist/adapters/sqlite/schemas/spatialite.d.ts.map +1 -1
  25. package/dist/adapters/sqlite/schemas/text.d.ts +36 -0
  26. package/dist/adapters/sqlite/schemas/text.d.ts.map +1 -1
  27. package/dist/adapters/sqlite/sqlite-adapter.d.ts +6 -0
  28. package/dist/adapters/sqlite/sqlite-adapter.d.ts.map +1 -1
  29. package/dist/adapters/sqlite/tools/admin/backup/create.d.ts.map +1 -1
  30. package/dist/adapters/sqlite/tools/admin/backup/dump.d.ts.map +1 -1
  31. package/dist/adapters/sqlite/tools/admin/backup/restore.d.ts.map +1 -1
  32. package/dist/adapters/sqlite/tools/admin/index.d.ts.map +1 -1
  33. package/dist/adapters/sqlite/tools/admin/pragma.d.ts +0 -4
  34. package/dist/adapters/sqlite/tools/admin/pragma.d.ts.map +1 -1
  35. package/dist/adapters/sqlite/tools/admin/verify.d.ts.map +1 -1
  36. package/dist/adapters/sqlite/tools/codemode.d.ts.map +1 -1
  37. package/dist/adapters/sqlite/tools/core/convenience.d.ts.map +1 -1
  38. package/dist/adapters/sqlite/tools/core/index.d.ts.map +1 -1
  39. package/dist/adapters/sqlite/tools/core/queries.d.ts.map +1 -1
  40. package/dist/adapters/sqlite/tools/core/tables.d.ts.map +1 -1
  41. package/dist/adapters/sqlite/tools/core/versioning.d.ts +19 -0
  42. package/dist/adapters/sqlite/tools/core/versioning.d.ts.map +1 -0
  43. package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -1
  44. package/dist/adapters/sqlite/tools/introspection/diagnostics/indexes.d.ts.map +1 -1
  45. package/dist/adapters/sqlite/tools/introspection/graph/tools.d.ts.map +1 -1
  46. package/dist/adapters/sqlite/tools/json-helpers/read.d.ts.map +1 -1
  47. package/dist/adapters/sqlite/tools/json-operations/crud.d.ts.map +1 -1
  48. package/dist/adapters/sqlite/tools/json-operations/query.d.ts.map +1 -1
  49. package/dist/adapters/sqlite/tools/migration/helpers.d.ts.map +1 -1
  50. package/dist/adapters/sqlite/tools/text/helpers.d.ts +9 -0
  51. package/dist/adapters/sqlite/tools/text/helpers.d.ts.map +1 -1
  52. package/dist/adapters/sqlite/tools/text/index.d.ts.map +1 -1
  53. package/dist/adapters/sqlite/tools/text/search.d.ts +4 -0
  54. package/dist/adapters/sqlite/tools/text/search.d.ts.map +1 -1
  55. package/dist/adapters/sqlite/tools/vector/metadata.d.ts.map +1 -1
  56. package/dist/adapters/sqlite/tools/vector/search.d.ts.map +1 -1
  57. package/dist/adapters/sqlite/tools/vector/storage.d.ts.map +1 -1
  58. package/dist/adapters/sqlite/tools/virtual/vtable/analyze-csv.d.ts.map +1 -1
  59. package/dist/adapters/sqlite/tools/virtual/vtable/csv.d.ts.map +1 -1
  60. package/dist/adapters/sqlite/tools/virtual/vtable/info.d.ts.map +1 -1
  61. package/dist/adapters/sqlite/types.d.ts +5 -1
  62. package/dist/adapters/sqlite/types.d.ts.map +1 -1
  63. package/dist/adapters/sqlite-native/index.d.ts +1 -1
  64. package/dist/adapters/sqlite-native/index.d.ts.map +1 -1
  65. package/dist/adapters/sqlite-native/native-sqlite-adapter.d.ts.map +1 -1
  66. package/dist/adapters/sqlite-native/tools/spatialite/tools.d.ts.map +1 -1
  67. package/dist/adapters/sqlite-native/tools/window/helpers.d.ts +52 -0
  68. package/dist/adapters/sqlite-native/tools/window/helpers.d.ts.map +1 -0
  69. package/dist/adapters/sqlite-native/tools/window/index.d.ts +7 -0
  70. package/dist/adapters/sqlite-native/tools/window/index.d.ts.map +1 -0
  71. package/dist/adapters/sqlite-native/tools/window/lag-lead.d.ts +7 -0
  72. package/dist/adapters/sqlite-native/tools/window/lag-lead.d.ts.map +1 -0
  73. package/dist/adapters/sqlite-native/tools/window/moving-average.d.ts +7 -0
  74. package/dist/adapters/sqlite-native/tools/window/moving-average.d.ts.map +1 -0
  75. package/dist/adapters/sqlite-native/tools/window/ntile.d.ts +7 -0
  76. package/dist/adapters/sqlite-native/tools/window/ntile.d.ts.map +1 -0
  77. package/dist/adapters/sqlite-native/tools/window/rank.d.ts +7 -0
  78. package/dist/adapters/sqlite-native/tools/window/rank.d.ts.map +1 -0
  79. package/dist/adapters/sqlite-native/tools/window/row-number.d.ts +7 -0
  80. package/dist/adapters/sqlite-native/tools/window/row-number.d.ts.map +1 -0
  81. package/dist/adapters/sqlite-native/tools/window/running-total.d.ts +7 -0
  82. package/dist/adapters/sqlite-native/tools/window/running-total.d.ts.map +1 -0
  83. package/dist/adapters/sqlite-native/tools/window/schemas.d.ts +159 -0
  84. package/dist/adapters/sqlite-native/tools/window/schemas.d.ts.map +1 -0
  85. package/dist/adapters/sqlite-native/transaction-methods.d.ts.map +1 -1
  86. package/dist/audit/interceptor.d.ts.map +1 -1
  87. package/dist/audit/logger.d.ts +26 -25
  88. package/dist/audit/logger.d.ts.map +1 -1
  89. package/dist/auth/authorization-server-discovery.d.ts.map +1 -1
  90. package/dist/auth/scopes/mapping.d.ts.map +1 -1
  91. package/dist/auth/token-validator.d.ts.map +1 -1
  92. package/dist/{chunk-W5WQVNVX.js → chunk-27C5EE6U.js} +23 -17
  93. package/dist/chunk-2TYICG7B.js +1183 -0
  94. package/dist/{chunk-37G4DLL6.js → chunk-LLIAIJPO.js} +1146 -539
  95. package/dist/{chunk-NV34JSQM.js → chunk-UE7GVOBV.js} +1757 -1331
  96. package/dist/{chunk-L552U3QS.js → chunk-XLIYO3YA.js} +401 -77
  97. package/dist/cli.js +116 -11
  98. package/dist/codemode/api-constants.d.ts.map +1 -1
  99. package/dist/codemode/api.d.ts.map +1 -1
  100. package/dist/codemode/sandbox-factory.d.ts.map +1 -1
  101. package/dist/codemode/sandbox.d.ts +0 -3
  102. package/dist/codemode/sandbox.d.ts.map +1 -1
  103. package/dist/codemode/security.d.ts.map +1 -1
  104. package/dist/codemode/types.d.ts +2 -0
  105. package/dist/codemode/types.d.ts.map +1 -1
  106. package/dist/constants/server-instructions.d.ts +1 -1
  107. package/dist/constants/server-instructions.d.ts.map +1 -1
  108. package/dist/filtering/tool-constants.d.ts +11 -11
  109. package/dist/filtering/tool-constants.d.ts.map +1 -1
  110. package/dist/{http-HWTUVFIA.js → http-ZDMK46QU.js} +195 -32
  111. package/dist/index.js +4 -4
  112. package/dist/observability/metrics.d.ts +36 -0
  113. package/dist/observability/metrics.d.ts.map +1 -0
  114. package/dist/observability/system-db.d.ts +13 -0
  115. package/dist/observability/system-db.d.ts.map +1 -0
  116. package/dist/server/mcp-server.d.ts +3 -0
  117. package/dist/server/mcp-server.d.ts.map +1 -1
  118. package/dist/server/registration/admin-tools.d.ts +6 -0
  119. package/dist/server/registration/admin-tools.d.ts.map +1 -0
  120. package/dist/server/registration/audit-tools/backup.d.ts +8 -0
  121. package/dist/server/registration/audit-tools/backup.d.ts.map +1 -0
  122. package/dist/server/registration/audit-tools/helpers.d.ts +11 -0
  123. package/dist/server/registration/audit-tools/helpers.d.ts.map +1 -0
  124. package/dist/server/registration/audit-tools/index.d.ts +4 -0
  125. package/dist/server/registration/audit-tools/index.d.ts.map +1 -0
  126. package/dist/server/registration/audit-tools/resource.d.ts +8 -0
  127. package/dist/server/registration/audit-tools/resource.d.ts.map +1 -0
  128. package/dist/server/registration/audit-tools/search.d.ts +7 -0
  129. package/dist/server/registration/audit-tools/search.d.ts.map +1 -0
  130. package/dist/server/registration/help-resources.d.ts.map +1 -1
  131. package/dist/server/registration/index.d.ts +3 -1
  132. package/dist/server/registration/index.d.ts.map +1 -1
  133. package/dist/server/registration/observability-resources.d.ts +11 -0
  134. package/dist/server/registration/observability-resources.d.ts.map +1 -0
  135. package/dist/server/subscription-manager.d.ts +35 -0
  136. package/dist/server/subscription-manager.d.ts.map +1 -0
  137. package/dist/{sqlite-TB56Z7G3.js → sqlite-XWZPEZJO.js} +195 -19
  138. package/dist/{sqlite-native-IF75BB3O.js → sqlite-native-5GQ3WKCZ.js} +311 -147
  139. package/dist/transports/http/middleware.d.ts.map +1 -1
  140. package/dist/transports/http/oauth.d.ts.map +1 -1
  141. package/dist/transports/http/sessions/legacy-sse.d.ts.map +1 -1
  142. package/dist/transports/http/sessions/stateful.d.ts +5 -1
  143. package/dist/transports/http/sessions/stateful.d.ts.map +1 -1
  144. package/dist/transports/http/transport.d.ts +2 -0
  145. package/dist/transports/http/transport.d.ts.map +1 -1
  146. package/dist/transports/http/types.d.ts +11 -0
  147. package/dist/transports/http/types.d.ts.map +1 -1
  148. package/dist/types/auth.d.ts +4 -0
  149. package/dist/types/auth.d.ts.map +1 -1
  150. package/dist/types/server.d.ts +5 -0
  151. package/dist/types/server.d.ts.map +1 -1
  152. package/dist/utils/annotations.d.ts +8 -0
  153. package/dist/utils/annotations.d.ts.map +1 -1
  154. package/dist/utils/errors/categories.d.ts +16 -11
  155. package/dist/utils/errors/categories.d.ts.map +1 -1
  156. package/dist/utils/errors/classes.d.ts +37 -0
  157. package/dist/utils/errors/classes.d.ts.map +1 -1
  158. package/dist/utils/errors/format.d.ts +2 -2
  159. package/dist/utils/errors/format.d.ts.map +1 -1
  160. package/dist/utils/errors/index.d.ts +1 -1
  161. package/dist/utils/errors/index.d.ts.map +1 -1
  162. package/dist/utils/errors/suggestions.d.ts +1 -0
  163. package/dist/utils/errors/suggestions.d.ts.map +1 -1
  164. package/dist/utils/index.d.ts +3 -0
  165. package/dist/utils/index.d.ts.map +1 -1
  166. package/dist/utils/logger/types.d.ts +1 -1
  167. package/dist/utils/logger/types.d.ts.map +1 -1
  168. package/dist/utils/security-utils.d.ts +29 -0
  169. package/dist/utils/security-utils.d.ts.map +1 -0
  170. package/dist/utils/stream-utils.d.ts +14 -0
  171. package/dist/utils/stream-utils.d.ts.map +1 -0
  172. package/dist/utils/tokens.d.ts +15 -0
  173. package/dist/utils/tokens.d.ts.map +1 -0
  174. package/dist/utils/where-clause.d.ts +0 -13
  175. package/dist/utils/where-clause.d.ts.map +1 -1
  176. package/package.json +43 -44
  177. package/dist/adapters/sqlite-native/tools/window.d.ts +0 -7
  178. package/dist/adapters/sqlite-native/tools/window.d.ts.map +0 -1
  179. package/dist/chunk-E5IESRTK.js +0 -489
  180. package/dist/server/registration/audit-tools.d.ts +0 -13
  181. package/dist/server/registration/audit-tools.d.ts.map +0 -1
  182. package/dist/utils/insights-manager.d.ts +0 -39
  183. package/dist/utils/insights-manager.d.ts.map +0 -1
@@ -0,0 +1,1183 @@
1
+ import { ConfigurationError, SCOPES, ValidationError, DbMcpError, ErrorCategory } from './chunk-XLIYO3YA.js';
2
+ import { createRequire } from 'module';
3
+ import { resolve, parse, dirname, relative, join, sep, isAbsolute, basename, normalize } from 'path';
4
+ import { realpathSync, lstatSync, existsSync } from 'fs';
5
+ import { z } from 'zod';
6
+
7
+ var _require = createRequire(import.meta.url);
8
+ var pkg = _require("../package.json");
9
+ var VERSION = pkg.version;
10
+ var NAME = pkg.name;
11
+ var IoPathError = class extends DbMcpError {
12
+ constructor(message) {
13
+ super(message, "SECURITY_ERROR", ErrorCategory.VALIDATION, {
14
+ suggestion: "Check that the target path is within the allowed IO roots.",
15
+ recoverable: false
16
+ });
17
+ this.name = "IoPathError";
18
+ }
19
+ };
20
+ function assertSafeIoPath(targetPath, allowedRoots, validateExtension = true) {
21
+ if (targetPath.includes("\0")) {
22
+ throw new IoPathError("Security: path must not contain null bytes.");
23
+ }
24
+ if (targetPath.startsWith("file:") || targetPath.includes("?")) {
25
+ throw new IoPathError(
26
+ "Security: SQLite URIs and query parameters are not allowed."
27
+ );
28
+ }
29
+ const normalized = targetPath.replace(/\\/g, "/");
30
+ const segments = normalized.split("/");
31
+ if (segments.some((s) => s === "..")) {
32
+ throw new IoPathError("Security: Path traversal (..) detected.");
33
+ }
34
+ const base = segments[segments.length - 1];
35
+ if (!base) {
36
+ throw new IoPathError("Security: Invalid path structure.");
37
+ }
38
+ if (base.startsWith(".")) {
39
+ throw new IoPathError("Security: Cannot access hidden files or dotfiles.");
40
+ }
41
+ if (validateExtension) {
42
+ const validExtensions = [
43
+ ".db",
44
+ ".sqlite",
45
+ ".sqlite3",
46
+ ".sql",
47
+ ".csv",
48
+ ".tsv"
49
+ ];
50
+ const hasValidExt = validExtensions.some(
51
+ (ext) => base.toLowerCase().endsWith(ext)
52
+ );
53
+ if (!hasValidExt) {
54
+ throw new IoPathError(
55
+ `Security: Invalid file extension. Allowed extensions are: ${validExtensions.join(", ")}`
56
+ );
57
+ }
58
+ }
59
+ const resolved = resolve(targetPath);
60
+ let currentDir = resolved;
61
+ let existingRealPath = "";
62
+ while (currentDir !== parse(currentDir).root) {
63
+ try {
64
+ existingRealPath = realpathSync(currentDir);
65
+ break;
66
+ } catch {
67
+ currentDir = dirname(currentDir);
68
+ }
69
+ }
70
+ if (!existingRealPath) {
71
+ try {
72
+ existingRealPath = realpathSync(currentDir);
73
+ } catch {
74
+ existingRealPath = currentDir;
75
+ }
76
+ }
77
+ const remainder = relative(currentDir, resolved);
78
+ const finalTargetPath = remainder ? join(existingRealPath, remainder) : existingRealPath;
79
+ if (allowedRoots.length === 0) {
80
+ throw new IoPathError(
81
+ "No allowed input/output roots configured for sandbox boundary. Please configure ALLOWED_IO_ROOTS env variable or pass --allowed-io-roots with absolute paths to enable filesystem operations."
82
+ );
83
+ }
84
+ const safeRoots = [];
85
+ for (const root of allowedRoots) {
86
+ try {
87
+ safeRoots.push(realpathSync(resolve(root)));
88
+ } catch {
89
+ safeRoots.push(resolve(root));
90
+ }
91
+ }
92
+ const isAllowed = safeRoots.some((root) => {
93
+ const rel = relative(root, finalTargetPath);
94
+ return rel !== ".." && !rel.startsWith(".." + sep) && !isAbsolute(rel);
95
+ });
96
+ if (!isAllowed) {
97
+ throw new IoPathError(
98
+ `Directory path escapes allowed sandbox boundaries: ${targetPath}`
99
+ );
100
+ }
101
+ let isSymlink = false;
102
+ try {
103
+ const stats = lstatSync(resolved);
104
+ if (stats.isSymbolicLink()) {
105
+ isSymlink = true;
106
+ }
107
+ } catch {
108
+ }
109
+ if (isSymlink) {
110
+ throw new IoPathError(
111
+ `Symlinks are strictly forbidden for file operations: ${targetPath}`
112
+ );
113
+ }
114
+ }
115
+ function parseAllowedIoRoots(raw) {
116
+ if (!raw) return void 0;
117
+ if (raw.length > 51200) {
118
+ throw new ConfigurationError(
119
+ "ALLOWED_IO_ROOTS configuration exceeds size limit (50KB)"
120
+ );
121
+ }
122
+ let paths;
123
+ try {
124
+ if (raw.trim().startsWith("[")) {
125
+ const parsed = JSON.parse(raw);
126
+ if (Array.isArray(parsed) && parsed.every((p) => typeof p === "string" && isAbsolute(p))) {
127
+ paths = parsed;
128
+ } else {
129
+ throw new ConfigurationError("Must be an array of absolute paths");
130
+ }
131
+ } else {
132
+ paths = raw.split(",").map((s) => s.trim()).filter(Boolean);
133
+ if (paths.some((p) => !isAbsolute(p))) {
134
+ throw new ConfigurationError("All paths must be absolute");
135
+ }
136
+ }
137
+ } catch (e) {
138
+ const errName = e instanceof Error ? e.message : String(e);
139
+ throw new ConfigurationError(
140
+ `Invalid ALLOWED_IO_ROOTS configuration: ${errName}`,
141
+ "CONFIG_ERROR",
142
+ {
143
+ cause: e instanceof Error ? e : void 0
144
+ }
145
+ );
146
+ }
147
+ for (const p of paths) {
148
+ try {
149
+ if (!existsSync(p)) {
150
+ console.warn(`
151
+ [WARN] ALLOWED_IO_ROOTS path does not exist: ${p}
152
+ `);
153
+ }
154
+ } catch {
155
+ }
156
+ }
157
+ return paths;
158
+ }
159
+
160
+ // src/utils/annotations.ts
161
+ var READ_ONLY = {
162
+ readOnlyHint: true,
163
+ destructiveHint: false,
164
+ openWorldHint: false,
165
+ sensitiveHint: false
166
+ };
167
+ var WRITE = {
168
+ readOnlyHint: false,
169
+ destructiveHint: false,
170
+ openWorldHint: false,
171
+ sensitiveHint: false
172
+ };
173
+ var DESTRUCTIVE = {
174
+ readOnlyHint: false,
175
+ destructiveHint: true,
176
+ openWorldHint: false,
177
+ sensitiveHint: false
178
+ };
179
+ var IDEMPOTENT = {
180
+ readOnlyHint: false,
181
+ destructiveHint: false,
182
+ idempotentHint: true,
183
+ openWorldHint: false,
184
+ sensitiveHint: false
185
+ };
186
+ var ADMIN = {
187
+ readOnlyHint: false,
188
+ destructiveHint: true,
189
+ openWorldHint: false,
190
+ sensitiveHint: true
191
+ // System maintenance may expose internal db structures
192
+ };
193
+ function readOnly(title) {
194
+ return { title, ...READ_ONLY };
195
+ }
196
+ function write(title) {
197
+ return { title, ...WRITE };
198
+ }
199
+ function destructive(title) {
200
+ return { title, ...DESTRUCTIVE };
201
+ }
202
+ function idempotent(title) {
203
+ return { title, ...IDEMPOTENT };
204
+ }
205
+ function admin(title) {
206
+ return { title, ...ADMIN };
207
+ }
208
+ var ADMIN_FS = {
209
+ readOnlyHint: false,
210
+ destructiveHint: true,
211
+ openWorldHint: true,
212
+ sensitiveHint: true
213
+ };
214
+ var WRITE_FS = {
215
+ readOnlyHint: false,
216
+ destructiveHint: false,
217
+ openWorldHint: true,
218
+ sensitiveHint: true
219
+ };
220
+ function adminFs(title) {
221
+ return { title, ...ADMIN_FS };
222
+ }
223
+ function writeFs(title) {
224
+ return { title, ...WRITE_FS };
225
+ }
226
+ function toSDK(annotations) {
227
+ return annotations;
228
+ }
229
+
230
+ // src/utils/icons.ts
231
+ var MDI_BASE = "https://cdn.jsdelivr.net/npm/@mdi/svg@7.4.47/svg";
232
+ var SERVER_ICONS = [
233
+ {
234
+ src: `${MDI_BASE}/server.svg`,
235
+ mimeType: "image/svg+xml"
236
+ }
237
+ ];
238
+ var TOOL_GROUP_ICONS = {
239
+ core: [{ src: `${MDI_BASE}/database.svg`, mimeType: "image/svg+xml" }],
240
+ json: [{ src: `${MDI_BASE}/code-json.svg`, mimeType: "image/svg+xml" }],
241
+ text: [{ src: `${MDI_BASE}/format-text.svg`, mimeType: "image/svg+xml" }],
242
+ stats: [{ src: `${MDI_BASE}/chart-bar.svg`, mimeType: "image/svg+xml" }],
243
+ vector: [
244
+ { src: `${MDI_BASE}/vector-polyline.svg`, mimeType: "image/svg+xml" }
245
+ ],
246
+ admin: [{ src: `${MDI_BASE}/cog.svg`, mimeType: "image/svg+xml" }],
247
+ transactions: [
248
+ { src: `${MDI_BASE}/swap-horizontal.svg`, mimeType: "image/svg+xml" }
249
+ ],
250
+ geo: [{ src: `${MDI_BASE}/earth.svg`, mimeType: "image/svg+xml" }],
251
+ introspection: [
252
+ { src: `${MDI_BASE}/graph-outline.svg`, mimeType: "image/svg+xml" }
253
+ ],
254
+ migration: [
255
+ { src: `${MDI_BASE}/source-branch.svg`, mimeType: "image/svg+xml" }
256
+ ],
257
+ codemode: [{ src: `${MDI_BASE}/code-braces.svg`, mimeType: "image/svg+xml" }]
258
+ };
259
+ function getToolGroupIcon(group) {
260
+ return TOOL_GROUP_ICONS[group];
261
+ }
262
+
263
+ // src/utils/redaction.ts
264
+ var SENSITIVE_KEY_PATTERN = /(?:sk-|Bearer |token\s*[:=]\s*|password\s*[:=]\s*|secret\s*[:=]\s*|apikey\s*[:=]\s*|api_key\s*[:=]\s*|AWS_SECRET_ACCESS_KEY\s*[:=]\s*|GITHUB_TOKEN\s*[:=]\s*|ghp_|gho_|ghu_|ghs_|xoxb-|xoxp-|xoxs-|AZURE_[A-Z_]*\s*[:=]\s*|DATABASE_URL\s*[:=]\s*|AKIA|sk-ant-api[a-zA-Z0-9_-]+|sk_live_[a-zA-Z0-9_]+|rk_live_[a-zA-Z0-9_]+|SG\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+|npm_[a-zA-Z0-9]{30,}|dpl_[a-zA-Z0-9]{30,}|hvs\.[a-zA-Z0-9_-]+)[^\s'",;)}\]]{2,}/i;
265
+ var SENSITIVE_VALUE_REGEX = new RegExp(SENSITIVE_KEY_PATTERN.source, "gi");
266
+ var SENSITIVE_KEY_REGEX = /^(password|passwd|token|secret|authorization|api_?key|credential|private_?key|access_?token|refresh_?token|database_url)$/i;
267
+ function redactObject(obj, depth = 0, maxDepth = 15) {
268
+ if (depth > maxDepth || obj === null || obj === void 0) {
269
+ return obj;
270
+ }
271
+ if (typeof obj === "string") {
272
+ return obj.replace(SENSITIVE_VALUE_REGEX, "[REDACTED]");
273
+ }
274
+ if (typeof obj !== "object") {
275
+ return obj;
276
+ }
277
+ if (Array.isArray(obj)) {
278
+ return obj.map((item) => redactObject(item, depth + 1, maxDepth));
279
+ }
280
+ const redacted = {};
281
+ for (const [key, value] of Object.entries(obj)) {
282
+ if (SENSITIVE_KEY_REGEX.test(key)) {
283
+ redacted[key] = "[REDACTED]";
284
+ } else {
285
+ redacted[key] = redactObject(value, depth + 1, maxDepth);
286
+ }
287
+ }
288
+ return redacted;
289
+ }
290
+
291
+ // src/auth/scope-map.ts
292
+ var toolScopeMap = /* @__PURE__ */ new Map();
293
+ function registerToolScope(toolName, scope) {
294
+ toolScopeMap.set(toolName, scope);
295
+ if (!toolName.startsWith("sqlite_")) {
296
+ toolScopeMap.set(`sqlite_${toolName}`, scope);
297
+ } else {
298
+ toolScopeMap.set(toolName.slice(7), scope);
299
+ }
300
+ }
301
+ function getRequiredScope(toolName) {
302
+ return toolScopeMap.get(toolName) ?? SCOPES.ADMIN;
303
+ }
304
+
305
+ // src/utils/where-clause.ts
306
+ var UnsafeWhereClauseError = class extends Error {
307
+ constructor(reason) {
308
+ super(`Unsafe WHERE clause: ${reason}`);
309
+ this.name = "UnsafeWhereClauseError";
310
+ }
311
+ };
312
+ var DANGEROUS_PATTERNS = [
313
+ // Statement terminators and new statements
314
+ // Comprehensive keyword list including statements missed in earlier versions:
315
+ // REPLACE, VACUUM, ANALYZE, BEGIN, COMMIT, ROLLBACK, SAVEPOINT, RELEASE
316
+ {
317
+ pattern: /;\s*(DROP|DELETE|TRUNCATE|INSERT|UPDATE|CREATE|ALTER|ATTACH|DETACH|SELECT|REPLACE|VACUUM|ANALYZE|BEGIN|COMMIT|ROLLBACK|SAVEPOINT|RELEASE|REINDEX|EXPLAIN)\b/i,
318
+ reason: "contains statement terminator followed by SQL keyword"
319
+ },
320
+ // Trailing semicolons (potential statement injection)
321
+ {
322
+ pattern: /;\s*$/,
323
+ reason: "contains trailing semicolon"
324
+ },
325
+ // SQL comments (can be used to comment out security checks)
326
+ {
327
+ pattern: /--/,
328
+ reason: "contains SQL line comment"
329
+ },
330
+ {
331
+ pattern: /\/\*/,
332
+ reason: "contains SQL block comment"
333
+ },
334
+ // REGEXP and MATCH injection (blind extraction oracles)
335
+ {
336
+ pattern: /\bREGEXP\s+/i,
337
+ reason: "contains REGEXP (potential blind extraction oracle)"
338
+ },
339
+ {
340
+ pattern: /\bMATCH\s+/i,
341
+ reason: "contains MATCH (potential blind extraction oracle)"
342
+ },
343
+ // UNION injection (data exfiltration)
344
+ {
345
+ pattern: /\bUNION\s+(ALL\s+)?SELECT\b/i,
346
+ reason: "contains UNION SELECT"
347
+ },
348
+ // SQLite-specific: Extension loading (code execution)
349
+ {
350
+ pattern: /\bload_extension\s*\(/i,
351
+ reason: "contains load_extension (code execution)"
352
+ },
353
+ // SQLite-specific: ATTACH database (file system access)
354
+ {
355
+ pattern: /\bATTACH\s+(DATABASE\s+)?['"`]/i,
356
+ reason: "contains ATTACH DATABASE (file system access)"
357
+ },
358
+ // SQLite-specific: Pragma manipulation
359
+ {
360
+ pattern: /\bPRAGMA\s+/i,
361
+ reason: "contains PRAGMA statement"
362
+ },
363
+ // SQLite-specific: writefile/readfile (if using fileio extension)
364
+ {
365
+ pattern: /\b(writefile|readfile)\s*\(/i,
366
+ reason: "contains file I/O function"
367
+ },
368
+ // SQLite-specific: fts3_tokenizer (potential code execution)
369
+ {
370
+ pattern: /\bfts3_tokenizer\s*\(/i,
371
+ reason: "contains FTS tokenizer function"
372
+ },
373
+ // Subquery injection (data exfiltration via boolean-based blind)
374
+ {
375
+ pattern: /\(\s*SELECT\b/i,
376
+ reason: "contains subquery (potential data exfiltration)"
377
+ },
378
+ // Generic: Hexadecimal string injection
379
+ {
380
+ pattern: /\bX'[0-9A-Fa-f]+'/,
381
+ reason: "contains hex string literal (potential binary injection)"
382
+ },
383
+ // CASE WHEN (potential blind injection without subqueries)
384
+ {
385
+ pattern: /\bCASE\s+WHEN\b/i,
386
+ reason: "contains CASE WHEN (potential blind injection)"
387
+ },
388
+ // IIF() — conditional bypass alternative to CASE WHEN
389
+ {
390
+ pattern: /\bIIF\s*\(/i,
391
+ reason: "contains IIF() (potential blind injection)"
392
+ },
393
+ // GROUP_CONCAT() — data aggregation for exfiltration
394
+ {
395
+ pattern: /\bGROUP_CONCAT\s*\(/i,
396
+ reason: "contains GROUP_CONCAT() (potential data exfiltration)"
397
+ },
398
+ // GLOB — case-sensitive wildcard operator usable for character extraction oracles
399
+ {
400
+ pattern: /\bGLOB\b/i,
401
+ reason: "contains GLOB (potential case-sensitive oracle)"
402
+ },
403
+ // Conditional functions — blind injection oracles (bypass for CASE WHEN / IIF)
404
+ {
405
+ pattern: /\bCOALESCE\s*\(/i,
406
+ reason: "contains COALESCE() (potential blind injection oracle)"
407
+ },
408
+ {
409
+ pattern: /\bNULLIF\s*\(/i,
410
+ reason: "contains NULLIF() (potential blind injection oracle)"
411
+ },
412
+ {
413
+ pattern: /\bTYPEOF\s*\(/i,
414
+ reason: "contains TYPEOF() (potential blind injection oracle)"
415
+ },
416
+ {
417
+ pattern: /\bIFNULL\s*\(/i,
418
+ reason: "contains IFNULL() (potential blind injection oracle)"
419
+ },
420
+ // Memory allocation DoS — RANDOMBLOB(N) / ZEROBLOB(N) can allocate large blocks (CWE-400)
421
+ {
422
+ pattern: /\bRANDOMBLOB\s*\(/i,
423
+ reason: "contains RANDOMBLOB() (potential memory allocation DoS)"
424
+ },
425
+ {
426
+ pattern: /\bZEROBLOB\s*\(/i,
427
+ reason: "contains ZEROBLOB() (potential memory allocation DoS)"
428
+ },
429
+ // Blind extraction oracle functions — can be composed for character-by-character
430
+ // data extraction without subqueries or CASE WHEN (CWE-89, H-1 audit finding).
431
+ // Example: INSTR('abc...', SUBSTR(sqlite_version(), 1, 1)) = N
432
+ {
433
+ pattern: /\bINSTR\s*\(/i,
434
+ reason: "contains INSTR() (potential blind extraction oracle)"
435
+ },
436
+ {
437
+ pattern: /\bSUBSTR\s*\(/i,
438
+ reason: "contains SUBSTR() (potential blind extraction oracle)"
439
+ },
440
+ {
441
+ pattern: /\bSUBSTRING\s*\(/i,
442
+ reason: "contains SUBSTRING() (potential blind extraction oracle)"
443
+ },
444
+ {
445
+ pattern: /\bLENGTH\s*\(/i,
446
+ reason: "contains LENGTH() (potential blind extraction oracle)"
447
+ },
448
+ // TRIM functions — blind extraction oracle (bypass for LIKE / SUBSTR)
449
+ {
450
+ pattern: /\b(?:L|R)?TRIM\s*\(/i,
451
+ reason: "contains TRIM() (potential blind extraction oracle)"
452
+ },
453
+ {
454
+ pattern: /\bUNICODE\s*\(/i,
455
+ reason: "contains UNICODE() (potential blind extraction oracle)"
456
+ },
457
+ {
458
+ pattern: /\bCHAR\s*\(/i,
459
+ reason: "contains CHAR() (potential blind extraction oracle)"
460
+ },
461
+ {
462
+ pattern: /\bREPLACE\s*\(/i,
463
+ reason: "contains REPLACE() (potential blind extraction oracle)"
464
+ },
465
+ // ABS() — can be combined with subtraction to create numeric oracles (CWE-89)
466
+ {
467
+ pattern: /\bABS\s*\(/i,
468
+ reason: "contains ABS() (potential blind extraction oracle)"
469
+ },
470
+ // HEX() — encodes values for character-by-character extraction (CWE-89)
471
+ {
472
+ pattern: /\bHEX\s*\(/i,
473
+ reason: "contains HEX() (potential blind extraction oracle)"
474
+ },
475
+ // QUOTE() — returns SQL-literal representation, can leak type/value info (CWE-89)
476
+ {
477
+ pattern: /\bQUOTE\s*\(/i,
478
+ reason: "contains QUOTE() (potential blind extraction oracle)"
479
+ },
480
+ // PRINTF() — format-string based extraction of internal values (CWE-89)
481
+ {
482
+ pattern: /\bPRINTF\s*\(/i,
483
+ reason: "contains PRINTF() (potential blind extraction oracle)"
484
+ },
485
+ // FORMAT() — SQLite 3.38.0+ alias for printf() (CWE-89)
486
+ {
487
+ pattern: /\bFORMAT\s*\(/i,
488
+ reason: "contains FORMAT() (potential blind extraction oracle)"
489
+ },
490
+ // CAST() — can be used to convert text to numeric oracles (CWE-89)
491
+ {
492
+ pattern: /\bCAST\s*\(/i,
493
+ reason: "contains CAST() (potential blind extraction oracle)"
494
+ }
495
+ ];
496
+ var FULLWIDTH_START = 65281;
497
+ var FULLWIDTH_END = 65374;
498
+ var FULLWIDTH_ASCII_OFFSET = 65248;
499
+ function normalizeForPatternMatching(input) {
500
+ let normalized = input.normalize("NFC");
501
+ let hasFullwidth = false;
502
+ for (let i = 0; i < normalized.length; i++) {
503
+ const code = normalized.charCodeAt(i);
504
+ if (code >= FULLWIDTH_START && code <= FULLWIDTH_END) {
505
+ hasFullwidth = true;
506
+ break;
507
+ }
508
+ }
509
+ if (hasFullwidth) {
510
+ const chars = [];
511
+ for (let i = 0; i < normalized.length; i++) {
512
+ const code = normalized.charCodeAt(i);
513
+ if (code >= FULLWIDTH_START && code <= FULLWIDTH_END) {
514
+ chars.push(String.fromCharCode(code - FULLWIDTH_ASCII_OFFSET));
515
+ } else {
516
+ chars.push(normalized.charAt(i));
517
+ }
518
+ }
519
+ normalized = chars.join("");
520
+ }
521
+ return normalized;
522
+ }
523
+ function sanitizeWhereClause(where) {
524
+ if (!where || typeof where !== "string") {
525
+ throw new UnsafeWhereClauseError("WHERE clause must be a non-empty string");
526
+ }
527
+ const MAX_WHERE_LENGTH = 10240;
528
+ if (where.length > MAX_WHERE_LENGTH) {
529
+ throw new UnsafeWhereClauseError(
530
+ `WHERE clause exceeds maximum length of ${String(MAX_WHERE_LENGTH)} characters`
531
+ );
532
+ }
533
+ const normalized = normalizeForPatternMatching(where);
534
+ for (const { pattern, reason } of DANGEROUS_PATTERNS) {
535
+ if (pattern.test(normalized)) {
536
+ throw new UnsafeWhereClauseError(reason);
537
+ }
538
+ }
539
+ return where;
540
+ }
541
+ function buildWhereClause(conditions, whereClause) {
542
+ let finalSql = "";
543
+ const params = [];
544
+ const clauses = [];
545
+ if (conditions !== void 0 && conditions !== null && conditions.length > 0) {
546
+ const allowedOperators = /* @__PURE__ */ new Set([
547
+ "=",
548
+ "!=",
549
+ ">",
550
+ ">=",
551
+ "<",
552
+ "<=",
553
+ "LIKE",
554
+ "IN",
555
+ "IS",
556
+ "IS NOT",
557
+ "NOT LIKE"
558
+ ]);
559
+ for (const cond of conditions) {
560
+ if (!allowedOperators.has(cond.operator.toUpperCase())) {
561
+ throw new ValidationError(`Invalid operator: ${cond.operator}`);
562
+ }
563
+ const col = `"${cond.column.replace(/"/g, '""')}"`;
564
+ if (cond.operator.toUpperCase() === "IN" && Array.isArray(cond.value)) {
565
+ const placeholders = cond.value.map(() => "?").join(", ");
566
+ clauses.push(`${col} IN (${placeholders})`);
567
+ params.push(...cond.value);
568
+ } else {
569
+ clauses.push(`${col} ${cond.operator} ?`);
570
+ params.push(cond.value);
571
+ }
572
+ }
573
+ finalSql = clauses.join(" AND ");
574
+ }
575
+ if (whereClause) {
576
+ const safeWhere = sanitizeWhereClause(whereClause);
577
+ if (finalSql) {
578
+ finalSql = `${finalSql} AND ${safeWhere}`;
579
+ } else {
580
+ finalSql = safeWhere;
581
+ }
582
+ }
583
+ return { sql: finalSql, params };
584
+ }
585
+
586
+ // src/utils/identifiers.ts
587
+ var IDENTIFIER_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
588
+ var MAX_IDENTIFIER_LENGTH = 255;
589
+ var InvalidIdentifierError = class extends Error {
590
+ constructor(identifier, reason) {
591
+ super(`Invalid identifier "${identifier}": ${reason}`);
592
+ this.identifier = identifier;
593
+ this.reason = reason;
594
+ this.name = "InvalidIdentifierError";
595
+ }
596
+ identifier;
597
+ reason;
598
+ };
599
+ function validateIdentifier(name) {
600
+ if (!name || typeof name !== "string") {
601
+ throw new InvalidIdentifierError(
602
+ name,
603
+ "Identifier must be a non-empty string"
604
+ );
605
+ }
606
+ if (name.length > MAX_IDENTIFIER_LENGTH) {
607
+ throw new InvalidIdentifierError(
608
+ name,
609
+ `Identifier exceeds maximum length of ${String(MAX_IDENTIFIER_LENGTH)} characters`
610
+ );
611
+ }
612
+ if (!IDENTIFIER_PATTERN.test(name)) {
613
+ throw new InvalidIdentifierError(
614
+ name,
615
+ "Identifier contains invalid characters. Must start with a letter or underscore and contain only letters, digits, or underscores"
616
+ );
617
+ }
618
+ }
619
+ function sanitizeIdentifier(name) {
620
+ validateIdentifier(name);
621
+ const escaped = name.replace(/"/g, '""');
622
+ return `"${escaped}"`;
623
+ }
624
+ function sanitizeIdentifiers(names) {
625
+ return names.map(sanitizeIdentifier);
626
+ }
627
+ function createColumnList(columns) {
628
+ return sanitizeIdentifiers(columns).join(", ");
629
+ }
630
+
631
+ // src/utils/tokens.ts
632
+ function estimateTokens(text, contentType = "text") {
633
+ const bytes = Buffer.byteLength(text, "utf8");
634
+ switch (contentType) {
635
+ case "json":
636
+ return Math.ceil(bytes / 3);
637
+ case "sql":
638
+ return Math.ceil(bytes / 3.5);
639
+ case "text":
640
+ default:
641
+ return Math.ceil(bytes / 4);
642
+ }
643
+ }
644
+
645
+ // src/utils/progress-utils.ts
646
+ function buildProgressContext(ctx) {
647
+ if (ctx?.server === void 0 || ctx.progressToken === void 0) {
648
+ return void 0;
649
+ }
650
+ return {
651
+ server: ctx.server,
652
+ progressToken: ctx.progressToken
653
+ };
654
+ }
655
+ async function sendProgress(ctx, progress, total, message) {
656
+ if (ctx === void 0) return;
657
+ if (ctx.progressToken === void 0) return;
658
+ try {
659
+ const notification = {
660
+ method: "notifications/progress",
661
+ params: {
662
+ progressToken: ctx.progressToken,
663
+ progress,
664
+ ...total !== void 0 && { total },
665
+ ...message !== void 0 && message !== "" && { message }
666
+ }
667
+ };
668
+ await ctx.server.notification(notification);
669
+ } catch {
670
+ }
671
+ }
672
+
673
+ // src/utils/stream-utils.ts
674
+ var STREAM_CHUNK_SIZE = 10;
675
+ async function streamResultRows(ctx, rows, chunkSize = STREAM_CHUNK_SIZE) {
676
+ if (rows.length === 0) {
677
+ return 0;
678
+ }
679
+ const effectiveChunkSize = Math.max(1, chunkSize);
680
+ const totalChunks = Math.ceil(rows.length / effectiveChunkSize);
681
+ for (let i = 0; i < totalChunks; i++) {
682
+ const start = i * effectiveChunkSize;
683
+ const end = Math.min(start + effectiveChunkSize, rows.length);
684
+ const chunk = rows.slice(start, end);
685
+ await sendProgress(ctx, i + 1, totalChunks, JSON.stringify(chunk));
686
+ }
687
+ return totalChunks;
688
+ }
689
+ function validateSameDirPath(targetPath, dbPath) {
690
+ if (targetPath.includes("\0")) {
691
+ return {
692
+ valid: false,
693
+ error: "Security: path must not contain null bytes.",
694
+ dbDir: dbPath === ":memory:" ? "" : dirname(resolve(dbPath))
695
+ };
696
+ }
697
+ if (targetPath.startsWith("file:") || targetPath.includes("?")) {
698
+ return {
699
+ valid: false,
700
+ error: "Security: SQLite URIs and query parameters are not allowed.",
701
+ dbDir: dbPath === ":memory:" ? "" : dirname(resolve(dbPath))
702
+ };
703
+ }
704
+ const base = basename(targetPath);
705
+ if (base.startsWith(".")) {
706
+ return {
707
+ valid: false,
708
+ error: "Security: Cannot access hidden files or dotfiles.",
709
+ dbDir: dbPath === ":memory:" ? "" : dirname(resolve(dbPath))
710
+ };
711
+ }
712
+ const validExtensions = [
713
+ ".db",
714
+ ".sqlite",
715
+ ".sqlite3",
716
+ ".sql",
717
+ ".csv",
718
+ ".tsv"
719
+ ];
720
+ const hasValidExt = validExtensions.some(
721
+ (ext) => base.toLowerCase().endsWith(ext)
722
+ );
723
+ if (!hasValidExt) {
724
+ return {
725
+ valid: false,
726
+ error: `Security: Invalid file extension. Allowed extensions are: ${validExtensions.join(", ")}`,
727
+ dbDir: dbPath === ":memory:" ? "" : dirname(resolve(dbPath))
728
+ };
729
+ }
730
+ if (dbPath === ":memory:") {
731
+ return {
732
+ valid: false,
733
+ error: "Security: Filesystem operations are not permitted for :memory: databases.",
734
+ dbDir: ""
735
+ };
736
+ }
737
+ const dbDir = dirname(resolve(dbPath));
738
+ let resolvedTarget = resolve(targetPath);
739
+ try {
740
+ resolvedTarget = realpathSync(resolvedTarget);
741
+ } catch {
742
+ try {
743
+ const parentDir = realpathSync(dirname(resolvedTarget));
744
+ resolvedTarget = resolve(parentDir, basename(resolvedTarget));
745
+ } catch {
746
+ return {
747
+ valid: false,
748
+ error: "Security: Target parent directory must exist.",
749
+ dbDir
750
+ };
751
+ }
752
+ }
753
+ let resolvedDbDir;
754
+ try {
755
+ resolvedDbDir = realpathSync(dbDir);
756
+ } catch {
757
+ return {
758
+ valid: false,
759
+ error: "Security: Database directory must exist.",
760
+ dbDir
761
+ };
762
+ }
763
+ const normalizedTarget = normalize(resolvedTarget);
764
+ const normalizedDir = normalize(resolvedDbDir);
765
+ const targetDir = normalize(dirname(resolvedTarget));
766
+ if (relative(normalizedDir, targetDir) !== "") {
767
+ return {
768
+ valid: false,
769
+ error: `Security: path must be within the database directory. Path traversal is not allowed.`,
770
+ dbDir
771
+ };
772
+ }
773
+ return { valid: true, resolvedPath: normalizedTarget };
774
+ }
775
+
776
+ // src/utils/validate-json-path.ts
777
+ var VALID_JSON_PATH_PATTERN = /^\$(\.[a-zA-Z_][a-zA-Z0-9_ -]*|\[\d+\]|\[#\]|\[\*\])*$/;
778
+ var MAX_JSON_PATH_LENGTH = 500;
779
+ function validateJsonPath(path, param = "path") {
780
+ if (!path.startsWith("$")) {
781
+ throw new ValidationError(
782
+ `JSON ${param} must start with $`,
783
+ "INVALID_JSON_PATH",
784
+ {
785
+ suggestion: "Use a valid JSON path starting with $. For example: $.key or $[0]"
786
+ }
787
+ );
788
+ }
789
+ if (path.length > MAX_JSON_PATH_LENGTH) {
790
+ throw new ValidationError(
791
+ `JSON ${param} exceeds maximum length of ${MAX_JSON_PATH_LENGTH} characters`,
792
+ "INVALID_JSON_PATH"
793
+ );
794
+ }
795
+ if (!VALID_JSON_PATH_PATTERN.test(path)) {
796
+ throw new ValidationError(
797
+ `Invalid JSON ${param} syntax: ${path}`,
798
+ "INVALID_JSON_PATH",
799
+ {
800
+ suggestion: "Use $.key, $[0], or $[*] patterns. Member names must start with a letter or underscore."
801
+ }
802
+ );
803
+ }
804
+ }
805
+ var ALLOWED_AGGREGATE_FUNCTIONS = /* @__PURE__ */ new Set([
806
+ "count",
807
+ "sum",
808
+ "avg",
809
+ "min",
810
+ "max",
811
+ "group_concat",
812
+ "total"
813
+ ]);
814
+ var AGGREGATE_FUNCTION_PATTERN = /^([A-Za-z_]+)\(\s*(\*|"[a-zA-Z_][a-zA-Z0-9_]*"|[a-zA-Z_][a-zA-Z0-9_]*)(?:\s*,\s*'[^']*')?\s*\)$/;
815
+ function validateAggregateFunction(fn) {
816
+ const match = AGGREGATE_FUNCTION_PATTERN.exec(fn.trim());
817
+ if (!match) {
818
+ throw new ValidationError(
819
+ `Invalid aggregate function syntax: ${fn}`,
820
+ "INVALID_AGGREGATE_FUNCTION",
821
+ {
822
+ suggestion: "Use a standard aggregate function like COUNT(*), SUM(column), AVG(column), MIN(column), MAX(column), GROUP_CONCAT(column), or TOTAL(column)."
823
+ }
824
+ );
825
+ }
826
+ const funcName = match[1]?.toLowerCase();
827
+ if (!funcName || !ALLOWED_AGGREGATE_FUNCTIONS.has(funcName)) {
828
+ throw new ValidationError(
829
+ `Disallowed aggregate function: ${match[1]}. Allowed: ${[...ALLOWED_AGGREGATE_FUNCTIONS].join(", ").toUpperCase()}`,
830
+ "INVALID_AGGREGATE_FUNCTION"
831
+ );
832
+ }
833
+ }
834
+ var ErrorResponseFields = z.object({
835
+ error: z.string().optional().describe("Error message (human-readable)"),
836
+ code: z.string().optional().describe("Error code (e.g. VALIDATION_ERROR, QUERY_ERROR)"),
837
+ category: z.string().optional().describe("Error category (validation, query, connection, internal)"),
838
+ recoverable: z.boolean().optional().describe("Whether the error is recoverable"),
839
+ suggestion: z.string().optional().describe("Suggested fix for the error"),
840
+ details: z.record(z.string(), z.unknown()).optional().describe("Additional error context")
841
+ });
842
+ var coerceNumber = (val) => {
843
+ if (typeof val === "string") {
844
+ if (val.trim() === "") return void 0;
845
+ const num = Number(val);
846
+ return isNaN(num) ? val : num;
847
+ }
848
+ return val;
849
+ };
850
+ var BackupSchema = z.object({
851
+ targetPath: z.string().describe("Path for backup file")
852
+ });
853
+ var AnalyzeSchema = z.object({
854
+ table: z.string().optional().describe("Specific table to analyze (default: all)")
855
+ });
856
+ var IntegrityCheckSchema = z.object({
857
+ maxErrors: z.preprocess(
858
+ coerceNumber,
859
+ z.number().int().optional().default(100).describe("Maximum errors to report")
860
+ )
861
+ });
862
+ var OptimizeSchema = z.object({
863
+ table: z.string().optional().describe("Specific table to optimize"),
864
+ reindex: z.boolean().optional().default(false),
865
+ analyze: z.boolean().optional().default(true)
866
+ });
867
+ var RestoreSchema = z.object({
868
+ sourcePath: z.string().describe("Path to backup file to restore from"),
869
+ allowTriggers: z.boolean().optional().default(false).describe(
870
+ "If true, allows triggers in the backup file to be restored. This is a security risk if the backup file is untrusted."
871
+ )
872
+ });
873
+ var VerifyBackupSchema = z.object({
874
+ backupPath: z.string().describe("Path to backup file to verify")
875
+ });
876
+ var IndexStatsSchema = z.object({
877
+ table: z.string().optional().describe("Filter indexes by table name (default: all tables)"),
878
+ excludeSystemIndexes: z.boolean().optional().default(true).describe(
879
+ "Exclude SpatiaLite system indexes (default: true). Set to false to include all indexes."
880
+ )
881
+ });
882
+ var PragmaOptimizeSchema = z.object({
883
+ mask: z.preprocess(
884
+ coerceNumber,
885
+ z.number().int().optional().describe("Optional optimization mask (default: 0xfffe)")
886
+ )
887
+ });
888
+ var PragmaSettingsSchema = z.object({
889
+ pragma: z.string().describe("PRAGMA name (e.g., 'cache_size', 'journal_mode')"),
890
+ value: z.union([z.string(), z.number().int()]).optional().describe("Value to set (omit to only read)")
891
+ });
892
+ var PragmaTableInfoSchema = z.object({
893
+ table: z.string().describe("Table name to get column information for")
894
+ });
895
+ var PragmaCompileOptionsSchema = z.object({
896
+ filter: z.string().optional().describe(
897
+ "Optional filter pattern (case-insensitive substring match) to limit returned options"
898
+ )
899
+ });
900
+ var PragmaDatabaseListSchema = z.object({}).strict();
901
+ z.object({
902
+ analyze: z.boolean().optional().default(true).describe("Run ANALYZE after VACUUM")
903
+ });
904
+ var AttachDatabaseSchema = z.object({
905
+ filepath: z.string().describe("Path to the database file to attach"),
906
+ alias: z.string().regex(
907
+ /^[a-zA-Z_]\w*$/,
908
+ "Alias must start with a letter or underscore and contain only alphanumeric characters"
909
+ ).describe("Schema alias for the attached database (e.g., 'analytics')")
910
+ });
911
+ var DetachDatabaseSchema = z.object({
912
+ alias: z.string().describe("Schema alias of the database to detach (cannot be 'main')")
913
+ });
914
+ var VacuumIntoCopySchema = z.object({
915
+ outputPath: z.string().describe(
916
+ "Path for the output database file. Creates a compacted copy of the database."
917
+ )
918
+ });
919
+ var AuditListBackupsSchema = z.object({
920
+ limit: z.preprocess(
921
+ coerceNumber,
922
+ z.number().int().min(1).max(100).optional().default(10).describe("Maximum number of snapshots to return (default 10, max 100)")
923
+ ),
924
+ offset: z.preprocess(
925
+ coerceNumber,
926
+ z.number().int().min(0).optional().default(0).describe("Pagination offset")
927
+ )
928
+ });
929
+ z.object({
930
+ filename: z.string().describe(
931
+ "Snapshot filename from sqlite_audit_list_backups results (e.g., '2025-01-01T00-00-00-000Z_sqlite_drop_table_users.snapshot.json.gz')"
932
+ ),
933
+ dryRun: z.boolean().optional().default(false).describe(
934
+ "If true, returns the DDL that would be executed without applying changes"
935
+ )
936
+ });
937
+ z.object({
938
+ filename: z.string().describe("Snapshot filename to compare against the live database schema")
939
+ });
940
+ var AuditSearchSchema = z.object({
941
+ tool: z.string().optional().describe("Filter by exact tool name"),
942
+ category: z.enum(["read", "write", "admin", "auth", "error"]).optional().describe("Filter by operation category"),
943
+ success: z.boolean().optional().describe("Filter by success status"),
944
+ requestId: z.string().optional().describe("Filter by exact request ID"),
945
+ fromTimestamp: z.string().optional().describe("Filter by start timestamp (ISO 8601)"),
946
+ toTimestamp: z.string().optional().describe("Filter by end timestamp (ISO 8601)"),
947
+ limit: z.preprocess(
948
+ coerceNumber,
949
+ z.number().int().min(1).max(1e3).optional().default(10).describe("Maximum number of entries to return (default 10)")
950
+ ),
951
+ offset: z.preprocess(
952
+ coerceNumber,
953
+ z.number().int().min(0).optional().default(0).describe("Pagination offset")
954
+ )
955
+ });
956
+ var SqlDumpSchema = z.object({
957
+ outputPath: z.string().describe(
958
+ "Absolute path where the SQL text dump file will be written (e.g. '/path/to/dump.sql')"
959
+ )
960
+ });
961
+ var AuditListBackupsOutputSchema = z.object({
962
+ success: z.boolean(),
963
+ snapshots: z.array(z.unknown()).optional(),
964
+ count: z.number().optional(),
965
+ totalCount: z.number().optional(),
966
+ _meta: z.object({ tokenEstimate: z.number() }).optional()
967
+ }).extend(ErrorResponseFields.shape);
968
+ var AuditGetBackupOutputSchema = z.object({
969
+ success: z.boolean(),
970
+ metadata: z.unknown().optional(),
971
+ ddl: z.string().optional(),
972
+ data: z.string().optional()
973
+ }).extend(ErrorResponseFields.shape);
974
+ var AuditCleanupOutputSchema = z.object({
975
+ success: z.boolean(),
976
+ deletedCount: z.number().optional(),
977
+ message: z.string().optional()
978
+ }).extend(ErrorResponseFields.shape);
979
+ var AuditDiffBackupOutputSchema = z.object({
980
+ success: z.boolean(),
981
+ diffs: z.array(z.unknown()).optional(),
982
+ snapshotTimestamp: z.string().optional(),
983
+ snapshotTarget: z.string().optional()
984
+ }).extend(ErrorResponseFields.shape);
985
+ var AuditRestoreBackupOutputSchema = z.object({
986
+ success: z.boolean(),
987
+ message: z.string().optional(),
988
+ ddl: z.string().optional(),
989
+ dryRun: z.boolean().optional(),
990
+ changesApplied: z.number().optional()
991
+ }).extend(ErrorResponseFields.shape);
992
+ var AuditSearchOutputSchema = z.object({
993
+ success: z.boolean(),
994
+ entries: z.array(z.unknown()).optional(),
995
+ count: z.number().optional(),
996
+ totalCount: z.number().optional()
997
+ }).extend(ErrorResponseFields.shape);
998
+ var VacuumOutputSchema = z.object({
999
+ success: z.boolean(),
1000
+ message: z.string().optional(),
1001
+ durationMs: z.number().optional(),
1002
+ wasmLimitation: z.boolean().optional(),
1003
+ sizeChange: z.object({
1004
+ before: z.number(),
1005
+ after: z.number(),
1006
+ saved: z.number()
1007
+ }).optional()
1008
+ }).extend(ErrorResponseFields.shape);
1009
+ var BackupOutputSchema = z.object({
1010
+ success: z.boolean(),
1011
+ message: z.string().optional(),
1012
+ path: z.string().optional(),
1013
+ sizeBytes: z.number().optional(),
1014
+ durationMs: z.number().optional(),
1015
+ wasmLimitation: z.boolean().optional(),
1016
+ note: z.string().optional()
1017
+ }).extend(ErrorResponseFields.shape);
1018
+ var SqlDumpOutputSchema = z.object({
1019
+ success: z.boolean(),
1020
+ message: z.string().optional(),
1021
+ path: z.string().optional(),
1022
+ durationMs: z.number().optional(),
1023
+ wasmLimitation: z.boolean().optional()
1024
+ }).extend(ErrorResponseFields.shape);
1025
+ var AnalyzeOutputSchema = z.object({
1026
+ success: z.boolean(),
1027
+ message: z.string().optional(),
1028
+ tablesAnalyzed: z.number().optional(),
1029
+ durationMs: z.number().optional()
1030
+ }).extend(ErrorResponseFields.shape);
1031
+ var OptimizeOutputSchema = z.object({
1032
+ success: z.boolean(),
1033
+ message: z.string().optional(),
1034
+ operations: z.array(z.string()).optional(),
1035
+ durationMs: z.number().optional()
1036
+ }).extend(ErrorResponseFields.shape);
1037
+ var IntegrityCheckOutputSchema = z.object({
1038
+ success: z.boolean(),
1039
+ integrity: z.enum(["ok", "errors_found"]).optional(),
1040
+ errorCount: z.number().optional(),
1041
+ messages: z.array(z.string()).optional()
1042
+ }).extend(ErrorResponseFields.shape);
1043
+ var RestoreOutputSchema = z.object({
1044
+ success: z.boolean(),
1045
+ message: z.string().optional(),
1046
+ sourcePath: z.string().optional(),
1047
+ durationMs: z.number().optional(),
1048
+ wasmLimitation: z.boolean().optional(),
1049
+ skippedTables: z.array(z.string()).optional(),
1050
+ note: z.string().optional()
1051
+ }).extend(ErrorResponseFields.shape);
1052
+ var VerifyBackupOutputSchema = z.object({
1053
+ success: z.boolean(),
1054
+ valid: z.boolean().optional(),
1055
+ pageCount: z.number().optional(),
1056
+ pageSize: z.number().optional(),
1057
+ integrity: z.enum(["ok", "errors_found"]).optional(),
1058
+ messages: z.array(z.string()).optional(),
1059
+ message: z.string().optional(),
1060
+ wasmLimitation: z.boolean().optional(),
1061
+ backupPath: z.string().optional()
1062
+ }).extend(ErrorResponseFields.shape);
1063
+ var IndexColumnSchema = z.object({
1064
+ name: z.string(),
1065
+ seqno: z.number()
1066
+ });
1067
+ var IndexStatsEntrySchema = z.object({
1068
+ name: z.string(),
1069
+ table: z.string(),
1070
+ unique: z.boolean(),
1071
+ partial: z.boolean(),
1072
+ columns: z.array(IndexColumnSchema)
1073
+ });
1074
+ var IndexStatsOutputSchema = z.object({
1075
+ success: z.boolean(),
1076
+ indexes: z.array(IndexStatsEntrySchema).optional()
1077
+ }).extend(ErrorResponseFields.shape);
1078
+ var PragmaCompileOptionsOutputSchema = z.object({
1079
+ success: z.boolean(),
1080
+ options: z.array(z.string()).optional()
1081
+ }).extend(ErrorResponseFields.shape);
1082
+ var DatabaseListEntrySchema = z.object({
1083
+ seq: z.number(),
1084
+ name: z.string(),
1085
+ file: z.string()
1086
+ });
1087
+ var PragmaDatabaseListOutputSchema = z.object({
1088
+ success: z.boolean(),
1089
+ databases: z.array(DatabaseListEntrySchema).optional(),
1090
+ configuredPath: z.string().optional(),
1091
+ note: z.string().optional()
1092
+ }).extend(ErrorResponseFields.shape);
1093
+ var PragmaOptimizeOutputSchema = z.object({
1094
+ success: z.boolean(),
1095
+ message: z.string().optional(),
1096
+ durationMs: z.number().optional()
1097
+ }).extend(ErrorResponseFields.shape);
1098
+ var PragmaSettingsOutputSchema = z.object({
1099
+ success: z.boolean(),
1100
+ pragma: z.string().optional(),
1101
+ value: z.unknown().optional(),
1102
+ oldValue: z.unknown().optional(),
1103
+ newValue: z.unknown().optional()
1104
+ }).extend(ErrorResponseFields.shape);
1105
+ var PragmaTableInfoColumnSchema = z.object({
1106
+ cid: z.number(),
1107
+ name: z.string(),
1108
+ type: z.string(),
1109
+ notNull: z.boolean(),
1110
+ defaultValue: z.unknown().nullable(),
1111
+ pk: z.number()
1112
+ });
1113
+ var PragmaTableInfoOutputSchema = z.object({
1114
+ success: z.boolean(),
1115
+ table: z.string().optional(),
1116
+ columns: z.array(PragmaTableInfoColumnSchema).optional()
1117
+ }).extend(ErrorResponseFields.shape);
1118
+ var AttachDatabaseOutputSchema = z.object({
1119
+ success: z.boolean(),
1120
+ message: z.string().optional(),
1121
+ alias: z.string().optional(),
1122
+ filepath: z.string().optional()
1123
+ }).extend(ErrorResponseFields.shape);
1124
+ var DetachDatabaseOutputSchema = z.object({
1125
+ success: z.boolean(),
1126
+ message: z.string().optional(),
1127
+ alias: z.string().optional()
1128
+ }).extend(ErrorResponseFields.shape);
1129
+ var VacuumIntoCopyOutputSchema = z.object({
1130
+ success: z.boolean(),
1131
+ message: z.string().optional(),
1132
+ outputPath: z.string().optional(),
1133
+ sizeBytes: z.number().optional(),
1134
+ durationMs: z.number().optional(),
1135
+ wasmLimitation: z.boolean().optional()
1136
+ }).extend(ErrorResponseFields.shape);
1137
+ var ReindexSchema = z.object({
1138
+ target: z.string().optional().describe(
1139
+ "Index name, table name, or collation name to reindex. Omit to reindex the entire database."
1140
+ )
1141
+ });
1142
+ var ReindexOutputSchema = z.object({
1143
+ success: z.boolean(),
1144
+ message: z.string().optional(),
1145
+ sql: z.string().optional(),
1146
+ durationMs: z.number().optional()
1147
+ }).extend(ErrorResponseFields.shape);
1148
+ var WalSchema = z.object({
1149
+ action: z.enum(["status", "enable", "disable", "checkpoint"]).describe(
1150
+ "WAL action: 'status' = check journal_mode, 'enable' = switch to WAL, 'disable' = switch to DELETE (default journal mode), 'checkpoint' = force WAL checkpoint"
1151
+ ),
1152
+ checkpointMode: z.enum(["PASSIVE", "FULL", "RESTART", "TRUNCATE"]).optional().default("PASSIVE").describe(
1153
+ "Checkpoint mode (only used with 'checkpoint' action). PASSIVE = checkpoint without blocking readers (default). FULL = wait for readers to finish. RESTART = same as FULL but restart WAL file. TRUNCATE = same as RESTART but truncate WAL file to zero bytes."
1154
+ )
1155
+ });
1156
+ var WalOutputSchema = z.object({
1157
+ success: z.boolean(),
1158
+ message: z.string().optional(),
1159
+ journalMode: z.string().optional(),
1160
+ previousMode: z.string().optional(),
1161
+ walPages: z.number().optional(),
1162
+ checkpointedPages: z.number().optional()
1163
+ }).extend(ErrorResponseFields.shape);
1164
+
1165
+ // src/utils/resource-annotations.ts
1166
+ var HIGH_PRIORITY = {
1167
+ audience: ["user", "assistant"],
1168
+ priority: 0.9
1169
+ };
1170
+ var MEDIUM_PRIORITY = {
1171
+ audience: ["user", "assistant"],
1172
+ priority: 0.6
1173
+ };
1174
+ var LOW_PRIORITY = {
1175
+ audience: ["user", "assistant"],
1176
+ priority: 0.4
1177
+ };
1178
+ var ASSISTANT_FOCUSED = {
1179
+ audience: ["assistant"],
1180
+ priority: 0.5
1181
+ };
1182
+
1183
+ export { ASSISTANT_FOCUSED, AnalyzeOutputSchema, AnalyzeSchema, AttachDatabaseOutputSchema, AttachDatabaseSchema, AuditCleanupOutputSchema, AuditDiffBackupOutputSchema, AuditGetBackupOutputSchema, AuditListBackupsOutputSchema, AuditListBackupsSchema, AuditRestoreBackupOutputSchema, AuditSearchOutputSchema, AuditSearchSchema, BackupOutputSchema, BackupSchema, DetachDatabaseOutputSchema, DetachDatabaseSchema, ErrorResponseFields, HIGH_PRIORITY, IndexStatsOutputSchema, IndexStatsSchema, IntegrityCheckOutputSchema, IntegrityCheckSchema, LOW_PRIORITY, MEDIUM_PRIORITY, NAME, OptimizeOutputSchema, OptimizeSchema, PragmaCompileOptionsOutputSchema, PragmaCompileOptionsSchema, PragmaDatabaseListOutputSchema, PragmaDatabaseListSchema, PragmaOptimizeOutputSchema, PragmaOptimizeSchema, PragmaSettingsOutputSchema, PragmaSettingsSchema, PragmaTableInfoOutputSchema, PragmaTableInfoSchema, READ_ONLY, ReindexOutputSchema, ReindexSchema, RestoreOutputSchema, RestoreSchema, SENSITIVE_KEY_PATTERN, SERVER_ICONS, SqlDumpOutputSchema, SqlDumpSchema, VERSION, VacuumIntoCopyOutputSchema, VacuumIntoCopySchema, VacuumOutputSchema, VerifyBackupOutputSchema, VerifyBackupSchema, WalOutputSchema, WalSchema, admin, adminFs, assertSafeIoPath, buildProgressContext, buildWhereClause, createColumnList, destructive, estimateTokens, getRequiredScope, getToolGroupIcon, idempotent, parseAllowedIoRoots, readOnly, redactObject, registerToolScope, sanitizeIdentifier, sanitizeWhereClause, sendProgress, streamResultRows, toSDK, validateAggregateFunction, validateIdentifier, validateJsonPath, validateSameDirPath, write, writeFs };