db-mcp 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitleaks.toml +9 -0
- package/.trivyignore +8 -0
- package/README.md +193 -120
- package/dist/{chunk-DWJXQEFA.js → chunk-5Y42NPBP.js} +4168 -2411
- package/dist/{chunk-AOUL5SHS.js → chunk-645ZEFLA.js} +70 -20
- package/dist/chunk-OKOVZ5QE.js +28 -0
- package/dist/chunk-SFJQCNG7.js +131 -0
- package/dist/{chunk-S5IDDSSB.js → chunk-VIDSICEL.js} +12 -1
- package/dist/chunk-WBER5YY4.js +2053 -0
- package/dist/{chunk-4IA3DB5C.js → chunk-X3MUUOWM.js} +19 -2
- package/dist/{chunk-Z2GFQU3G.js → chunk-Z7C2TM4L.js} +114 -21
- package/dist/cli.js +79 -5
- package/dist/{http-VSB7DBJR.js → http-6KF4ULDI.js} +199 -77
- package/dist/index.d.ts +231 -8
- package/dist/index.js +6 -5
- package/dist/{sqlite-VHBA4ABV.js → sqlite-U5KSYQXK.js} +63 -140
- package/dist/{sqlite-native-D2LH5ZT7.js → sqlite-native-JXMCFQBA.js} +576 -114
- package/dist/worker-script.js +34 -10
- package/logs/.gitkeep +1 -0
- package/mcp-config-example.json +83 -0
- package/package.json +9 -8
- package/playwright.config.ts +1 -1
- package/scripts/update-badges.ts +99 -0
- package/server.json +7 -5
- package/test-server/README.md +20 -23
- package/test-server/code-map.md +45 -33
- package/test-server/reset-database.ps1 +59 -17
- package/test-server/scripts/README.md +27 -0
- package/test-server/{test-help-resources.mjs → scripts/test-help-resources.mjs} +12 -5
- package/test-server/scripts/test-prompts.mjs +251 -0
- package/test-server/{test-tool-annotations.mjs → scripts/test-tool-annotations.mjs} +9 -4
- package/test-server/test-advanced/README.md +70 -0
- package/test-server/test-advanced/test-codemode-advanced-admin.md +174 -0
- package/test-server/test-advanced/test-codemode-advanced-core.md +193 -0
- package/test-server/test-advanced/test-codemode-advanced-geo.md +157 -0
- package/test-server/test-advanced/test-codemode-advanced-introspection.md +171 -0
- package/test-server/test-advanced/test-codemode-advanced-json.md +169 -0
- package/test-server/test-advanced/test-codemode-advanced-migration.md +160 -0
- package/test-server/test-advanced/test-codemode-advanced-stats.md +185 -0
- package/test-server/test-advanced/test-codemode-advanced-text.md +183 -0
- package/test-server/test-advanced/test-codemode-advanced-transactions.md +136 -0
- package/test-server/test-advanced/test-codemode-advanced-vector.md +141 -0
- package/test-server/test-codemode/README.md +121 -0
- package/test-server/test-codemode/test-codemode-admin.md +223 -0
- package/test-server/test-codemode/test-codemode-core.md +286 -0
- package/test-server/test-codemode/test-codemode-geo.md +177 -0
- package/test-server/test-codemode/test-codemode-introspection.md +190 -0
- package/test-server/test-codemode/test-codemode-json.md +237 -0
- package/test-server/test-codemode/test-codemode-migration.md +278 -0
- package/test-server/test-codemode/test-codemode-sandbox.md +413 -0
- package/test-server/test-codemode/test-codemode-stats.md +232 -0
- package/test-server/test-codemode/test-codemode-text.md +237 -0
- package/test-server/test-codemode/test-codemode-transactions.md +236 -0
- package/test-server/test-codemode/test-codemode-vector.md +244 -0
- package/test-server/test-codemode/test-codemode-wasm-degradation.md +394 -0
- package/test-server/test-database.sql +37 -1
- package/test-server/test-resources.md +43 -16
- package/test-server/test-tool-groups/README.md +100 -0
- package/test-server/test-tool-groups/test-admin-core.md +165 -0
- package/test-server/test-tool-groups/test-admin-extensions.md +133 -0
- package/test-server/{test-tools.md → test-tool-groups/test-core-data.md} +103 -17
- package/test-server/test-tool-groups/test-core-schema.md +240 -0
- package/test-server/test-tool-groups/test-geo-haversine.md +130 -0
- package/test-server/test-tool-groups/test-geo-spatialite.md +110 -0
- package/test-server/test-tool-groups/test-introspection-diagnostics.md +123 -0
- package/test-server/test-tool-groups/test-introspection-schema.md +133 -0
- package/test-server/test-tool-groups/test-json-read.md +219 -0
- package/test-server/test-tool-groups/test-json-write.md +157 -0
- package/test-server/test-tool-groups/test-migration.md +193 -0
- package/test-server/test-tool-groups/test-stats-advanced.md +118 -0
- package/test-server/test-tool-groups/test-stats-basic.md +156 -0
- package/test-server/test-tool-groups/test-text-advanced.md +169 -0
- package/test-server/test-tool-groups/test-text-basic.md +177 -0
- package/test-server/test-tool-groups/test-transactions.md +179 -0
- package/test-server/test-tool-groups/test-vector-read.md +130 -0
- package/test-server/test-tool-groups/test-vector-write.md +115 -0
- package/test-server/tool-reference.md +79 -58
- package/tsconfig.build.json +6 -0
- package/dist/chunk-DZQLDEQS.js +0 -879
- package/test-server/test-agent-experience.md +0 -243
- package/test-server/test-group-tools.md +0 -861
- package/test-server/test-tools-advanced-1.md +0 -517
- package/test-server/test-tools-advanced-2.md +0 -487
- package/test-server/test-tools-codemode.md +0 -629
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# db-mcp Advanced Stress Test — [introspection]
|
|
2
|
+
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Do not track progress in this file.** Track your test progress, coverage matrix, and findings in your internal task tracking system (artifact). However, you SHOULD edit this file to fix any factual errors, broken code, or incorrect assertions in the test prompts.
|
|
5
|
+
> If there is nothing to fix, don't update UNRELEASED.md.
|
|
6
|
+
> We're currently testing Native mode.
|
|
7
|
+
|
|
8
|
+
**Step 1:** Read `C:\Users\chris\Desktop\db-mcp\src\constants\server-instructions\gotchas.md` using `view_file`.
|
|
9
|
+
|
|
10
|
+
**Step 2:** Execute each numbered stress test below using `sqlite_execute_code` (code mode).
|
|
11
|
+
|
|
12
|
+
**Step 3:** The agent should update C:\Users\chris\Desktop\db-mcp\UNRELEASED.md with any/all changes/fixes.
|
|
13
|
+
|
|
14
|
+
## WASM Mode
|
|
15
|
+
|
|
16
|
+
> When testing against a **WASM backend** (`--sqlite` / sql.js): All 9 introspection tools are fully WASM-compatible. No categories to skip.
|
|
17
|
+
>
|
|
18
|
+
> **Minor difference**: `schemaSnapshot` may report `test_articles_fts` in virtual tables but it is not queryable (FTS5 is unavailable in WASM). Treat its presence as expected but non-functional.
|
|
19
|
+
|
|
20
|
+
> **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.
|
|
21
|
+
|
|
22
|
+
## Code Mode Execution
|
|
23
|
+
|
|
24
|
+
- **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
|
|
25
|
+
|
|
26
|
+
All tests via `sqlite_execute_code`. Use `sqlite.introspection.*` for all introspection tools.
|
|
27
|
+
State persists across calls. All introspection tools are **read-only** — no cleanup needed.
|
|
28
|
+
|
|
29
|
+
## Test Database Schema
|
|
30
|
+
|
|
31
|
+
| Table | Rows | Key Columns |
|
|
32
|
+
| ----------------- | ---- | ------------------------------------------------------ |
|
|
33
|
+
| test_products | 16 | id, name, price, category |
|
|
34
|
+
| test_orders | 20 | id, product_id (FK→test_products), total_price, status |
|
|
35
|
+
| test_measurements | 200 | id, sensor_id, temperature, humidity, pressure |
|
|
36
|
+
|
|
37
|
+
**Key FK:** `test_orders.product_id → test_products.id`
|
|
38
|
+
**Redundant index (intentional):** `idx_orders_status` is a prefix of `idx_orders_status_date` — used to test index audit.
|
|
39
|
+
|
|
40
|
+
## Reporting Format
|
|
41
|
+
|
|
42
|
+
- ❌ Fail | ⚠️ Issue | 📦 Payload (monitor `metrics.tokenEstimate`) | ✅ Confirmed (inline only)
|
|
43
|
+
|
|
44
|
+
## Structured Error Response Pattern
|
|
45
|
+
|
|
46
|
+
Handler error ✅ = JSON with `success` + `error`. MCP error ❌ = raw text, `isError: true`.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## introspection Group Tools (9)
|
|
51
|
+
|
|
52
|
+
1. sqlite_dependency_graph
|
|
53
|
+
2. sqlite_topological_sort
|
|
54
|
+
3. sqlite_cascade_simulator
|
|
55
|
+
4. sqlite_schema_snapshot
|
|
56
|
+
5. sqlite_constraint_analysis
|
|
57
|
+
6. sqlite_migration_risks
|
|
58
|
+
7. sqlite_storage_analysis
|
|
59
|
+
8. sqlite_index_audit
|
|
60
|
+
9. sqlite_query_plan
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
### Category 1: Graph Analysis Edge Cases
|
|
65
|
+
|
|
66
|
+
**1.1 Full Dependency Graph**
|
|
67
|
+
|
|
68
|
+
1. `sqlite.introspection.dependencyGraph({})` → full graph. Verify edge `test_orders → test_products` present.
|
|
69
|
+
2. `sqlite.introspection.dependencyGraph({includeRowCounts: false})` → verify rowCount omitted.
|
|
70
|
+
3. Verify `stats.rootTables` and `stats.leafTables` are populated and disjoint.
|
|
71
|
+
|
|
72
|
+
**1.2 Topological Sort Direction Stress**
|
|
73
|
+
|
|
74
|
+
4. `sqlite.introspection.topologicalSort({direction: "create"})` → `test_products` BEFORE `test_orders`
|
|
75
|
+
5. `sqlite.introspection.topologicalSort({direction: "drop"})` → `test_orders` BEFORE `test_products`
|
|
76
|
+
6. Verify both directions list the same set of tables (just reordered)
|
|
77
|
+
|
|
78
|
+
**1.3 Cascade Chains**
|
|
79
|
+
|
|
80
|
+
7. `sqlite.introspection.cascadeSimulator({table: "test_products"})` → affectedTables includes `test_orders` with FK action
|
|
81
|
+
8. `sqlite.introspection.cascadeSimulator({table: "test_measurements"})` → affectedTables empty (leaf table)
|
|
82
|
+
9. `sqlite.introspection.cascadeSimulator({table: "test_orders"})` → affectedTables empty (nothing references test_orders via FK)
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### Category 2: Schema Snapshot Completeness
|
|
87
|
+
|
|
88
|
+
10. `sqlite.introspection.schemaSnapshot({})` → full snapshot:
|
|
89
|
+
- tables ≥ 11 (10 regular + FTS virtual)
|
|
90
|
+
- indexes ≥ 4 (`idx_orders_status`, `idx_orders_date`, `idx_products_category`, `idx_orders_status_date`)
|
|
91
|
+
- generatedAt is valid ISO timestamp
|
|
92
|
+
11. `sqlite.introspection.schemaSnapshot({sections: ["indexes"]})` → only indexes section. Tables absent.
|
|
93
|
+
12. `sqlite.introspection.schemaSnapshot({sections: ["tables", "indexes"]})` → both sections present
|
|
94
|
+
13. `sqlite.introspection.schemaSnapshot({compact: true})` → tables present but columns arrays absent
|
|
95
|
+
14. `sqlite.introspection.schemaSnapshot({compact: false})` → column details (name, type, nullable, pk) present
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
### Category 3: Constraint Analysis Stress
|
|
100
|
+
|
|
101
|
+
15. `sqlite.introspection.constraintAnalysis({})` → all tables analyzed. Verify summary.byType and summary.bySeverity keys.
|
|
102
|
+
16. `sqlite.introspection.constraintAnalysis({checks: ["unindexed_fk"]})` → only unindexed FK findings.
|
|
103
|
+
17. `sqlite.introspection.constraintAnalysis({table: "test_users"})` → only test_users findings. No other tables referenced.
|
|
104
|
+
18. `sqlite.introspection.constraintAnalysis({table: "nonexistent_table_xyz"})` → report behavior: empty findings or structured error?
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
### Category 4: Storage Analysis & Index Audit Depth
|
|
109
|
+
|
|
110
|
+
**4.1 Storage Analysis Verification**
|
|
111
|
+
|
|
112
|
+
19. `sqlite.introspection.storageAnalysis({})` → verify database.totalSizeBytes = pageSize × totalPages (arithmetic check)
|
|
113
|
+
20. `sqlite.introspection.storageAnalysis({})` → verify tables sorted by size descending
|
|
114
|
+
21. `sqlite.introspection.storageAnalysis({includeTableDetails: false})` → tables absent. Database-level metrics present.
|
|
115
|
+
22. `sqlite.introspection.storageAnalysis({limit: 3})` → only top 3 tables (if supported)
|
|
116
|
+
23. `sqlite.introspection.storageAnalysis({})` → verify fragmentationPct 0-100, journalMode and autoVacuum non-empty
|
|
117
|
+
|
|
118
|
+
**4.2 Index Audit Cross-Validation**
|
|
119
|
+
|
|
120
|
+
24. `sqlite.introspection.indexAudit({})` → flag `idx_orders_status` as `type: "redundant"` (prefix of `idx_orders_status_date`). Field name is `index`.
|
|
121
|
+
25. `sqlite.introspection.indexAudit({})` → verify `redundantOf` points to `idx_orders_status_date`
|
|
122
|
+
26. `sqlite.introspection.indexAudit({})` → check for `missing_fk_index` on `test_orders.product_id`
|
|
123
|
+
27. `sqlite.introspection.indexAudit({table: "test_products"})` → only test_products findings. `idx_products_category` NOT redundant.
|
|
124
|
+
28. `sqlite.introspection.indexAudit({table: "test_measurements"})` → 200 rows, no secondary indexes. `unindexed_large_table` threshold is 1000 → no finding expected.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### Category 5: Query Plan Deep Analysis
|
|
129
|
+
|
|
130
|
+
29. `sqlite.introspection.queryPlan({sql: "SELECT * FROM test_orders WHERE status = 'completed'"})` → use `idx_orders_status`
|
|
131
|
+
30. `sqlite.introspection.queryPlan({sql: "SELECT * FROM test_products WHERE name = 'Laptop Pro 15'"})` → full scan (no index on name). Verify `analysis.fullScans` includes `test_products`, `suggestions` array exists.
|
|
132
|
+
31. `sqlite.introspection.queryPlan({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 with multiple entries.
|
|
133
|
+
32. `sqlite.introspection.queryPlan({sql: "SELECT * FROM test_orders WHERE status = 'completed' AND order_date > '2026-01-20'"})` → compound WHERE. Verify index choice.
|
|
134
|
+
33. `sqlite.introspection.queryPlan({sql: "SELECT COUNT(*) FROM test_measurements GROUP BY sensor_id"})` → GROUP BY without dedicated index. Expect full scan.
|
|
135
|
+
34. `sqlite.introspection.queryPlan({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.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### Category 6: Migration Risk Assessment Depth
|
|
140
|
+
|
|
141
|
+
35. `sqlite.introspection.migrationRisks({statements: ["DROP TABLE test_products"]})` → critical/high risk. Mentions FK dependents.
|
|
142
|
+
36. `sqlite.introspection.migrationRisks({statements: ["ALTER TABLE test_products ADD COLUMN temp_col TEXT"]})` → low risk (additive)
|
|
143
|
+
37. `sqlite.introspection.migrationRisks({statements: ["CREATE INDEX idx_temp ON test_products(name)"]})` → low risk
|
|
144
|
+
38. `sqlite.introspection.migrationRisks({statements: ["DROP INDEX idx_orders_status"]})` → medium risk. Verify `riskLevel: "medium"`, `category: "index_removal"`.
|
|
145
|
+
39. `sqlite.introspection.migrationRisks({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. `summary.totalStatements = 3`, `summary.highestRisk ≥ "high"`.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
### Category 7: Error Message Quality
|
|
150
|
+
|
|
151
|
+
40. `sqlite.introspection.queryPlan({sql: "DELETE FROM test_products WHERE id = 1"})` → structured error rejecting non-SELECT
|
|
152
|
+
41. `sqlite.introspection.queryPlan({sql: "SELECT * FROM nonexistent_table_xyz"})` → structured error mentioning table
|
|
153
|
+
42. `sqlite.introspection.queryPlan({})` → Zod error for missing `sql` — must be handler error, NOT raw MCP
|
|
154
|
+
43. `sqlite.introspection.cascadeSimulator({})` → Zod error for missing `table`
|
|
155
|
+
44. `sqlite.introspection.migrationRisks({})` → Zod error for missing `statements`
|
|
156
|
+
45. `sqlite.introspection.storageAnalysis({limit: 0})` → Zod error (min: 1)
|
|
157
|
+
46. `sqlite.introspection.storageAnalysis({limit: -5})` → Zod error
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Final Cleanup
|
|
162
|
+
|
|
163
|
+
All tools read-only — no cleanup needed. Confirm `test_products` (16), `test_orders` (20), `test_measurements` (200) unchanged.
|
|
164
|
+
|
|
165
|
+
## Post-Test Procedures
|
|
166
|
+
|
|
167
|
+
1. **Fix EVERY finding** — ❌, ⚠️, 📦
|
|
168
|
+
2. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
|
|
169
|
+
3. **Commit**: Stage and commit — do NOT push
|
|
170
|
+
4. **Re-test**: After server rebuild
|
|
171
|
+
5. **Token audit**: Report most expensive block
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# db-mcp Advanced Stress Test — [json]
|
|
2
|
+
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Do not track progress in this file.** Track your test progress, coverage matrix, and findings in your internal task tracking system (artifact). However, you SHOULD edit this file to fix any factual errors, broken code, or incorrect assertions in the test prompts.
|
|
5
|
+
> If there is nothing to fix, don't update UNRELEASED.md.
|
|
6
|
+
> We're currently testing Native mode.
|
|
7
|
+
|
|
8
|
+
**Step 1:** Read `C:\Users\chris\Desktop\db-mcp\src\constants\server-instructions\gotchas.md` using `view_file`.
|
|
9
|
+
|
|
10
|
+
**Step 2:** Execute each numbered stress test below using `sqlite_execute_code` (code mode).
|
|
11
|
+
|
|
12
|
+
**Step 3:** The agent should update C:\Users\chris\Desktop\db-mcp\UNRELEASED.md with any/all changes/fixes.
|
|
13
|
+
|
|
14
|
+
## WASM Mode
|
|
15
|
+
|
|
16
|
+
> When testing against a **WASM backend** (`--sqlite` / sql.js): All 24 JSON tools are fully WASM-compatible. No categories to skip or adjust.
|
|
17
|
+
|
|
18
|
+
## Code Mode Execution
|
|
19
|
+
|
|
20
|
+
- **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
|
|
21
|
+
|
|
22
|
+
All tests via `sqlite_execute_code`. Use `sqlite.json.*` for JSON tools, `sqlite.core.*` for read/write.
|
|
23
|
+
State persists across calls. Do NOT pass `readonly: true`. Group related tests into single calls.
|
|
24
|
+
|
|
25
|
+
## Test Database Schema
|
|
26
|
+
|
|
27
|
+
| Table | Rows | Key Columns |
|
|
28
|
+
| --------------- | ---- | -------------------------------------------------------------- |
|
|
29
|
+
| test_jsonb_docs | 6 | id, doc (JSON), metadata (JSON), tags (JSON array), created_at |
|
|
30
|
+
| test_events | 100 | id, event_type, user_id, payload (JSON), event_date |
|
|
31
|
+
|
|
32
|
+
**test_jsonb_docs key data:**
|
|
33
|
+
|
|
34
|
+
- Row 1: `doc.type="article"`, `doc.author="Alice"`, `doc.views=1250`, `doc.rating=4.5`
|
|
35
|
+
- Row 4: `doc.nested.level1.level2 = "deep value"`
|
|
36
|
+
- Row 5: `doc.type="podcast"` (no `doc.views` field)
|
|
37
|
+
|
|
38
|
+
## Naming & Cleanup
|
|
39
|
+
|
|
40
|
+
- **Temporary tables**: `stress_*` prefix. Drop at end.
|
|
41
|
+
- If DROP fails due to lock, note and move on.
|
|
42
|
+
|
|
43
|
+
## Reporting Format
|
|
44
|
+
|
|
45
|
+
- ❌ Fail | ⚠️ Issue | 📦 Payload (monitor `metrics.tokenEstimate`) | ✅ Confirmed (inline only)
|
|
46
|
+
|
|
47
|
+
### Error Message Quality Rating
|
|
48
|
+
|
|
49
|
+
| Level | Verdict |
|
|
50
|
+
| -------------------------------------- | ------- |
|
|
51
|
+
| 5 - Excellent (name + code + context) | ✅ |
|
|
52
|
+
| 4 - Good (name) | ✅ |
|
|
53
|
+
| 3 - Adequate (raw SQLite, informative) | ⚠️ |
|
|
54
|
+
| 2 - Poor (no object name) | ⚠️ |
|
|
55
|
+
| 1 - Useless (generic) | ❌ |
|
|
56
|
+
|
|
57
|
+
## Structured Error Response Pattern
|
|
58
|
+
|
|
59
|
+
Handler error ✅ = JSON with `success` + `error`. MCP error ❌ = raw text, `isError: true`.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## json Group Tools (24 + codemode)
|
|
64
|
+
|
|
65
|
+
1. sqlite_json_valid
|
|
66
|
+
2. sqlite_json_extract
|
|
67
|
+
3. sqlite_json_set
|
|
68
|
+
4. sqlite_json_remove
|
|
69
|
+
5. sqlite_json_type
|
|
70
|
+
6. sqlite_json_array_length
|
|
71
|
+
7. sqlite_json_array_append
|
|
72
|
+
8. sqlite_json_keys
|
|
73
|
+
9. sqlite_json_each
|
|
74
|
+
10. sqlite_json_group_array
|
|
75
|
+
11. sqlite_json_group_object
|
|
76
|
+
12. sqlite_json_pretty
|
|
77
|
+
13. sqlite_jsonb_convert
|
|
78
|
+
14. sqlite_json_storage_info
|
|
79
|
+
15. sqlite_json_normalize_column
|
|
80
|
+
16. sqlite_json_insert
|
|
81
|
+
17. sqlite_json_update
|
|
82
|
+
18. sqlite_json_select
|
|
83
|
+
19. sqlite_json_query
|
|
84
|
+
20. sqlite_json_validate_path
|
|
85
|
+
21. sqlite_json_merge
|
|
86
|
+
22. sqlite_json_analyze_schema
|
|
87
|
+
23. sqlite_create_json_collection
|
|
88
|
+
24. sqlite_json_security_scan
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
### Category 1: Deep JSON Operations
|
|
93
|
+
|
|
94
|
+
**1.1 Deeply Nested Access**
|
|
95
|
+
|
|
96
|
+
1. `sqlite.json.extract({table: "test_jsonb_docs", column: "doc", path: "$.nested.level1.level2", whereClause: "id = 4"})` → `"deep value"`
|
|
97
|
+
2. `sqlite.json.extract({table: "test_jsonb_docs", column: "doc", path: "$.nested.level1.nonexistent", whereClause: "id = 4"})` → null or empty (not error)
|
|
98
|
+
3. `sqlite.json.extract({table: "test_jsonb_docs", column: "doc", path: "$.nonexistent_key", whereClause: "id = 1"})` → null or empty
|
|
99
|
+
|
|
100
|
+
**1.2 Array Manipulation Edge Cases**
|
|
101
|
+
|
|
102
|
+
4. `sqlite.json.arrayLength({table: "test_jsonb_docs", column: "tags", whereClause: "id = 3"})` → 3 (["mcp","protocol","ai"])
|
|
103
|
+
5. Create `stress_json_test` with a row containing `tags = '[]'` (empty array) → `sqlite.json.arrayLength` → 0
|
|
104
|
+
6. `sqlite.json.each` on an empty array → 0 expanded rows (not error)
|
|
105
|
+
|
|
106
|
+
**1.3 Merge Conflict Behavior**
|
|
107
|
+
|
|
108
|
+
> `sqlite_json_merge` uses `json_patch()` which follows RFC 7396 merge-patch semantics.
|
|
109
|
+
|
|
110
|
+
Insert test rows into `stress_json_test`: row 2 = `{"a": 1, "b": {"c": 2}}`, row 3 = `{"a": [1, 2]}`:
|
|
111
|
+
|
|
112
|
+
7. `sqlite.json.merge({table: "stress_json_test", column: "tags", mergeData: {"b": {"d": 3}}, whereClause: "id = 2"})` → verify deep merge: `b.c` preserved, `b.d` added
|
|
113
|
+
8. `sqlite.json.merge({table: "stress_json_test", column: "tags", mergeData: {"a": [3, 4]}, whereClause: "id = 3"})` → arrays replaced (not concatenated) per RFC 7396
|
|
114
|
+
|
|
115
|
+
**1.4 Type Coercion Edge Cases**
|
|
116
|
+
|
|
117
|
+
9. `sqlite.json.type({table: "test_jsonb_docs", column: "doc", path: "$.views", whereClause: "id = 1"})` → `"integer"` (views=1250)
|
|
118
|
+
10. `sqlite.json.type({table: "test_jsonb_docs", column: "doc", path: "$.rating", whereClause: "id = 1"})` → `"real"` (rating=4.5)
|
|
119
|
+
11. `sqlite.json.type({table: "test_jsonb_docs", column: "doc", path: "$.nested", whereClause: "id = 4"})` → `"object"`
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### Category 2: JSON Query & Filter Stress
|
|
124
|
+
|
|
125
|
+
> `sqlite_json_query` uses `filterPaths` (equality-only, `Record<path, value>`) and `selectPaths`.
|
|
126
|
+
|
|
127
|
+
12. `sqlite.json.query({table: "test_jsonb_docs", column: "doc", filterPaths: {"$.type": "article"}})` → 4 rows
|
|
128
|
+
13. `sqlite.json.query({table: "test_jsonb_docs", column: "doc", filterPaths: {"$.type": "article", "$.author": "Alice"}, selectPaths: ["$.title", "$.views"]})` → 1 row (Alice's article)
|
|
129
|
+
14. `sqlite.json.query({table: "test_events", column: "payload", filterPaths: {"$.page": "home"}})` → 25 rows (every 4th event)
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
### Category 3: Error Message Quality
|
|
134
|
+
|
|
135
|
+
15. `sqlite.json.extract({table: "nonexistent_table_xyz", column: "doc", path: "$.x"})` → structured error mentioning table name
|
|
136
|
+
16. `sqlite.json.extract({table: "test_jsonb_docs", column: "nonexistent_col", path: "$.x"})` → structured error mentioning column
|
|
137
|
+
17. `sqlite.json.set({table: "test_jsonb_docs", column: "doc", path: "$.author", value: "\"Modified\"", whereClause: "id = 99999"})` → report behavior for nonexistent row
|
|
138
|
+
18. `sqlite.json.validatePath({path: ""})` → report behavior for empty path
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### Category 4: Write Operation Safety
|
|
143
|
+
|
|
144
|
+
19. Create `stress_json_write` table → insert 3 JSON documents → perform `sqlite.json.set`, `sqlite.json.remove`, `sqlite.json.insert` → verify mutations → cleanup
|
|
145
|
+
> **Note:** `sqlite_json_insert` is a **row-level INSERT** (creates new row with JSON data, provided via the `data` parameter), not a path-level JSON insert.
|
|
146
|
+
20. `sqlite.json.normalizeColumn(...)` on `stress_json_write` → verify keys sorted/compacted without data loss
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### Category 5: Security Scan Stress
|
|
151
|
+
|
|
152
|
+
21. `sqlite.json.securityScan({table: "test_jsonb_docs", column: "doc"})` → scan result with `riskLevel`
|
|
153
|
+
22. Create `stress_json_inject` with rows containing suspicious patterns (`<script>`, `' OR 1=1`, `${cmd}`) → `sqlite.json.securityScan` → verify detection
|
|
154
|
+
23. Cleanup: drop `stress_json_inject`
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### Final Cleanup
|
|
159
|
+
|
|
160
|
+
Drop all `stress_*` tables. Confirm `test_jsonb_docs` row count is still 6 and contents unchanged.
|
|
161
|
+
|
|
162
|
+
## Post-Test Procedures
|
|
163
|
+
|
|
164
|
+
1. **Cleanup**: Drop all `stress_*` objects
|
|
165
|
+
2. **Fix EVERY finding** — ❌, ⚠️, 📦. Consistent with `code-map.md`
|
|
166
|
+
3. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
|
|
167
|
+
4. **Commit**: Stage and commit — do NOT push
|
|
168
|
+
5. **Re-test**: After server rebuild
|
|
169
|
+
6. **Token audit**: Report most expensive block
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# db-mcp Advanced Stress Test — [migration]
|
|
2
|
+
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> **Do not track progress in this file.** Track your test progress, coverage matrix, and findings in your internal task tracking system (artifact). However, you SHOULD edit this file to fix any factual errors, broken code, or incorrect assertions in the test prompts.
|
|
5
|
+
> If there is nothing to fix, don't update UNRELEASED.md.
|
|
6
|
+
> We're currently testing Native mode.
|
|
7
|
+
|
|
8
|
+
**Step 1:** Read `C:\Users\chris\Desktop\db-mcp\src\constants\server-instructions\gotchas.md` using `view_file`.
|
|
9
|
+
|
|
10
|
+
**Step 2:** Execute each numbered stress test below using `sqlite_execute_code` (code mode).
|
|
11
|
+
|
|
12
|
+
**Step 3:** The agent should update C:\Users\chris\Desktop\db-mcp\UNRELEASED.md with any/all changes/fixes.
|
|
13
|
+
|
|
14
|
+
> **⚠️ After testing, run `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1`** — migration testing creates the `_mcp_migrations` tracking table and may ALTER/CREATE/DROP tables. Always reset after.
|
|
15
|
+
|
|
16
|
+
## WASM Mode
|
|
17
|
+
|
|
18
|
+
> When testing against a **WASM backend** (`--sqlite` / sql.js): All 6 migration tools are fully WASM-compatible. No categories to skip or adjust.
|
|
19
|
+
|
|
20
|
+
## Code Mode Execution
|
|
21
|
+
|
|
22
|
+
- **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
|
|
23
|
+
|
|
24
|
+
All tests via `sqlite_execute_code`. Use `sqlite.migration.*` for migration tools, `sqlite.core.*` for read/write.
|
|
25
|
+
State persists across calls. Do NOT pass `readonly: true`.
|
|
26
|
+
|
|
27
|
+
> **⚠️ Migration tests are stateful** — each depends on state from the previous. Run lifecycle tests sequentially.
|
|
28
|
+
|
|
29
|
+
## Test Database Schema
|
|
30
|
+
|
|
31
|
+
| Table | Rows | Key Columns |
|
|
32
|
+
| ------------- | ---- | ---------------------------------------- |
|
|
33
|
+
| test_products | 16 | id, name, price, category |
|
|
34
|
+
| test_orders | 20 | id, product_id (FK), total_price, status |
|
|
35
|
+
|
|
36
|
+
## Naming & Cleanup
|
|
37
|
+
|
|
38
|
+
- **Temporary tables**: `stress_*` prefix.
|
|
39
|
+
- **After testing**: Run `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1` to undo schema modifications.
|
|
40
|
+
|
|
41
|
+
## Reporting Format
|
|
42
|
+
|
|
43
|
+
- ❌ Fail | ⚠️ Issue | 📦 Payload (monitor `metrics.tokenEstimate`) | ✅ Confirmed (inline only)
|
|
44
|
+
|
|
45
|
+
## Structured Error Response Pattern
|
|
46
|
+
|
|
47
|
+
Handler error ✅ = JSON with `success` + `error`. MCP error ❌ = raw text, `isError: true`.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## migration Group Tools (6)
|
|
52
|
+
|
|
53
|
+
1. sqlite_migration_init
|
|
54
|
+
2. sqlite_migration_record
|
|
55
|
+
3. sqlite_migration_apply
|
|
56
|
+
4. sqlite_migration_rollback
|
|
57
|
+
5. sqlite_migration_history
|
|
58
|
+
6. sqlite_migration_status
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
62
|
+
### Category 1: Initialization & Idempotency
|
|
63
|
+
|
|
64
|
+
1. `sqlite.migration.migrationInit({})` → success, `_mcp_migrations` table created
|
|
65
|
+
2. `sqlite.migration.migrationInit({})` → idempotent: should succeed without error
|
|
66
|
+
3. `sqlite.migration.migrationStatus({})` → empty/clean state
|
|
67
|
+
4. `sqlite.migration.migrationHistory({})` → empty list
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### Category 2: Full Lifecycle (Record → Apply → Rollback)
|
|
72
|
+
|
|
73
|
+
**2.1 Simple ALTER TABLE Migration**
|
|
74
|
+
|
|
75
|
+
5. `sqlite.migration.migrationRecord({version: "stress_001_add_col", description: "Add stress flag", sql: "ALTER TABLE test_products ADD COLUMN stress_flag INTEGER DEFAULT 0"})` → recorded (SQL not executed)
|
|
76
|
+
6. `sqlite.migration.migrationStatus({})` → shows 1 recorded migration
|
|
77
|
+
7. Verify column is NOT yet added
|
|
78
|
+
8. `sqlite.migration.migrationApply({version: "stress_001_add_col", description: "Add stress flag", sql: "ALTER TABLE test_products ADD COLUMN stress_flag INTEGER DEFAULT 0"})` → applied (SQL executed)
|
|
79
|
+
9. `sqlite.migration.migrationStatus({})` → shows 1 applied
|
|
80
|
+
|
|
81
|
+
**2.2 CREATE TABLE Migration**
|
|
82
|
+
|
|
83
|
+
10. `sqlite.migration.migrationApply({version: "stress_002_create_table", description: "Create data table", sql: "CREATE TABLE stress_migration_data (id INTEGER PRIMARY KEY, name TEXT NOT NULL, value REAL)", rollbackSql: "DROP TABLE IF EXISTS stress_migration_data"})` → applied
|
|
84
|
+
11. `sqlite.migration.migrationHistory({})` → both migrations with timestamps
|
|
85
|
+
|
|
86
|
+
**2.3 Rollback Chain**
|
|
87
|
+
|
|
88
|
+
12. `sqlite.migration.migrationRollback({version: "stress_002_create_table"})` → rollback with stored rollbackSql
|
|
89
|
+
13. Verify `stress_migration_data` is gone
|
|
90
|
+
14. `sqlite.migration.migrationHistory({})` → check status
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
### Category 3: State Pollution & Ordering
|
|
95
|
+
|
|
96
|
+
**3.1 Re-Record After Rollback**
|
|
97
|
+
|
|
98
|
+
15. `sqlite.migration.migrationApply({version: "stress_003_recreate", description: "Recreate", sql: "CREATE TABLE stress_migration_data (id INTEGER PRIMARY KEY, value TEXT)", rollbackSql: "DROP TABLE IF EXISTS stress_migration_data"})` → applied
|
|
99
|
+
16. `sqlite.migration.migrationStatus({})` → verify counts
|
|
100
|
+
|
|
101
|
+
**3.2 Duplicate Detection**
|
|
102
|
+
|
|
103
|
+
17. `sqlite.migration.migrationRecord({version: "stress_001_add_col", description: "Duplicate", sql: "SELECT 1"})` → report behavior: should error (duplicate version) or allow?
|
|
104
|
+
|
|
105
|
+
**3.3 SHA-256 Duplicate SQL Detection**
|
|
106
|
+
|
|
107
|
+
18. `sqlite.migration.migrationRecord({version: "stress_004_dup_sql", description: "Dup SQL", sql: "ALTER TABLE test_products ADD COLUMN stress_flag INTEGER DEFAULT 0"})` → report behavior: same SQL hash as stress_001
|
|
108
|
+
|
|
109
|
+
**3.4 Multi-Statement Apply Verification**
|
|
110
|
+
|
|
111
|
+
19. `sqlite.migration.migrationApply({version: "stress_005_index", description: "Add index", sql: "CREATE INDEX stress_idx_flag ON test_products(stress_flag)", rollbackSql: "DROP INDEX IF EXISTS stress_idx_flag"})` → applied
|
|
112
|
+
20. Verify index created with `sqlite.core.getIndexes({table: "test_products"})`
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### Category 4: Error Paths & Recovery
|
|
117
|
+
|
|
118
|
+
**4.1 Apply Failures**
|
|
119
|
+
|
|
120
|
+
21. `sqlite.migration.migrationApply({version: "stress_006_bad_sql", description: "Bad SQL", sql: "ALTER TABLE nonexistent_xyz ADD COLUMN foo TEXT"})` → records but execute fails
|
|
121
|
+
22. `sqlite.migration.migrationStatus({})` → verify failed migration state is tracked
|
|
122
|
+
|
|
123
|
+
**4.2 Nonexistent Migration Operations**
|
|
124
|
+
|
|
125
|
+
23. `sqlite.migration.migrationRollback({version: "nonexistent_migration_xyz"})` → structured error (not raw MCP)
|
|
126
|
+
|
|
127
|
+
**4.3 Zod Validation Errors**
|
|
128
|
+
|
|
129
|
+
24. `sqlite.migration.migrationRecord({})` → Zod error for missing required params — must be handler error
|
|
130
|
+
25. `sqlite.migration.migrationApply({})` → Zod error for missing required params
|
|
131
|
+
26. `sqlite.migration.migrationRollback({})` → Zod error for missing `version`
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### Category 5: Error Message Quality
|
|
136
|
+
|
|
137
|
+
Rate each error response 1-5:
|
|
138
|
+
|
|
139
|
+
27. `sqlite.migration.migrationRollback({version: "nonexistent_migration_xyz"})` → does it mention the version?
|
|
140
|
+
28. `sqlite.migration.migrationRecord({})` → does it list missing required fields?
|
|
141
|
+
29. `sqlite.migration.migrationRollback({version: "stress_001_add_col"})` → rate error clarity (no rollbackSql stored)
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
### Final Cleanup
|
|
146
|
+
|
|
147
|
+
1. Drop `_mcp_migrations`: `sqlite.admin.dropTable({table: "_mcp_migrations"})`
|
|
148
|
+
2. Drop `stress_migration_data`: `sqlite.admin.dropTable({table: "stress_migration_data"})`
|
|
149
|
+
3. Drop `stress_idx_flag`: _Handled by database reset below_
|
|
150
|
+
4. **Reset database** with `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1` to undo `stress_flag` column on `test_products`
|
|
151
|
+
5. After reset, verify: `test_products` has 16 rows and original columns (no `stress_flag`)
|
|
152
|
+
|
|
153
|
+
## Post-Test Procedures
|
|
154
|
+
|
|
155
|
+
1. **⚠️ Reset database**: `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1`
|
|
156
|
+
2. **Fix EVERY finding** — ❌, ⚠️, 📦
|
|
157
|
+
3. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
|
|
158
|
+
4. **Commit**: Stage and commit — do NOT push
|
|
159
|
+
5. **Re-test**: After server rebuild
|
|
160
|
+
6. **Token audit**: Report most expensive block
|