db-mcp 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +860 -0
  3. package/dist/adapters/DatabaseAdapter.d.ts +141 -0
  4. package/dist/adapters/DatabaseAdapter.d.ts.map +1 -0
  5. package/dist/adapters/DatabaseAdapter.js +131 -0
  6. package/dist/adapters/DatabaseAdapter.js.map +1 -0
  7. package/dist/adapters/sqlite/SchemaManager.d.ts +58 -0
  8. package/dist/adapters/sqlite/SchemaManager.d.ts.map +1 -0
  9. package/dist/adapters/sqlite/SchemaManager.js +187 -0
  10. package/dist/adapters/sqlite/SchemaManager.js.map +1 -0
  11. package/dist/adapters/sqlite/SqliteAdapter.d.ts +161 -0
  12. package/dist/adapters/sqlite/SqliteAdapter.d.ts.map +1 -0
  13. package/dist/adapters/sqlite/SqliteAdapter.js +741 -0
  14. package/dist/adapters/sqlite/SqliteAdapter.js.map +1 -0
  15. package/dist/adapters/sqlite/index.d.ts +9 -0
  16. package/dist/adapters/sqlite/index.d.ts.map +1 -0
  17. package/dist/adapters/sqlite/index.js +8 -0
  18. package/dist/adapters/sqlite/index.js.map +1 -0
  19. package/dist/adapters/sqlite/json-utils.d.ts +100 -0
  20. package/dist/adapters/sqlite/json-utils.d.ts.map +1 -0
  21. package/dist/adapters/sqlite/json-utils.js +274 -0
  22. package/dist/adapters/sqlite/json-utils.js.map +1 -0
  23. package/dist/adapters/sqlite/output-schemas.d.ts +1187 -0
  24. package/dist/adapters/sqlite/output-schemas.d.ts.map +1 -0
  25. package/dist/adapters/sqlite/output-schemas.js +1337 -0
  26. package/dist/adapters/sqlite/output-schemas.js.map +1 -0
  27. package/dist/adapters/sqlite/prompts.d.ts +13 -0
  28. package/dist/adapters/sqlite/prompts.d.ts.map +1 -0
  29. package/dist/adapters/sqlite/prompts.js +605 -0
  30. package/dist/adapters/sqlite/prompts.js.map +1 -0
  31. package/dist/adapters/sqlite/resources.d.ts +13 -0
  32. package/dist/adapters/sqlite/resources.d.ts.map +1 -0
  33. package/dist/adapters/sqlite/resources.js +251 -0
  34. package/dist/adapters/sqlite/resources.js.map +1 -0
  35. package/dist/adapters/sqlite/tools/admin.d.ts +14 -0
  36. package/dist/adapters/sqlite/tools/admin.d.ts.map +1 -0
  37. package/dist/adapters/sqlite/tools/admin.js +788 -0
  38. package/dist/adapters/sqlite/tools/admin.js.map +1 -0
  39. package/dist/adapters/sqlite/tools/core.d.ts +25 -0
  40. package/dist/adapters/sqlite/tools/core.d.ts.map +1 -0
  41. package/dist/adapters/sqlite/tools/core.js +359 -0
  42. package/dist/adapters/sqlite/tools/core.js.map +1 -0
  43. package/dist/adapters/sqlite/tools/fts.d.ts +13 -0
  44. package/dist/adapters/sqlite/tools/fts.d.ts.map +1 -0
  45. package/dist/adapters/sqlite/tools/fts.js +347 -0
  46. package/dist/adapters/sqlite/tools/fts.js.map +1 -0
  47. package/dist/adapters/sqlite/tools/geo.d.ts +14 -0
  48. package/dist/adapters/sqlite/tools/geo.d.ts.map +1 -0
  49. package/dist/adapters/sqlite/tools/geo.js +252 -0
  50. package/dist/adapters/sqlite/tools/geo.js.map +1 -0
  51. package/dist/adapters/sqlite/tools/index.d.ts +30 -0
  52. package/dist/adapters/sqlite/tools/index.d.ts.map +1 -0
  53. package/dist/adapters/sqlite/tools/index.js +61 -0
  54. package/dist/adapters/sqlite/tools/index.js.map +1 -0
  55. package/dist/adapters/sqlite/tools/json-helpers.d.ts +14 -0
  56. package/dist/adapters/sqlite/tools/json-helpers.d.ts.map +1 -0
  57. package/dist/adapters/sqlite/tools/json-helpers.js +477 -0
  58. package/dist/adapters/sqlite/tools/json-helpers.js.map +1 -0
  59. package/dist/adapters/sqlite/tools/json-operations.d.ts +14 -0
  60. package/dist/adapters/sqlite/tools/json-operations.d.ts.map +1 -0
  61. package/dist/adapters/sqlite/tools/json-operations.js +839 -0
  62. package/dist/adapters/sqlite/tools/json-operations.js.map +1 -0
  63. package/dist/adapters/sqlite/tools/stats.d.ts +15 -0
  64. package/dist/adapters/sqlite/tools/stats.d.ts.map +1 -0
  65. package/dist/adapters/sqlite/tools/stats.js +1219 -0
  66. package/dist/adapters/sqlite/tools/stats.js.map +1 -0
  67. package/dist/adapters/sqlite/tools/text.d.ts +14 -0
  68. package/dist/adapters/sqlite/tools/text.d.ts.map +1 -0
  69. package/dist/adapters/sqlite/tools/text.js +1141 -0
  70. package/dist/adapters/sqlite/tools/text.js.map +1 -0
  71. package/dist/adapters/sqlite/tools/vector.d.ts +14 -0
  72. package/dist/adapters/sqlite/tools/vector.d.ts.map +1 -0
  73. package/dist/adapters/sqlite/tools/vector.js +613 -0
  74. package/dist/adapters/sqlite/tools/vector.js.map +1 -0
  75. package/dist/adapters/sqlite/tools/virtual.d.ts +13 -0
  76. package/dist/adapters/sqlite/tools/virtual.d.ts.map +1 -0
  77. package/dist/adapters/sqlite/tools/virtual.js +930 -0
  78. package/dist/adapters/sqlite/tools/virtual.js.map +1 -0
  79. package/dist/adapters/sqlite/types.d.ts +207 -0
  80. package/dist/adapters/sqlite/types.d.ts.map +1 -0
  81. package/dist/adapters/sqlite/types.js +186 -0
  82. package/dist/adapters/sqlite/types.js.map +1 -0
  83. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts +163 -0
  84. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts.map +1 -0
  85. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js +748 -0
  86. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js.map +1 -0
  87. package/dist/adapters/sqlite-native/index.d.ts +11 -0
  88. package/dist/adapters/sqlite-native/index.d.ts.map +1 -0
  89. package/dist/adapters/sqlite-native/index.js +11 -0
  90. package/dist/adapters/sqlite-native/index.js.map +1 -0
  91. package/dist/adapters/sqlite-native/tools/spatialite.d.ts +19 -0
  92. package/dist/adapters/sqlite-native/tools/spatialite.d.ts.map +1 -0
  93. package/dist/adapters/sqlite-native/tools/spatialite.js +628 -0
  94. package/dist/adapters/sqlite-native/tools/spatialite.js.map +1 -0
  95. package/dist/adapters/sqlite-native/tools/transactions.d.ts +12 -0
  96. package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +1 -0
  97. package/dist/adapters/sqlite-native/tools/transactions.js +255 -0
  98. package/dist/adapters/sqlite-native/tools/transactions.js.map +1 -0
  99. package/dist/adapters/sqlite-native/tools/window.d.ts +12 -0
  100. package/dist/adapters/sqlite-native/tools/window.d.ts.map +1 -0
  101. package/dist/adapters/sqlite-native/tools/window.js +370 -0
  102. package/dist/adapters/sqlite-native/tools/window.js.map +1 -0
  103. package/dist/auth/AuthorizationServerDiscovery.d.ts +90 -0
  104. package/dist/auth/AuthorizationServerDiscovery.d.ts.map +1 -0
  105. package/dist/auth/AuthorizationServerDiscovery.js +204 -0
  106. package/dist/auth/AuthorizationServerDiscovery.js.map +1 -0
  107. package/dist/auth/OAuthResourceServer.d.ts +65 -0
  108. package/dist/auth/OAuthResourceServer.d.ts.map +1 -0
  109. package/dist/auth/OAuthResourceServer.js +121 -0
  110. package/dist/auth/OAuthResourceServer.js.map +1 -0
  111. package/dist/auth/TokenValidator.d.ts +60 -0
  112. package/dist/auth/TokenValidator.d.ts.map +1 -0
  113. package/dist/auth/TokenValidator.js +235 -0
  114. package/dist/auth/TokenValidator.js.map +1 -0
  115. package/dist/auth/errors.d.ts +74 -0
  116. package/dist/auth/errors.d.ts.map +1 -0
  117. package/dist/auth/errors.js +133 -0
  118. package/dist/auth/errors.js.map +1 -0
  119. package/dist/auth/index.d.ts +13 -0
  120. package/dist/auth/index.d.ts.map +1 -0
  121. package/dist/auth/index.js +15 -0
  122. package/dist/auth/index.js.map +1 -0
  123. package/dist/auth/middleware.d.ts +81 -0
  124. package/dist/auth/middleware.d.ts.map +1 -0
  125. package/dist/auth/middleware.js +291 -0
  126. package/dist/auth/middleware.js.map +1 -0
  127. package/dist/auth/scopes.d.ts +136 -0
  128. package/dist/auth/scopes.d.ts.map +1 -0
  129. package/dist/auth/scopes.js +349 -0
  130. package/dist/auth/scopes.js.map +1 -0
  131. package/dist/auth/types.d.ts +257 -0
  132. package/dist/auth/types.d.ts.map +1 -0
  133. package/dist/auth/types.js +8 -0
  134. package/dist/auth/types.js.map +1 -0
  135. package/dist/cli.d.ts +8 -0
  136. package/dist/cli.d.ts.map +1 -0
  137. package/dist/cli.js +236 -0
  138. package/dist/cli.js.map +1 -0
  139. package/dist/constants/ServerInstructions.d.ts +45 -0
  140. package/dist/constants/ServerInstructions.d.ts.map +1 -0
  141. package/dist/constants/ServerInstructions.js +356 -0
  142. package/dist/constants/ServerInstructions.js.map +1 -0
  143. package/dist/filtering/ToolConstants.d.ts +34 -0
  144. package/dist/filtering/ToolConstants.d.ts.map +1 -0
  145. package/dist/filtering/ToolConstants.js +174 -0
  146. package/dist/filtering/ToolConstants.js.map +1 -0
  147. package/dist/filtering/ToolFilter.d.ts +82 -0
  148. package/dist/filtering/ToolFilter.d.ts.map +1 -0
  149. package/dist/filtering/ToolFilter.js +296 -0
  150. package/dist/filtering/ToolFilter.js.map +1 -0
  151. package/dist/index.d.ts +13 -0
  152. package/dist/index.d.ts.map +1 -0
  153. package/dist/index.js +17 -0
  154. package/dist/index.js.map +1 -0
  155. package/dist/server/McpServer.d.ts +61 -0
  156. package/dist/server/McpServer.d.ts.map +1 -0
  157. package/dist/server/McpServer.js +270 -0
  158. package/dist/server/McpServer.js.map +1 -0
  159. package/dist/transports/http.d.ts +134 -0
  160. package/dist/transports/http.d.ts.map +1 -0
  161. package/dist/transports/http.js +516 -0
  162. package/dist/transports/http.js.map +1 -0
  163. package/dist/transports/index.d.ts +5 -0
  164. package/dist/transports/index.d.ts.map +1 -0
  165. package/dist/transports/index.js +5 -0
  166. package/dist/transports/index.js.map +1 -0
  167. package/dist/types/index.d.ts +380 -0
  168. package/dist/types/index.d.ts.map +1 -0
  169. package/dist/types/index.js +68 -0
  170. package/dist/types/index.js.map +1 -0
  171. package/dist/utils/annotations.d.ts +44 -0
  172. package/dist/utils/annotations.d.ts.map +1 -0
  173. package/dist/utils/annotations.js +77 -0
  174. package/dist/utils/annotations.js.map +1 -0
  175. package/dist/utils/errors.d.ts +155 -0
  176. package/dist/utils/errors.d.ts.map +1 -0
  177. package/dist/utils/errors.js +329 -0
  178. package/dist/utils/errors.js.map +1 -0
  179. package/dist/utils/identifiers.d.ts +121 -0
  180. package/dist/utils/identifiers.d.ts.map +1 -0
  181. package/dist/utils/identifiers.js +319 -0
  182. package/dist/utils/identifiers.js.map +1 -0
  183. package/dist/utils/index.d.ts +7 -0
  184. package/dist/utils/index.d.ts.map +1 -0
  185. package/dist/utils/index.js +7 -0
  186. package/dist/utils/index.js.map +1 -0
  187. package/dist/utils/insightsManager.d.ts +39 -0
  188. package/dist/utils/insightsManager.d.ts.map +1 -0
  189. package/dist/utils/insightsManager.js +63 -0
  190. package/dist/utils/insightsManager.js.map +1 -0
  191. package/dist/utils/logger.d.ts +189 -0
  192. package/dist/utils/logger.d.ts.map +1 -0
  193. package/dist/utils/logger.js +394 -0
  194. package/dist/utils/logger.js.map +1 -0
  195. package/dist/utils/progress-utils.d.ts +54 -0
  196. package/dist/utils/progress-utils.d.ts.map +1 -0
  197. package/dist/utils/progress-utils.js +74 -0
  198. package/dist/utils/progress-utils.js.map +1 -0
  199. package/dist/utils/resourceAnnotations.d.ts +36 -0
  200. package/dist/utils/resourceAnnotations.d.ts.map +1 -0
  201. package/dist/utils/resourceAnnotations.js +57 -0
  202. package/dist/utils/resourceAnnotations.js.map +1 -0
  203. package/dist/utils/where-clause.d.ts +41 -0
  204. package/dist/utils/where-clause.d.ts.map +1 -0
  205. package/dist/utils/where-clause.js +116 -0
  206. package/dist/utils/where-clause.js.map +1 -0
  207. package/package.json +83 -0
  208. package/server.json +53 -0
@@ -0,0 +1,741 @@
1
+ /**
2
+ * SQLite Adapter
3
+ *
4
+ * MCP adapter for SQLite databases using sql.js (WebAssembly).
5
+ * Provides 73 tools for database operations, JSON, text processing,
6
+ * statistics, vector search, and geospatial features.
7
+ */
8
+ import initSqlJs from "sql.js";
9
+ import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { DatabaseAdapter } from "../DatabaseAdapter.js";
11
+ import { createModuleLogger, ERROR_CODES } from "../../utils/logger.js";
12
+ import { QueryError, ConnectionError, ConfigurationError, } from "../../utils/errors.js";
13
+ import { SchemaManager } from "./SchemaManager.js";
14
+ // Tool definitions from modular files
15
+ import { getAllToolDefinitions } from "./tools/index.js";
16
+ import { getResourceDefinitions } from "./resources.js";
17
+ import { getPromptDefinitions } from "./prompts.js";
18
+ import { isJsonbSupportedVersion, setJsonbSupported } from "./json-utils.js";
19
+ // Module logger
20
+ const log = createModuleLogger("SQLITE");
21
+ /**
22
+ * SQLite Database Adapter
23
+ *
24
+ * Implements the DatabaseAdapter interface for SQLite using sql.js.
25
+ * Supports file-based and in-memory databases.
26
+ */
27
+ export class SqliteAdapter extends DatabaseAdapter {
28
+ type = "sqlite";
29
+ name = "SQLite Adapter";
30
+ version = "1.0.0";
31
+ /**
32
+ * Check if this adapter uses native (better-sqlite3) backend.
33
+ * Returns false for WASM/sql.js adapter.
34
+ */
35
+ isNativeBackend() {
36
+ return false;
37
+ }
38
+ /**
39
+ * Get the configured database file path.
40
+ * Returns the user-configured path, not internal WASM virtual filesystem paths.
41
+ */
42
+ getConfiguredPath() {
43
+ return this.config?.filePath ?? this.config?.connectionString ?? ":memory:";
44
+ }
45
+ db = null;
46
+ config = null;
47
+ sqlJsInstance = null;
48
+ schemaManager = null;
49
+ /**
50
+ * Connect to a SQLite database
51
+ */
52
+ async connect(config) {
53
+ if (config.type !== "sqlite") {
54
+ throw new ConfigurationError(`Invalid database type: expected 'sqlite', got '${config.type}'`, "DB_TYPE_MISMATCH");
55
+ }
56
+ this.config = config;
57
+ try {
58
+ // Initialize sql.js
59
+ this.sqlJsInstance = await initSqlJs();
60
+ const filePath = this.config.filePath ?? this.config.connectionString ?? ":memory:";
61
+ if (filePath === ":memory:") {
62
+ // Create in-memory database
63
+ this.db = new this.sqlJsInstance.Database();
64
+ log.info("Connected to in-memory SQLite database", {
65
+ code: "SQLITE_CONNECT",
66
+ });
67
+ }
68
+ else {
69
+ // For file-based databases, we need to read the file
70
+ // sql.js works in-memory but can load/save to files
71
+ try {
72
+ const fs = await import("fs");
73
+ if (fs.existsSync(filePath)) {
74
+ const buffer = fs.readFileSync(filePath);
75
+ this.db = new this.sqlJsInstance.Database(buffer);
76
+ log.info(`Connected to SQLite database: ${filePath}`, {
77
+ code: "SQLITE_CONNECT",
78
+ });
79
+ }
80
+ else {
81
+ // Create new database
82
+ this.db = new this.sqlJsInstance.Database();
83
+ log.info(`Created new SQLite database: ${filePath}`, {
84
+ code: "SQLITE_CONNECT",
85
+ });
86
+ }
87
+ }
88
+ catch {
89
+ // Browser environment or no file access - create in-memory
90
+ this.db = new this.sqlJsInstance.Database();
91
+ log.warning("File access unavailable, using in-memory database", {
92
+ code: "SQLITE_FALLBACK",
93
+ });
94
+ }
95
+ }
96
+ // Apply options
97
+ this.applyOptions(this.config.options);
98
+ // Enable WAL mode by default for file-based databases (better concurrency)
99
+ // Only if not already configured and not in-memory
100
+ if (filePath !== ":memory:" && !this.config.options?.walMode) {
101
+ try {
102
+ this.db.run("PRAGMA journal_mode = WAL");
103
+ log.info("Enabled WAL mode for better concurrency", {
104
+ code: "SQLITE_WAL",
105
+ });
106
+ }
107
+ catch {
108
+ // WAL mode may not be supported (e.g., sql.js limitations)
109
+ }
110
+ }
111
+ // Detect JSONB support based on SQLite version
112
+ try {
113
+ const versionResult = this.db.exec("SELECT sqlite_version()");
114
+ const version = versionResult[0]?.values[0]?.[0] ?? "0.0.0";
115
+ const jsonbSupported = isJsonbSupportedVersion(version);
116
+ setJsonbSupported(jsonbSupported);
117
+ if (jsonbSupported) {
118
+ log.info(`JSONB support enabled (SQLite ${version})`, {
119
+ code: "SQLITE_JSONB",
120
+ });
121
+ }
122
+ }
123
+ catch {
124
+ setJsonbSupported(false);
125
+ }
126
+ // Initialize SchemaManager with this adapter as the executor
127
+ this.schemaManager = new SchemaManager(this);
128
+ this.connected = true;
129
+ }
130
+ catch (error) {
131
+ const message = error instanceof Error ? error.message : String(error);
132
+ log.error(`Failed to connect to SQLite: ${message}`, {
133
+ code: ERROR_CODES.DB.CONNECT_FAILED.full,
134
+ });
135
+ throw new ConnectionError(`SQLite connection failed: ${message}`, "DB_CONNECT_FAILED", {
136
+ cause: error instanceof Error ? error : undefined,
137
+ });
138
+ }
139
+ }
140
+ /**
141
+ * Apply SQLite PRAGMA options
142
+ */
143
+ applyOptions(options) {
144
+ if (!this.db || !options)
145
+ return;
146
+ if (options.walMode) {
147
+ this.db.run("PRAGMA journal_mode = WAL");
148
+ }
149
+ if (options.foreignKeys !== undefined) {
150
+ this.db.run(`PRAGMA foreign_keys = ${options.foreignKeys ? "ON" : "OFF"}`);
151
+ }
152
+ if (options.busyTimeout !== undefined) {
153
+ this.db.run(`PRAGMA busy_timeout = ${options.busyTimeout}`);
154
+ }
155
+ if (options.cacheSize !== undefined) {
156
+ this.db.run(`PRAGMA cache_size = ${options.cacheSize}`);
157
+ }
158
+ }
159
+ /**
160
+ * Disconnect from the database
161
+ */
162
+ async disconnect() {
163
+ if (this.db) {
164
+ // Save to file if configured
165
+ if (this.config?.filePath && this.config.filePath !== ":memory:") {
166
+ try {
167
+ const fs = await import("fs");
168
+ const data = this.db.export();
169
+ fs.writeFileSync(this.config.filePath, Buffer.from(data));
170
+ log.info(`Saved database to: ${this.config.filePath}`, {
171
+ code: "SQLITE_DISCONNECT",
172
+ });
173
+ }
174
+ catch {
175
+ log.warning("Could not save database to file", {
176
+ code: "SQLITE_SAVE_FAILED",
177
+ });
178
+ }
179
+ }
180
+ this.db.close();
181
+ this.db = null;
182
+ this.connected = false;
183
+ log.info("Disconnected from SQLite database", {
184
+ code: "SQLITE_DISCONNECT",
185
+ });
186
+ }
187
+ }
188
+ /**
189
+ * Get database health status
190
+ */
191
+ getHealth() {
192
+ if (!this.db) {
193
+ return Promise.resolve({ connected: false, error: "Not connected" });
194
+ }
195
+ try {
196
+ const start = Date.now();
197
+ const result = this.db.exec("SELECT sqlite_version() as version");
198
+ const latencyMs = Date.now() - start;
199
+ const version = result[0]?.values[0]?.[0] ?? "unknown";
200
+ return Promise.resolve({
201
+ connected: true,
202
+ latencyMs,
203
+ version,
204
+ details: {
205
+ filePath: this.config?.filePath ??
206
+ this.config?.connectionString ??
207
+ ":memory:",
208
+ walMode: this.config?.options?.walMode ?? false,
209
+ },
210
+ });
211
+ }
212
+ catch (error) {
213
+ return Promise.resolve({
214
+ connected: false,
215
+ error: error instanceof Error ? error.message : String(error),
216
+ });
217
+ }
218
+ }
219
+ /**
220
+ * Normalize parameters for SQLite binding
221
+ * Converts booleans to integers since SQLite doesn't have native boolean type
222
+ */
223
+ normalizeParams(params) {
224
+ if (!params)
225
+ return undefined;
226
+ return params.map((p) => {
227
+ if (typeof p === "boolean")
228
+ return p ? 1 : 0;
229
+ return p;
230
+ });
231
+ }
232
+ /**
233
+ * Execute a read-only query
234
+ */
235
+ executeReadQuery(sql, params) {
236
+ this.ensureConnected();
237
+ this.validateQuery(sql, true);
238
+ const db = this.ensureDb();
239
+ const start = Date.now();
240
+ try {
241
+ const normalizedParams = this.normalizeParams(params);
242
+ const results = normalizedParams
243
+ ? db.exec(sql, normalizedParams)
244
+ : db.exec(sql);
245
+ if (results.length === 0) {
246
+ return Promise.resolve({
247
+ rows: [],
248
+ executionTimeMs: Date.now() - start,
249
+ });
250
+ }
251
+ const firstResult = results[0];
252
+ if (!firstResult) {
253
+ return Promise.resolve({
254
+ rows: [],
255
+ executionTimeMs: Date.now() - start,
256
+ });
257
+ }
258
+ const columns = firstResult.columns.map((name) => ({
259
+ name,
260
+ type: "unknown",
261
+ }));
262
+ const rows = firstResult.values.map((row) => {
263
+ const obj = {};
264
+ firstResult.columns.forEach((col, i) => {
265
+ obj[col] = row[i];
266
+ });
267
+ return obj;
268
+ });
269
+ return Promise.resolve({
270
+ rows,
271
+ columns,
272
+ executionTimeMs: Date.now() - start,
273
+ });
274
+ }
275
+ catch (error) {
276
+ const message = error instanceof Error ? error.message : String(error);
277
+ log.error(`Query failed: ${message}`, {
278
+ code: ERROR_CODES.DB.QUERY_FAILED.full,
279
+ });
280
+ throw new QueryError(`Query execution failed: ${message}`, "DB_QUERY_FAILED", {
281
+ sql,
282
+ cause: error instanceof Error ? error : undefined,
283
+ });
284
+ }
285
+ }
286
+ /**
287
+ * Execute a write query
288
+ */
289
+ executeWriteQuery(sql, params, skipValidation = false) {
290
+ this.ensureConnected();
291
+ if (!skipValidation) {
292
+ this.validateQuery(sql, false);
293
+ }
294
+ const db = this.ensureDb();
295
+ const start = Date.now();
296
+ try {
297
+ const normalizedParams = this.normalizeParams(params);
298
+ if (normalizedParams) {
299
+ db.run(sql, normalizedParams);
300
+ }
301
+ else {
302
+ db.run(sql);
303
+ }
304
+ const changes = db.getRowsModified();
305
+ // Auto-invalidate schema cache on DDL operations
306
+ const normalizedSql = sql.trim().toUpperCase();
307
+ if (normalizedSql.startsWith("CREATE") ||
308
+ normalizedSql.startsWith("ALTER") ||
309
+ normalizedSql.startsWith("DROP")) {
310
+ this.clearSchemaCache();
311
+ }
312
+ return Promise.resolve({
313
+ rowsAffected: changes,
314
+ executionTimeMs: Date.now() - start,
315
+ });
316
+ }
317
+ catch (error) {
318
+ const message = error instanceof Error ? error.message : String(error);
319
+ log.error(`Write query failed: ${message}`, {
320
+ code: ERROR_CODES.DB.QUERY_FAILED.full,
321
+ });
322
+ throw new QueryError(`Write query failed: ${message}`, "DB_WRITE_FAILED", {
323
+ sql,
324
+ cause: error instanceof Error ? error : undefined,
325
+ });
326
+ }
327
+ }
328
+ /**
329
+ * Execute any query (for admin operations)
330
+ */
331
+ executeQuery(sql, params) {
332
+ this.ensureConnected();
333
+ const db = this.ensureDb();
334
+ const start = Date.now();
335
+ try {
336
+ const normalizedParams = this.normalizeParams(params);
337
+ const results = normalizedParams
338
+ ? db.exec(sql, normalizedParams)
339
+ : db.exec(sql);
340
+ if (results.length === 0) {
341
+ // Auto-invalidate schema cache on DDL operations
342
+ const normalizedSql = sql.trim().toUpperCase();
343
+ if (normalizedSql.startsWith("CREATE") ||
344
+ normalizedSql.startsWith("ALTER") ||
345
+ normalizedSql.startsWith("DROP")) {
346
+ this.clearSchemaCache();
347
+ }
348
+ return Promise.resolve({
349
+ rowsAffected: db.getRowsModified(),
350
+ executionTimeMs: Date.now() - start,
351
+ });
352
+ }
353
+ const firstResult = results[0];
354
+ if (!firstResult) {
355
+ return Promise.resolve({
356
+ rowsAffected: db.getRowsModified(),
357
+ executionTimeMs: Date.now() - start,
358
+ });
359
+ }
360
+ const rows = firstResult.values.map((row) => {
361
+ const obj = {};
362
+ firstResult.columns.forEach((col, i) => {
363
+ obj[col] = row[i];
364
+ });
365
+ return obj;
366
+ });
367
+ // Auto-invalidate schema cache on DDL operations
368
+ const normalizedSql = sql.trim().toUpperCase();
369
+ if (normalizedSql.startsWith("CREATE") ||
370
+ normalizedSql.startsWith("ALTER") ||
371
+ normalizedSql.startsWith("DROP")) {
372
+ this.clearSchemaCache();
373
+ }
374
+ return Promise.resolve({
375
+ rows,
376
+ executionTimeMs: Date.now() - start,
377
+ });
378
+ }
379
+ catch (error) {
380
+ const message = error instanceof Error ? error.message : String(error);
381
+ throw new Error(`Query failed: ${message}`);
382
+ }
383
+ }
384
+ /**
385
+ * Get full database schema (cached via SchemaManager)
386
+ */
387
+ async getSchema() {
388
+ this.ensureConnected();
389
+ if (this.schemaManager) {
390
+ return this.schemaManager.getSchema();
391
+ }
392
+ // Fallback if SchemaManager not initialized
393
+ const tables = await this.listTables();
394
+ const indexes = await this.getIndexes();
395
+ return { tables, indexes };
396
+ }
397
+ /**
398
+ * List all tables (cached via SchemaManager)
399
+ */
400
+ async listTables() {
401
+ this.ensureConnected();
402
+ if (this.schemaManager) {
403
+ return this.schemaManager.listTables();
404
+ }
405
+ // Fallback if SchemaManager not initialized
406
+ const result = await this.executeReadQuery(`SELECT name, type FROM sqlite_master
407
+ WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%'
408
+ ORDER BY name`);
409
+ const tables = [];
410
+ for (const row of result.rows ?? []) {
411
+ const name = row["name"];
412
+ const type = row["type"];
413
+ const tableInfo = await this.describeTable(name);
414
+ tables.push({ ...tableInfo, type });
415
+ }
416
+ return tables;
417
+ }
418
+ /**
419
+ * Describe a table's structure (cached via SchemaManager)
420
+ */
421
+ async describeTable(tableName) {
422
+ this.ensureConnected();
423
+ if (this.schemaManager) {
424
+ return this.schemaManager.describeTable(tableName);
425
+ }
426
+ // Fallback if SchemaManager not initialized
427
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(tableName)) {
428
+ throw new Error("Invalid table name");
429
+ }
430
+ const result = await this.executeReadQuery(`PRAGMA table_info("${tableName}")`);
431
+ const columns = (result.rows ?? []).map((row) => ({
432
+ name: row["name"],
433
+ type: row["type"],
434
+ nullable: row["notnull"] === 0,
435
+ primaryKey: row["pk"] === 1,
436
+ defaultValue: row["dflt_value"],
437
+ }));
438
+ const countResult = await this.executeReadQuery(`SELECT COUNT(*) as count FROM "${tableName}"`);
439
+ const rowCount = countResult.rows?.[0]?.["count"] ?? 0;
440
+ return {
441
+ name: tableName,
442
+ type: "table",
443
+ columns,
444
+ rowCount,
445
+ };
446
+ }
447
+ /**
448
+ * List available schemas (SQLite has only 'main')
449
+ */
450
+ listSchemas() {
451
+ return Promise.resolve(["main"]);
452
+ }
453
+ /**
454
+ * Get indexes, optionally for a specific table (cached via SchemaManager)
455
+ */
456
+ async getIndexes(table) {
457
+ this.ensureConnected();
458
+ if (this.schemaManager) {
459
+ if (table) {
460
+ return this.schemaManager.getTableIndexes(table);
461
+ }
462
+ return this.schemaManager.getAllIndexes();
463
+ }
464
+ // Fallback if SchemaManager not initialized
465
+ let sql = `SELECT name, tbl_name, sql FROM sqlite_master
466
+ WHERE type = 'index' AND sql IS NOT NULL`;
467
+ if (table) {
468
+ sql += ` AND tbl_name = '${table.replace(/'/g, "''")}'`;
469
+ }
470
+ const result = await this.executeReadQuery(sql);
471
+ const indexes = [];
472
+ for (const row of result.rows ?? []) {
473
+ const indexName = row["name"];
474
+ const tableName = row["tbl_name"];
475
+ const sqlDef = row["sql"];
476
+ // Get column info for this index via PRAGMA index_info
477
+ let columns = [];
478
+ try {
479
+ const indexInfo = await this.executeReadQuery(`PRAGMA index_info("${indexName}")`);
480
+ columns = (indexInfo.rows ?? []).map((col) => col["name"]);
481
+ }
482
+ catch {
483
+ // If PRAGMA fails, fall back to empty columns
484
+ columns = [];
485
+ }
486
+ indexes.push({
487
+ name: indexName,
488
+ tableName,
489
+ columns,
490
+ unique: sqlDef?.toUpperCase().includes("UNIQUE") ?? false,
491
+ });
492
+ }
493
+ return indexes;
494
+ }
495
+ /**
496
+ * Get all indexes in a single query (cached via SchemaManager)
497
+ * Performance optimization: eliminates N+1 query pattern
498
+ */
499
+ async getAllIndexes() {
500
+ return this.getIndexes();
501
+ }
502
+ /**
503
+ * Clear the schema metadata cache
504
+ * Call after DDL operations or when fresh data is needed
505
+ */
506
+ clearSchemaCache() {
507
+ if (this.schemaManager) {
508
+ this.schemaManager.clearCache();
509
+ }
510
+ }
511
+ /**
512
+ * Get adapter capabilities
513
+ */
514
+ getCapabilities() {
515
+ return {
516
+ json: true,
517
+ fullTextSearch: true, // FTS5 support
518
+ vector: true, // Custom implementation
519
+ geospatial: false, // SpatiaLite not bundled
520
+ transactions: true,
521
+ preparedStatements: true,
522
+ connectionPooling: false, // sql.js is single-connection
523
+ };
524
+ }
525
+ /**
526
+ * Get supported tool groups
527
+ */
528
+ getSupportedToolGroups() {
529
+ return ["core", "json", "text", "stats", "vector", "admin", "geo"];
530
+ }
531
+ /**
532
+ * Get all tool definitions
533
+ */
534
+ getToolDefinitions() {
535
+ return getAllToolDefinitions(this);
536
+ }
537
+ /**
538
+ * Get resource definitions
539
+ */
540
+ getResourceDefinitions() {
541
+ return getResourceDefinitions(this);
542
+ }
543
+ /**
544
+ * Get prompt definitions
545
+ */
546
+ getPromptDefinitions() {
547
+ return getPromptDefinitions(this);
548
+ }
549
+ /**
550
+ * Get adapter info for metadata resource
551
+ */
552
+ getInfo() {
553
+ return {
554
+ type: this.type,
555
+ name: this.name,
556
+ version: this.version,
557
+ connected: this.connected,
558
+ };
559
+ }
560
+ /**
561
+ * Register a single tool with the MCP server
562
+ * Uses modern registerTool() API for MCP 2025-11-25 compliance
563
+ */
564
+ registerTool(server, tool) {
565
+ // Build tool options for registerTool()
566
+ const toolOptions = {
567
+ description: tool.description,
568
+ };
569
+ // Pass full inputSchema (not just .shape) for proper validation
570
+ if (tool.inputSchema !== undefined) {
571
+ toolOptions["inputSchema"] = tool.inputSchema;
572
+ }
573
+ // MCP 2025-11-25: Pass outputSchema for structured responses
574
+ if (tool.outputSchema !== undefined) {
575
+ toolOptions["outputSchema"] = tool.outputSchema;
576
+ }
577
+ // MCP 2025-11-25: Pass annotations for behavioral hints
578
+ if (tool.annotations) {
579
+ toolOptions["annotations"] = tool.annotations;
580
+ }
581
+ // Track whether tool has outputSchema for response handling
582
+ const hasOutputSchema = Boolean(tool.outputSchema);
583
+ server.registerTool(tool.name, toolOptions, async (args, extra) => {
584
+ try {
585
+ // Extract progressToken from extra._meta (SDK passes RequestHandlerExtra)
586
+ const extraMeta = extra;
587
+ const progressToken = extraMeta?._meta?.progressToken;
588
+ // Create context with progress support
589
+ const context = this.createContext(undefined, server.server, progressToken);
590
+ const result = await tool.handler(args, context);
591
+ // MCP 2025-11-25: Return structuredContent if outputSchema present
592
+ if (hasOutputSchema) {
593
+ return {
594
+ content: [
595
+ {
596
+ type: "text",
597
+ text: JSON.stringify(result, null, 2),
598
+ },
599
+ ],
600
+ structuredContent: result,
601
+ };
602
+ }
603
+ // Standard text content response
604
+ return {
605
+ content: [
606
+ {
607
+ type: "text",
608
+ text: typeof result === "string"
609
+ ? result
610
+ : JSON.stringify(result, null, 2),
611
+ },
612
+ ],
613
+ };
614
+ }
615
+ catch (error) {
616
+ return {
617
+ content: [
618
+ {
619
+ type: "text",
620
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`,
621
+ },
622
+ ],
623
+ isError: true,
624
+ };
625
+ }
626
+ });
627
+ }
628
+ /**
629
+ * Register a single resource with the MCP server
630
+ * Handles both static resources and URI templates
631
+ */
632
+ registerResource(server, resource) {
633
+ // Check if URI contains template placeholders like {tableName}
634
+ const isTemplate = /\{[^}]+\}/.test(resource.uri);
635
+ if (isTemplate) {
636
+ // Create ResourceTemplate for parameterized URIs
637
+ // list: undefined signals no enumeration callback for this template
638
+ const template = new ResourceTemplate(resource.uri, { list: undefined });
639
+ server.registerResource(resource.name, template, {
640
+ mimeType: resource.mimeType ?? "application/json",
641
+ description: resource.description,
642
+ },
643
+ // Callback receives URL and extracted template variables
644
+ async (resourceUri, _variables) => {
645
+ // Pass full URI to handler so it can extract variables
646
+ const context = this.createContext();
647
+ const content = await resource.handler(resourceUri.toString(), context);
648
+ return {
649
+ contents: [
650
+ {
651
+ uri: resourceUri.toString(),
652
+ mimeType: resource.mimeType ?? "application/json",
653
+ text: typeof content === "string"
654
+ ? content
655
+ : JSON.stringify(content, null, 2),
656
+ },
657
+ ],
658
+ };
659
+ });
660
+ }
661
+ else {
662
+ // Static resource registration
663
+ server.registerResource(resource.name, resource.uri, {
664
+ mimeType: resource.mimeType ?? "application/json",
665
+ description: resource.description,
666
+ }, async (resourceUri) => {
667
+ const context = this.createContext();
668
+ const content = await resource.handler(resourceUri.toString(), context);
669
+ return {
670
+ contents: [
671
+ {
672
+ uri: resourceUri.toString(),
673
+ mimeType: resource.mimeType ?? "application/json",
674
+ text: typeof content === "string"
675
+ ? content
676
+ : JSON.stringify(content, null, 2),
677
+ },
678
+ ],
679
+ };
680
+ });
681
+ }
682
+ }
683
+ /**
684
+ * Register a single prompt with the MCP server
685
+ */
686
+ registerPrompt(server, prompt) {
687
+ server.registerPrompt(prompt.name, { description: prompt.description }, async (args) => {
688
+ const context = this.createContext();
689
+ const result = await prompt.handler(args, context);
690
+ // Type-safe message construction
691
+ const messages = Array.isArray(result)
692
+ ? result
693
+ : [
694
+ {
695
+ role: "assistant",
696
+ content: {
697
+ type: "text",
698
+ text: typeof result === "string"
699
+ ? result
700
+ : JSON.stringify(result),
701
+ },
702
+ },
703
+ ];
704
+ return { messages };
705
+ });
706
+ }
707
+ /**
708
+ * Ensure database is connected
709
+ */
710
+ ensureConnected() {
711
+ if (!this.db || !this.connected) {
712
+ throw new Error("Not connected to database");
713
+ }
714
+ }
715
+ /**
716
+ * Ensure database is connected and return the database instance
717
+ */
718
+ ensureDb() {
719
+ if (!this.db || !this.connected) {
720
+ throw new Error("Not connected to database");
721
+ }
722
+ return this.db;
723
+ }
724
+ /**
725
+ * Get the raw database instance (for tools)
726
+ */
727
+ getDatabase() {
728
+ return this.ensureDb();
729
+ }
730
+ /**
731
+ * Execute raw SQL and return results (for tools)
732
+ */
733
+ rawQuery(sql, params) {
734
+ return this.executeQuery(sql, params);
735
+ }
736
+ }
737
+ // Factory function
738
+ export function createSqliteAdapter() {
739
+ return new SqliteAdapter();
740
+ }
741
+ //# sourceMappingURL=SqliteAdapter.js.map