db-mcp 1.1.1 → 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-TVIZ3XJH.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-FW7UCRLN.js → chunk-VIDSICEL.js} +3 -0
- 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-26V3Y4MK.js → sqlite-U5KSYQXK.js} +62 -138
- package/dist/{sqlite-native-5O7FZJGB.js → sqlite-native-JXMCFQBA.js} +575 -113
- 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-RHVEZ42P.js +0 -873
- 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,278 @@
|
|
|
1
|
+
# db-mcp Code Mode Testing: [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:** Conduct an exhaustive test of the **migration** tool group using ONLY `sqlite_execute_code`. Do not use direct tool calls or terminal.
|
|
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 modifies schema. 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 phases to skip or adjust.
|
|
19
|
+
|
|
20
|
+
## Reporting Format
|
|
21
|
+
|
|
22
|
+
- ❌ Fail: Tool errors or produces incorrect results
|
|
23
|
+
- ⚠️ Issue: Unexpected behavior or improvement opportunity
|
|
24
|
+
- 📦 Payload: Unnecessarily large response — monitor `metrics.tokenEstimate`.
|
|
25
|
+
|
|
26
|
+
## Test Database Schema
|
|
27
|
+
|
|
28
|
+
| Table | Rows | Key Columns |
|
|
29
|
+
| ------------- | ---- | ---------------------------------------- |
|
|
30
|
+
| test_products | 16 | id, name, price, category |
|
|
31
|
+
| test_orders | 20 | id, product_id (FK), total_price, status |
|
|
32
|
+
|
|
33
|
+
## Testing Requirements
|
|
34
|
+
|
|
35
|
+
> [!CAUTION]
|
|
36
|
+
> **Zero tolerance for raw MCP errors.** Report as ❌.
|
|
37
|
+
|
|
38
|
+
1. **Batched scripting**: Bundle checks with `failures` array where possible.
|
|
39
|
+
2. **Error path testing**: Every tool with `{}` (Zod) and domain error.
|
|
40
|
+
3. **Token tracking**: Monitor `metrics.tokenEstimate`.
|
|
41
|
+
4. **Coverage Matrix**: `| Tool | Happy Path | Domain Error | Zod Error |`
|
|
42
|
+
5. **Deterministic checklist first**.
|
|
43
|
+
6. **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
|
|
44
|
+
|
|
45
|
+
> **⚠️ Migration ordering matters**: Migration tests are stateful — each depends on the previous. Run lifecycle tests sequentially, not batched.
|
|
46
|
+
|
|
47
|
+
## Structured Error Response Pattern
|
|
48
|
+
|
|
49
|
+
Handler error ✅ = JSON with `success` + `error`. MCP error ❌ = raw text, `isError: true`.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## Phase 1: Initialization & Recording — Happy Paths (sequential)
|
|
54
|
+
|
|
55
|
+
### 1.1 — Init migrations
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
return await sqlite.migration.migrationInit();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Expected: `{success: true}`, creates `_mcp_migrations` table (idempotent).
|
|
62
|
+
|
|
63
|
+
### 1.2 — Init again (idempotency)
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
return await sqlite.migration.migrationInit();
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Expected: Succeeds without error.
|
|
70
|
+
|
|
71
|
+
### 1.3 — Check status (empty)
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
return await sqlite.migration.migrationStatus();
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Expected: No migrations applied.
|
|
78
|
+
|
|
79
|
+
### 1.4 — Record a migration (no execution)
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
return await sqlite.migration.migrationRecord({
|
|
83
|
+
version: "1.0.0",
|
|
84
|
+
description: "Create temp table",
|
|
85
|
+
migrationSql:
|
|
86
|
+
"CREATE TABLE temp_cm_mig_test (id INTEGER PRIMARY KEY, name TEXT)",
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Expected: Recorded (SQL not executed — only logged).
|
|
91
|
+
|
|
92
|
+
### 1.5 — Check status (1 migration)
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
return await sqlite.migration.migrationStatus();
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Expected: Count incremented.
|
|
99
|
+
|
|
100
|
+
### 1.6 — Check history
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
return await sqlite.migration.migrationHistory();
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Expected: Version 1.0.0 listed.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Phase 2: Apply & Execute — Happy Paths (sequential)
|
|
111
|
+
|
|
112
|
+
### 2.1 — Apply a migration (SQL executed)
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
return await sqlite.migration.migrationApply({
|
|
116
|
+
version: "1.0.1",
|
|
117
|
+
description: "Create applied table",
|
|
118
|
+
migrationSql:
|
|
119
|
+
"CREATE TABLE temp_cm_mig_applied (id INTEGER PRIMARY KEY, value TEXT)",
|
|
120
|
+
});
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Expected: Applied (SQL executed AND recorded).
|
|
124
|
+
|
|
125
|
+
### 2.2 — Verify table exists
|
|
126
|
+
|
|
127
|
+
```javascript
|
|
128
|
+
return await sqlite.core.readQuery(
|
|
129
|
+
"SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_applied'",
|
|
130
|
+
);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Expected: Table exists.
|
|
134
|
+
|
|
135
|
+
### 2.3 — Check history (2 migrations)
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
return await sqlite.migration.migrationHistory();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Expected: Both 1.0.0 and 1.0.1 listed.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Phase 3: SHA-256 Deduplication
|
|
146
|
+
|
|
147
|
+
### 3.1 — Duplicate SQL detection
|
|
148
|
+
|
|
149
|
+
```javascript
|
|
150
|
+
return await sqlite.migration.migrationRecord({
|
|
151
|
+
version: "1.0.2",
|
|
152
|
+
description: "Duplicate test",
|
|
153
|
+
migrationSql:
|
|
154
|
+
"CREATE TABLE temp_cm_mig_test (id INTEGER PRIMARY KEY, name TEXT)",
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Expected: Fail — duplicate SQL hash detected.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Phase 4: Rollback — Happy Paths (sequential)
|
|
163
|
+
|
|
164
|
+
### 4.1 — Rollback without rollback SQL
|
|
165
|
+
|
|
166
|
+
```javascript
|
|
167
|
+
return await sqlite.migration.migrationRollback({ version: "1.0.1" });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Expected: Informative error (no rollbackSql was provided).
|
|
171
|
+
|
|
172
|
+
### 4.2 — Apply with rollback SQL
|
|
173
|
+
|
|
174
|
+
```javascript
|
|
175
|
+
return await sqlite.migration.migrationApply({
|
|
176
|
+
version: "1.0.3",
|
|
177
|
+
description: "With rollback",
|
|
178
|
+
migrationSql: "CREATE TABLE temp_cm_mig_rollback (id INTEGER PRIMARY KEY)",
|
|
179
|
+
rollbackSql: "DROP TABLE IF EXISTS temp_cm_mig_rollback",
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
Expected: Applied with rollback SQL stored.
|
|
184
|
+
|
|
185
|
+
### 4.3 — Execute rollback
|
|
186
|
+
|
|
187
|
+
```javascript
|
|
188
|
+
return await sqlite.migration.migrationRollback({ version: "1.0.3" });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Expected: Rollback SQL executed.
|
|
192
|
+
|
|
193
|
+
### 4.4 — Verify table gone
|
|
194
|
+
|
|
195
|
+
```javascript
|
|
196
|
+
return await sqlite.core.readQuery(
|
|
197
|
+
"SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_rollback'",
|
|
198
|
+
);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Expected: Table does NOT exist.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Phase 5: Migration Domain Errors (batched)
|
|
206
|
+
|
|
207
|
+
🔴 5.1. `sqlite.migration.migrationApply({version: "bad version!", description: "Invalid", migrationSql: "SELECT 1"})` → report behavior
|
|
208
|
+
🔴 5.2. `sqlite.migration.migrationRollback({version: "nonexistent_version"})` → `{success: false}`
|
|
209
|
+
|
|
210
|
+
---
|
|
211
|
+
|
|
212
|
+
## Phase 6: Migration Zod Validation (batched)
|
|
213
|
+
|
|
214
|
+
🔴 6.1. `sqlite.migration.migrationInit({})` → success (no required params)
|
|
215
|
+
🔴 6.2. `sqlite.migration.migrationRecord({})` → `{success: false}` (missing required params)
|
|
216
|
+
🔴 6.3. `sqlite.migration.migrationApply({})` → `{success: false}` (missing required params)
|
|
217
|
+
🔴 6.4. `sqlite.migration.migrationRollback({})` → `{success: false}` (missing `version`)
|
|
218
|
+
🔴 6.5. `sqlite.migration.migrationHistory({})` → success (no required params)
|
|
219
|
+
🔴 6.6. `sqlite.migration.migrationStatus({})` → success (no required params)
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Phase 7: Multi-Step Workflow
|
|
224
|
+
|
|
225
|
+
### 7.1 — Full migration lifecycle
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
const failures = [];
|
|
229
|
+
// Init
|
|
230
|
+
await sqlite.migration.migrationInit();
|
|
231
|
+
|
|
232
|
+
// Apply
|
|
233
|
+
await sqlite.migration.migrationApply({
|
|
234
|
+
version: "9.9.1",
|
|
235
|
+
description: "Lifecycle test",
|
|
236
|
+
migrationSql:
|
|
237
|
+
"CREATE TABLE temp_cm_mig_lifecycle (id INTEGER PRIMARY KEY, val TEXT)",
|
|
238
|
+
rollbackSql: "DROP TABLE IF EXISTS temp_cm_mig_lifecycle",
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
// Verify
|
|
242
|
+
const status = await sqlite.migration.migrationStatus();
|
|
243
|
+
const history = await sqlite.migration.migrationHistory();
|
|
244
|
+
const tableExists = await sqlite.core.readQuery(
|
|
245
|
+
"SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_lifecycle'",
|
|
246
|
+
);
|
|
247
|
+
|
|
248
|
+
if (!tableExists.rows || tableExists.rows.length === 0)
|
|
249
|
+
failures.push("table not created after apply");
|
|
250
|
+
|
|
251
|
+
// Rollback
|
|
252
|
+
await sqlite.migration.migrationRollback({ version: "9.9.1" });
|
|
253
|
+
const afterRollback = await sqlite.core.readQuery(
|
|
254
|
+
"SELECT name FROM sqlite_master WHERE name = 'temp_cm_mig_lifecycle'",
|
|
255
|
+
);
|
|
256
|
+
if (afterRollback.rows && afterRollback.rows.length > 0)
|
|
257
|
+
failures.push("table still exists after rollback");
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
failures,
|
|
261
|
+
success: failures.length === 0,
|
|
262
|
+
statusBefore: status,
|
|
263
|
+
historyEntries: history,
|
|
264
|
+
};
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## Post-Test Procedures
|
|
270
|
+
|
|
271
|
+
1. **⚠️ Explicit Cleanup**: Execute a final Code Mode script to `DROP TABLE IF EXISTS` all `temp_*` tables created during the test, as the active MCP server lock prevents the reset script from clearing them.
|
|
272
|
+
2. **⚠️ Reset database**: Run `Set-Location C:\Users\chris\Desktop\db-mcp\test-server; .\reset-database.ps1` to re-seed the test database.
|
|
273
|
+
3. **Triage findings**: Create implementation plan if issues found
|
|
274
|
+
4. **Scope of fixes**: Handler code, server-instructions, this prompt
|
|
275
|
+
5. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
|
|
276
|
+
6. **Commit**: Stage and commit — do NOT push
|
|
277
|
+
7. **Token audit**: Report most expensive block
|
|
278
|
+
8. **Final summary**: After testing/re-testing
|
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
# db-mcp Code Mode Testing: [sandbox]
|
|
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:** Conduct an exhaustive test of the **Code Mode sandbox** using ONLY `sqlite_execute_code`. Do not use direct tool calls or terminal.
|
|
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), apply these adjustments:
|
|
17
|
+
|
|
18
|
+
- **Phase 2.1** (top-level help): Expect fewer than 10 groups — `transactions` is not listed (0 tools registered in WASM). `totalMethods` will be ~125 instead of ~151.
|
|
19
|
+
- **Phase 2.3** (all groups exist): The `transactions` group property exists on the `sqlite` object but returns 0 methods. Adjust the assertion to allow 0 methods for `transactions`.
|
|
20
|
+
- **Phase 4.5** (stats read-only): Stats tools are fully WASM-compatible — no adjustment needed.
|
|
21
|
+
|
|
22
|
+
## Reporting Format
|
|
23
|
+
|
|
24
|
+
- ❌ Fail: Tool errors or produces incorrect results (include error message)
|
|
25
|
+
- ⚠️ Issue: Unexpected behavior or improvement opportunity
|
|
26
|
+
- 📦 Payload: Unnecessarily large response — **blocking, equally important as ❌ bugs**. You **MUST** monitor `metrics.tokenEstimate` for every operation. Report the response size in tokens/KB and suggest optimization.
|
|
27
|
+
|
|
28
|
+
## Test Database Schema
|
|
29
|
+
|
|
30
|
+
| Table | Rows | Key Columns |
|
|
31
|
+
| ------------- | ---- | ------------------------------------------------------------------------------------------- |
|
|
32
|
+
| test_products | 16 | id, name, description, price (REAL), category (TEXT lowercase), created_at |
|
|
33
|
+
| test_orders | 20 | id, product_id (FK→test_products), customer_name, quantity, total_price, order_date, status |
|
|
34
|
+
|
|
35
|
+
> **Note:** This prompt tests the sandbox execution environment, not specific tool groups. It uses `test_products` and `test_orders` as representative tables for validation.
|
|
36
|
+
|
|
37
|
+
## Testing Requirements
|
|
38
|
+
|
|
39
|
+
> [!CAUTION]
|
|
40
|
+
> **Zero tolerance for raw MCP errors.** Any response that is a raw MCP error (no `success` field) is a bug — report as ❌.
|
|
41
|
+
|
|
42
|
+
1. **Error path testing**: Validate structured error responses for invalid inputs.
|
|
43
|
+
2. **Token tracking**: Monitor `metrics.tokenEstimate` on every response. Report the most expensive block.
|
|
44
|
+
3. **Deterministic checklist first**: Complete ALL numbered items before freeform exploration.
|
|
45
|
+
4. **Code Over Docs**: Fix the handler code if standards (Structured Errors/Zod) are violated. Do NOT change docs/prompts to accommodate broken code.
|
|
46
|
+
|
|
47
|
+
## Structured Error Response Pattern
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{ "success": false, "error": "Human-readable error message" }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Type | What you see | Verdict |
|
|
54
|
+
| -------------------- | --------------------------------------------- | ------- |
|
|
55
|
+
| **Handler error** ✅ | JSON object with `success` and `error` fields | Correct |
|
|
56
|
+
| **MCP error** ❌ | Raw text, `isError: true`, no `success` field | Bug |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Phase 1: Sandbox Basics (9 tests)
|
|
61
|
+
|
|
62
|
+
> These tests validate the Code Mode sandbox itself — run them first.
|
|
63
|
+
|
|
64
|
+
### 1.1 — Simple return value
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
return 42;
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Expected: `{success: true, result: 42}`
|
|
71
|
+
|
|
72
|
+
### 1.2 — Object return
|
|
73
|
+
|
|
74
|
+
```javascript
|
|
75
|
+
return { name: "test", values: [1, 2, 3] };
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 1.3 — Async/await support
|
|
79
|
+
|
|
80
|
+
```javascript
|
|
81
|
+
const result = await Promise.resolve("async works");
|
|
82
|
+
return result;
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 1.4 — Runtime error handling
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
const x = undefinedVariable;
|
|
89
|
+
return x;
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Expected: `{success: false, error: "...not defined..."}` — structured, not crash.
|
|
93
|
+
|
|
94
|
+
### 1.5 — Empty code
|
|
95
|
+
|
|
96
|
+
Call `sqlite_execute_code` with `code: ""`.
|
|
97
|
+
Expected: `{success: false}` with validation error, not raw MCP error.
|
|
98
|
+
|
|
99
|
+
### 1.6 — Empty params
|
|
100
|
+
|
|
101
|
+
Call `sqlite_execute_code` with `{}` (no `code` param).
|
|
102
|
+
Expected: structured handler error, NOT raw MCP `-32602`.
|
|
103
|
+
|
|
104
|
+
### 1.7 — Return null
|
|
105
|
+
|
|
106
|
+
```javascript
|
|
107
|
+
return null;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Expected: `{success: true, result: null}` — sandbox must handle null return values.
|
|
111
|
+
|
|
112
|
+
### 1.8 — Return undefined
|
|
113
|
+
|
|
114
|
+
```javascript
|
|
115
|
+
return undefined;
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Expected: `{success: true}` — sandbox must handle undefined without crashing. `result` may be absent or null.
|
|
119
|
+
|
|
120
|
+
### 1.9 — Return large nested object
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
const nested = {};
|
|
124
|
+
let current = nested;
|
|
125
|
+
for (let i = 0; i < 10; i++) {
|
|
126
|
+
current.level = i;
|
|
127
|
+
current.child = {};
|
|
128
|
+
current = current.child;
|
|
129
|
+
}
|
|
130
|
+
current.leaf = "deep value";
|
|
131
|
+
return nested;
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Expected: `{success: true}` — sandbox must serialize deeply nested objects.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Phase 2: API Discoverability (7 tests)
|
|
139
|
+
|
|
140
|
+
### 2.1 — Top-level help
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
return await sqlite.help();
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Expected: `{groups: [...], totalMethods: <number>, usage: "..."}` with 10 groups listed (including transactions). **WASM**: Fewer groups — `transactions` is absent; `totalMethods` ≈ 125.
|
|
147
|
+
|
|
148
|
+
### 2.2 — Group help (core)
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
return await sqlite.core.help();
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Expected: `{group: "core", methods: [...]}` with methods including `readQuery`, `writeQuery`, `listTables`, `describeTable`, `upsert`, `batchInsert`, `count`, `exists`, `truncate`.
|
|
155
|
+
|
|
156
|
+
### 2.3 — All groups exist
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
const groups = [
|
|
160
|
+
"core",
|
|
161
|
+
"json",
|
|
162
|
+
"text",
|
|
163
|
+
"stats",
|
|
164
|
+
"vector",
|
|
165
|
+
"admin",
|
|
166
|
+
"transactions",
|
|
167
|
+
"geo",
|
|
168
|
+
"introspection",
|
|
169
|
+
"migration",
|
|
170
|
+
];
|
|
171
|
+
const results = {};
|
|
172
|
+
for (const g of groups) {
|
|
173
|
+
const h = await sqlite[g].help();
|
|
174
|
+
results[g] = h.methods.length;
|
|
175
|
+
}
|
|
176
|
+
return results;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Expected: All 10 groups return >0 methods. **WASM**: `transactions` returns 0 methods — adjust assertion to allow this.
|
|
180
|
+
|
|
181
|
+
### 2.4 — Method aliases resolve
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
const r1 = await sqlite.core.query("SELECT 1 AS num");
|
|
185
|
+
const r2 = await sqlite.core.readQuery("SELECT 1 AS num");
|
|
186
|
+
return { aliasResult: r1, canonicalResult: r2 };
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Expected: Both return identical results.
|
|
190
|
+
|
|
191
|
+
### 2.5 — Top-level convenience aliases
|
|
192
|
+
|
|
193
|
+
```javascript
|
|
194
|
+
const tables = await sqlite.listTables();
|
|
195
|
+
return { success: true, tableCount: tables.tables?.length };
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### 2.6 — Positional args
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
return await sqlite.core.readQuery("SELECT name FROM test_products LIMIT 2");
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Expected: Works with string positional arg (not just object).
|
|
205
|
+
|
|
206
|
+
### 2.7 — Built-in tools not in sandbox
|
|
207
|
+
|
|
208
|
+
```javascript
|
|
209
|
+
return {
|
|
210
|
+
serverInfo: typeof sqlite.serverInfo,
|
|
211
|
+
serverHealth: typeof sqlite.serverHealth,
|
|
212
|
+
listAdapters: typeof sqlite.listAdapters,
|
|
213
|
+
server_info: typeof sqlite.server_info,
|
|
214
|
+
server_health: typeof sqlite.server_health,
|
|
215
|
+
list_adapters: typeof sqlite.list_adapters,
|
|
216
|
+
};
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Expected: All values are `"undefined"`. The 3 built-in tools (`server_info`, `server_health`, `list_adapters`) are always-on MCP tools available outside Code Mode but must NOT be accessible in the `sqlite.*` sandbox namespace.
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Phase 3: Security & Error Handling (7 tests)
|
|
224
|
+
|
|
225
|
+
### 3.1 — Blocked pattern (require)
|
|
226
|
+
|
|
227
|
+
```javascript
|
|
228
|
+
const fs = require("fs");
|
|
229
|
+
return fs.readFileSync("/etc/passwd");
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Expected: `{success: false, code: "CODEMODE_VALIDATION_FAILED"}`
|
|
233
|
+
|
|
234
|
+
### 3.2 — Blocked pattern (process)
|
|
235
|
+
|
|
236
|
+
```javascript
|
|
237
|
+
return process.env;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Expected: `{success: false}` — blocked pattern or runtime error.
|
|
241
|
+
|
|
242
|
+
### 3.3 — Blocked pattern (eval)
|
|
243
|
+
|
|
244
|
+
```javascript
|
|
245
|
+
return eval("1+1");
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Expected: `{success: false, code: "CODEMODE_VALIDATION_FAILED"}`
|
|
249
|
+
|
|
250
|
+
### 3.4 — Timeout enforcement
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
while (true) {}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Call with `timeout: 2000`. Expected: `{success: false}` with timeout error within ~2s.
|
|
257
|
+
|
|
258
|
+
### 3.5 — Timeout enforcement (tight tolerance)
|
|
259
|
+
|
|
260
|
+
```javascript
|
|
261
|
+
const start = Date.now();
|
|
262
|
+
while (Date.now() - start < 1000) {} // busy-wait 1s
|
|
263
|
+
return "completed";
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Call with `timeout: 500`. Expected: `{success: false}` with timeout error — the 500ms timeout must fire before the 1s loop completes.
|
|
267
|
+
|
|
268
|
+
### 3.6 — Invalid tool call via API
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
return await sqlite.core.readQuery({ query: "SELECT * FROM nonexistent_xyz" });
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Expected: Returns `{success: false, error: "..."}` — sandbox must not crash.
|
|
275
|
+
|
|
276
|
+
### 3.7 — Undefined API group
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
return await sqlite.nonexistent.help();
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Expected: runtime error, not crash.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## Phase 4: Readonly Mode (5 tests)
|
|
287
|
+
|
|
288
|
+
All tests use `readonly: true` on the `sqlite_execute_code` call.
|
|
289
|
+
|
|
290
|
+
### 4.1 — Read operations work
|
|
291
|
+
|
|
292
|
+
```javascript
|
|
293
|
+
// readonly: true
|
|
294
|
+
return await sqlite.core.readQuery("SELECT COUNT(*) AS cnt FROM test_products");
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Expected: `{success: true, rows: [{cnt: 16}]}`
|
|
298
|
+
|
|
299
|
+
### 4.2 — Write operations blocked
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
// readonly: true
|
|
303
|
+
return await sqlite.core.writeQuery(
|
|
304
|
+
"INSERT INTO test_products (name) VALUES ('blocked')",
|
|
305
|
+
);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Expected: `{success: false, code: "CODEMODE_READONLY_VIOLATION"}`
|
|
309
|
+
|
|
310
|
+
### 4.3 — Read methods still discoverable
|
|
311
|
+
|
|
312
|
+
```javascript
|
|
313
|
+
// readonly: true
|
|
314
|
+
const help = await sqlite.core.help();
|
|
315
|
+
return {
|
|
316
|
+
hasWriteQuery: help.methods.includes("writeQuery"),
|
|
317
|
+
methods: help.methods,
|
|
318
|
+
};
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
Expected: `writeQuery` still appears in help (for discoverability) but is guarded.
|
|
322
|
+
|
|
323
|
+
### 4.4 — Create table blocked
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
// readonly: true
|
|
327
|
+
return await sqlite.core.writeQuery(
|
|
328
|
+
"CREATE TABLE temp_readonly_test (id INTEGER)",
|
|
329
|
+
);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Expected: `{success: false, code: "CODEMODE_READONLY_VIOLATION"}`
|
|
333
|
+
|
|
334
|
+
### 4.5 — Stats read-only works
|
|
335
|
+
|
|
336
|
+
```javascript
|
|
337
|
+
// readonly: true
|
|
338
|
+
return await sqlite.stats.statsBasic({
|
|
339
|
+
table: "test_products",
|
|
340
|
+
column: "price",
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Expected: succeeds — stats tools are read-only.
|
|
345
|
+
|
|
346
|
+
---
|
|
347
|
+
|
|
348
|
+
## Phase 5: State Isolation (2 tests)
|
|
349
|
+
|
|
350
|
+
### 5.1 — Variables don't persist between calls
|
|
351
|
+
|
|
352
|
+
Run two separate `sqlite_execute_code` calls:
|
|
353
|
+
|
|
354
|
+
**Call 1:**
|
|
355
|
+
|
|
356
|
+
```javascript
|
|
357
|
+
var persistTest = "should not persist";
|
|
358
|
+
return persistTest;
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Call 2:**
|
|
362
|
+
|
|
363
|
+
```javascript
|
|
364
|
+
try {
|
|
365
|
+
return { persisted: typeof persistTest !== "undefined", value: persistTest };
|
|
366
|
+
} catch (e) {
|
|
367
|
+
return { persisted: false, error: e.message };
|
|
368
|
+
}
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Expected: Call 2 returns `{persisted: false}` — variables from Call 1 must not leak.
|
|
372
|
+
|
|
373
|
+
### 5.2 — Database state persists between calls
|
|
374
|
+
|
|
375
|
+
Run two separate `sqlite_execute_code` calls:
|
|
376
|
+
|
|
377
|
+
**Call 1:**
|
|
378
|
+
|
|
379
|
+
```javascript
|
|
380
|
+
await sqlite.core.createTable({
|
|
381
|
+
table: "temp_cm_iso_test",
|
|
382
|
+
columns: [
|
|
383
|
+
{ name: "id", type: "INTEGER", primaryKey: true },
|
|
384
|
+
{ name: "val", type: "TEXT" },
|
|
385
|
+
],
|
|
386
|
+
});
|
|
387
|
+
await sqlite.core.writeQuery(
|
|
388
|
+
"INSERT INTO temp_cm_iso_test VALUES (1, 'persisted')",
|
|
389
|
+
);
|
|
390
|
+
return "created";
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Call 2:**
|
|
394
|
+
|
|
395
|
+
```javascript
|
|
396
|
+
const result = await sqlite.core.readQuery("SELECT * FROM temp_cm_iso_test");
|
|
397
|
+
await sqlite.core.dropTable({ table: "temp_cm_iso_test", ifExists: true });
|
|
398
|
+
return result;
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
Expected: Call 2 reads the row inserted in Call 1 — database state persists across sandbox invocations (sandbox is stateless, database is not).
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
405
|
+
## Post-Test Procedures
|
|
406
|
+
|
|
407
|
+
1. **Cleanup**: Confirm all `temp_*` tables are removed
|
|
408
|
+
2. **Triage findings**: Create implementation plan if issues found
|
|
409
|
+
3. **Scope of fixes**: Handler code, server-instructions, this prompt
|
|
410
|
+
4. **Validate**: Instruct the user to run the test suite (Vitest/Playwright), lint, and typecheck. Do NOT run them yourself.
|
|
411
|
+
5. **Commit**: Stage and commit — do NOT push
|
|
412
|
+
6. **Token audit**: Report `metrics.tokenEstimate` for the most expensive block
|
|
413
|
+
7. **Final summary**: After testing/re-testing
|