db-mcp 1.0.2 → 1.1.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 (241) hide show
  1. package/.gitattributes +2 -0
  2. package/LICENSE +1 -1
  3. package/README.md +244 -518
  4. package/dist/chunk-4IA3DB5C.js +135 -0
  5. package/dist/chunk-AOUL5SHS.js +930 -0
  6. package/dist/chunk-DWJXQEFA.js +13759 -0
  7. package/dist/chunk-DZQLDEQS.js +879 -0
  8. package/dist/chunk-S5IDDSSB.js +74 -0
  9. package/dist/chunk-Z2GFQU3G.js +363 -0
  10. package/dist/cli.d.ts +0 -7
  11. package/dist/cli.js +227 -183
  12. package/dist/http-VSB7DBJR.js +1541 -0
  13. package/dist/index.d.ts +842 -10
  14. package/dist/index.js +5 -17
  15. package/dist/sqlite-VHBA4ABV.js +600 -0
  16. package/dist/sqlite-native-D2LH5ZT7.js +2498 -0
  17. package/dist/worker-script.d.ts +2 -0
  18. package/dist/worker-script.js +126 -0
  19. package/package.json +26 -16
  20. package/playwright.config.ts +101 -0
  21. package/scripts/generate-server-instructions.ts +111 -0
  22. package/server.json +5 -6
  23. package/test-server/README.md +118 -0
  24. package/test-server/code-map.md +409 -0
  25. package/test-server/fixtures/sample.csv +6 -0
  26. package/test-server/reset-database.ps1 +373 -0
  27. package/test-server/sample.csv +11 -0
  28. package/test-server/test-agent-experience.md +243 -0
  29. package/test-server/test-database.sql +388 -0
  30. package/test-server/test-group-tools.md +861 -0
  31. package/test-server/test-help-resources.mjs +238 -0
  32. package/test-server/test-preflight.md +53 -0
  33. package/test-server/test-prompts.md +354 -0
  34. package/test-server/test-resources.md +245 -0
  35. package/test-server/test-tool-annotations.mjs +157 -0
  36. package/test-server/test-tools-advanced-1.md +517 -0
  37. package/test-server/test-tools-advanced-2.md +487 -0
  38. package/test-server/test-tools-codemode.md +629 -0
  39. package/test-server/test-tools.md +176 -0
  40. package/test-server/tool-reference.md +236 -0
  41. package/tsconfig.test.json +9 -0
  42. package/dist/adapters/DatabaseAdapter.d.ts +0 -141
  43. package/dist/adapters/DatabaseAdapter.d.ts.map +0 -1
  44. package/dist/adapters/DatabaseAdapter.js +0 -131
  45. package/dist/adapters/DatabaseAdapter.js.map +0 -1
  46. package/dist/adapters/sqlite/SchemaManager.d.ts +0 -58
  47. package/dist/adapters/sqlite/SchemaManager.d.ts.map +0 -1
  48. package/dist/adapters/sqlite/SchemaManager.js +0 -187
  49. package/dist/adapters/sqlite/SchemaManager.js.map +0 -1
  50. package/dist/adapters/sqlite/SqliteAdapter.d.ts +0 -161
  51. package/dist/adapters/sqlite/SqliteAdapter.d.ts.map +0 -1
  52. package/dist/adapters/sqlite/SqliteAdapter.js +0 -741
  53. package/dist/adapters/sqlite/SqliteAdapter.js.map +0 -1
  54. package/dist/adapters/sqlite/index.d.ts +0 -9
  55. package/dist/adapters/sqlite/index.d.ts.map +0 -1
  56. package/dist/adapters/sqlite/index.js +0 -8
  57. package/dist/adapters/sqlite/index.js.map +0 -1
  58. package/dist/adapters/sqlite/json-utils.d.ts +0 -100
  59. package/dist/adapters/sqlite/json-utils.d.ts.map +0 -1
  60. package/dist/adapters/sqlite/json-utils.js +0 -274
  61. package/dist/adapters/sqlite/json-utils.js.map +0 -1
  62. package/dist/adapters/sqlite/output-schemas.d.ts +0 -1187
  63. package/dist/adapters/sqlite/output-schemas.d.ts.map +0 -1
  64. package/dist/adapters/sqlite/output-schemas.js +0 -1337
  65. package/dist/adapters/sqlite/output-schemas.js.map +0 -1
  66. package/dist/adapters/sqlite/prompts.d.ts +0 -13
  67. package/dist/adapters/sqlite/prompts.d.ts.map +0 -1
  68. package/dist/adapters/sqlite/prompts.js +0 -605
  69. package/dist/adapters/sqlite/prompts.js.map +0 -1
  70. package/dist/adapters/sqlite/resources.d.ts +0 -13
  71. package/dist/adapters/sqlite/resources.d.ts.map +0 -1
  72. package/dist/adapters/sqlite/resources.js +0 -251
  73. package/dist/adapters/sqlite/resources.js.map +0 -1
  74. package/dist/adapters/sqlite/tools/admin.d.ts +0 -14
  75. package/dist/adapters/sqlite/tools/admin.d.ts.map +0 -1
  76. package/dist/adapters/sqlite/tools/admin.js +0 -788
  77. package/dist/adapters/sqlite/tools/admin.js.map +0 -1
  78. package/dist/adapters/sqlite/tools/core.d.ts +0 -25
  79. package/dist/adapters/sqlite/tools/core.d.ts.map +0 -1
  80. package/dist/adapters/sqlite/tools/core.js +0 -359
  81. package/dist/adapters/sqlite/tools/core.js.map +0 -1
  82. package/dist/adapters/sqlite/tools/fts.d.ts +0 -13
  83. package/dist/adapters/sqlite/tools/fts.d.ts.map +0 -1
  84. package/dist/adapters/sqlite/tools/fts.js +0 -347
  85. package/dist/adapters/sqlite/tools/fts.js.map +0 -1
  86. package/dist/adapters/sqlite/tools/geo.d.ts +0 -14
  87. package/dist/adapters/sqlite/tools/geo.d.ts.map +0 -1
  88. package/dist/adapters/sqlite/tools/geo.js +0 -252
  89. package/dist/adapters/sqlite/tools/geo.js.map +0 -1
  90. package/dist/adapters/sqlite/tools/index.d.ts +0 -30
  91. package/dist/adapters/sqlite/tools/index.d.ts.map +0 -1
  92. package/dist/adapters/sqlite/tools/index.js +0 -61
  93. package/dist/adapters/sqlite/tools/index.js.map +0 -1
  94. package/dist/adapters/sqlite/tools/json-helpers.d.ts +0 -14
  95. package/dist/adapters/sqlite/tools/json-helpers.d.ts.map +0 -1
  96. package/dist/adapters/sqlite/tools/json-helpers.js +0 -477
  97. package/dist/adapters/sqlite/tools/json-helpers.js.map +0 -1
  98. package/dist/adapters/sqlite/tools/json-operations.d.ts +0 -14
  99. package/dist/adapters/sqlite/tools/json-operations.d.ts.map +0 -1
  100. package/dist/adapters/sqlite/tools/json-operations.js +0 -839
  101. package/dist/adapters/sqlite/tools/json-operations.js.map +0 -1
  102. package/dist/adapters/sqlite/tools/stats.d.ts +0 -15
  103. package/dist/adapters/sqlite/tools/stats.d.ts.map +0 -1
  104. package/dist/adapters/sqlite/tools/stats.js +0 -1219
  105. package/dist/adapters/sqlite/tools/stats.js.map +0 -1
  106. package/dist/adapters/sqlite/tools/text.d.ts +0 -14
  107. package/dist/adapters/sqlite/tools/text.d.ts.map +0 -1
  108. package/dist/adapters/sqlite/tools/text.js +0 -1141
  109. package/dist/adapters/sqlite/tools/text.js.map +0 -1
  110. package/dist/adapters/sqlite/tools/vector.d.ts +0 -14
  111. package/dist/adapters/sqlite/tools/vector.d.ts.map +0 -1
  112. package/dist/adapters/sqlite/tools/vector.js +0 -613
  113. package/dist/adapters/sqlite/tools/vector.js.map +0 -1
  114. package/dist/adapters/sqlite/tools/virtual.d.ts +0 -13
  115. package/dist/adapters/sqlite/tools/virtual.d.ts.map +0 -1
  116. package/dist/adapters/sqlite/tools/virtual.js +0 -930
  117. package/dist/adapters/sqlite/tools/virtual.js.map +0 -1
  118. package/dist/adapters/sqlite/types.d.ts +0 -207
  119. package/dist/adapters/sqlite/types.d.ts.map +0 -1
  120. package/dist/adapters/sqlite/types.js +0 -186
  121. package/dist/adapters/sqlite/types.js.map +0 -1
  122. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts +0 -163
  123. package/dist/adapters/sqlite-native/NativeSqliteAdapter.d.ts.map +0 -1
  124. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js +0 -748
  125. package/dist/adapters/sqlite-native/NativeSqliteAdapter.js.map +0 -1
  126. package/dist/adapters/sqlite-native/index.d.ts +0 -11
  127. package/dist/adapters/sqlite-native/index.d.ts.map +0 -1
  128. package/dist/adapters/sqlite-native/index.js +0 -11
  129. package/dist/adapters/sqlite-native/index.js.map +0 -1
  130. package/dist/adapters/sqlite-native/tools/spatialite.d.ts +0 -19
  131. package/dist/adapters/sqlite-native/tools/spatialite.d.ts.map +0 -1
  132. package/dist/adapters/sqlite-native/tools/spatialite.js +0 -628
  133. package/dist/adapters/sqlite-native/tools/spatialite.js.map +0 -1
  134. package/dist/adapters/sqlite-native/tools/transactions.d.ts +0 -12
  135. package/dist/adapters/sqlite-native/tools/transactions.d.ts.map +0 -1
  136. package/dist/adapters/sqlite-native/tools/transactions.js +0 -255
  137. package/dist/adapters/sqlite-native/tools/transactions.js.map +0 -1
  138. package/dist/adapters/sqlite-native/tools/window.d.ts +0 -12
  139. package/dist/adapters/sqlite-native/tools/window.d.ts.map +0 -1
  140. package/dist/adapters/sqlite-native/tools/window.js +0 -370
  141. package/dist/adapters/sqlite-native/tools/window.js.map +0 -1
  142. package/dist/auth/AuthorizationServerDiscovery.d.ts +0 -90
  143. package/dist/auth/AuthorizationServerDiscovery.d.ts.map +0 -1
  144. package/dist/auth/AuthorizationServerDiscovery.js +0 -204
  145. package/dist/auth/AuthorizationServerDiscovery.js.map +0 -1
  146. package/dist/auth/OAuthResourceServer.d.ts +0 -65
  147. package/dist/auth/OAuthResourceServer.d.ts.map +0 -1
  148. package/dist/auth/OAuthResourceServer.js +0 -121
  149. package/dist/auth/OAuthResourceServer.js.map +0 -1
  150. package/dist/auth/TokenValidator.d.ts +0 -60
  151. package/dist/auth/TokenValidator.d.ts.map +0 -1
  152. package/dist/auth/TokenValidator.js +0 -235
  153. package/dist/auth/TokenValidator.js.map +0 -1
  154. package/dist/auth/errors.d.ts +0 -74
  155. package/dist/auth/errors.d.ts.map +0 -1
  156. package/dist/auth/errors.js +0 -133
  157. package/dist/auth/errors.js.map +0 -1
  158. package/dist/auth/index.d.ts +0 -13
  159. package/dist/auth/index.d.ts.map +0 -1
  160. package/dist/auth/index.js +0 -15
  161. package/dist/auth/index.js.map +0 -1
  162. package/dist/auth/middleware.d.ts +0 -81
  163. package/dist/auth/middleware.d.ts.map +0 -1
  164. package/dist/auth/middleware.js +0 -291
  165. package/dist/auth/middleware.js.map +0 -1
  166. package/dist/auth/scopes.d.ts +0 -136
  167. package/dist/auth/scopes.d.ts.map +0 -1
  168. package/dist/auth/scopes.js +0 -349
  169. package/dist/auth/scopes.js.map +0 -1
  170. package/dist/auth/types.d.ts +0 -257
  171. package/dist/auth/types.d.ts.map +0 -1
  172. package/dist/auth/types.js +0 -8
  173. package/dist/auth/types.js.map +0 -1
  174. package/dist/cli.d.ts.map +0 -1
  175. package/dist/cli.js.map +0 -1
  176. package/dist/constants/ServerInstructions.d.ts +0 -45
  177. package/dist/constants/ServerInstructions.d.ts.map +0 -1
  178. package/dist/constants/ServerInstructions.js +0 -356
  179. package/dist/constants/ServerInstructions.js.map +0 -1
  180. package/dist/filtering/ToolConstants.d.ts +0 -34
  181. package/dist/filtering/ToolConstants.d.ts.map +0 -1
  182. package/dist/filtering/ToolConstants.js +0 -174
  183. package/dist/filtering/ToolConstants.js.map +0 -1
  184. package/dist/filtering/ToolFilter.d.ts +0 -82
  185. package/dist/filtering/ToolFilter.d.ts.map +0 -1
  186. package/dist/filtering/ToolFilter.js +0 -296
  187. package/dist/filtering/ToolFilter.js.map +0 -1
  188. package/dist/index.d.ts.map +0 -1
  189. package/dist/index.js.map +0 -1
  190. package/dist/server/McpServer.d.ts +0 -61
  191. package/dist/server/McpServer.d.ts.map +0 -1
  192. package/dist/server/McpServer.js +0 -270
  193. package/dist/server/McpServer.js.map +0 -1
  194. package/dist/transports/http.d.ts +0 -134
  195. package/dist/transports/http.d.ts.map +0 -1
  196. package/dist/transports/http.js +0 -516
  197. package/dist/transports/http.js.map +0 -1
  198. package/dist/transports/index.d.ts +0 -5
  199. package/dist/transports/index.d.ts.map +0 -1
  200. package/dist/transports/index.js +0 -5
  201. package/dist/transports/index.js.map +0 -1
  202. package/dist/types/index.d.ts +0 -380
  203. package/dist/types/index.d.ts.map +0 -1
  204. package/dist/types/index.js +0 -68
  205. package/dist/types/index.js.map +0 -1
  206. package/dist/utils/annotations.d.ts +0 -44
  207. package/dist/utils/annotations.d.ts.map +0 -1
  208. package/dist/utils/annotations.js +0 -77
  209. package/dist/utils/annotations.js.map +0 -1
  210. package/dist/utils/errors.d.ts +0 -155
  211. package/dist/utils/errors.d.ts.map +0 -1
  212. package/dist/utils/errors.js +0 -329
  213. package/dist/utils/errors.js.map +0 -1
  214. package/dist/utils/identifiers.d.ts +0 -121
  215. package/dist/utils/identifiers.d.ts.map +0 -1
  216. package/dist/utils/identifiers.js +0 -319
  217. package/dist/utils/identifiers.js.map +0 -1
  218. package/dist/utils/index.d.ts +0 -7
  219. package/dist/utils/index.d.ts.map +0 -1
  220. package/dist/utils/index.js +0 -7
  221. package/dist/utils/index.js.map +0 -1
  222. package/dist/utils/insightsManager.d.ts +0 -39
  223. package/dist/utils/insightsManager.d.ts.map +0 -1
  224. package/dist/utils/insightsManager.js +0 -63
  225. package/dist/utils/insightsManager.js.map +0 -1
  226. package/dist/utils/logger.d.ts +0 -189
  227. package/dist/utils/logger.d.ts.map +0 -1
  228. package/dist/utils/logger.js +0 -394
  229. package/dist/utils/logger.js.map +0 -1
  230. package/dist/utils/progress-utils.d.ts +0 -54
  231. package/dist/utils/progress-utils.d.ts.map +0 -1
  232. package/dist/utils/progress-utils.js +0 -74
  233. package/dist/utils/progress-utils.js.map +0 -1
  234. package/dist/utils/resourceAnnotations.d.ts +0 -36
  235. package/dist/utils/resourceAnnotations.d.ts.map +0 -1
  236. package/dist/utils/resourceAnnotations.js +0 -57
  237. package/dist/utils/resourceAnnotations.js.map +0 -1
  238. package/dist/utils/where-clause.d.ts +0 -41
  239. package/dist/utils/where-clause.d.ts.map +0 -1
  240. package/dist/utils/where-clause.js +0 -116
  241. package/dist/utils/where-clause.js.map +0 -1
@@ -0,0 +1,487 @@
1
+ # Advanced Stress Test — db-mcp (SQLite) — Part 2
2
+
3
+ **Ignore Native content. Test WASM Mode Only**
4
+
5
+ **Step 1:** Read `server-instructions.ts` and `src/constants/server-instructions/gotchas.md` using `view_file` (not grep or search) to understand documented behaviors, edge cases, and response structures.
6
+
7
+ **Step 2:** Execute each numbered stress test below using `sqlite_execute_code` (code mode), not with a browser, scripts, or terminal.
8
+
9
+ **Note** If temp tables are present from a previous test pass, it's because the database is locked. Ignore and work around them.
10
+
11
+ ## Code Mode Execution
12
+
13
+ All tests should be executed via `sqlite_execute_code` code mode. Tests are written in direct tool call syntax for readability — translate to code mode:
14
+
15
+ | Direct Tool Call | Code Mode Equivalent |
16
+ | --------------------------------------------------------- | ------------------------------------------------------------- |
17
+ | `sqlite_read_query({query: "..."})` | `sqlite.core.readQuery({query: "..."})` |
18
+ | `sqlite_write_query({query: "..."})` | `sqlite.core.writeQuery({query: "..."})` |
19
+ | `sqlite_create_table({tableName: "...", columns: [...]})` | `sqlite.core.createTable({tableName: "...", columns: [...]})` |
20
+ | `sqlite_describe_table({tableName: "..."})` | `sqlite.core.describeTable({tableName: "..."})` |
21
+ | `sqlite_drop_table({tableName: "..."})` | `sqlite.core.dropTable({tableName: "..."})` |
22
+ | `sqlite_create_index({...})` | `sqlite.core.createIndex({...})` |
23
+ | `sqlite_get_indexes({tableName: "..."})` | `sqlite.core.getIndexes({tableName: "..."})` |
24
+ | `sqlite_json_*({...})` | `sqlite.json.*({...})` |
25
+ | `sqlite_text_*` / `sqlite_regex_*` / etc. | `sqlite.text.*` |
26
+ | `sqlite_stats_*` / `sqlite_window_*` | `sqlite.stats.*` |
27
+ | `sqlite_vector_*` | `sqlite.vector.*` |
28
+ | `sqlite_fts_*` | `sqlite.text.*` (FTS tools are in the text group) |
29
+ | `sqlite_create_view` / `sqlite_drop_view` / etc. | `sqlite.admin.*` |
30
+ | `sqlite_geo_*` / `sqlite_spatialite_*` | `sqlite.geo.*` |
31
+ | `sqlite_dependency_graph` / `sqlite_index_audit` / etc. | `sqlite.introspection.*` |
32
+ | `sqlite_migration_*` | `sqlite.migration.*` |
33
+
34
+ **Key rules:**
35
+
36
+ - Use `sqlite.<group>.help()` to discover method names and parameters for each group
37
+ - State **persists** across `sqlite_execute_code` calls — create a table in one call, query it in the next
38
+ - Do **NOT** pass `readonly: true` when tests need to create/write/drop objects
39
+ - Group multiple related tests into a single code mode call when practical
40
+
41
+ ## Test Database Schema
42
+
43
+ Same as `test-tools.md` — refer to that file for the full schema reference. Key tables: `test_products` (16 rows), `test_orders` (20), `test_jsonb_docs` (6), `test_articles` (8), `test_users` (9), `test_measurements` (200), `test_embeddings` (20), `test_locations` (15), `test_categories` (17), `test_events` (100).
44
+
45
+ ## Naming & Cleanup
46
+
47
+ - **Temporary tables**: Prefix with `stress_` (e.g., `stress_empty_table`)
48
+ - **Temporary indexes**: Prefix with `stress_idx_`
49
+ - **Temporary views**: Prefix with `stress_view_`
50
+ - **Cleanup**: Attempt to remove all `temp_*` tables. If DROP fails due to a database lock, note the leftover tables and move on — they are inert and will be cleaned up on next database regeneration
51
+
52
+ ## Reporting Format
53
+
54
+ - ❌ Fail: Tool errors or produces incorrect results (include error message)
55
+ - ⚠️ Issue: Unexpected behavior or improvement opportunity
56
+ - 📦 Payload: Unnecessarily large response that should be optimized — **blocking, equally important as ❌ bugs**. Oversized payloads waste LLM context window tokens and degrade downstream tool-calling quality. Report the response size in KB and suggest a concrete optimization (e.g., filter system tables, add `compact` option, omit empty arrays).
57
+ - ✅ Confirmed: Edge case handled correctly (use only inline during testing; omit from Final Summary)
58
+
59
+ ### Error Code Consistency
60
+
61
+ When rating errors, flag any generic code (`RESOURCE_ERROR`, `UNKNOWN_ERROR`) that should be a specific code (e.g., `TABLE_NOT_FOUND`, `COLUMN_NOT_FOUND`, `VALIDATION_ERROR`). These are fixable in `src/utils/errors/` (see `suggestions.ts` and `classes.ts`) by adding a `code` override to the matching error class. Treat as ⚠️ Issue and include in fix plan.
62
+
63
+ ## Post-Test Procedures
64
+
65
+ At the end, confirm cleanup of all `stress_*` objects, then **fix every finding** — not just ❌ Fails, but also ⚠️ Issues (behavioral improvements, missing warnings, error code consistency) and 📦 Payload problems (responses that should be truncated or offer a `limit` param). Create a plan covering all findings; if the plan does not require important decision choices, proceed with implementation. When complete, run the full test suite and fix any broken tests, run lint and typecheck and fix any issues, run prettier, update the changelog (being careful not to create duplicate headers), and commit without pushing. Then re-test your fixes with code mode calls.
66
+
67
+ ---
68
+
69
+ ## admin Group Advanced Tests
70
+
71
+ ### Built-in Tools (3)
72
+
73
+ 1. server_info
74
+ 2. server_health
75
+ 3. list_adapters
76
+
77
+ ### admin Group Tools — Native (33)
78
+
79
+ 4. sqlite_generate_series
80
+ 5. sqlite_create_view
81
+ 6. sqlite_list_views
82
+ 7. sqlite_drop_view
83
+ 8. sqlite_dbstat
84
+ 9. sqlite_vacuum
85
+ 10. sqlite_list_virtual_tables
86
+ 11. sqlite_virtual_table_info
87
+ 12. sqlite_drop_virtual_table
88
+ 13. sqlite_create_csv_table
89
+ 14. sqlite_analyze_csv_schema
90
+ 15. sqlite_create_rtree_table
91
+ 16. sqlite_create_series_table
92
+ 17. sqlite_backup
93
+ 18. sqlite_analyze
94
+ 19. sqlite_integrity_check
95
+ 20. sqlite_optimize
96
+ 21. sqlite_restore
97
+ 22. sqlite_verify_backup
98
+ 23. sqlite_index_stats
99
+ 24. sqlite_pragma_compile_options
100
+ 25. sqlite_pragma_database_list
101
+ 26. sqlite_pragma_optimize
102
+ 27. sqlite_pragma_settings
103
+ 28. sqlite_pragma_table_info
104
+ 29. sqlite_append_insight
105
+ 30. sqlite_transaction_begin
106
+ 31. sqlite_transaction_commit
107
+ 32. sqlite_transaction_rollback
108
+ 33. sqlite_transaction_savepoint
109
+ 34. sqlite_transaction_release
110
+ 35. sqlite_transaction_rollback_to
111
+ 36. sqlite_transaction_execute
112
+
113
+ ### admin Group Tools — WASM (26)
114
+
115
+ Same as Native minus the 7 transaction management tools (items 30-36).
116
+
117
+ ### Category 1: View Lifecycle Stress
118
+
119
+ 1. `sqlite_create_view({viewName: "stress_view_orders", selectQuery: "SELECT product_id, COUNT(*) as cnt FROM test_orders GROUP BY product_id"})` → success
120
+ 2. `sqlite_list_views` → verify `stress_view_orders` present
121
+ 3. `sqlite_drop_view({viewName: "stress_view_orders"})` → success
122
+ 4. `sqlite_drop_view({viewName: "stress_view_orders"})` → expect structured error or "not found" (not raw crash)
123
+ 5. `sqlite_create_view({viewName: "stress_view_orders", selectQuery: "SELECT product_id, COUNT(*) as cnt FROM test_orders GROUP BY product_id"})` → recreate success
124
+
125
+ ### Category 2: Virtual Table Edge Cases
126
+
127
+ 6. `sqlite_create_rtree_table({tableName: "stress_rtree_test", dimensions: 2})` → success
128
+ 7. `sqlite_list_virtual_tables` → verify `stress_rtree_test` present alongside `test_articles_fts` (Native)
129
+ 8. `sqlite_virtual_table_info({tableName: "stress_rtree_test"})` → correct module and column info
130
+ 9. `sqlite_drop_virtual_table({tableName: "stress_rtree_test"})` → success
131
+ 10. `sqlite_virtual_table_info({tableName: "nonexistent_vtable_xyz"})` → structured error
132
+
133
+ ### Category 3: Backup/Restore Integrity
134
+
135
+ 11. `sqlite_backup({targetPath: "test-server/stress-backup.db"})` → success
136
+ 12. `sqlite_verify_backup({backupPath: "test-server/stress-backup.db"})` → integrity verified
137
+ 13. `sqlite_verify_backup({backupPath: "nonexistent_file.db"})` → structured error
138
+ 14. Cleanup: note backup file for manual removal
139
+
140
+ ### Category 4: Transaction Edge Cases `[NATIVE ONLY]`
141
+
142
+ **4.1 Aborted Transaction Recovery**
143
+
144
+ 15. `sqlite_transaction_begin` → get transaction ID
145
+ 16. `sqlite_transaction_execute({statements: ["INSERT INTO nonexistent_table VALUES (1)"]})` → should fail
146
+ 17. Start new transaction → verify it works normally (no lingering aborted state)
147
+
148
+ **4.2 Savepoint Stress Test**
149
+
150
+ 18. `sqlite_transaction_begin` → get transaction ID
151
+ 19. Create savepoint `sp1`
152
+ 20. `sqlite_write_query` → INSERT a row into a temp table (within transaction)
153
+ 21. Create savepoint `sp2`
154
+ 22. `sqlite_write_query` → INSERT another row
155
+ 23. `sqlite_transaction_rollback_to({name: "sp2"})` → should undo sp2's insert
156
+ 24. `sqlite_transaction_rollback_to({name: "sp1"})` → should undo all inserts
157
+ 25. `sqlite_transaction_commit` → only pre-sp1 state persists
158
+
159
+ **4.3 Transaction Execute Mixed Statements**
160
+
161
+ 26. `sqlite_transaction_execute({statements: ["CREATE TABLE stress_tx_test (id INTEGER PRIMARY KEY, name TEXT)", "INSERT INTO stress_tx_test VALUES (1, 'alpha')", "INSERT INTO stress_tx_test VALUES (2, 'beta')"]})` → success, 3 statements executed
162
+ 27. Verify `stress_tx_test` exists with 2 rows
163
+
164
+ **4.4 Transaction Execute Failure Rollback**
165
+
166
+ 28. `sqlite_transaction_execute({statements: ["CREATE TABLE stress_tx_fail (id INT)", "INSERT INTO nonexistent_xyz VALUES (1)", "CREATE TABLE stress_tx_fail2 (id INT)"]})` → failure
167
+ 29. Verify: `stress_tx_fail` does NOT exist (atomic rollback worked)
168
+
169
+ ### Category 5: Pragma Edge Cases
170
+
171
+ 30. `sqlite_pragma_compile_options({filter: "THREAD"})` → filtered result subset
172
+ 31. `sqlite_pragma_settings` → verify key settings structure
173
+ 32. `sqlite_pragma_table_info({tableName: "nonexistent_table_xyz"})` → report behavior
174
+
175
+ ### Category 6: Error Message Quality
176
+
177
+ 33. `sqlite_drop_view({viewName: "nonexistent_view_xyz"})` → structured error
178
+ 34. `sqlite_create_csv_table({tableName: "stress_csv", filePath: "nonexistent_file.csv"})` → structured error
179
+ 35. `sqlite_verify_backup({backupPath: "nonexistent_backup.db"})` → structured error
180
+
181
+ ### Category 7: WASM Boundary Verification
182
+
183
+ For WASM testing only:
184
+
185
+ 36. Confirm transaction tools are NOT present in the tool list
186
+ 37. All 26 non-transaction admin tools should work identically in WASM and Native
187
+
188
+ ### Final Cleanup
189
+
190
+ Drop all `stress_*` tables and views. Confirm `test_products` (16 rows) and `test_orders` (20 rows) are unchanged.
191
+
192
+ ---
193
+
194
+ ## geo Group Advanced Tests
195
+
196
+ ### Built-in Tools (3)
197
+
198
+ 1. server_info
199
+ 2. server_health
200
+ 3. list_adapters
201
+
202
+ ### geo Group Tools — Native (11)
203
+
204
+ 4. sqlite_geo_distance
205
+ 5. sqlite_geo_nearby
206
+ 6. sqlite_geo_bounding_box
207
+ 7. sqlite_geo_cluster
208
+ 8. sqlite_spatialite_load `[NATIVE ONLY]`
209
+ 9. sqlite_spatialite_create_table `[NATIVE ONLY]`
210
+ 10. sqlite_spatialite_query `[NATIVE ONLY]`
211
+ 11. sqlite_spatialite_analyze `[NATIVE ONLY]`
212
+ 12. sqlite_spatialite_index `[NATIVE ONLY]`
213
+ 13. sqlite_spatialite_transform `[NATIVE ONLY]`
214
+ 14. sqlite_spatialite_import `[NATIVE ONLY]`
215
+
216
+ ### geo Group Tools — WASM (4)
217
+
218
+ Only the Haversine-based tools: items 4-7.
219
+
220
+ ### Category 1: Haversine Boundary Conditions
221
+
222
+ 1. `sqlite_geo_distance({lat1: 0, lon1: 0, lat2: 0, lon2: 0})` → distance = 0 (same point)
223
+ 2. `sqlite_geo_distance({lat1: 90, lon1: 0, lat2: -90, lon2: 0})` → antipodal distance ≈ 20,015 km (half Earth circumference)
224
+ 3. `sqlite_geo_distance({lat1: 0, lon1: -180, lat2: 0, lon2: 180})` → distance ≈ 0 (same point, opposite notation)
225
+ 4. `sqlite_geo_distance({lat1: 91, lon1: 0, lat2: 0, lon2: 0})` → report behavior for out-of-bounds latitude (>90°)
226
+ 5. `sqlite_geo_distance({lat1: 0, lon1: 181, lat2: 0, lon2: 0})` → report behavior for out-of-bounds longitude (>180°)
227
+
228
+ ### Category 2: Nearby Search Edge Cases
229
+
230
+ 6. `sqlite_geo_nearby({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", centerLat: 40.7829, centerLon: -73.9654, radius: 0.1, unit: "km"})` → very small radius — should find only Central Park (within 100m)
231
+ 7. `sqlite_geo_nearby({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", centerLat: 40.7829, centerLon: -73.9654, radius: 50000, unit: "km"})` → very large radius — should find ALL 15 locations
232
+ 8. `sqlite_geo_nearby({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", centerLat: 0, centerLon: 0, radius: 100, unit: "km"})` → no locations near (0,0) — 0 results (not error)
233
+
234
+ ### Category 3: Bounding Box Edge Cases
235
+
236
+ 9. `sqlite_geo_bounding_box({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", minLat: -90, maxLat: 90, minLon: -180, maxLon: 180})` → all 15 locations (global bounding box)
237
+ 10. `sqlite_geo_bounding_box({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", minLat: 0, maxLat: 0, minLon: 0, maxLon: 0})` → 0 results (point bounding box)
238
+ 11. `sqlite_geo_bounding_box({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", minLat: 50, maxLat: 52, minLon: -1, maxLon: 1})` → London locations (Big Ben, Tower Bridge, Buckingham Palace)
239
+
240
+ ### Category 4: Clustering Edge Cases
241
+
242
+ 12. `sqlite_geo_cluster({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", gridSize: 180})` → single cluster with all 15 points (huge grid)
243
+ 13. `sqlite_geo_cluster({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", gridSize: 0.001})` → ~15 clusters (tiny grid, one per location)
244
+ 14. `sqlite_geo_cluster({table: "test_locations", latColumn: "latitude", lonColumn: "longitude", gridSize: 0.1})` → approximately one cluster per city
245
+
246
+ ### Category 5: SpatiaLite Integration `[NATIVE ONLY]`
247
+
248
+ 15. `sqlite_spatialite_load` → verify version string returned
249
+ 16. `sqlite_spatialite_create_table({tableName: "stress_geo_spatial", geometryColumn: "geom", geometryType: "POINT", srid: 4326, additionalColumns: [{name: "name", type: "TEXT"}, {name: "type", type: "TEXT"}]})` → success
250
+ 17. Import 3 points (NYC, Paris, Tokyo) via `sqlite_spatialite_import`
251
+ 18. `sqlite_spatialite_query({query: "SELECT name, AsText(geom) FROM stress_geo_spatial"})` → 3 rows with WKT
252
+ 19. `sqlite_spatialite_transform({operation: "buffer", geometry1: "POINT(-73.9654 40.7829)", distance: 0.01})` → buffered polygon
253
+ 20. `sqlite_spatialite_transform({operation: "centroid", geometry1: "POLYGON((-74 40, -74 41, -73 41, -73 40, -74 40))"})` → centroid point
254
+ 21. `sqlite_spatialite_index({tableName: "stress_geo_spatial", geometryColumn: "geom", action: "create"})` → R-Tree index
255
+ 22. `sqlite_spatialite_index({tableName: "stress_geo_spatial", geometryColumn: "geom", action: "check"})` → index integrity
256
+ 23. `sqlite_spatialite_analyze({analysisType: "spatial_extent", sourceTable: "stress_geo_spatial", geometryColumn: "geom"})` → spatial extent
257
+
258
+ ### Category 6: Error Message Quality
259
+
260
+ 24. `sqlite_geo_nearby({table: "nonexistent_table_xyz", latColumn: "lat", lonColumn: "lon", centerLat: 0, centerLon: 0, radius: 100, unit: "km"})` → structured error
261
+ 25. `sqlite_geo_nearby({table: "test_locations", latColumn: "nonexistent_col", lonColumn: "longitude", centerLat: 0, centerLon: 0, radius: 100, unit: "km"})` → structured error about column
262
+ 26. `sqlite_spatialite_query({query: "SELECT * FROM nonexistent_table_xyz"})` `[NATIVE ONLY]` → structured error
263
+
264
+ ### Category 7: WASM Boundary Verification
265
+
266
+ For WASM testing only:
267
+
268
+ 27. Confirm SpatiaLite tools (items 8-14) are NOT present in the tool list
269
+ 28. All 4 Haversine tools should produce identical results in WASM and Native
270
+
271
+ ### Final Cleanup
272
+
273
+ Drop `stress_geo_spatial` (if created). Confirm `test_locations` count is still 15.
274
+
275
+ ---
276
+
277
+ ## introspection Group Advanced Tests
278
+
279
+ > **Note:** All introspection tools are **read-only**. The test database has **one FK** (`test_orders.product_id → test_products.id`) and a **deliberately redundant index** (`idx_orders_status` is a prefix of `idx_orders_status_date`).
280
+
281
+ > **Code Mode Required:** Several optional params (`table`, `direction`, `sections`, `compact`, `checks`, `includeTableDetails`, `limit`) are defined in tool schemas but NOT exposed in MCP tool definitions. Use `sqlite_execute_code` to test these params via `sqlite.introspection.*` API.
282
+
283
+ ### Built-in Tools (3)
284
+
285
+ 1. server_info
286
+ 2. server_health
287
+ 3. list_adapters
288
+
289
+ ### introspection Group Tools (9)
290
+
291
+ 4. sqlite_dependency_graph
292
+ 5. sqlite_topological_sort
293
+ 6. sqlite_cascade_simulator
294
+ 7. sqlite_schema_snapshot
295
+ 8. sqlite_constraint_analysis
296
+ 9. sqlite_migration_risks
297
+ 10. sqlite_storage_analysis
298
+ 11. sqlite_index_audit
299
+ 12. sqlite_query_plan
300
+
301
+ ### Category 1: Graph Analysis Edge Cases
302
+
303
+ **1.1 Full Dependency Graph**
304
+
305
+ 1. `sqlite_dependency_graph({})` → full graph. Verify edge `test_orders → test_products` present in edges array.
306
+ 2. `sqlite_dependency_graph({includeRowCounts: false})` → verify rowCount is omitted from node entries.
307
+ 3. `sqlite_dependency_graph({})` → verify `stats.rootTables` and `stats.leafTables` are populated and disjoint.
308
+
309
+ **1.2 Topological Sort Direction Stress**
310
+
311
+ 4. `sqlite_topological_sort({direction: "create"})` → `test_products` appears BEFORE `test_orders` (dependency order)
312
+ 5. `sqlite_topological_sort({direction: "drop"})` → `test_orders` appears BEFORE `test_products` (reverse)
313
+ 6. Verify both directions list the same set of tables (just reordered)
314
+
315
+ **1.3 Cascade Chains**
316
+
317
+ 7. `sqlite_cascade_simulator({table: "test_products"})` → affectedTables includes `test_orders` with action from FK definition (CASCADE)
318
+ 8. `sqlite_cascade_simulator({table: "test_measurements"})` → affectedTables is empty (leaf table, nothing references it)
319
+ 9. `sqlite_cascade_simulator({table: "test_orders"})` → verify behavior: nothing references `test_orders` via FK, so affectedTables should be empty even though it has outgoing FKs
320
+
321
+ ### Category 2: Schema Snapshot Completeness
322
+
323
+ 10. `sqlite_schema_snapshot({})` → full snapshot. Verify:
324
+ - tables ≥ 11 (10 regular + FTS virtual)
325
+ - indexes ≥ 4 (`idx_orders_status`, `idx_orders_date`, `idx_products_category`, `idx_orders_status_date`)
326
+ - generatedAt is a valid ISO timestamp
327
+ 11. `sqlite_schema_snapshot({sections: ["indexes"]})` → only indexes section populated. Verify table section is absent/empty.
328
+ 12. `sqlite_schema_snapshot({sections: ["tables", "indexes"]})` → both sections present
329
+ 13. `sqlite_schema_snapshot({compact: true})` → verify tables exist but columns arrays are absent from each table entry
330
+ 14. `sqlite_schema_snapshot({compact: false})` → verify column details (name, type, nullable, pk) are present for each table
331
+
332
+ ### Category 3: Constraint Analysis Stress
333
+
334
+ 15. `sqlite_constraint_analysis({})` → all tables analyzed. Verify summary.byType keys and summary.bySeverity keys.
335
+ 16. `sqlite_constraint_analysis({checks: ["unindexed_fk"]})` → only unindexed FK findings. The `test_orders.product_id` FK may or may not be flagged depending on whether `idx_orders_status` counts as a covering index.
336
+ 17. `sqlite_constraint_analysis({table: "test_users"})` → only findings for `test_users`. Verify no findings reference other tables.
337
+ 18. `sqlite_constraint_analysis({table: "nonexistent_table_xyz"})` → report behavior: empty findings, or structured error?
338
+
339
+ ### Category 4: Storage Analysis & Index Audit Depth
340
+
341
+ **4.1 Storage Analysis Verification**
342
+
343
+ 19. `sqlite_storage_analysis({})` → verify database.totalSizeBytes = database.pageSize × database.totalPages (arithmetic check)
344
+ 20. `sqlite_storage_analysis({})` → verify tables array is sorted by size descending (or largest tables first)
345
+ 21. `sqlite_storage_analysis({includeTableDetails: false})` → tables property is absent. Database-level metrics still present.
346
+ 22. `sqlite_storage_analysis({limit: 3})` → only top 3 tables returned (if limit parameter is supported)
347
+ 23. `sqlite_storage_analysis({})` → verify database.fragmentationPct is a number between 0 and 100. Check database.journalMode and database.autoVacuum are non-empty strings.
348
+
349
+ **4.2 Index Audit Cross-Validation**
350
+
351
+ 24. `sqlite_index_audit({})` → should flag `idx_orders_status` as `type: "redundant"` (prefix of `idx_orders_status_date`). Note: the field name is `index` (not `indexName`).
352
+ 25. `sqlite_index_audit({})` → verify `redundantOf` field points to `idx_orders_status_date` (the superset index)
353
+ 26. `sqlite_index_audit({})` → check for `missing_fk_index` on `test_orders.product_id` (FK column without dedicated index)
354
+ 27. `sqlite_index_audit({table: "test_products"})` → filtered findings. Only `test_products` findings returned. Verify `idx_products_category` is NOT flagged as redundant (it's the only index on that table).
355
+ 28. `sqlite_index_audit({table: "test_measurements"})` → table with 200 rows and no secondary indexes. Note: `unindexed_large_table` threshold is 1000 rows, so no finding expected here.
356
+
357
+ ### Category 5: Query Plan Deep Analysis
358
+
359
+ 29. `sqlite_query_plan({sql: "SELECT * FROM test_orders WHERE status = 'completed'"})` → should use `idx_orders_status`. Verify `analysis.indexScans` includes a reference.
360
+ 30. `sqlite_query_plan({sql: "SELECT * FROM test_products WHERE name = 'Laptop Pro 15'"})` → full scan (no index on `name`). Verify:
361
+ - `analysis.fullScans` includes `test_products`
362
+ - `suggestions` array is non-empty with index creation recommendation
363
+ 31. `sqlite_query_plan({sql: "SELECT p.name, o.quantity FROM test_products p JOIN test_orders o ON o.product_id = p.id WHERE o.status = 'completed'"})` → join plan. Verify plan has multiple entries and analysis reflects join strategy.
364
+ 32. `sqlite_query_plan({sql: "SELECT * FROM test_orders WHERE status = 'completed' AND order_date > '2026-01-20'"})` → compound WHERE. Verify which index is chosen (`idx_orders_status` or `idx_orders_status_date`).
365
+ 33. `sqlite_query_plan({sql: "SELECT COUNT(*) FROM test_measurements GROUP BY sensor_id"})` → GROUP BY plan without dedicated index on `sensor_id`. Expect full scan.
366
+ 34. `sqlite_query_plan({sql: "WITH top_orders AS (SELECT * FROM test_orders ORDER BY total_price DESC LIMIT 5) SELECT t.*, p.name FROM top_orders t JOIN test_products p ON p.id = t.product_id"})` → CTE + JOIN plan. Verify multi-step plan.
367
+
368
+ ### Category 6: Migration Risk Assessment Depth
369
+
370
+ 35. `sqlite_migration_risks({statements: ["DROP TABLE test_products"]})` → critical/high risk. Verify risk mentions FK dependents (`test_orders`).
371
+ 36. `sqlite_migration_risks({statements: ["ALTER TABLE test_products ADD COLUMN temp_col TEXT"]})` → low risk (additive, non-destructive)
372
+ 37. `sqlite_migration_risks({statements: ["CREATE INDEX idx_temp ON test_products(name)"]})` → low risk
373
+ 38. `sqlite_migration_risks({statements: ["DROP INDEX idx_orders_status"]})` → medium risk (removing a supporting index). Verify `riskLevel: "medium"` and `category: "index_removal"`.
374
+ 39. `sqlite_migration_risks({statements: ["ALTER TABLE test_products ADD COLUMN temp1 TEXT", "DROP TABLE test_orders", "CREATE TABLE new_orders (id INTEGER PRIMARY KEY)"]})` → 3 statements, mixed risk levels. Verify `summary.totalStatements = 3` and `summary.highestRisk ≥ "high"`.
375
+
376
+ ### Category 7: Error Message Quality
377
+
378
+ 40. `sqlite_query_plan({sql: "DELETE FROM test_products WHERE id = 1"})` → structured error rejecting non-SELECT
379
+ 41. `sqlite_query_plan({sql: "SELECT * FROM nonexistent_table_xyz"})` → structured error mentioning table
380
+ 42. `sqlite_query_plan({})` → Zod error for missing `sql` param — must be handler error, NOT raw MCP error
381
+ 43. `sqlite_cascade_simulator({})` → Zod error for missing `table` param
382
+ 44. `sqlite_migration_risks({})` → Zod error for missing `statements` param
383
+ 45. `sqlite_storage_analysis({limit: 0})` → Zod error (min: 1)
384
+ 46. `sqlite_storage_analysis({limit: -5})` → Zod error
385
+
386
+ ### Final Cleanup
387
+
388
+ All tools in this group are read-only — no cleanup needed. Confirm `test_products` (16 rows), `test_orders` (20 rows), and `test_measurements` (200 rows) are unchanged.
389
+
390
+ ---
391
+
392
+ ## migration Group Advanced Tests
393
+
394
+ > **Note:** Migration tools create a `_mcp_migrations` tracking table and may ALTER/CREATE/DROP tables. **Always reset the database after this group.**
395
+
396
+ ### Built-in Tools (3)
397
+
398
+ 1. server_info
399
+ 2. server_health
400
+ 3. list_adapters
401
+
402
+ ### migration Group Tools (6)
403
+
404
+ 4. sqlite_migration_init
405
+ 5. sqlite_migration_record
406
+ 6. sqlite_migration_apply
407
+ 7. sqlite_migration_rollback
408
+ 8. sqlite_migration_history
409
+ 9. sqlite_migration_status
410
+
411
+ ### Category 1: Initialization & Idempotency
412
+
413
+ 1. `sqlite_migration_init({})` → success, `_mcp_migrations` table created
414
+ 2. `sqlite_migration_init({})` → idempotent call: should succeed without error (table already exists)
415
+ 3. `sqlite_migration_status({})` → empty/clean state, no pending migrations
416
+ 4. `sqlite_migration_history({})` → empty list
417
+
418
+ ### Category 2: Full Lifecycle (Record → Apply → Rollback)
419
+
420
+ **2.1 Simple ALTER TABLE Migration**
421
+
422
+ 5. `sqlite_migration_record({version: "stress_001_add_col", migrationSql: "ALTER TABLE test_products ADD COLUMN stress_flag INTEGER DEFAULT 0"})` → recorded (note: `migrationRecord` only stores metadata in `_mcp_migrations`; use `migrationApply` to execute the SQL)
423
+ 6. `sqlite_migration_status({})` → shows 1 recorded migration
424
+ 7. Verify column is NOT yet added until `migrationApply` is called. Use `sqlite_migration_apply` with the same `version` and `migrationSql` to execute.
425
+ 8. `sqlite_migration_status({})` → shows 1 applied after `migrationApply`
426
+
427
+ **2.2 CREATE TABLE Migration**
428
+
429
+ 9. `sqlite_migration_record({version: "stress_002_create_table", migrationSql: "CREATE TABLE stress_migration_data (id INTEGER PRIMARY KEY, name TEXT NOT NULL, value REAL)"})` → recorded (does NOT create the table). Use `migrationApply` to execute.
430
+ 10. `sqlite_migration_history({})` → shows both migrations with timestamps
431
+
432
+ **2.3 Rollback Chain**
433
+
434
+ 11. `sqlite_migration_rollback({version: "stress_002_create_table"})` → report behavior: rollback may require stored rollbackSql from apply step
435
+ 12. `sqlite_list_tables` → verify `stress_migration_data` status
436
+ 13. `sqlite_migration_history({})` → check `stress_002_create_table` status
437
+
438
+ ### Category 3: State Pollution & Ordering
439
+
440
+ **3.1 Re-Record After Rollback**
441
+
442
+ 14. `sqlite_migration_record({version: "stress_003_recreate", migrationSql: "CREATE TABLE stress_migration_data (id INTEGER PRIMARY KEY, value TEXT)"})` → recorded and applied (different schema from rolled-back migration)
443
+ 15. `sqlite_migration_status({})` → verify correct counts
444
+
445
+ **3.2 Duplicate Name Detection**
446
+
447
+ 16. `sqlite_migration_record({version: "stress_001_add_col", migrationSql: "SELECT 1"})` → report behavior: should error (duplicate version) or allow re-record?
448
+
449
+ **3.3 Multi-Statement Apply Verification**
450
+
451
+ 17. Record a migration with a complex SQL statement:
452
+ `sqlite_migration_record({version: "stress_004_complex", migrationSql: "CREATE INDEX stress_idx_flag ON test_products(stress_flag)"})`
453
+ 18. Verify index created with `sqlite_get_indexes({tableName: "test_products"})`.
454
+
455
+ ### Category 4: Error Paths & Recovery
456
+
457
+ **4.1 Apply Failures**
458
+
459
+ 19. `sqlite_migration_record({version: "stress_005_bad_sql", migrationSql: "ALTER TABLE nonexistent_xyz ADD COLUMN foo TEXT"})` → records successfully (record only stores metadata, does not validate SQL executability)
460
+ 20. `sqlite_migration_status({})` → verify the failed migration state is tracked (not lost)
461
+
462
+ **4.2 Nonexistent Migration Operations**
463
+
464
+ 21. `sqlite_migration_apply({version: "nonexistent_migration_xyz"})` → structured error (not raw MCP error)
465
+ 22. `sqlite_migration_rollback({version: "nonexistent_migration_xyz"})` → structured error
466
+
467
+ **4.3 Zod Validation Errors**
468
+
469
+ 23. `sqlite_migration_record({})` → Zod error for missing required params (`version`, `migrationSql`) — must be handler error
470
+ 24. `sqlite_migration_apply({})` → Zod error for missing `version`
471
+ 25. `sqlite_migration_rollback({})` → Zod error for missing params
472
+
473
+ ### Category 5: Error Message Quality
474
+
475
+ Rate each error response 1-5 for contextual usefulness:
476
+
477
+ 26. `sqlite_migration_apply({version: "nonexistent_migration_xyz"})` → rate error: does it mention the migration version?
478
+ 27. `sqlite_migration_record({})` → rate error: does it list the missing required fields?
479
+ 28. `sqlite_migration_rollback({version: "stress_001_add_col"})` (already applied, not rolled back yet — or already rolled back) → rate error clarity
480
+
481
+ ### Final Cleanup
482
+
483
+ 1. Drop `_mcp_migrations`: `sqlite_write_query({query: "DROP TABLE IF EXISTS _mcp_migrations"})`
484
+ 2. Drop `stress_migration_data`: `sqlite_write_query({query: "DROP TABLE IF EXISTS stress_migration_data"})`
485
+ 3. Drop `stress_idx_flag`: `sqlite_write_query({query: "DROP INDEX IF EXISTS stress_idx_flag"})`
486
+ 4. **Reset the database** with `pwsh -ExecutionPolicy Bypass -File .\reset-database.ps1` to undo the `stress_flag` column addition on `test_products` (SQLite cannot DROP COLUMN in older versions)
487
+ 5. After reset, verify: `test_products` has 16 rows and original 6 columns (no `stress_flag`)