Skip to content

v1.1.0 - Security, Structured Errors & Developer Experience#86

Closed
neverinfamous wants to merge 308 commits intomainfrom
release/v1.1.0
Closed

v1.1.0 - Security, Structured Errors & Developer Experience#86
neverinfamous wants to merge 308 commits intomainfrom
release/v1.1.0

Conversation

@neverinfamous
Copy link
Copy Markdown
Owner

v1.1.0 — Security, Structured Errors & Developer Experience

Highlights

  • 🧪 Exhaustive E2E Test Suite — 12 Playwright specs + 6 gap-closing spec files covering dual-adapter (WASM + Native) and dual-transport (SSE + Streamable HTTP) scenarios. Total E2E coverage now exceeds 300 tests.
  • 🔒 Deterministic Structured Errors — Every tool across all 9 groups now returns {success: false, error, code, category, suggestion, recoverable} on failure instead of raw MCP -32602 frames. ~108 handler catch blocks migrated.
  • 🧩 Introspection & Migration Tool Groups — 12 new tools for read-only schema analysis (dependency graphs, topological sorts, cascade simulation, schema snapshots) and opt-in migration lifecycle management with SHA-256 deduplication.
  • 💻 Code Mode (Sandboxed Execution)sqlite_execute_code lets agents write JavaScript against sqlite.* API for 70–90% token reduction. Dual sandbox modes (worker_threads / vm), security validation, rate limiting.
  • 🔐 OAuth 2.1 Foundation — Full scope hierarchy (read ⊂ write ⊂ admin ⊂ full), transport-agnostic auth, AsyncLocalStorage context threading, and 8 new auth unit test files.

Added

  • Introspection Tool Group — 6 read-only tools: dependency_graph, topological_sort, cascade_simulator, schema_snapshot, constraint_analysis, migration_risks
  • Migration Tool Group — 6 tools: migration_init, migration_record, migration_apply, migration_rollback, migration_history, migration_status
  • Code Modesqlite_execute_code sandboxed JavaScript execution with sqlite.* API bridge, help(), aliases, and positional params
  • sqlite_drop_index — New core tool with existence pre-validation
  • Dual HTTP Transport — Simultaneous Streamable HTTP (MCP 2025-03-26) + Legacy SSE (MCP 2024-11-05) with cross-protocol session guards
  • Tool Icons — All tools, resources, and prompts include Material Design Icons via MCP 2025-11-25 spec
  • Help Resourcessqlite://help and sqlite://help/{group} pull-based reference docs (9 groups)
  • Performance Benchmark Suite — 9 benchmark files measuring framework overhead on critical hot paths
  • OAuth Enhancementsfull scope, TOOL_GROUP_SCOPES mapping, scope utilities, scope-map, auth-context, transport-agnostic auth
  • Transport FeaturestrustProxy, opt-in HSTS, wildcard subdomain CORS, server host binding
  • Security Headers — 7 headers on all HTTP responses (CSP, X-Frame-Options, HSTS, etc.)
  • Rate Limiting — Per-IP sliding-window (100 req/min), health exempt
  • Body Size Enforcement — 1 MB JSON limit with 413 response

Security

  • Removed .strict() from all Zod input schemas (prevented structured error handling)
  • SQL injection guard on savepoint names
  • DNS rebinding protection via localhostHostValidation() middleware
  • SHA-pinned all GitHub Actions across 4 CI workflows
  • Bumped Actions to latest major versions (Node 24 runtime)
  • WHERE clause validation added to 15 previously unguarded JSON tool SQL interpolation points
  • Table name regex guard added to native adapter's describeTable fallback
  • HTTP server timeouts (120s request, 65s keep-alive, 66s headers) against slowloris DoS
  • Docker Scout gate hardened to fail-fast on scan errors
  • Fixed transitive vulnerabilities: minimatch ReDoS, hono multiple CVEs, express-rate-limit IPv6 bypass

Changed

  • Error Handling Overhaul — All ~115 output schemas include ErrorFieldsMixin; ~108 catch blocks migrated to formatHandlerError()
  • File Modularity — Split 8+ oversized files (500–986 lines) into directory modules with barrel exports
  • File Naming — Renamed 19 PascalCase/camelCase files to kebab-case
  • Help Architecture — Replaced --instruction-level with pull-based sqlite://help resources
  • Code Quality — 35+ generic ErrorDbMcpError, shared WAL/JSONB/PRAGMA/extension helpers, logger module split, types file split, dead code removal
  • Deterministic Error Handling — Structured responses across all tools with specific error codes (TABLE_NOT_FOUND, COLUMN_NOT_FOUND, DIMENSION_MISMATCH, etc.)
  • Column Existence Validation — All text, stats, and geo tools validate columns before query execution
  • Parameter AliasesresolveAliases() for backward compatibility (tableNametable, sqlquery)
  • Dockerfile — Removed builder apk upgrade, fixed tool count label (124→139)

Fixed

  • 200+ bug fixes including: output schema leaks, validation refinement leaks, enum coercion, dimension validation, FTS5 WASM crashes, Code Mode positional params, restore/backup path resolution, migration dedup scope, window function annotations, and more
  • Error Code RefinementDbMcpError subclasses auto-refine generic codes to specific ones (DB_QUERY_FAILEDTABLE_NOT_FOUND)
  • Input Coercion — 50+ parameters now use z.preprocess() so wrong-type inputs fall to defaults instead of raw MCP errors
  • Payload Optimization — System tables excluded by default in list_tables, get_indexes, schema_snapshot, storage_analysis, dependency_graph, topological_sort
  • Post-Review Hardening — CTE write support, semicolon normalization before LIMIT injection, SQL injection hardening via parameterized queries in get_indexes/index_stats, N+1 column validation batch optimization, structured savepoint errors, WASM capability accuracy

Performance

  • Compact JSON serialization (~15-20% reduction on large payloads)
  • Incremental TypeScript builds
  • Vitest thread pool parallelism
  • SchemaManager TTL-based caching for native adapter
  • Logger regex pre-compilation and taint-breaking optimization
  • SQL validation regex hoisted to module scope
  • CI node_modules caching (20-30s savings per run)

Dependencies

  • Bumped @eslint/js 9.39.2→10.0.1, eslint 9.39.2→10.0.3 (major)
  • Bumped @modelcontextprotocol/sdk 1.25.3→1.27.1
  • Bumped better-sqlite3 12.6.2→12.8.0
  • Bumped sql.js 1.13.0→1.14.1, jose 6.1.3→6.2.1
  • Bumped vitest/@vitest/coverage-v8 4.0.18→4.1.0
  • Removed unused pg, @types/pg, dotenv

Full Changelog: v1.0.2...v1.1.0

Install:

npm install @neverinfamous/db-mcp@1.1.0
docker pull neverinfamous/db-mcp:1.1.0

Temp added 30 commits March 5, 2026 02:10
…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)
…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.
Chris & Mike added 25 commits March 17, 2026 20:37
…verify_backup, create_rtree_table, create_csv_table, analyze_csv_schema
- 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
Copilot AI review requested due to automatic review settings March 18, 2026 20:38

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

Unused variable calledPragma.

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.

Suggested changeset 1
tests/adapters/sqlite/tools/virtual/vtable.test.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/tests/adapters/sqlite/tools/virtual/vtable.test.ts b/tests/adapters/sqlite/tools/virtual/vtable.test.ts
--- a/tests/adapters/sqlite/tools/virtual/vtable.test.ts
+++ b/tests/adapters/sqlite/tools/virtual/vtable.test.ts
@@ -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({
EOF
@@ -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({
Copilot is powered by AI and may make mistakes. Always verify output.
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +21 to +23
const tableCheck = await adapter.executeReadQuery(
`SELECT 1 FROM sqlite_master WHERE type IN ('table', 'view') AND name='${tableName.replace(/'/g, "''")}'`,
);
Comment on lines +51 to +53
const result = await adapter.executeReadQuery(
`SELECT name FROM pragma_table_info('${tableName.replace(/'/g, "''")}') WHERE name = '${columnName.replace(/'/g, "''")}' LIMIT 1`,
);
Comment on lines +82 to +84
const pragmaResult = await adapter.executeReadQuery(
`SELECT name FROM pragma_table_info('${tableName.replace(/'/g, "''")}')`,
);
Comment on lines +72 to +75
if (table) {
sql += ` AND tbl_name = '${table.replace(/'/g, "''")}'`;
}
const result = await adapter.executeReadQuery(sql);
Comment on lines +90 to +101
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
Comment on lines +82 to +88
return {
success: false,
error: error instanceof Error ? error.message : String(error),
code: "ATTACH_FAILED",
backupPath: input.backupPath,
};
}
Comment on lines +35 to +39
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.",
);
}
Comment on lines +14 to +25
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,
];
Comment thread server.json
Comment on lines 5 to +6
"description": "SQLite MCP server with OAuth 2.1, HTTP/SSE, 122 tools, and smart tool filtering",
"version": "1.0.2",
"version": "1.1.0",
Comment on lines +110 to +115
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,
}));
@neverinfamous neverinfamous deleted the release/v1.1.0 branch March 18, 2026 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants