v1.1.0 - Security, Structured Errors & Developer Experience#86
v1.1.0 - Security, Structured Errors & Developer Experience#86neverinfamous wants to merge 308 commits intomainfrom
Conversation
…ng, CORS, body size
…, logger, transport, and Docker
…con via CDN-hosted MDI SVGs
… Code Mode support
…trospection group 6->9)
…xports Split the following files that exceeded the 500-line target: - output-schemas.ts (1,735 lines) -> output-schemas/ (14 modules) - admin.ts (1,062 lines) -> admin/ (5 modules) - json-operations.ts (1,191 lines) -> json-operations/ (5 modules) - text.ts (1,525 lines) -> text/ (5 modules) - stats.ts (1,819 lines) -> stats/ (5 modules) - virtual.ts (1,186 lines) -> virtual/ (6 modules) Fixed all resulting import/export issues: - Cleaned 61+ unused imports from helpers.ts barrel files - Fixed schema imports in crud.ts (split between types.ts and helpers.ts) - Exported 5 formatting utilities for cross-module use in search.ts - Replaced dynamic import with static import in verify.ts - Added missing sanitizeIdentifier import in backup.ts - Updated NativeSqliteAdapter.ts to use explicit /index.js import paths - Fixed import type in output-schemas/server.ts - Moved createJsonArrayAppendTool import to correct source module All lint, typecheck, and tests passing.
Phase 1 — Adapter Deduplication: - Extract shared registerTool/registerResource/registerPrompt into DatabaseAdapter base class - NativeSqliteAdapter.ts (956→727), SqliteAdapter.ts (945→721) Phase 2 — Transport Split: - Split http.ts (986) into http/ directory (types, middleware, session, oauth, transport, index) - Update McpServer.ts dynamic import path Phase 3 — Tool File Splits: - spatialite.ts (915) → spatialite/ (schemas, loader, tools, index) - vector.ts (826) → vector/ (schemas, helpers, tools, index) - core.ts (770) → core/ (queries, tables, indexes, index) - Update 6 source consumers + 1 test import All 1024 tests passing, lint + typecheck clean.
… params
Two-layer fix for MCP -32602 raw errors on all 23 JSON tools:
1. DatabaseAdapter.registerTool(): Wraps inputSchema with .partial() so the
SDK accepts any param subset (including {}). Previously, the SDK validated
required fields at the transport layer and returned -32602 before the
handler could run.
2. Handler-level try/catch: All 23 JSON handlers wrap Schema.parse(params)
in try/catch blocks that return {success: false, error: ...} via
formatError(). This catches missing required fields that pass the
lenient SDK schema.
Files changed:
- DatabaseAdapter.ts: .partial() wrapping in registerTool()
- crud.ts: 7 handlers (valid, extract, set, remove, type, arrayLength, arrayAppend)
- query.ts: 4 handlers (keys, each, groupArray, groupObject)
- transform.ts: 4 handlers (pretty, jsonbConvert, storageInfo, normalizeColumn)
- json-helpers.ts: 8 handlers (insert, update, select, query, validatePath, merge, analyzeSchema, createCollection)
…te_table, describe_table, drop_table)
…d/validation errors
- sqlite_pragma_table_info, sqlite_virtual_table_info, sqlite_create_csv_table,
sqlite_create_rtree_table, sqlite_create_series_table, sqlite_append_insight
now return {success: false} for Zod/sanitizeIdentifier errors
- AppendInsightSchema.insight now requires .min(1) to reject empty strings
SDK validates inputSchema.min(1) before handler runs, bypassing try-catch. Moved empty-string check into handler body for structured error response.
Wrap Schema.parse(params) in try/catch for sqlite_backup, sqlite_restore,
sqlite_generate_series, sqlite_analyze_csv_schema, and
sqlite_transaction_execute. Previously, calling these tools with empty or
invalid parameters returned raw MCP error frames instead of structured
{success: false} handler errors.
.partial() in DatabaseAdapter.registerTool() makes keys optional for SDK
validation, but doesn't strip refinements like min(1). When sql: '' was
passed, the min(1) check fired at the SDK level, producing raw MCP error
-32602 instead of a handler error.
Removed .min(1) from QueryPlanSchema.sql and added handler-level validation
for empty sql strings, returning structured {success: false} error.
Remove .min(-90).max(90) / .min(-180).max(180) refinements from all
lat/lon fields in GeoDistanceSchema, GeoNearbySchema, and
GeoBoundingBoxSchema. Add validateCoordinates() helper for handler-level
range validation. Out-of-range coordinates now return structured
{success: false} errors instead of raw MCP -32602.
…es in json_extract
…verify_backup, create_rtree_table, create_csv_table, analyze_csv_schema
…d more (87.99% coverage)
- Add crud.test.ts: 7 JSON CRUD tools (validate, extract, set, remove, type, array-length, array-append) - Add query.test.ts: 4 JSON query/aggregation tools (keys, each, group-array, group-object) - Add transform.test.ts: 4 JSON transform tools (pretty, jsonb-convert, storage-info, normalize-column) - Add vector.test.ts: 6 vector tools (search, get, create-table, store, batch-store, delete) - Update README.md and DOCKER_README.md badges: 1911 tests, 1136 E2E, 90% coverage
…code mode, OAuth 2.1, E2E test suite
…native adapter transactions
|
|
||
| it("should handle module not available", async () => { | ||
| const adapter = createMockAdapter(); | ||
| let calledPragma = false; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 month ago
In general, unused local variables should be removed unless they are kept intentionally (e.g., for future use or as documentation) and are explicitly exempted from linting. Here, calledPragma is not used anywhere in the test, so removing its declaration is the minimal change that preserves existing behavior.
Concretely, in tests/adapters/sqlite/tools/virtual/vtable.test.ts, within the it("should handle module not available", ...) test case, delete the line let calledPragma = false; at line 144. No additional imports, helpers, or code changes are needed, since the variable is not referenced elsewhere.
| @@ -141,7 +141,6 @@ | ||
|
|
||
| it("should handle module not available", async () => { | ||
| const adapter = createMockAdapter(); | ||
| let calledPragma = false; | ||
| adapter.executeReadQuery.mockImplementation((sql: string) => { | ||
| if (sql.includes("sqlite_master")) { | ||
| return Promise.resolve({ |
There was a problem hiding this comment.
Pull request overview
This PR ships the v1.1.0 release focusing on security hardening, deterministic structured errors, and a more modular SQLite adapter/tooling architecture.
Changes:
- Adds/rewrites SQLite core/admin tooling (queries, indexes, backup/verify, transactions) with structured error formatting and scope annotations.
- Extracts adapter logic into dedicated modules (query executors, schema lifecycle, validation, registration) and updates exports/paths to kebab-case.
- Introduces Playwright E2E setup and CI workflows while bumping versions/metadata for the 1.1.0 release.
Reviewed changes
Copilot reviewed 94 out of 434 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| src/adapters/sqlite/tools/core/queries.ts | Adds read/write query tools with statement gating and safety LIMIT injection. |
| src/adapters/sqlite/tools/core/indexes.ts | Adds index management tools with identifier validation and existence checks. |
| src/adapters/sqlite/tools/core/index.ts | Exposes core tool group via barrel exports. |
| src/adapters/sqlite/tools/column-validation.ts | Introduces shared table/column existence validators used across tool groups. |
| src/adapters/sqlite/tools/admin/verify.ts | Adds backup verification and index stats admin tools. |
| src/adapters/sqlite/tools/admin/index.ts | Registers admin tools via barrel index. |
| src/adapters/sqlite/tools/admin/helpers.ts | Centralizes admin Zod schemas and coercion helpers. |
| src/adapters/sqlite/tools/admin/backup/restore.ts | Implements restore workflow with progress reporting and environment guards. |
| src/adapters/sqlite/tools/admin/backup/optimize.ts | Adds optimize tool for REINDEX/ANALYZE with progress reporting. |
| src/adapters/sqlite/tools/admin/backup/integrity.ts | Adds integrity check tool with structured output. |
| src/adapters/sqlite/tools/admin/backup/index.ts | Barrel exports for admin backup tools. |
| src/adapters/sqlite/tools/admin/backup/create.ts | Adds VACUUM INTO backup tool with WASM limitation handling. |
| src/adapters/sqlite/tools/admin/backup/analyze.ts | Adds ANALYZE tool with optional table targeting. |
| src/adapters/sqlite/sqlite-adapter/schema.ts | Adds fallback schema/table/index discovery helpers for adapter. |
| src/adapters/sqlite/sqlite-adapter/lifecycle.ts | Extracts sql.js connection lifecycle logic and shared pragma setup. |
| src/adapters/sqlite/sqlite-adapter.ts | Refactors SqliteAdapter to use extracted lifecycle/schema/query executor modules. |
| src/adapters/sqlite/schema-manager.ts | Improves caching, error typing, and documents index metadata fetching behavior. |
| src/adapters/sqlite/resources.ts | Updates resource wiring/import paths and improves error typing for invalid URIs. |
| src/adapters/sqlite/query-executor.ts | Extracts sql.js execution paths into reusable executor functions. |
| src/adapters/sqlite/prompts/schema.ts | Adds schema-focused prompt definitions. |
| src/adapters/sqlite/prompts/query.ts | Adds query/migration/debug prompt definitions. |
| src/adapters/sqlite/prompts/index.ts | Barrel re-export and prompt registry builder. |
| src/adapters/sqlite/prompts/analysis.ts | Adds analysis/workflow/demo prompts. |
| src/adapters/sqlite/output-schemas/*.ts | Introduces structured output schemas across all tool groups via ErrorFields mixin. |
| src/adapters/sqlite/json-utils.ts | Converts JSONB parsing errors to DbMcpError for structured handling. |
| src/adapters/sqlite/index.ts | Updates public exports to kebab-case adapter file naming. |
| src/adapters/sqlite-native/transaction-methods.ts | Extracts native transaction primitives into a module. |
| src/adapters/sqlite-native/tools/transactions.ts | Adds structured outputs/error handling and annotations for transaction tools. |
| src/adapters/sqlite-native/tools/spatialite/schemas.ts | Adds coercion and handler-level enum validation strategy for SpatiaLite tools. |
| src/adapters/sqlite-native/tools/spatialite/loader.ts | Implements SpatiaLite extension discovery/loading and loaded-state tracking. |
| src/adapters/sqlite-native/tools/spatialite/index.ts | Barrel exports SpatiaLite tools and loader helpers. |
| src/adapters/sqlite-native/registration/index.ts | Extracts native adapter tool registration and icon attachment logic. |
| src/adapters/sqlite-native/native-query-executor.ts | Extracts better-sqlite3 query execution into reusable executor functions. |
| src/adapters/sqlite-native/index.ts | Updates exports and SpatiaLite path to new module structure. |
| src/adapters/sqlite-native/extensions.ts | Adds centralized extension loading (SpatiaLite/CSV) with project-root discovery. |
| src/adapters/sqlite-helpers.ts | Adds shared DDL detection, param normalization, and pragma/WAL/JSONB helpers. |
| src/adapters/registration/tools.ts | Adds shared tool registration implementation with schema passthrough/partial handling. |
| src/adapters/registration/resources.ts | Adds shared resource registration implementation for static + template resources. |
| src/adapters/registration/prompts.ts | Adds shared prompt registration with required-args schema handling. |
| src/adapters/registration/index.ts | Barrel exports registration helpers. |
| src/adapters/query-validation.ts | Extracts SQL validation logic and hoists dangerous regex patterns. |
| src/adapters/database-adapter.ts | Refactors adapter base to use shared registration and extracted query validation. |
| server.json | Updates registry metadata to v1.1.0 and docker tag. |
| scripts/generate-server-instructions.ts | Adds generator script for instructions/help content from markdown. |
| releases/v1.1.0.md | Adds v1.1.0 release notes. |
| playwright.config.ts | Adds Playwright config for multi-project E2E runs (wasm/native/auth). |
| package.json | Bumps to v1.1.0, switches build to tsup, adds e2e/bench scripts, updates deps. |
| eslint.config.js | Adds explicit test-file ESLint config and ignore patterns. |
| docs/KEYCLOAK_SETUP.md | Removes Keycloak setup doc. |
| UNRELEASED.md | Adds unreleased changelog stub. |
| LICENSE | Updates copyright year range. |
| Dockerfile | Updates build hardening steps, healthcheck behavior, and tool count label. |
| CODE_OF_CONDUCT.md | Replaces with Contributor Covenant v2.1 content. |
| .vscode/settings.json | Adds editor/ESLint/Prettier settings for DX. |
| .npmignore | Updates publish ignore list (dist-focused) and packaging exclusions. |
| .github/workflows/*.yml | Pins actions, adds E2E workflow, benchmark job, and improves security gate behavior. |
| .dockerignore | Expands docker ignore coverage for cleaner build contexts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| const tableCheck = await adapter.executeReadQuery( | ||
| `SELECT 1 FROM sqlite_master WHERE type IN ('table', 'view') AND name='${tableName.replace(/'/g, "''")}'`, | ||
| ); |
| const result = await adapter.executeReadQuery( | ||
| `SELECT name FROM pragma_table_info('${tableName.replace(/'/g, "''")}') WHERE name = '${columnName.replace(/'/g, "''")}' LIMIT 1`, | ||
| ); |
| const pragmaResult = await adapter.executeReadQuery( | ||
| `SELECT name FROM pragma_table_info('${tableName.replace(/'/g, "''")}')`, | ||
| ); |
| if (table) { | ||
| sql += ` AND tbl_name = '${table.replace(/'/g, "''")}'`; | ||
| } | ||
| const result = await adapter.executeReadQuery(sql); |
| if (rejectedPrefix) { | ||
| return { | ||
| ...formatHandlerError( | ||
| new ValidationError( | ||
| `Statement type not allowed: ${rejectedPrefix} is not a SELECT query. Use sqlite_write_query for INSERT/UPDATE/DELETE, or appropriate admin tools for DDL.`, | ||
| ), | ||
| ), | ||
| rowCount: 0, | ||
| rows: [], | ||
| }; | ||
| } | ||
| // Fall through to let the adapter handle unrecognized statements |
| return { | ||
| success: false, | ||
| error: error instanceof Error ? error.message : String(error), | ||
| code: "ATTACH_FAILED", | ||
| backupPath: input.backupPath, | ||
| }; | ||
| } |
| if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(name)) { | ||
| throw new Error( | ||
| "Invalid savepoint name. Must start with a letter/underscore and contain only alphanumeric chars.", | ||
| ); | ||
| } |
| const DANGEROUS_SQL_PATTERNS: RegExp[] = [ | ||
| /;\s*DROP\s+/i, | ||
| /;\s*DELETE\s+/i, | ||
| /;\s*TRUNCATE\s+/i, | ||
| /;\s*ALTER\s+/i, | ||
| /UNION\s+ALL\s+SELECT/i, | ||
| /UNION\s+SELECT/i, | ||
| /--.*$/m, | ||
| /\/\*[\s\S]*?\*\//, | ||
| /;\s*ATTACH\s+/i, | ||
| /;\s*DETACH\s+/i, | ||
| ]; |
| "description": "SQLite MCP server with OAuth 2.1, HTTP/SSE, 122 tools, and smart tool filtering", | ||
| "version": "1.0.2", | ||
| "version": "1.1.0", |
| let indexes = (result.rows ?? []).map((row) => ({ | ||
| name: row["name"] as string, | ||
| table: row["tbl_name"] as string, | ||
| unique: (row["sql"] as string)?.includes("UNIQUE") ?? false, | ||
| sql: row["sql"] as string, | ||
| })); |
v1.1.0 — Security, Structured Errors & Developer Experience
Highlights
{success: false, error, code, category, suggestion, recoverable}on failure instead of raw MCP-32602frames. ~108 handler catch blocks migrated.sqlite_execute_codelets agents write JavaScript againstsqlite.*API for 70–90% token reduction. Dual sandbox modes (worker_threads / vm), security validation, rate limiting.read ⊂ write ⊂ admin ⊂ full), transport-agnostic auth, AsyncLocalStorage context threading, and 8 new auth unit test files.Added
dependency_graph,topological_sort,cascade_simulator,schema_snapshot,constraint_analysis,migration_risksmigration_init,migration_record,migration_apply,migration_rollback,migration_history,migration_statussqlite_execute_codesandboxed JavaScript execution withsqlite.*API bridge, help(), aliases, and positional paramssqlite_drop_index— New core tool with existence pre-validationsqlite://helpandsqlite://help/{group}pull-based reference docs (9 groups)fullscope,TOOL_GROUP_SCOPESmapping, scope utilities, scope-map, auth-context, transport-agnostic authtrustProxy, opt-in HSTS, wildcard subdomain CORS, server host bindingSecurity
.strict()from all Zod input schemas (prevented structured error handling)localhostHostValidation()middlewaredescribeTablefallbackminimatchReDoS,honomultiple CVEs,express-rate-limitIPv6 bypassChanged
ErrorFieldsMixin; ~108 catch blocks migrated toformatHandlerError()--instruction-levelwith pull-basedsqlite://helpresourcesError→DbMcpError, shared WAL/JSONB/PRAGMA/extension helpers, logger module split, types file split, dead code removalTABLE_NOT_FOUND,COLUMN_NOT_FOUND,DIMENSION_MISMATCH, etc.)resolveAliases()for backward compatibility (tableName→table,sql→query)apk upgrade, fixed tool count label (124→139)Fixed
DbMcpErrorsubclasses auto-refine generic codes to specific ones (DB_QUERY_FAILED→TABLE_NOT_FOUND)z.preprocess()so wrong-type inputs fall to defaults instead of raw MCP errorslist_tables,get_indexes,schema_snapshot,storage_analysis,dependency_graph,topological_sortget_indexes/index_stats, N+1 column validation batch optimization, structured savepoint errors, WASM capability accuracyPerformance
node_modulescaching (20-30s savings per run)Dependencies
@eslint/js9.39.2→10.0.1,eslint9.39.2→10.0.3 (major)@modelcontextprotocol/sdk1.25.3→1.27.1better-sqlite312.6.2→12.8.0sql.js1.13.0→1.14.1,jose6.1.3→6.2.1vitest/@vitest/coverage-v84.0.18→4.1.0pg,@types/pg,dotenvFull Changelog: v1.0.2...v1.1.0
Install: