Skip to content

Latest commit

 

History

History
2275 lines (2032 loc) · 269 KB

File metadata and controls

2275 lines (2032 loc) · 269 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

5.0.1 - 2026-06-12

Changed

Dependency Updates

  • Bumped @types/node from 25.9.1 to 25.9.3
  • Bumped typescript-eslint from 8.60.1 to 8.61.0
  • Bumped github/gh-aw-actions from 0.64.2 to 0.79.7
  • Bumped pnpm/action-setup to fc06bc1257f339d1d5d8b3a19a8cae5388b55320

Security

  • Resolved Alpine OpenSSL CVEs (CVE-2026-34182, etc.) in Docker base image by fetching latest edge packages during build.

5.0.0 - 2026-06-06

Added

  • Contextual README.md files to core directories (.agents, .github, config, extensions, scripts, src, tests).
  • TimeoutError, RateLimitError, and ConflictError typed error classes.
  • WASM adapter request serialization via reader-writer lock.
  • stream: true and chunkSize parameters to sqlite_read_query.
  • ALLOWED_IO_ROOTS sandbox via env var and CLI flag.
  • HTTP stateful session enforcement with 30-minute idle timeout and in-flight request locks.
  • Optimistic Concurrency Control (OCC) tools in the core group: sqlite_enable_versioning, sqlite_disable_versioning, sqlite_check_version, and sqlite_conditional_update.
  • Automatic snake_case to camelCase parameter mapping in validation schemas and the Code Mode V8 proxy.
  • Test scripts verify-schemas.mjs, test-zod-errors.mjs, and test-tool-annotations.mjs.
  • Comprehensive vitest coverage suites for HTTP session initialization, system db, OAuth resource server, vector schemas, and SpatiaLite loader to achieve >90% overall project coverage.

Changed

  • Deprecated worker Code Mode isolation options in .env.example.
  • Updated default CODE_MODE_MAX_RESULT_SIZE limit documentation to match 10MB runtime default.
  • Updated dependencies: GitHub Actions and npm packages.
  • Clarified Code Mode testing rules in prompt-template.md and test scripts.
  • Surfaced Code Mode errors as structured typed errors instead of generic internals.
  • Returned structured JSON for HTTP rate limit responses.
  • sqlite_write_query and sqlite_upsert require an expectedVersion parameter for version-enabled tables.
  • Bumped isolated-vm to 7.0.0 for Node.js 26 compatibility.
  • Migrated package manager from npm to pnpm (v9.15.4) and updated Dockerfile.
  • Simplified gotchas.md by moving tool-specific instructions to native tool group URIs.
  • Expanded agent prompts and E2E tests to validate ALLOWED_IO_ROOTS, OCC, and chunked streaming.
  • Split complex tool handlers (audit-tools.ts, window.ts) into sub-modules and grouped exports via barrel files.
  • Optimized error serialization overhead by extracting RegExp constants and adding match extraction caching.
  • Optimized ReadWriteLock for WASM concurrency.
  • Accelerated Code Mode AST parsing with an LRU cache.
  • Replaced generic Error classes with domain-specific errors in core logic.
  • Updated server instructions (gotchas.md) to formally document structured ValidationError responses.
  • Added (opt-in) annotation to sqlite.migration in Code Mode groups list.
  • Optimized sqlite_schema_snapshot to use compact: true by default.
  • Reduced sqlite_stats_sample default sampleSize to 20 and max cap to 50.
  • Truncated sqlite_transaction_execute results array to a maximum of 50 items.
  • Changed sqlite_dbstat default summarize to true.
  • Reduced sqlite_audit_search default limit to 10.
  • Converted test-server/reset-database.ps1 to reset-database.mjs.
  • Refactored ErrorCategory enum to a literal union type.

Fixed

  • Clean up orphaned SQLite Write-Ahead Log (-wal) and Shared Memory (-shm) files during test environment resets.
  • sqlite_read_query degrades gracefully to full buffering in Code Mode when stream: true is requested.
  • Missing PROJECT_REGISTRY and TEAM_DB_PATH variables in mcp-config-example.json and .env.example.
  • ci-health-monitor permissions in strict mode.
  • Enforced single quotes in YAML frontmatter for agentic workflows.
  • Enforced strict parsing (.strict()) on empty schema objects in migration, admin, and transaction tools.
  • Typecast isolated any types to unknown in admin schemas and metrics tests.
  • Refactored logger.ts to be fully synchronous.
  • Removed unused zod-to-json-schema dependency.
  • Code Mode sandbox timeouts now correctly throw TimeoutError.
  • Native addon crashes during Vitest by changing the execution pool from threads to forks.
  • False-positive Promise rejections in sqlite-adapter-methods.test.ts.
  • Synced AUDIT_REDACT default to true in .env.example and mcp-config-example.json.
  • Configured ALLOWED_IO_ROOTS in test scripts to automatically silence fallback sandbox warnings.
  • Generation script README exclusion now uses case-insensitive prefix matching.
  • Removed unused devDependency rimraf from package.json.
  • Structured error responses in vector tool handlers.
  • Structured error responses in the admin-audit tool group.
  • Case-insensitive operation parsing in sqlite_cascade_simulator.
  • Coerce empty arrays in sqlite_schema_diff schema.
  • Optional table parameter filtering in sqlite_dependency_graph.
  • Descriptive messages in json-write output.
  • findSuggestion regex pattern for missing column errors.
  • Strict validation in transactions tool schemas.
  • ifExists default in DisableVersioningSchema.
  • Context extraction in sqlite_fts_headline when column is omitted.
  • Structured error category in sqlite_analyze_csv_schema for IO rejections.
  • Structured error fields in sqlite_virtual_table_info.
  • sqlite_audit_search documentation parameter naming.

Security

  • Hard Gate: Code Mode strictly fail-closes if isolated-vm native bindings fail to load.
  • Hard Gate: HTTP transports fail to start if ALLOWED_IO_ROOTS is omitted.
  • Stdio transport defaults to no filesystem access if omitted.
  • Hardened all filesystem-touching tools to use symlink-aware realpath resolution (assertSafeIoPath).
  • Sessions exceeding timeout limits are automatically expired and cleaned up.

4.0.0 - 2026-06-03

Added

  • CI/CD workflow documentation and Mermaid diagrams in .github/workflows/README.md.
  • Performance-Tuning.md GitHub Wiki guide covering cache TTLs, WASM vs Native backends, and token efficiency.
  • Dependabot verification step in .github/workflows/ci-health-monitor.md.
  • Internal server metrics exposed at /metrics and via sqlite://metrics resource.
  • sqlite_hybrid_search tool combining FTS5 text search and vector embedding search via Reciprocal Rank Fusion (RRF).
  • sqlite_audit_search tool for querying server audit logs.
  • sqlite_server_config administrative tool to dynamically manage logging levels.
  • includeFacets and cursor parameters for faceted search and pagination in search/read queries.
  • recommendComposite and queriesToAnalyze options in sqlite_index_audit for automatic index recommendations.
  • SystemDb observability architecture with structured SQLite sidecar (system.db) and MetricsRegistry persistence.
  • Subscription capability via SubscriptionManager with schemaChanged events for sqlite://schema and sqlite://tables.
  • Configuration file support (.yaml, .json) via --config and --dump-config CLI flags.
  • Encryption at rest (SQLCipher) for Native backend and SystemDb logs via --encryption-key or DB_ENCRYPTION_KEY.
  • Capacity Planning Guide covering scaling, memory requirements, and token budgets.
  • Continuous wiki documentation drift check workflow in .github/workflows/wiki-drift-detector.md.
  • Data Privacy, Compliance policies, and Supply Chain Security guidance in SECURITY.md.

Changed

  • GitHub Actions workflows updated to use actions/checkout@v6 and actions/setup-node@v6 via SHA pinning.
  • sqlite_read_query instructions updated with token conservation guidance.
  • Dependencies bumped: @vitest/coverage-v8 to 4.1.8, typescript-eslint to 8.60.1, and vitest to 4.1.8.
  • Agentic workflows updated to strictly use single quotes in YAML frontmatter and explicitly reference gh copilot.
  • mcp-config-example.json populated with meaningful placeholder values.

Removed

  • sqlite_append_insight tool and memo://insights resource.

Fixed

  • MCP_HOST default documentation discrepancy in README.md and DOCKER_README.md (127.0.0.1 locally, 0.0.0.0 in Docker).
  • Missing MCP_ENABLE_HSTS variable in DOCKER_README.md Environment Variables table.
  • Silent fallbacks in introspection schemas swallowing wrong-type validation errors for enum properties.
  • sqlite_spatialite_load omitting version string required by the schema output.
  • Native build failure on Node 26 for Windows caused by LLVM/Clang LTO flags.
  • FTS5 syntax errors on malformed user input.
  • V8 Garbage Collection STATUS_ACCESS_VIOLATION crashes during CodeModeSandbox teardown.
  • Native V8 thread leaks on Windows.
  • SQLCipher PRAGMA key syntax errors causing "file is not a database" failures.
  • DB_ENCRYPTION_KEY environment variable leakage breaking unencrypted Playwright E2E tests.
  • SubscriptionManager silently dropping subscriptions over stateless stdio transports.
  • SchemaManager/describeTable omitting generated columns (resolved by cross-referencing table_xinfo and sqlite_master DDL).
  • Code Mode API normalization regression where parameter arrays were incorrectly processed in searchRegex.
  • Missing AST validation error trigger in sandbox.test.ts.
  • Automated subscription test scripts attempting DDL via sqlite_write_query instead of dedicated DDL tools and using outdated SDK signatures.
  • reset-database.ps1 crashing with SQLITE_NOTADB during encryption when database is locked (now gracefully warns).
  • Defunct --auth-token argument remaining in cli.ts help text.
  • SubscriptionManager blindly broadcasting resource update notifications without verifying active subscribers for the URI.
  • Test output clarity and missing assertions in test-subscriptions-raw.mjs and test-subscriptions-sdk.mjs.
  • Test suite spawning failures with SQLITE_NOTADB when DB_ENCRYPTION_KEY is present in the global environment.
  • EXPECTED_TOOL_COUNT and missing administrative tools in SDK_REGISTERED_TOOLS in test-tool-annotations.mjs.
  • Refactored test-progress.mjs to systematically iterate and rigorously verify all 7 progress-enabled tools instead of testing a single isolated loop.

Security

  • Bumped npm bundled tar in Dockerfile to 7.5.16 to apply latest security patches.

3.0.2 - 2026-05-31

Added

  • Documentation: Created GitHub Wiki with 11 pages covering Quick Start, Tool Filtering, Code Mode, Tool Reference, HTTP Transport, SQLite Extensions, Resources & Prompts, OAuth & Security, Audit Trail, and Troubleshooting
  • CI/CD: Added Docker smoke test jobs to docker-publish.yml and lint-and-test.yml that verify stdio, HTTP, and native SQLite backends start successfully on both amd64 and arm64 runners before images are pushed
  • CI/CD: Refactored docker-publish.yml from monolithic QEMU-emulated build to per-platform native runner matrix (ubuntu-24.04 + ubuntu-24.04-arm), matching the fleet standard used by postgres-mcp and mysql-mcp
  • Tests: Added build-externals.test.ts invariant test ensuring every tsup.config.ts external entry has a corresponding production dependency

Fixed

  • Docker: Fixed fatal startup crash in Docker image caused by missing acorn dependency (#149). The package was externalized in the build config but not listed in dependencies, causing it to be pruned from the production node_modules
  • Docker: Fixed ARM64 better-sqlite3 native addon crash (Could not locate the bindings file) by switching from QEMU-emulated cross-compilation to native ARM64 runners. Added explicit npm rebuild better-sqlite3 in Dockerfile for defense-in-depth

3.0.1 - 2026-05-30

Changed

  • Dependency Updates: Updated npm dependencies (e.g. eslint to 10.4.1).
  • Rewrote test-server/scripts/test-tool-annotations.mjs from a basic openWorldHint counter into a comprehensive annotation validation suite. Now validates all 5 annotation fields (openWorldHint, readOnlyHint, destructiveHint, sensitiveHint, idempotentHint), checks logical consistency (e.g., no readOnly+destructive contradiction), enforces an exact allowlist for openWorldHint=true tools, and validates title presence.

Fixed

  • Fixed sqlite_pragma_settings annotation: removed incorrect openWorldHint: true override. PRAGMA operations are internal to the SQLite engine and don't interact with the filesystem or network.
  • Fixed a bug in .github/workflows/codeql.yml where CodeQL severity validation failed to block deployments. The SARIF parser now correctly inherits defaultConfiguration.level when the finding level is omitted, and explicitly excludes the tests/ directory from blocking production releases.
  • Fixed tsconfig.test.json to properly include the tests/ directory and added npm run typecheck:tests to the main check script so CI catches test-related type errors.
  • Fixed "Invocation of non-function" CodeQL alerts in utilities.bench.ts and transport-auth.bench.ts by removing dead benchmark code referencing non-existent functions.

3.0.0 - 2026-05-29

Added

  • 20 new tools across Core, Admin, Stats, JSON, Introspection, and Server Audit groups.
  • sqlite.reportProgress() utility in Code Mode for sandboxed execution feedback.
  • onlyDifferences flag in sqlite_json_diff tool to filter identical rows.
  • Output schema registry and reference documentation for LLM invocations.

Changed

  • Migrated Code Mode execution to native isolated-vm for V8 memory separation (with node:vm fallback).
  • Bumped dependencies, including @modelcontextprotocol/sdk to 1.29.0 and zod to 4.4.3.
  • Optimized token context-window usage via pagination, result truncation, wide-column validation, and computed date columns.
  • Optimized sqlite_text_replace to skip rows without matches, saving DB I/O.
  • Enhanced DDL tools with support for STRICT tables, generated columns, and sqlite_temp_master.
  • Improved Code Mode performance with LRU eviction and global WASM engine caching.
  • Upgraded schema caching with a 30-second TTL and targeted DDL invalidation.
  • Replaced sqlite-parser with an internal regex parser for structural validation.
  • Added MCP 2025 Specification annotations globally (sensitiveHint, ASSISTANT_FOCUSED).
  • Filtered internal shadow tables from introspection resources.
  • Migrated HTTP transport and Code Mode to support multi-instance Redis rate limiting.
  • Standardized canonical names and tool inventory metrics across documentation.
  • Clarified backend-switching documentation in READMEs.

Removed

  • Simple Bearer Token authentication (replaced by strict OAuth 2.1).
  • Redundant test-wasm-degradation.md prompt from the test suite.

Fixed

  • Fixed raw -32602 MCP errors by enforcing structured Zod validation across all tools.
  • Fixed numeric coercion falling back to undefined on invalid strings.
  • Restored RETURNING * support in batch insert tools and fixed aliasing bugs in date functions.
  • Fixed Windows SpatiaLite loading by replacing process.env.PATH mutations with a native C++ addon.
  • Fixed schema introspection failing to accurately map temporary table indexes.
  • Fixed sqlite_audit_restore_backup crashing on comment-only snapshots.
  • Fixed false-positive path traversal violations on Windows caused by drive letter case sensitivity.
  • Fixed WASM degradation test assertions for Code Mode.
  • Fixed sqlite_wal failing to enable WAL mode.
  • Fixed sqlite_describe_table failing to accurately report the strict property.
  • Fixed incorrect index assertion in Code Mode introspection queryPlan test prompt.

Security

  • Sandbox Isolation: Secured prototype freezing, disabled string code generation, and blocked constructor chain escapes.
  • SQL Injection: Replaced template strings with native parameterized bindings and hardened WHERE clause generation.
  • Authorization: Enforced explicit OAuth per-tool scopes and bound session IDs to authenticated subjects.
  • Information Disclosure: Implemented recursive JSON redaction to sanitize credentials from outputs and logs.
  • Transport: Bound HTTP server to 127.0.0.1, replaced insecure proxy headers, and mitigated timing attacks.
  • DoS: Upgraded rate limiters, capped Code Mode payloads to 50MB, and implemented 10KB query string bounds.
  • Path Traversal: Blocked :memory:, symlinks, and .. sequence bypasses, and added filesystem boundary validations.
  • Supply Chain: Removed persistent credentials from workflows, enforced SHA pinning for actions, and verified lockfile integrity.

2.0.0 - 2026-05-21

Added

  • Test Coverage: Added comprehensive test suites for anomaly detection (sqlite_stats_detect_anomalies), bloat detection (sqlite_stats_detect_bloat), schema risk detection (sqlite_stats_detect_schema_risks), native extension loading (loadSpatialite, loadCsvExtension), BackupManager snapshot generation/cleanup, FTS5 execution paths, WorkerSandbox API bindings and RPC functionality, resource error handling (sqlite_table_schema, sqlite_meta, sqlite_pragma, sqlite_compile_options), and adapter lifecycle fallback paths, reaching the 90.34% test coverage milestone.

  • Progress Notifications: Added support for MCP long-running task progress notifications. Notifications are now correctly emitted during lengthy operations including sqlite_backup (admin/backup), sqlite_migration_apply (migration/apply), and sqlite_virtual_analysis (virtual/analysis), ensuring cross-server parity with postgres-mcp and mysql-mcp.

  • Initialization SQL: Added initializationSql?: string[] to SqliteConfig for SQLite connections, enabling per-connection session setup (e.g. PRAGMA foreign_keys = ON;). This executes exactly once when the adapter connects, satisfying the requirement for session-level guardrails across both Native (better-sqlite3) and WASM (sql.js) backends.

  • Convenience Tools: Added 5 new tools to the core group (sqlite_upsert, sqlite_batch_insert, sqlite_count, sqlite_exists, sqlite_truncate) to achieve complete feature parity with postgres-mcp. These tools are available in both Native and WASM backends, with sqlite_upsert utilizing SQLite's native INSERT ON CONFLICT DO UPDATE or INSERT OR REPLACE fallback.

  • sqlite_transaction_status: New read-only tool to check whether a SQLite transaction is currently active (native backend only). Returns {status: "active" | "none", active: boolean}. Ported from pg_transaction_status for cross-server parity.

  • Audit Logging: JSONL audit trail with async-buffered writes, log rotation (10MB, 5-file cascade), and sqlite://audit resource for agent access to the last 50 entries. Configurable via --audit-log <path>, --audit-redact, --audit-reads CLI flags or AUDIT_LOG, AUDIT_REDACT, AUDIT_READS environment variables. Write/admin tools are always logged; read tools optionally.

  • DDL Backup Snapshots: Pre-mutation DDL capture for destructive operations (sqlite_drop_table, sqlite_drop_index, sqlite_drop_view, sqlite_import_csv, sqlite_backup). Gzip-compressed snapshots with retention policy (age + count limits). Tools: sqlite_audit_list_backups, sqlite_audit_get_backup, sqlite_audit_cleanup. Enabled via --audit-backup / AUDIT_BACKUP.

  • Token Burn-Rate: Every tool response now includes _meta.tokenEstimate (~4 bytes/token heuristic). Code Mode responses include metrics.tokenEstimate. Matches postgres-mcp and mysql-mcp for cross-server parity.

  • Anomaly Detection Suite: 3 new stats tools for cross-server parity with postgres-mcp and mysql-mcp. sqlite_stats_detect_anomalies (z-score data distribution analysis), sqlite_stats_detect_bloat (multi-factor fragmentation/bloat risk scoring via PRAGMA + dbstat), sqlite_stats_detect_schema_risks (schema health risk scoring — missing FK indexes, wide tables, missing PKs). All read-only, available in both WASM and Native backends, with Code Mode support via sqlite.stats.*.

  • JSON Security Scan: New sqlite_json_security_scan tool for cross-server parity with pg_jsonb_security_scan. Scans JSON columns for sensitive keys (password, token, ssn, etc.), SQL injection patterns, and XSS attack vectors. Returns riskLevel (low/medium/high) and detailed issue breakdown. Uses JS-side regex scanning on sampled rows. Available in both WASM and Native backends.

  • Text Sentiment: New sqlite_text_sentiment tool for cross-server parity with pg_text_sentiment. Basic keyword-based sentiment analysis on raw text input. Returns sentiment classification (very_positive/positive/neutral/negative/very_negative), score, confidence, and optionally matched words. Pure JS implementation — available in both WASM and Native backends.

  • FTS5 Headline: New sqlite_fts_headline tool for cross-server parity with pg_text_headline. Generates highlighted snippets from FTS5 search results using SQLite's native highlight() and snippet() functions. Supports custom highlight markers and context window size. Native backend only.

  • ExtensionNotAvailableError: New typed error class for extension unavailability (SpatiaLite, CSV, R-Tree). Code: EXTENSION_MISSING, category: config. Replaces ad-hoc inline error returns with a structured, instanceof-testable error. Ported from postgres-mcp for cross-server parity.

  • Introspection Resources: Added sqlite://compile_options (compile-time build features) and sqlite://pragma (runtime configuration snapshot) resources to achieve resource count parity with postgres-mcp. Both are read-only and available unconditionally via the read_resource MCP tool.

  • WASM Mode Test Suite: Added §7 WASM Mode Execution section to the Code Mode test suite README with agent instructions for skipping [NATIVE ONLY] items, validating graceful degradation, and adjusting expectations for WASM-specific behavior (dbstat fallback, FTS3 vs FTS5, phantom FTS5 tables).

  • WASM Degradation Prompt: New 11th test prompt (test-tool-group-codemode-wasm-degradation.md) covering 10 categories of WASM-specific graceful degradation tests: API surface verification, backup/restore/verify errors, CSV/R-Tree unavailability, FTS5 phantom table behavior, dbstat fallback, PRAGMA compile options, and Zod validation of degraded tools.

  • WASM Mode Advanced Tests: Added inline ## WASM Mode sections to all 10 advanced stress test prompts (test-advanced/) with per-prompt skip rules, graceful degradation guidance, and adjusted expectations. Fixed admin Category 7 which incorrectly claimed all 26 admin tools work identically in WASM.

  • WASM Mode Standard Tests: Added inline ## WASM Mode sections to all 10 direct-tool test prompts (test-tool-groups/), replacing the static Ignore WASM content. Test Native Mode Only directive. Each prompt now contains self-contained WASM skip rules with specific item numbers. Added §2.6 WASM Mode Execution section to the README with skip rules, graceful degradation table, adjusted expectations, and the "unknown tool" note for unregistered Native-only tools.

Changed

  • Doc Parity Audit: Finalized repository documentation audit for v1.1.1. Synchronized all documentation across README.md, DOCKER_README.md, and test-resources.md to reflect the current state of 151 Native / 125 WASM tools, 10 Tool Groups, and 20 Resources.

  • Documentation Marketing Audit: Strengthened marketing copy in README.md and DOCKER_README.md. Promoted V8 isolate sandbox architecture in hero table Code Mode rows (previously described as generic "secure JavaScript sandbox"). Added _meta.tokenEstimate token burn-rate metric to Token-Optimized Payloads rows. Standardized token savings range to "70–90%" across both docs. Removed unsubstantiated "2 Minutes" Quick Start claim from Docker README. Fixed stray backslash in DOCKER_README env var table (OAUTH_AUDIENCE row). Fixed broken emoji ( → 🔌) in README SQLite Extensions heading. Merged redundant Performance/Dual SQLite Backends hero table rows in README.

  • Benchmark Ranges: Updated README benchmark summary from single-point estimates to 3-run ranges (e.g., "Tool dispatch: 11–14M ops/sec"). Added new "Sandbox execution" bullet (~4.4–4.9K exec/sec). Ranges reflect real-world variance from thermal throttling and background load.

  • Resource Payload Filtration Findings: Completed comprehensive testing of all 20 db-mcp resources (11 data + 9 help). Discovered that sqlite_schema, sqlite_tables, and sqlite_views include internal Spatialite metadata tables/views (e.g., geometry_columns, vector_layers). Recommendation: Filter out Spatialite internal objects similarly to FTS5 shadow tables to keep resource listings clean. All other resources (including schema templates, PRAGMA snapshots, Code Mode insights, and help files) and base tool annotations (openWorldHint: false) successfully passed validation.

  • OAuth Identity in Audit Logs: Audit log entries now capture the authenticated user's identity (user field from claims.sub) and granted scopes (scopes array) when OAuth 2.1 is configured. Previously hardcoded as null/[]. Identity is read from AsyncLocalStorage via getAuthContext(), matching the postgres-mcp reference implementation. When OAuth is not configured (stdio transport, no auth), fields remain null/[] as before.

  • Zero-Suppression Architecture: Finalized the Zod Schema Registry by completely purging all inline z.object definitions and Zod imports from the src/adapters/sqlite/tools/ directory. All schemas (including geo, fts, admin, json-operations, and vector) and their associated coercion utilities (coerceNumber, coerceUnit, coerceEnumValues) are now strictly centralized within src/adapters/sqlite/schemas/, ensuring 100% modular decoupling and zero-suppression compliance.

  • Documentation Parity: Updated all tool count references across README.md, DOCKER_README.md, server.json, test-server/tool-reference.md, and test-server/code-map.md to reflect the expanded inventory (151 Native / 125 WASM tools), including the 5 new core convenience tools, JSON security scan, text sentiment, and FTS5 headline.

  • Testing Prompts: Updated all 40 advanced and standard test prompts to default to the internal agent task tracking system instead of hardcoding a temporary local workspace file.

  • BREAKING: Transaction Group Split: Moved 8 transaction tools (sqlite_transaction_begin, sqlite_transaction_status, sqlite_transaction_commit, sqlite_transaction_rollback, sqlite_transaction_savepoint, sqlite_transaction_release, sqlite_transaction_rollback_to, sqlite_transaction_execute) from admin group into a dedicated transactions group for improved discoverability. OAuth scope for transactions changed from admin to write (matching mysql-mcp and postgres-mcp). Code Mode exposes transactions via sqlite.transactions.* namespace.

  • BREAKING: Text Group Payload Optimization: Removed the redundant original string field from the output schemas of 6 text tools (sqlite_text_case, sqlite_text_normalize, sqlite_text_split, sqlite_text_substring, sqlite_text_trim, and sqlite_text_sentiment). Tools now return rowid for traceability, immediately cutting JSON payload sizes by up to 50% for operations on large text columns.

  • BREAKING: Vector Schema Parity: Standardized vector search and distance tool outputs (sqlite.vector.search now returns rows; sqlite.vector.distance now returns distance) to align with cross-server canonical implementations (e.g., postgres-mcp).

  • BREAKING: Query Pagination Default: Lowered the default safety limit for unbounded SELECT queries from 1000 to 50 to prevent unnecessary payload bloat and align with token-efficiency guidelines.

  • BREAKING: Phonetic Payload Bloat: Changed includeRowData default in PhoneticMatchSchema from true to false.

  • BREAKING: Migration Tools Hardening: Standardized the migration SQL payload property to migrationSql (from sql) across the SQLite handler code, Zod schemas, unit tests, and Playwright E2E tests, ensuring strict symmetry with rollbackSql.

  • Updated vitest and @vitest/coverage-v8 to 4.1.7.

  • Updated @types/node to 25.9.1, tsx to 4.22.3, and typescript-eslint to 8.59.4.

  • Updated typescript to ^6.0.3, zod to ^4.4.3, jose to ^6.2.3, typescript-eslint to ^8.59.3, and bumped various packages including @playwright/test, @types/node, @modelcontextprotocol/sdk, eslint, vitest, tsx to ^4.22.1, and better-sqlite3. Updated Dockerfile overrides for diff (9.0.0), tar (7.5.15), and minimatch (10.2.5). Updated GitHub Actions to their latest SHA-pinned versions (docker/build-push-action, actions/upload-artifact, docker/login-action, github/codeql-action, actions/cache, actions/setup-node).

Fixed

  • json-read: Fixed a Zod validation leak in sqlite_json_query where filterPaths would throw a raw MCP -32602 error if a client or LLM sent it as a stringified object instead of a record.
  • JSON Group Object Defaults: Fixed an issue in sqlite_json_group_object where keyColumn was strictly required by Zod. It now correctly defaults to "rowid" when omitted, allowing queries to easily map values without specifying a key column.
  • JSON Read Numeric Coercion: Fixed a regression in coerceNumber that returned unparseable strings (like "abc") instead of undefined. This ensures parameters like limit and sampleSize correctly fall back to their defaults instead of throwing raw MCP -32602 validation errors.
  • Anomaly Detection Column Parsing: Fixed an issue in sqlite_stats_detect_anomalies where providing a single column argument was ignored, causing the tool to fall back to analyzing all numeric columns. Added column to the DetectAnomaliesSchema and updated the tool handler to correctly prioritize single-column targets over the plural columns array.
  • Resource Error Quality: Improved the error mapping logic in query-executor.ts to intercept raw SQLite errors (Query execution failed: no such table/column) and translate them into strongly-typed ResourceNotFoundError objects. This elevates the error message quality from Level 3 (adequate) to Level 5 (excellent) by embedding the exact table/column name, appropriate TABLE_NOT_FOUND / COLUMN_NOT_FOUND codes, and actionable suggestions, completely replacing the raw SQLite fallback.
  • JSON Security Scan Parity: Fixed an issue in sqlite_json_security_scan where the ported SQL injection pattern did not detect ' OR 1=1 variants and command/template injection patterns (${cmd}) were missing entirely. Added a new cmd_injection_pattern to the Zod schema and expanded regex matching.
  • Code Mode Undefined Serialization: Fixed an issue where returning undefined from the sandbox resulted in a serialized error object ({"_error":"Result could not be serialized","_type":"undefined"}) rather than properly handling it as an empty result. sanitizeResult now explicitly handles undefined while preserving the serialization catch for unsupported types like functions or symbols.
  • E2E Transport Timeouts: Resolved intermittent 60-second timeouts (TypeError: Expected a ServerResponse) in the WASM Playwright E2E suite by introducing a connectionMutex in session.ts to strictly serialize McpServer connection handoffs and synchronously clean up legacy Protocol._transport states.
  • Reset Script: Fixed a PowerShell here-string syntax error (ParseException due to missing terminator) in test-server/reset-database.ps1 that prevented the test database from being reset.
  • Fixed OAuth scope enforcement gap where tools were missing authorization level verification at the HTTP transport layer before being dispatched to the MCP handler.
  • Code Mode last-expression auto-return — Bare expressions like sqlite.help() now correctly surface their return value from sqlite_execute_code. Previously, the async IIFE wrapper silently returned undefined for non-return statements. New transformAutoReturn() utility prepends return to the last expression statement, mimicking Node REPL semantics. Applied to both VM and Worker sandbox paths.
  • Structured Error Parity — Fixed an issue in sqlite_generate_series and sqlite_create_series_table where validation errors for missing parameters (due to SDK compatibility constraints) bypassed Zod and returned ad-hoc objects missing code (VALIDATION_ERROR) and category fields.
  • Schema Strict Validation Leak — Fixed an issue in sqlite_count and sqlite_exists where ZodSchema definitions lacked .strict() and caused unknown parameters (e.g., typos like whereClause instead of where) to be silently ignored, executing broad queries instead of rejecting the input. Aliased whereClause correctly to where in convenience-schemas.
  • Code Mode Discovery paritysqlite.help() within Code Mode worker processes now properly computes and returns totalMethods and usage instructions to match the top-level API shape.
  • Audit Logging Silent Failure — Fixed a bug where audit logs were not writing to the configured JSONL file despite being enabled. Tool names in toolScopeMap were missing their sqlite_ prefix (e.g., "execute_code" instead of "sqlite_execute_code"), causing them to fall back to the read scope and skip logging when --audit-reads was false. Added correct prefixing during scope map initialization and fixed typescript-eslint typing strictness issues (no-unsafe-call, strict-boolean-expressions) in the audit interceptor.
  • Migration Tools Hardening — Standardized the migration SQL payload property to migrationSql (from sql) across the SQLite handler code, Zod schemas, unit tests, and Playwright E2E tests, ensuring strict symmetry with rollbackSql and resolving validation discrepancies.
  • Admin Code Mode Prompt: Fixed a syntax error in the admin code mode test prompt (test-tool-group-codemode-admin.md) where sqlite.core.describeTable("...") was incorrectly used instead of the object-parameter syntax sqlite.core.describeTable({table: "..."}).
  • Automated Coverage & E2E Badges — Ported update-badges.ts script to automatically update the README.md and DOCKER_README.md coverage and E2E statistics. Updated vitest.config.ts and playwright.config.ts to output json-summary and json results respectively, and hooked the badge updater into the test:coverage and test:e2e npm scripts.
  • Code Mode Text Tests — Fixed a documentation discrepancy in server-instructions/text.md where sqlite_text_replace was documented with search/replacement instead of searchPattern/replaceWith.
  • Code Mode Transactions Tests — Remediated syntax discrepancies in the transactions tool group testing prompt where the test template incorrectly used sqlite.transactions.transactionStatus() instead of sqlite.transactions.status().
  • Testing Prompts: Reverted test-tool-group-codemode-vector.md and E2E tests to enforce strict output schemas (rows instead of results, distance instead of value) under the Code-Over-Docs policy.
  • Gotchas Documentation: Removed vector schema discrepancy caveats from gotchas.md now that the canonical outputs are enforced.
  • Core Group Stress Testing: Fixed schema aliases in CountSchema and BasicStatsSchema to properly accept tableName and columnName inputs, standardizing parameter names across the core and stats tool groups and resolving validation errors encountered during Code Mode execution.
  • Sentiment Tool Parity: Refactored the sqlite.text.sentiment handler and associated schemas to process a pure JS text string rather than executing database queries, resolving schema mismatch errors and aligning the SQLite implementation with the postgres-mcp parity standard.
  • Sentiment Tool Types & Linting: Resolved TypeScript (no-explicit-any) and ESLint (require-await) errors within the sentiment tool by typing the output with a strict SentimentResult interface and correctly handling async handler requirements.
  • Text Group Test Suite: Rewrote tests/adapters/sqlite/tools/text/sentiment.test.ts to pass literal strings and evaluate the new direct object payload, allowing 100% test coverage to pass cleanly.
  • RowID Aliasing Bug: Fixed an issue in sqlite_text_normalize, sqlite_text_validate, and sqlite_text_sentiment where the rowid property was missing or returned 0 for tables with INTEGER PRIMARY KEY. Properly aliased rowid as id in the read queries to ensure consistent row identification.
  • RowID Aliasing Bug (Part 2): Extended the rowid aliasing fix (SELECT rowid as __rowid) to sqlite_text_trim, sqlite_text_case, and sqlite_text_substring tools to ensure consistent row identification across the entire text group, preventing better-sqlite3 from overriding the rowid alias with the primary key name.
  • FTS Create Schema Alias: Updated FtsCreateSchema and the handler logic in sqlite_fts_create to accept ftsTable as an alias for tableName, resolving parameter discrepancies during tool group testing while adhering to the "Code Over Docs" policy.
  • Bloat Payload Scaling: Fixed an issue in sqlite_stats_detect_bloat and sqlite_stats_detect_schema_risks where the tools returned the entire table list unconditionally. Added an includeZeroRisk parameter (default: false) to filter out zero-risk tables, reducing the detect_schema_risks payload by >70% on healthy databases.
  • WASM Code Mode Capability Filtering: Fixed a bug where sqlite.help() within Code Mode exposed empty namespaces (like transactions) or incorrectly filtered out the 4 basic geo tools (distance, nearby, bounding box, cluster) on the WASM backend. Updated SqliteAdapter.getAvailableToolDefinitions() to strictly filter out only SpatiaLite tools and FTS5 tools, correctly reporting 9 accessible groups in WASM.
  • Introspection Graph Row Counts: Fixed a bug where sqlite_dependency_graph hardcoded rowCount to 0 by default. Modified buildForeignKeyGraph to explicitly query actual row counts when includeRowCounts is true. This also resolves an issue where sqlite_cascade_simulator erroneously reported estimatedRows: 0 for all cascaded table actions.
  • Introspection Payload Bloat: Fixed an issue where sqlite_schema_snapshot and sqlite_dependency_graph included all FTS5 shadow tables (e.g., *_fts_data, *_fts_idx), unnecessarily bloating payload sizes. FTS shadow tables are now explicitly filtered out from tables, views, indexes, and triggers arrays.
  • Resource Templating Error Pattern: Fixed an issue where the sqlite_table_schema resource threw an unhandled framework exception when requesting the schema for a nonexistent table. Wrapped the adapter.describeTable() call in a try/catch to cleanly return a structured JSON error response ({"success": false, "error": "Table '...' does not exist"}).
  • Help Resource Registration Leak: Fixed a registration gap where group-specific help resources (e.g. sqlite://help/admin) were not properly exposed when the codemode tool filter was uniquely enabled. Refined the explicit check in mcp-server.ts to this.toolFilter.enabledGroups.size === 1 && this.toolFilter.enabledGroups.has("codemode"), ensuring sandbox agents retain full access to internal group documentation without accidentally leaking help files to restricted filter profiles.
  • Test Documentation Alignment: Updated test-server/test-resources.md to align with the canonical sqlite_append_insight tool schema, changing the documented manual test payload from { category, finding } to the actually implemented { insight: "..." }.
  • Pragma Settings Exception Leak: Fixed an issue in sqlite_pragma_settings where writing to pragmas that do not return data (e.g., cache_size) threw an internal "does not return data" better-sqlite3 exception. The error was incorrectly caught and returned as a VALIDATION_ERROR. The handler now properly delegates PRAGMA writes to executeWriteQuery, ensuring successful writes complete without errors and no validation payload is incorrectly emitted.
  • Migration Rollback Validation: Fixed an issue in MigrationRollbackValidationSchema where an empty input {} bypassed Zod validation and triggered a downstream domain error. Added a requirement check in the superRefine block to enforce that either id or version must be provided, ensuring a VALIDATION_ERROR is correctly thrown before domain execution.
  • Code Mode Timeout Enforcement: Fixed an issue where the timeout parameter in sqlite_execute_code enforced a minimum of 1000ms, despite allowing configurations down to 500ms. Updated both the Zod schema (ExecuteCodeSchema) and the handler-level guard in codemode.ts to correctly allow timeouts down to 500ms.
  • Gotchas Documentation: Removed the obsolete FTS5 rebuild requirement (Gotcha #5) from gotchas.md since sqlite_fts_create automatically populates the index upon creation.
  • Read Query Validator Context: Fixed an issue where the sqlite_read_query and sqlite_write_query validators blocked invalid statements (e.g., misspelled keywords) with a generic VALIDATION_ERROR but provided no SQL context. Added the original query string to the error details.sql to satisfy "structured error with SQL syntax context" testing requirements.
  • Code Mode Silent Failures: Fixed an issue in the Code Mode Sandbox (sqlite_execute_code) where tool handlers that encountered validation errors or query failures silently returned an object { success: false, error: ... } instead of throwing a JavaScript exception. The API wrapper in src/codemode/api.ts now inspects handler results and explicitly throws an Error on failure, ensuring scripts fail fast natively and errors bubble up correctly without requiring explicit if (!res.success) checks.
  • Code Mode RPC Error Masking: Fixed an issue in sqlite_execute_code where validation errors for tools returning a message: "" property inadvertently overwrote the internal err.message during Sandbox proxy mapping, causing silent undefined resolutions. Additionally, upgraded the WorkerSandbox RPC payload (RpcResponse) to extract and transmit custom Error properties (e.g., code, category, sql), ensuring that structured errors correctly traverse the worker_threads boundary into the user's sandbox code.
  • Code Mode Error Throw Reversion: Reverted a previous change in src/codemode/api.ts that caused Code Mode to throw JS exceptions on domain/validation errors. To comply with the Structured Error standard, Code Mode API now correctly returns the { success: false, error: ... } object directly rather than throwing, allowing scripts to inspect errors natively without try/catch and preventing raw MCP errors from unhandled exceptions.
  • Migration Record Validation: Fixed an issue in MigrationRecordValidationSchema where passing an empty object {} bypassed the requirement for SQL content. Added a .superRefine check to enforce that either sql or migrationSql must be provided, ensuring a VALIDATION_ERROR is correctly thrown before domain execution.
  • Stats Error Standardization: Refactored the stats tool group to strictly throw ValidationError and ResourceNotFoundError exceptions instead of returning manual ad-hoc error objects. Updated statsHistogram, statsPercentile, statsCorrelation, statsDetectAnomalies, and the validateNumericColumn helper, ensuring complete parity with the project's Structured Error formats and allowing formatHandlerError to properly intercept and format the outputs.
  • Nested Transaction Execution: Fixed an issue in sqlite_transaction_execute where executing multiple statements inside an already-active manual transaction failed with TRANSACTION_CONFLICT. The tool now detects active transactions, skips the redundant BEGIN / COMMIT, executes the statements seamlessly within the parent transaction context, and correctly triggers a full rollback if any statement fails and rollbackOnError is enabled, eliminating lingering aborted states.
  • Transaction Failed To Start Logic: Fixed an issue in sqlite_transaction_execute where rolling back a pre-existing transaction during a failure inside .execute() incorrectly output the error message "Transaction failed to start" instead of "Transaction rolled back". Corrected transactions.ts by ensuring !originallyInTransaction check logic evaluates before overriding rollbackMessage.
  • Core Convenience Schema Return Values: Fixed an issue where sqlite_upsert and sqlite_batch_insert triggered raw MCP validation errors when passed returning: true as a boolean. Updated schemas to accept boolean OR array of strings, and improved handler to support RETURNING *.
  • Core Write Query Output Schema Parity: Fixed an issue where the WriteQueryOutputSchema lacked the rows property. It now explicitly declares rows: z.array(RowRecordSchema).optional() to ensure returned rows from INSERT/UPDATE... RETURNING statements are correctly validated by the SDK and not rejected as unexpected additional properties.
  • Core Write Query Return Rows: Fixed an issue in query-executor.ts (WASM) and native-query-executor.ts (Native) where executeWriteQuery failed to actually return the rows affected by RETURNING clauses because they defaulted to db.run() instead of .exec() or .all(). Handlers now correctly inspect the query or statement reader and extract the inserted/updated rows.
  • Core Data Test Prompt Fix: Identified that the test prompt erroneously expected CREATE TABLE and DROP TABLE to succeed via sqlite_write_query, despite explicit architectural enforcement rejecting DDL commands in favor of sqlite_create_table/sqlite_drop_table. Handlers correctly rejected these; no code changes were made to DDL constraints, but the test expectations were noted as factually incorrect.
  • Storage Analysis Limit Leak: Fixed an issue in StorageAnalysisSchema where the .min(1) and .max(500) Zod refinements on the limit parameter bypassed the try/catch handler and leaked as raw MCP framework errors. The refinements were removed from the schema and boundary validation logic was moved inside the sqlite_storage_analysis handler using ValidationError to guarantee strict structured {success: false, error: ..., code: "VALIDATION_ERROR"} responses.
  • SpatiaLite GeoJSON Validation: Fixed an issue in sqlite_spatialite_import where invalid GeoJSON input (such as a FeatureCollection) silently resulted in a NULL geometry insertion because the SQLite GeomFromGeoJSON function quietly returns null for invalid formats. Added a pre-validation query to ensure the parsed geometry is strictly valid before executing the INSERT, matching the existing WKT validation pipeline.
  • SpatiaLite Index Verification: Fixed an issue in sqlite_spatialite_index where checking for the existence of an index incorrectly queried sqlite_master for virtual tables, resulting in false negatives and null checks on SpatiaLite 5.x. The indexExists helper now queries the geometry_columns table (spatial_index_enabled flag) to accurately reflect index state. Additionally, added strict return value verification (=== 0) to CreateSpatialIndex and DisableSpatialIndex executions to prevent silent failures when generating or dropping the R-Tree tables.
  • JSON Error Standardization: Refactored the json tool group to strictly throw ValidationError exceptions instead of returning manual ad-hoc error objects. Updated tools across crud.ts and write.ts (e.g., sqlite_json_extract, sqlite_json_set, sqlite_json_insert, sqlite_json_update), ensuring complete parity with the project's Structured Error formats and allowing formatHandlerError to properly intercept and format the outputs for invalid JSON paths and missing required parameters.
  • Zod Schema Numeric Validation Leak: Fixed a major framework-level validation bypass where passing invalid string inputs to .optional().default(x) numeric properties (e.g., buckets: "four") resulted in a raw MCP SDK error (-32602 Input validation error: expected number, received string) rather than a structured internal error. This occurred because coerceNumber returned the invalid string directly to the schema instead of returning undefined. Updated coerceNumber across all 10 schema files (stats.ts, geo.ts, window.ts, etc.) to return undefined for isNaN inputs, ensuring Zod gracefully falls back to default values or emits proper handler-level VALIDATION_ERROR responses.
  • Introspection Tools Schema Parity: Fixed an issue where sqlite_get_indexes would not correctly accept the tableName alias from MCP clients because GetIndexesSchema lacked the alias definition, causing it to be stripped during strict SDK validation.
  • E2E Test DB State Corruption: Fixed E2E test suite cascading failures (test_orders row checks, constraint/cascade simulators, and prompt schema reads) caused by corrupted test database state left over from isolated Code Mode testing sessions. Reset test.db to its canonical seed state.
  • Code Mode Schema Mismatch: Added missing tokenEstimate field to ExecuteCodeOutputSchema metrics object to prevent silent output schema omissions and correctly validate metrics.tokenEstimate in Code Mode execution results.

Security

  • CI/CD Hardening: Added --provenance flag to npm publish in publish-npm.yml for SLSA Build L3 attestation. Added id-token: write permission for OIDC provenance token generation.
  • CI/CD Harmonization:
    • Added secrets-scanning.yml (TruffleHog + Gitleaks on every push/PR)
    • Added dependabot-auto-merge.yml (auto-squash patch/minor, manual review for major)
    • Added Trivy container scan + SARIF upload to docker-publish.yml security-scan job
    • Added .gitleaks.toml and .trivyignore configuration files
  • Vulnerability Remediation: Resolved Vite, Hono, path-to-regexp, fast-uri, Picomatch, and ip-address vulnerabilities via npm update and transitive lockfile resolutions.
  • Docker Image Hardening: Pinned Alpine edge packages (openssl, musl, nghttp2) and manually updated npm's bundled brace-expansion to resolve multiple Docker Scout CVEs.

1.1.1 - 2026-03-18

Changed

  • Version Management: Both SQLite adapters now import VERSION from src/version.ts — only package.json needs updating on version bumps
  • Version Test: Derive expected adapter version from VERSION constant instead of hardcoded string

Fixed

  • Docker Build: Adjusted Docker/CI build configuration so tsup receives the correct inputs, fixing "No input files" CI build failure
  • Docker Workflow: Updated all docker/setup-buildx-action refs from v3 (Node 20, deprecated) to v4 (Node 24)
  • Docker Workflow: Fixed peter-evans/dockerhub-description broken SHA — updated to v5 release (1b9a80c)
  • Prompt Handler: Made args optional in handleResult to prevent crash when SDK invokes prompts with undefined args
  • Transaction Methods: Replaced generic Error with ValidationError + INVALID_SAVEPOINT_NAME code for savepoint name validation
  • Index Tools: Centralized table existence checks via validateTableExists() from column-validation.ts

1.1.0 - 2026-03-18

Added

  • E2E Tests: Ported 32 HTTP transport e2e tests from memory-journal-mcp covering streaming (raw SSE for GET /mcp and GET /sse), advanced session management (cross-protocol guard, sequential isolation, post-DELETE rejection), rate limiting (429 burst, Retry-After header, health exemption), and OAuth 2.1 discovery (RFC 9728 metadata, scopes, auth gating). Enriched existing health and security specs with timestamp validation, session ID checks, CORS header assertions, and HSTS opt-in testing. Added startServer()/stopServer() managed child-process lifecycle helpers.
  • Integration Test Scripts: Ported test-instruction-levels.mjs and test-tool-annotations.mjs terminal scripts from memory-journal-mcp to test-server/.
  • MCP Compliance: Added READ_ONLY annotations (openWorldHint: false) to 3 built-in server tools (server_info, server_health, list_adapters). Added missing openWorldHint: false to sqlite_execute_code codemode tool. All 118+ tools now have complete MCP annotations.
  • Help Resources: Added sqlite://help and sqlite://help/{group} MCP resources for on-demand tool reference documentation. Agents receive a slim ~680-char instructions payload pointing to these resources, instead of the previous ~3.5K+ payload that exceeded MCP client character limits and was silently truncated. Help resources are filtered by --tool-filter — only enabled groups get help resources registered.
  • Help Resources: Added sqlite://help/introspection and sqlite://help/migration help resources — these tool groups were missing dedicated help content, leaving HTTP/SSE/streaming users without access to reference documentation for 15 tools.
  • E2E Tests: Added 6 new spec files (~209 tests) automating the deterministic portions of manual agent testing prompts: zod-sweep.spec.ts (Zod validation sweep — every tool with required params called with {}), errors-extended.spec.ts (per-group domain error paths), codemode.spec.ts (sandbox lifecycle, security, readonly, workflows), codemode-groups.spec.ts (all 9 groups via sqlite.* API), numeric-coercion.spec.ts (string-typed numeric params), boundary.spec.ts (empty tables, NULLs, idempotency, edge cases). Added expectHandlerError and callToolRaw helpers to helpers.ts.
  • E2E Tests: Added 3 native-only spec files expanding systematic validation coverage to native-exclusive tools: zod-sweep-native.spec.ts (20 tools — FTS5, window functions, transactions, SpatiaLite called with {}), errors-native.spec.ts (20 error path tests — nonexistent tables/columns, invalid SQL/WKT, bad savepoints), numeric-coercion-native.spec.ts (8 tests — string-typed numeric params for window windowSize/buckets/offset/limit, FTS limit, transaction mode). Raises Zod sweep coverage from 83% to 98% of all tools.
  • E2E Tests: Added help-resources.spec.ts (11 tests — validates sqlite://help root + all 8 group help resources are listed, readable, and return non-empty markdown) and aliases.spec.ts (14 tests — validates backward-compatible parameter aliases tableNametable, sqlquery, nameindexName across all 8 core tools including precedence and error paths).
  • Annotation Invariant Tests: Added tool-annotations.test.ts that enforces every tool in both WASM and Native adapters has annotations with explicit readOnlyHint. Includes per-group checks (all stats/introspection tools must be readOnly), specific window function assertions, and title validation. Would have caught the 6 missing window function annotations and the 7 missing transaction annotations.
  • Output Schema Invariant Tests: Added tool-output-schemas.test.ts that enforces every tool has an outputSchema defined, every schema is a valid Zod schema, every schema accepts error responses ({success: false, error: "..."}), schemas reference centralized output-schemas/ exports (not inline z.object()), specific tool-to-schema wiring for ~70 tools, and no orphan schemas exist. Covers both WASM and Native adapters.
  • E2E Tests: Added 6 window function readonly smoke tests to codemode.spec.ts — verifies all window tools (windowRowNumber, windowRank, windowLagLead, windowRunningTotal, windowMovingAvg, windowNtile) work in readonly: true mode on native and are correctly unavailable on WASM. Uses dual-branch assertions (zero skips).
  • Window Tool Tests: Added annotation assertions to ranking.test.ts — verifies all 6 window tools have readOnly annotations with titles.
  • E2E Tests (Prompt Audit): Added 12 gap-closing tests identified by auditing manual testing prompts against automated suites: (1) codemode.spec.ts — API discoverability tests for sqlite.help(), per-group help(), method aliases, convenience aliases, and all 9 groups returning >0 methods; timeout enforcement for infinite loops. (2) payloads-stats-advanced.spec.ts — self-correlation edge case (column1 === column2 → ≈1.0). (3) payloads-fts.spec.ts — FTS5 boolean AND/NOT operators. (4) payloads-migration.spec.ts — duplicate version string rejection. (5) boundary.spec.ts — vector empty table edge cases (count, search, stats, dimensions on table with 0 vectors). (6) New codemode-introspection.spec.ts (~16 tests) — introspection code-mode-only params (sections, compact, checks, table, includeTableDetails, limit, direction). (7) New transactions-nested.spec.ts (~4 tests) — nested savepoint data correctness (rollback_to sp2 keeps sp1 data; rollback_to sp1 undoes everything after sp1). (8) New integration-workflows.spec.ts (~8 tests) — cross-group pipelines (Core→JSON→Stats, Core→Vector→Text, Admin→Introspection health check, Core+Stats cross-validation, data integrity verification).
  • E2E Tests (Resource + Prompt Depth): Added 13 gap-closing tests by auditing test-resources.md and test-prompts.md against existing specs. Resources (R1–R9): schema table count + names, templated reads (sqlite://table/test_products/schema + test_orders), nonexistent table error, index name assertions (idx_orders_status, idx_products_category), health backend info, meta PRAGMA fields (page_size), views empty array, insights write+read cycle via sqlite_append_insight, help keyword assertions ("gotcha", "code mode", "wasm"). Prompts (P1–P4): data-fetching prompts embed real table names (explain_schema contains "test_products"), argsSchema on prompts with required args (query_builder ≥3, data_analysis ≥1, explain_schema 0), missing required args graceful handling, deeper content assertions (debug_query reflects submitted SQL, migration reflects change description).
  • Error Handling — TransactionError Subclass — New TransactionError class in utils/errors/classes.ts for commit/rollback/savepoint failures, using QUERY category with recoverable: true
  • Error Handling — ErrorContext Interface — New ErrorContext interface in utils/errors/format.ts for optional tool/table/sql context on error formatting calls
  • Error Handling — formatHandlerError Export — Canonical cross-project name for the primary error formatter; formatError remains as an alias
  • Error Handling — Zod Path ExtractionformatHandlerError now extracts field paths from ZodErrors (e.g., table: Required instead of raw JSON issue arrays)
  • OAuth — FULL Scope — Added full scope that grants unrestricted access to all operations, completing the full ⊃ admin ⊃ write ⊃ read hierarchy
  • OAuth — TOOL_GROUP_SCOPES Mapping — Declarative Record<ToolGroup, StandardScope> replaces imperative *_SCOPE_GROUPS arrays as single source of truth
  • OAuth — Scope Utilities — Added hasScope(), hasAnyScope(), hasAllScopes(), getScopeForToolGroup(), getScopeDisplayName() for hierarchical scope checks
  • OAuth — Scope Map — New scope-map.ts with getRequiredScope() for O(1) tool-name-to-scope reverse lookup
  • OAuth — Auth Context — New auth-context.ts using AsyncLocalStorage for per-request auth context threading to tool handlers
  • OAuth — Transport-Agnostic Auth — Added AuthenticatedContext, createAuthenticatedContext(), validateAuth(), formatOAuthError() to decouple auth from Express
  • OAuth — Resource Server Enhancements — Added isScopeSupported(), getWellKnownPath(), resource_documentation, resource_signing_alg_values_supported to RFC 9728 metadata
  • OAuth — Unit Test Coverage — Added 8 unit test files for complete auth module coverage: scopes, scope-map, auth-context, errors, oauth-resource-server, middleware, token-validator, authorization-server-discovery
  • Transport Feature BackporttrustProxy config option for X-Forwarded-For client IP extraction behind reverse proxies
  • Transport Feature BackportenableHSTS / hstsMaxAge config options (HSTS now opt-in, was always-on)
  • Transport Feature Backport — Wildcard subdomain CORS matching (e.g., *.example.com)
  • Transport Feature Backport — New middleware.test.ts with 14 unit tests for getClientIp() and matchesCorsOrigin()
  • Playwright E2E Test Suite — 12 spec files, dual-adapter (WASM + Native) and dual-transport (SSE + Streamable HTTP) coverage
    • health.spec.ts: Health endpoint and MCP initialization handshake
    • protocols.spec.ts: Streamable HTTP and Legacy SSE protocol validation (session IDs, invalid JSON, missing params)
    • tools.spec.ts: Tool listing, read/write execution, validation errors, Code Mode, and cross-group coverage (all 9 tool groups) via MCP SDK Client
    • security.spec.ts: 404 handler, 413 payload limit, security headers, CORS preflight, OAuth status, Referrer-Policy
    • sessions.spec.ts: Full Streamable HTTP session lifecycle — init, notifications, tool calls with session ID, SSE/DELETE rejection, termination
    • stateless.spec.ts: Stateless mode (--stateless) — session-free POST, SSE 405, DELETE no-op, legacy SSE 404, health
    • resources.spec.ts: All 7 static MCP resources (sqlite://schema, tables, health, indexes, views, meta, memo://insights) and resource templates via SDK Client
    • prompts.spec.ts: List + get all 10 MCP prompts with representative arguments
    • streamable-http.spec.ts: Streamable HTTP transport (MCP 2025-03-26) — init, tools, resources, prompts via modern transport
    • native.spec.ts: Native-only tools — transactions (begin/rollback), FTS5 search, window functions (row_number)
    • wasm.spec.ts: WASM graceful degradation — transactions rejected, backup/restore/verify return wasmLimitation
    • errors.spec.ts: Structured error response contract — TABLE_NOT_FOUND, COLUMN_NOT_FOUND, statement type mismatches, coordinate validation, non-numeric column detection
    • Dual-project playwright.config.ts: WASM adapter (port 3000) + Native adapter (port 3001) with --tool-filter +all
    • test:e2e npm script, dedicated e2e.yml CI workflow, E2E badge added to README
  • Performance Benchmark Suite — 9 benchmark files measuring framework overhead on critical hot paths
    • handler-dispatch.bench.ts: Tool lookup, error construction, progress notification overhead
    • utilities.bench.ts: Identifier sanitization, WHERE clause validation, SQL validation, metadata caching
    • tool-filtering.bench.ts: Filter parsing, group lookups, meta-group catalog generation
    • schema-parsing.bench.ts: Zod schema validation for simple/complex/large payloads and failure paths
    • logger-sanitization.bench.ts: Log call overhead, message sanitization, stack trace processing, sensitive data redaction
    • transport-auth.bench.ts: Token extraction, scope checking, error formatting, rate limiting
    • codemode.bench.ts: Sandbox creation/disposal, pool lifecycle, security validation, execution overhead
    • database-operations.bench.ts: PRAGMA operations, table metadata, query result processing, JSON path validation, schema caching
    • resource-prompts.bench.ts: Resource URI matching, content assembly, prompt generation, tool index generation
    • npm run bench and npm run bench:verbose scripts; vitest.config.ts benchmark configuration
  • Introspection Tool Group (6 tools) — Read-only schema analysis and dependency mapping
    • sqlite_dependency_graph: Build directed FK dependency graphs with depth/direction control
    • sqlite_topological_sort: Determine safe creation/drop order for tables
    • sqlite_cascade_simulator: Preview cascade effects before running DELETE/DROP
    • sqlite_schema_snapshot: Capture full or partial schema with SHA-256 fingerprinting
    • sqlite_constraint_analysis: Analyze FK constraints, detect orphans, unindexed FKs
    • sqlite_migration_risks: Assess risk levels for DDL migration statements
    • All tools are strictly read-only (no database modifications)
  • Migration Tool Group (6 tools) — Opt-in schema migration lifecycle management
    • sqlite_migration_init: Create _mcp_migrations tracking table
    • sqlite_migration_record: Record a migration without executing (audit/tracking)
    • sqlite_migration_apply: Execute + record migration atomically with rollback SQL
    • sqlite_migration_rollback: Reverse a migration using stored rollback SQL
    • sqlite_migration_history: Query migration history with status/version filters
    • sqlite_migration_status: Dashboard summary of migration state
    • SHA-256 deduplication prevents accidental re-application
    • All tools require write or admin scope
  • dev-schema Meta-Group Shortcut — New shortcut enabling core + introspection + migration + codemode for schema development workflows
  • Code Mode Introspection/Migration Supportsqlite.introspection.* and sqlite.migration.* groups added to sandbox API
    • Method aliases: deps, toposort, cascade, snapshot, constraints, risks, setup, log, run, undo
    • Positional parameter support and help() examples for both groups
    • Groups listed in sqlite_execute_code tool description and ServerInstructions.ts
  • Tool Icons (MCP 2025-11-25) — All tools, resources, and prompts now include visual icons
    • 8 group-level icons from Material Design Icons (CDN-hosted SVG via jsDelivr)
    • Built-in server tools (server_info, server_health, list_adapters) get a server icon
    • New src/utils/icons.ts utility with getToolGroupIcon() and SERVER_ICONS
    • Icon passthrough in both WASM and Native adapter registerTool()/registerResource()/registerPrompt() methods
    • McpIcon type added to types/index.ts; icons field added to ToolDefinition, ResourceDefinition, PromptDefinition
    • Dual HTTP Transport — HTTP transport now supports both Streamable HTTP (MCP 2025-03-26) and Legacy SSE (MCP 2024-11-05) protocols simultaneously
    • GET /sse — Opens Legacy SSE connection for backward-compatible clients
    • POST /messages?sessionId=<id> — Routes messages to Legacy SSE transport
    • Cross-protocol guard: SSE session IDs rejected on /mcp and vice versa
  • Security Headers — All HTTP responses now include 7 security headers: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Cache-Control: no-store, Content-Security-Policy, Permissions-Policy, Referrer-Policy, Strict-Transport-Security
  • Rate Limiting — Per-IP sliding-window rate limiting (100 requests/minute, health endpoint exempt)
  • Body Size Enforcement — JSON body limited to 1 MB via express.json({ limit }), returns 413 for oversized payloads
  • 404 Handler — Unknown paths now return 404 { error: "Not found" } instead of Express default HTML
  • Code Mode (Sandboxed Execution) — New sqlite_execute_code tool for executing JavaScript in a sandboxed environment
    • Agents write code using sqlite.* API to access all 7 tool groups (core, json, text, stats, vector, admin, geo)
    • 70-90% token reduction by replacing multiple sequential tool calls with a single code execution
    • Dual sandbox support: worker_threads (default, enhanced isolation) and vm module
    • Worker sandbox uses MessagePort RPC bridge for secure API proxy between threads
    • Security: code validation against blocked patterns, rate limiting (60 exec/min), result sanitization (10MB cap), audit logging
    • Built-in help() for discoverability: sqlite.help() for groups, sqlite.<group>.help() for methods
    • Positional parameter support: sqlite.core.readQuery("SELECT 1") maps to { query: "SELECT 1" }
    • Method aliases for ergonomic use (e.g., sqlite.core.query()readQuery)
    • New codemode tool group added to all meta-group shortcuts (starter, analytics, search, spatial, minimal, full)
    • Environment variable CODEMODE_ISOLATION=vm|worker to select sandbox mode (default: worker)
    • New files: src/codemode/ (types, security, sandbox, worker-sandbox, worker-script, sandbox-factory, api, index)
    • Updated: ToolGroup type, LogModule, ToolConstants, ServerInstructions, tool index
    • Auto-injected into all tool filter configurations (whitelist mode) — opt out with -codemode
    • sqlite_drop_index Tool — New core tool to drop indexes from the database
    • Validates index existence before dropping
    • Supports ifExists flag (default true) for graceful no-op when index doesn't exist
    • Registered in core group with DropIndexSchema / DropIndexOutputSchema
    • Added to ToolConstants.ts, ServerInstructions.ts, and positional param map
    • Core tool count: 8 → 9 (minimal meta-group: 9 → 10)
  • Server Host Binding — New --server-host CLI option and MCP_HOST environment variable
    • Configures which host/IP the HTTP transport binds to (default: 0.0.0.0)
    • Use --server-host 127.0.0.1 to restrict to local connections only
    • Precedence: CLI flag > MCP_HOST env var > HOST env var > default (0.0.0.0)
    • Essential for containerized deployments where binding to all interfaces is required

Changed

  • Inline Schema Consolidation: Relocated 7 migration output schemas (MigrationRecordEntry, MigrationInitOutputSchema, MigrationRecordOutputSchema, MigrationApplyOutputSchema, MigrationRollbackOutputSchema, MigrationHistoryOutputSchema, MigrationStatusOutputSchema) from tools/migration/schemas.ts to centralized output-schemas/migration.ts — the last tool group without dedicated output schema files. Original location now re-exports for backward compatibility.

  • Inline Schema Consolidation: Extracted 9 inline outputSchema: z.object() definitions from introspection tool handlers into centralized output-schemas/introspection.tsDependencyGraphOutputSchema, TopologicalSortOutputSchema, CascadeSimulatorOutputSchema, SchemaSnapshotOutputSchema, ConstraintAnalysisOutputSchema, MigrationRisksOutputSchema, StorageAnalysisOutputSchema, IndexAuditOutputSchema, QueryPlanOutputSchema. All output schemas are now consistently defined in centralized files with named exports — zero inline definitions remain across all tool groups.

  • Inline Schema Consolidation: Extracted 8 remaining inline outputSchema: z.object() definitions from tool handlers into centralized output-schemas/ files — virtual.ts (7 schemas: ListVirtualTablesOutputSchema, VirtualTableInfoOutputSchema, DropVirtualTableOutputSchema, CreateCsvTableOutputSchema, AnalyzeCsvSchemaOutputSchema, CreateRtreeTableOutputSchema, CreateSeriesTableOutputSchema), text.ts (1 schema: TextValidateOutputSchema), and stats.ts (1 schema: StatsHypothesisOutputSchema). All output schemas are now consistently defined in centralized files with named exports — zero inline definitions remain.

  • Complexity Refactor: Addressed source code complexity by splitting files exceeding logical grouping boundaries into modular directories with barrel exports:

    • Extracted query execution, initialization, and connection lifecycle handlers from sqlite-adapter.ts.
    • modularized authentication routines in middleware.ts and scopes.ts.
    • Refined administration and stats tools (backup.ts, tracking.ts, vtable.ts, inference.ts).
    • Extracted resource, tool, and prompt registration logic from database-adapter.ts.
  • Code Quality Audit: Addressed technical debt across the codebase by replacing generic any casts with type-safe structures, normalizing test file naming from .test to kebab-case, extracting massive native-sqlite-adapter.ts tooling logic into registration, and removing unsafe type imports.

  • Code Quality Audit: Removed dead code by deleting unused barrel files (src/auth/index.ts and src/transports/index.ts).

  • Performance Audit: Disabled source maps generation in the production build to significantly reduce bundle size (from 3.7MB to 1.5MB), optimized sandbox serialization to reduce runtime memory allocations, and added caching to schema introspection tools via SchemaManager.

  • Unified Audit: Enabled code splitting in tsup.config.ts to deduplicate shared modules across the 3 entry points.

  • MCP Compliance: Added openWorldHint: false to all tool annotation presets and openWorldHint to the ToolAnnotations type interface.

  • MCP Compliance: Added title to built-in server tools (server_info, server_health, list_adapters).

  • MCP Compliance: Added error field to ErrorResponseFields mixin (was 5 fields, now 6 per mcp-builder §2.2.2).

  • MCP Compliance: Created src/auth/transport-agnostic.ts re-exporting non-Express auth utilities for transport portability.

  • MCP Compliance: Renamed formatHandlerErrorResponseformatHandlerError across all tool handlers, tests, and barrel exports per mcp-builder §2.2.2 single-formatter standard. Old name preserved as deprecated alias in format.ts.

  • MCP Compliance: Wired prompt argsSchema to SDK registration — prompts with required arguments now expose typed schemas via prompts/list. All-optional and zero-arg prompts correctly omit argsSchema per SDK gotcha (§1.4).

  • MCP Compliance: Consolidated duplicate ErrorFieldsMixin / ErrorResponseFields to single source of truth in src/utils/errors/error-response-fields.ts with re-export alias.

  • Help Resource Architecture: Replaced tiered --instruction-level CLI flag and INSTRUCTION_LEVEL env var with pull-based sqlite://help resources. Removed instructionLevel from McpServerConfig. Replaced monolithic server-instructions.md with per-group .md files in src/constants/server-instructions/. Generate script updated to produce slim INSTRUCTIONS constant + HELP_CONTENT map.

  • HSTS: Wired --enable-hsts CLI flag and MCP_ENABLE_HSTS env var to the HTTP transport — previously defined in types but never reachable from the CLI.

  • Error Handling — Output Schema Migration — All 10 output schema files (~115 schemas) now include ErrorFieldsMixin via .extend(ErrorFieldsMixin.shape)

    • New error-mixin.ts defines shared mixin with all 6 ErrorResponse fields (error, code, category, suggestion, recoverable, details)
    • Replaces inconsistent inline error fields (some schemas had error+code+suggestion, others had none)
    • Ensures every tool's output schema can accommodate structured error responses
  • Error Handling — Handler Migration to formatHandlerError — ~108 catch blocks across ~25 handler files migrated to use formatHandlerError() directly

    • Eliminates Pattern A re-wrapping (const structured = formatError(error); return { success: false, message: structured.error })
    • Eliminates Pattern B inline error construction
    • All handler catch blocks now use return formatHandlerError(error) for consistent structured error responses
    • Affected groups: core, admin, text, json-helpers, json-operations, introspection, fts, codemode, stats, vector, geo, migration
    • 3 synchronous handlers wrapped with Promise.resolve() to satisfy handler: () => Promise<unknown> type constraint
  • Performance Audit Fix — Async File I/O — Replaced synchronous fs.readFileSync and fs.writeFileSync with fs.promises.readFile and fs.promises.writeFile in sqlite-adapter.ts to prevent event loop blocking during database initialization and teardown.

  • Code Quality Audit — Standardized Error — Replaced an instance of generic Error in sqlite_stats_regression (inference.ts) with DbMcpError using STATS_INSUFFICIENT_SAMPLE and VALIDATION category.

  • Code Quality Audit — Logger Module Split — Split monolithic logger.ts (543 lines) into utils/logger/ directory

    • types.ts: LogLevel, LogModule, LogContext type definitions
    • error-codes.ts: ErrorCode type, createErrorCode(), and ERROR_CODES constant map
    • module-logger.ts: ModuleLogger class for module-scoped logging
    • logger.ts: Core Logger class with sanitization and dual-mode output
    • index.ts: Barrel re-export with default logger instance and env initialization
    • Updated 30 consumer imports across source and test files
  • Code Quality Audit — Enhanced Error Handling — Replaced 35+ instances of generic throw new Error() with enhanced DbMcpError (and subclasses like ValidationError) across the codebase

    • Affected areas: HttpTransport, DbMcpServer, SandboxPool, SchemaManager, native-sqlite-adapter, and numerous tool modules (window.ts, geo.ts, inference.ts, validate.ts, etc.)
    • Ensures all errors follow the structured DbMcpError format with appropriate module-prefixed error codes and ErrorCategory classifications
  • Code Quality Audit — Shared WAL/JSONB Helpers — Extracted autoEnableWal() and detectAndSetJsonbSupport() into sqlite-helpers.ts

    • Both WASM and native adapters now delegate to shared helpers instead of duplicating logic
  • Code Quality Audit — Native Query Executor — Extracted nativeExecuteRead(), nativeExecuteWrite(), nativeExecuteGeneral() into native-query-executor.ts

    • Mirrors the existing WASM query-executor.ts pattern; native-sqlite-adapter.ts reduced from 653 to ~555 lines
  • Code Quality Audit — Transport Type Adapters — Created type-adapters.ts with asIncoming() and asServerResponse()

    • Replaced 16 inline as unknown as casts across session.ts
  • Code Quality Audit — Query Validation Extraction — Extracted validateQuery() and DANGEROUS_SQL_PATTERNS into query-validation.ts

    • database-adapter.ts reduced from 564 to ~520 lines
  • Code Quality Audit — LogModule Type — Added NATIVE_SQLITE and HTTP to the LogModule union type

  • Code Quality Audit — JSON-RPC Constants — Added JSONRPC_SERVER_ERROR and JSONRPC_INTERNAL_ERROR to transports/http/types.ts

    • Replaced inline magic numbers in session.ts
  • Code Quality Audit — Base Class ensureConnected() — Concrete ensureConnected() method on DatabaseAdapter with ConnectionError

    • Both adapters override with protected override calling super.ensureConnected() + db-null check
    • Eliminates duplicated connection-check logic between WASM and native adapters
  • Code Quality Audit — Transaction Method Extraction — Extracted 6 transaction functions into transaction-methods.ts

    • beginTransaction, commitTransaction, rollbackTransaction, savepoint, releaseSavepoint, rollbackToSavepoint
    • native-sqlite-adapter.ts delegates via thin one-liner methods; reduces file from 645 to ~605 lines
  • Code Quality Audit — PRAGMA Deduplication — Extracted PragmaExecutor interface and applyCommonPragmas() into sqlite-helpers.ts

    • Eliminates duplicated walMode/foreignKeys/busyTimeout/cacheSize PRAGMA logic between WASM and native adapters
    • Both adapters now delegate to the shared helper with a thin PragmaExecutor wrapper
  • Code Quality Audit — Extension Loading Extraction — Created sqlite-native/extensions.ts with loadSpatialite() and loadCsvExtension()

    • Moved SpatiaLite and CSV extension loading (candidate paths, Windows PATH augmentation, try-next-path loop) out of native-sqlite-adapter.ts
    • native-sqlite-adapter.ts reduced from 731 to 578 lines; sqlite-adapter.ts from 556 to 484 lines
  • Code Quality Audit — Row Mapping Deduplication — Extracted rowsFromSqlJsResult() helper in sqlite-adapter.ts

    • Replaced 2 identical row-mapping closures in executeReadQuery and executeQuery
  • Code Quality Audit — Query Executor Extraction — Extracted executeRead, executeWrite, executeGeneral into adapters/sqlite/query-executor.ts

    • sqlite-adapter.ts reduced from 679 to ~510 lines; adapter retains validation, connection, and schema cache responsibility
  • Code Quality Audit — HTTP Timeout Constants — Named magic timeout values in transports/http/types.ts

    • HTTP_REQUEST_TIMEOUT_MS (120s), HTTP_KEEP_ALIVE_TIMEOUT_MS (65s), HTTP_HEADERS_TIMEOUT_MS (66s)
    • transport.ts now imports named constants instead of using inline numbers
  • Code Quality Audit — Types File Split — Split types/index.ts (528 lines) into 5 sub-modules

    • database.ts, server.ts, auth.ts, filtering.ts, adapter.ts with barrel re-export
    • Zero consumer import changes — all continue importing from types/index.js
  • Code Quality Audit — Fixed stale --postgresql reference in CLI no-database warning; server only supports SQLite

  • Code Quality Audit — Removed extraneous blank lines in sqlite-adapter.ts

  • Code Quality Audit — Removed duplicate "Server Host Binding" CHANGELOG entry

  • Code Quality Audit — Native Adapter Error Handling — Replaced plain Error throws with typed error classes in native-sqlite-adapter.ts

    • connect(): ConfigurationError for type mismatch, ConnectionError for connection failures
    • executeReadQuery() / executeWriteQuery(): QueryError with SQL context and module-prefixed error codes
    • Matches the WASM adapter's error handling, which already used typed errors
  • Code Quality Audit — Extension Loading Deduplication — Extracted tryLoadExtension() helper and EXTENSIONS_DIR constant in native-sqlite-adapter.ts

    • SpatiaLite and CSV extension loading shared identical try-next-path loop, logging, and __dirname computation
    • Both now call the shared helper; ~50 lines of duplication removed
  • Code Quality Audit — Migration Record Mapping — Extracted toMigrationRecord() into migration/schemas.ts

    • Replaced 5 identical inline row→record mapping blocks in tracking.ts
  • Code Quality Audit — API Constants Extraction — Moved METHOD_ALIASES, GROUP_EXAMPLES, POSITIONAL_PARAM_MAP, GROUP_PREFIX_MAP, KEEP_PREFIX_GROUPS from api.ts to new codemode/api-constants.ts

    • api.ts reduced from 610 to ~330 lines
  • Code Quality Audit — validateColumnExists Deduplication — Extracted shared validateColumnExists() and validateColumnsExist() into adapters/sqlite/tools/column-validation.ts

    • Removed identical 40-line copies from geo.ts, text/helpers.ts, and stats/helpers.ts
    • All three modules now re-export from the shared utility; no consumer import changes needed
  • Code Quality Audit — normalizeParams Deduplication — Extracted shared normalizeSqliteParams() into adapters/sqlite-helpers.ts

    • Removed identical copies from sqlite-adapter.ts and native-sqlite-adapter.ts
    • Both adapters now import from the shared module
    • Also removed unnecessary DatabaseType as DbType alias in native adapter
  • Code Quality Audit — DatabaseType Narrowing — Narrowed DatabaseType union from 6 variants (sqlite | postgresql | mysql | mongodb | redis | sqlserver) to "sqlite" only

    • Other database types would require separate MCP server projects; unused variants were dead code
  • Code Quality Audit — DatabaseConfig Cleanup — Removed unused host, port, database, username, password fields

    • SQLite uses connectionString (file path) and options; relational connection fields were never referenced
  • Code Quality Audit — SqliteAdapter.getInfo() Override Removed — Deleted override that silently dropped capabilities and toolGroups fields from the parent DatabaseAdapter.getInfo()

  • Code Quality Audit — Magic Values Named — Replaced inline magic numbers with named constants

    • geo.ts: 111KM_PER_DEGREE_LAT (km per degree of latitude for bounding box pre-filter)
    • worker-sandbox.ts: 1000TIMEOUT_GRACE_MS (extra grace period for worker cleanup)
  • Code Quality Audit — Stale TODO Removed — Removed misleading TODO: Add other database adapters from cli.ts

    • Additional adapters belong in separate MCP server projects, not this codebase
  • File Naming Convention (Round 2) — Renamed 3 camelCase files to lowercase-with-dashes per project convention

    • Source: insightsManager.tsinsights-manager.ts, resourceAnnotations.tsresource-annotations.ts
    • Test: insightsManager.test.tsinsights-manager.test.ts
    • Updated 6 files with corrected import paths
  • isDDL() Helper Deduplication — Extracted shared isDDL() function into adapters/sqlite-helpers.ts

  • Version Constant DeduplicationVERSION and NAME now read from package.json at runtime via new version.ts module

    • Eliminated 3 hardcoded "1.0.2" strings in index.ts, mcp-server.ts, and cli.ts
    • index.ts re-exports from version.ts; mcp-server.ts and cli.ts import directly
    • Future version bumps only need to update package.json
  • File Size Refactoring — Split 4 oversized files into modular subdirectories

    • utils/errors.ts (559 lines) → errors/ directory (5 modules + barrel), updated 43 import paths
    • introspection/diagnostics.ts (738 lines) → diagnostics/ directory (3 tool modules + barrel)
    • introspection/analysis.ts (720 lines) → analysis/ directory (3 tool modules + barrel)
    • introspection/graph.ts (590 lines) → graph/ directory (helpers + tools + barrel)
  • File Naming Convention — Renamed 16 PascalCase files (11 source + 5 test) to lowercase-with-dashes per project convention

    • Source: DatabaseAdapter.ts, McpServer.ts, SqliteAdapter.ts, NativeSqliteAdapter.ts, SchemaManager.ts, ToolFilter.ts, ToolConstants.ts, ServerInstructions.ts, OAuthResourceServer.ts, AuthorizationServerDiscovery.ts, TokenValidator.ts
    • Tests: DatabaseAdapter.test.ts, SchemaManager.test.ts, SqliteAdapter.test.ts, NativeSqliteAdapter.test.ts, ToolFilter.test.ts
    • Updated 82 files with corrected import paths
  • Dead Code Cleanup — Removed extra blank lines in native-sqlite-adapter.ts

  • Dockerfile Builder Stage — Removed unnecessary apk upgrade --no-cache from builder stage (DK-3)

    • Builder is discarded after multi-stage build; security patches only needed in production stage
    • Saves ~5-10s per Docker build
  • Dockerfile Label Accuracy — Fixed tool count in LABEL from 124 to 139 (DK-2)

  • Tier 2 File Refactoring — Split 4 large files (700–986 lines) into modular directory structures

    • Phase 1 — Adapter Deduplication: Extracted shared registerTool/registerResource/registerPrompt logic into DatabaseAdapter base class, reducing NativeSqliteAdapter.ts (956→727) and SqliteAdapter.ts (945→721)
    • Phase 2 — Transport Split: Split http.ts (986 lines) into http/ directory with 6 files: types.ts, middleware.ts, session.ts, oauth.ts, transport.ts, index.ts
    • Phase 3 — Tool File Splits: Split 3 tool files into directory modules:
      • spatialite.ts (915) → spatialite/ (4 files: schemas.ts, loader.ts, tools.ts, index.ts)
      • vector.ts (826) → vector/ (4 files: schemas.ts, helpers.ts, tools.ts, index.ts)
      • core.ts (770) → core/ (4 files: queries.ts, tables.ts, indexes.ts, index.ts)
    • All consumer imports updated (6 source files + 1 test); no public API changes
  • Configurable CORS Origins — CORS refactored from hardcoded Access-Control-Allow-Origin: * to configurable corsOrigins array; supports explicit origins with Access-Control-Allow-Credentials: true; removed duplicated CORS middleware

  • Root EndpointGET / now lists Legacy SSE endpoints and updated description to "dual HTTP transport"

  • Deterministic Error Handling — Structured error responses across all tools

    • registerTool() catch block now uses formatError() to surface code, category, suggestion, recoverable fields
    • Applies to both WASM (SqliteAdapter) and native (NativeSqliteAdapter) adapters
    • Codemode error paths enriched: CODEMODE_VALIDATION_FAILED, CODEMODE_RATE_LIMITED, CODEMODE_EXECUTION_FAILED
    • Added 4 codemode-specific patterns to ERROR_SUGGESTIONS for auto-suggestion matching
  • Core Tool Handler-Level Error Handling — 5 core tool handlers now catch errors locally and return {success: false} responses

    • sqlite_read_query, sqlite_write_query, sqlite_describe_table, sqlite_create_index: Catch errors with formatError() and return structured {success: false, error, code, suggestion} instead of propagating as isError: true MCP exceptions
    • sqlite_drop_table: Checks table existence before DROP; returns "does not exist (no changes made)" when ifExists is true and table is absent, or {success: false} when ifExists is false
    • sqlite_describe_table: Pre-checks table existence and returns TABLE_NOT_FOUND error code instead of generic UNKNOWN_ERROR
    • sqlite_get_indexes: Validates table existence when tableName is specified; returns {success: false, code: "TABLE_NOT_FOUND"} instead of empty {success: true}
  • Text Tool Handler-Level Error Handling — All 13 text tool handlers now catch errors locally and return {success: false} responses

    • sqlite_regex_match, sqlite_regex_extract, sqlite_text_split, sqlite_text_concat, sqlite_text_replace, sqlite_text_trim, sqlite_text_case, sqlite_text_substring, sqlite_fuzzy_match, sqlite_phonetic_match, sqlite_text_normalize, sqlite_text_validate, sqlite_advanced_search: Catch errors with formatError() and return structured {success: false, error, code, suggestion} instead of propagating as raw MCP exceptions
    • Mirrors the same pattern already applied to core and JSON tool groups
  • Text Tool Column Existence Validation — All 13 text tools now validate column existence before query execution

    • Prevents silent success on nonexistent columns (SQLite treats double-quoted nonexistent identifiers as string literals)
    • Returns {success: false, code: "COLUMN_NOT_FOUND"} with suggestion to use sqlite_describe_table
    • validateColumnExists() uses PRAGMA table_info() to verify column presence
    • validateColumnsExist() handles multi-column tools (sqlite_text_concat)
    • Identifier validation (sanitizeIdentifier) runs first for security, then column existence check
    • 12 new error path tests added for nonexistent column on valid table scenarios
  • Stats Tool Handler-Level Error Handling — All 13 stats tool handlers now catch errors locally and return {success: false} responses

    • sqlite_stats_basic, sqlite_stats_count, sqlite_stats_group_by, sqlite_stats_histogram, sqlite_stats_percentile, sqlite_stats_correlation, sqlite_stats_top_n, sqlite_stats_distinct, sqlite_stats_summary, sqlite_stats_frequency, sqlite_stats_outliers, sqlite_stats_regression, sqlite_stats_hypothesis: Catch errors with formatError() and return structured {success: false, error, code, suggestion} instead of propagating as raw MCP exceptions
    • Mirrors the same pattern already applied to core, JSON, and text tool groups
  • Stats Tool Column Existence Validation — All 13 stats tools now validate column existence before query execution

    • sqlite_stats_summary validates user-specified columns; auto-detected columns skip validation
    • sqlite_stats_correlation validates both column1 and column2; sqlite_stats_regression validates both xColumn and yColumn
    • sqlite_stats_hypothesis validates column, column2 (ttest_two), and groupColumn (chi_square)
    • 15 new error path tests added for nonexistent table and column scenarios
  • Security Test Pattern Update — Updated security integration tests for stats tool structured error handling

    • tool-integration.test.ts: 57 stats injection tests now use assertRejectsInjection() helper accepting either throws or {success: false} responses
    • identifier-integration.test.ts: 4 stats identifier injection tests updated from rejects.toThrow() to structured error assertions
    • Fixed stats_group_by identifier test using wrong parameter names (column/groupColumnvalueColumn/groupByColumn/stat)
  • Compact JSON Serialization (R-1) — Tool responses now use compact JSON.stringify(result) instead of pretty-printed JSON.stringify(result, null, 2)

    • Reduces serialization overhead by ~15-20% on large payloads; MCP clients parse JSON programmatically
    • Error responses retain pretty-print for debugging readability
  • Incremental TypeScript Builds (B-1) — Added incremental: true and tsBuildInfoFile to tsconfig.json

    • Subsequent builds only recheck changed files, significantly reducing dev-loop build times
  • Vitest Thread Pool (T-1) — Configured pool: "threads" in vitest.config.ts

    • Enables worker thread execution for test parallelism on multi-core machines
  • isDDL() Helper Extraction (S-2/R-4) — Replaced 3× duplicated DDL detection blocks with module-scope isDDL() function

    • Eliminates redundant sql.trim().toUpperCase() allocations in SqliteAdapter.ts and NativeSqliteAdapter.ts
  • SchemaManager Array Pre-Allocation (R-7)getAllIndexes() now pre-allocates result array with new Array(rows.length)

    • Avoids incremental push() resizing; improved documentation of PRAGMA batching constraints
  • CI node_modules Caching (CI-1) — Added actions/cache@v4 for node_modules in lint-and-test.yml

    • Keyed on package-lock.json hash per Node.js version; skips npm ci on cache hit (~20-30s savings per run)
  • CI Benchmark Tracking (CI-2) — New benchmarks job in lint-and-test.yml (main branch only)

    • Runs npm run bench and uploads results as artifacts with 30-day retention for regression detection
  • NativeSqliteAdapter SchemaManager Integration — Schema metadata operations now use TTL-based caching

    • listTables(), describeTable(), getSchema(), getAllIndexes() delegate through SchemaManager (5s TTL)
    • Eliminates redundant PRAGMA table_info() queries on every metadata request
    • Auto-invalidates schema cache on DDL operations (CREATE, ALTER, DROP)
    • Matches the caching pattern already used by the WASM SqliteAdapter
  • Cached Tool DefinitionsNativeSqliteAdapter.getToolDefinitions() now lazily caches results

    • Tool definitions are immutable per adapter instance; avoids 13-way array spread on repeat calls
  • Logger Taint-Breaking OptimizationwriteToStderr() uses "".concat() instead of per-character copy

    • Previous O(n) character-by-character array+join replaced with single string concatenation
    • Still breaks CodeQL taint tracking without the allocation overhead
  • Logger Sensitive Key Matching — Pre-computed SENSITIVE_KEYS_ARRAY at module scope

    • Avoids spreading Set into a new array on every context key during sanitizeContext()
  • Logger Regex Pre-CompilationsanitizeMessage() and sanitizeStack() regex patterns hoisted to module scope

    • Avoids re-constructing RegExp objects (via String.fromCharCode()) on every log call
  • SQL Validation Regex Pre-CompilationDANGEROUS_SQL_PATTERNS hoisted to module scope in DatabaseAdapter.ts

    • Avoids re-allocating 5 RegExp objects per validateQuery() call
  • CORS Preflight Caching — Added Access-Control-Max-Age: 86400 to OPTIONS responses

    • Browsers cache preflight results for 24 hours, reducing repeated OPTIONS roundtrips
  • Docker HTTP Healthcheck — Healthcheck now validates /health endpoint for HTTP transport

    • Falls back to basic Node.js check for stdio mode
  • Bumped @eslint/js from 9.39.2 to 10.0.1 (major)

  • Bumped @modelcontextprotocol/sdk from 1.25.3 to 1.27.1

  • Bumped @types/node from 25.2.0 to 25.5.0

  • Bumped @vitest/coverage-v8 from 4.0.18 to 4.1.0

  • Bumped better-sqlite3 from 12.6.2 to 12.8.0

  • Bumped eslint from 9.39.2 to 10.0.3 (major)

  • Bumped globals from 17.3.0 to 17.4.0

  • Bumped jose from 6.1.3 to 6.2.1

  • Bumped rimraf from 6.1.2 to 6.1.3

  • Bumped sql.js from 1.13.0 to 1.14.1

  • Bumped typescript-eslint from 8.54.0 to 8.57.1

  • Bumped vitest from 4.0.18 to 4.1.0

  • Removed unused dotenv production dependency (never imported in source)

  • Removed unused pg and @types/pg dependencies (never imported in source)

  • Dockerfile tar dependency pinned to 7.5.11 for security compliance

  • Bumped @types/sql.js from 1.4.9 to 1.4.10

  • Bumped jose from 6.2.1 to 6.2.2


Fixed

  • Missing Annotations: Added readOnly(...) MCP annotations to all 6 window function tools (sqlite_window_row_number, sqlite_window_rank, sqlite_window_lag_lead, sqlite_window_running_total, sqlite_window_moving_avg, sqlite_window_ntile) — these were the only stats-group tools without annotations, causing the code mode readonly guard (fail-closed isWriteTool()) to incorrectly block them in readonly: true mode despite being pure SELECT queries.
  • Missing Annotations: Added write(...) MCP annotations to all 7 transaction tools (sqlite_transaction_begin, sqlite_transaction_commit, sqlite_transaction_rollback, sqlite_transaction_savepoint, sqlite_transaction_release, sqlite_transaction_rollback_to, sqlite_transaction_execute) — discovered by the new tool-annotations.test.ts invariant test. While the fail-closed isWriteTool() guard correctly blocked these in readonly mode (they are write tools), the missing annotations violated the structural invariant and prevented proper tool discoverability.
  • Output Schema Strictness: Made domain-specific fields optional in 24 output schemas across core.ts (5), admin.ts (9), virtual.ts (9), and native.ts (1) — fields like rowCount, rows, tables, count, columns, indexes, integrity, databases, options, message, durationMs, insightCount, statementsExecuted were required but absent from error responses ({success: false, error: "..."}), causing raw MCP -32602 output validation errors on error paths. Discovered by the new tool-output-schemas.test.ts invariant test.
  • Output Schema Enforcement: Wired existing TransactionBeginOutputSchema, TransactionCommitOutputSchema, TransactionRollbackOutputSchema, TransactionSavepointOutputSchema, TransactionReleaseOutputSchema, TransactionRollbackToOutputSchema, and TransactionExecuteOutputSchema to their corresponding 7 transaction tool definitions — schemas were defined in native.ts but never referenced, so the MCP SDK could not enforce output validation on these tools.
  • Input Coercion: Added z.preprocess() coercion for numeric parameters (limit, gridSize, srid, distance, simplifyTolerance, centerLat, centerLon, radius, minLat, maxLat, minLon, maxLon, lat1lon2) and enum parameters (unit, geometryType, analysisType, action, format, operation) in geo and SpatiaLite schemas — 22 params total. Non-numeric strings fall back to defaults, invalid enum values fall back to defaults instead of producing raw MCP -32602 validation frames.
  • Input Coercion: Added z.preprocess(coerceBoolean, ...) coercion for boolean parameters (forceReload, excludeSelf, includeGeometry) in SpatiaLite schemas — non-boolean strings now coerce to defaults instead of producing raw MCP -32602 validation frames.
  • Validation Leaks: Fixed Zod output schema errors in JSON tools (sqlite_json_valid, sqlite_json_validate_path) and core tools (sqlite_drop_table, sqlite_create_index, sqlite_drop_index) that caused the server to return raw MCP -32602 validation frames instead of structured domain errors, by marking conditional message fields as optional.
  • Input Coercion: Handled invalid numeric input types gracefully in JSON operations (sqlite_json_each, sqlite_json_query, sqlite_json_analyze_schema, sqlite_json_storage_info) and migration tools (sqlite_migration_rollback, sqlite_migration_history) by replacing z.coerce.number() with z.preprocess() for limit, sampleSize, id, and offset parameters — non-numeric values now silently fall back to defaults instead of producing raw MCP -32602 validation frames.
  • Validation Leaks: Fixed Zod output schema errors in text tools (sqlite_regex_match, sqlite_regex_extract, sqlite_text_split, sqlite_text_replace, sqlite_text_normalize, sqlite_text_validate) and FTS tools (sqlite_fts_create, sqlite_fts_search, sqlite_fts_rebuild, sqlite_fts_match_info) that caused raw MCP -32602 output validation errors on error paths, by marking non-error fields as optional so {success: false, error: "..."} responses pass output validation.
  • Input Coercion: Added z.preprocess() coercion for all numeric parameters in text tool schemas (limit, maxDistance, groupIndex, start, length, fuzzyThreshold, maxInvalid) and FTS search limit — non-numeric string values now silently fall back to defaults instead of producing raw MCP -32602 input validation frames.
  • Input Coercion: Added z.preprocess() coercion for all numeric parameters in stats schemas (limit, buckets, n, threshold, maxOutliers, degree, expectedMean) and window function schemas (limit, offset, windowSize, buckets) — 19 params total. Moved maxOutliers min/max refinements (.min(1).max(500)) to handler validation to avoid Zod refinement leaks.
  • Input Coercion: Added z.preprocess() coercion for numeric parameters (limit, sampleSize, dimensions) and enum parameters (metric) in vector tool schemas — non-numeric strings fall back to defaults, invalid metric values fall back to "cosine" default instead of producing raw MCP -32602 validation frames.
  • Input Coercion: Added z.preprocess() coercion for required array parameters in vector tool schemas (vector, queryVector, vector1, vector2, items, ids) — non-array inputs are coerced to empty arrays to pass SDK .partial() validation, then handler-level guards reject them with structured errors instead of raw MCP -32602 validation frames.
  • Dimension Validation: Fixed sqlite_vector_batch_store only validating the first item's vector dimensions against the table schema — now validates all items individually with per-item error reporting (e.g., "Dimension mismatch at item[1]").
  • Input Coercion: Added z.preprocess() coercion for numeric parameters in admin schemas (maxErrors, mask) and virtual table schemas (limit, start, stop, step, sampleRows, dimensions) — 12 params total. Moved dimensions min/max refinements (.min(2).max(5)) to handler validation to prevent Zod refinement leaks.
  • Input Coercion: Added z.preprocess() coercion for timeout parameter in sqlite_execute_code and moved .int().min(1000).max(30000) refinements to handler validation.
  • Refinement Leaks: Removed .regex() from SavepointSchema.name in transaction tools — handler already validates with inline regex check. Prevents raw MCP -32602 on invalid savepoint names.
  • Refinement Leaks: Added z.preprocess() enum coercion for BeginTransactionSchema.mode — invalid enum values now coerce to undefined and fall to the "deferred" default instead of producing raw MCP -32602 validation frames.
  • Error Handling: Added missing try/catch wrappers to admin handlers (integrityCheck, pragmaCompileOptions, pragmaDatabaseList, pragmaOptimize, dbstat, vacuum) — uncaught errors now return structured {success: false} responses via formatHandlerError.
  • JSON Serialization: Fixed an issue in sqlite_json_query where querying a column converted to JSONB would return the raw binary Buffer instead of the parsed JSON string by explicitly wrapping the column selection in json().
  • PRAGMA/EXPLAIN LIMIT: Fixed sqlite_read_query appending LIMIT 1000 to PRAGMA and EXPLAIN statements, causing syntax errors. Safety limit injection now only applies to SELECT and WITH queries.
  • Instruction Generation: Fixed enabledTools set in server constructor passing group names (e.g., "core", "json") instead of actual tool names, causing the Active Tools summary at full instruction level to never match any tools.
  • Restore Data Loss: Fixed sqlite_restore silently dropping user-created indexes, views, and triggers during backup→restore cycles. The handler only restored tables (type='table' from sqlite_master), permanently losing all other schema objects. Now restores indexes, views, and triggers from the backup source after table restoration.
  • Error Formatting: Standardized error handling across 11 admin/virtual tool handlers (create_view, drop_view, generate_series, create_rtree_table, create_series_table, virtual_table_info, drop_virtual_table, pragma_table_info, append_insight, dbstat, vacuum, analyze_csv_schema, create_csv_table, list_virtual_tables, list_views, transaction_execute) — replaced raw error.message (which produces unreadable Zod JSON arrays for validation errors) with formatHandlerError() for clean structured error responses.
  • Empty Path Validation: Added pre-validation guards to sqlite_backup, sqlite_restore, and sqlite_verify_backup — empty/blank path strings now return clear "targetPath/sourcePath/backupPath is required" errors instead of confusing CWD resolution errors.
  • Test Prompt Corrections: Fixed 15 parameter name mismatches in the admin group test checklist (test-group-tools.md): viewName/selectQuery for views, tableName for virtual tables, targetPath/sourcePath/backupPath for backup tools, filePath for CSV tools, insight for append_insight, pragma for pragmaSettings, plain string array for transaction_execute. Added required start/stop params for create_series_table, noted it creates a regular table (gotcha #15), and added absolute path warnings for backup and CSV tools.
  • Extension Path Resolution: Fixed EXTENSIONS_DIR in extensions.ts resolving to the wrong directory after tsup code splitting — the relative path ../../../extensions was correct for the source tree depth (3 levels) but wrong for compiled output in dist/ (1 level). Replaced with findProjectRoot() that walks up from the compiled file's directory to locate package.json, making CSV and future extension loading resilient to any bundler output structure. SpatiaLite was unaffected because it loaded via SPATIALITE_PATH env var.
  • Validation Leak: Fixed sqlite_pragma_settings({}) producing a raw MCP error by moving PragmaSettingsSchema.parse() inside the try/catch block — Zod validation errors now return structured {success: false} responses.
  • Error Field Consistency: Changed error field from message to error in {success: false} responses for sqlite_verify_backup, sqlite_create_rtree_table, sqlite_create_series_table, and sqlite_transaction_execute — all error responses now consistently use the error field per structured error convention.
  • Payload Optimization: Changed sqlite_dbstat default for excludeSystemTables from false to true — SpatiaLite system tables (37 objects including spatial_ref_sys at 1434 pages) are now excluded by default, dramatically reducing response size.
  • Misleading Note: Fixed sqlite_pragma_database_list showing a "WASM virtual filesystem paths" note in Native mode on Windows — the path comparison now normalizes slashes before comparing, so the note only appears when internal paths genuinely differ (i.e., in WASM mode).
  • Error Field Consistency: Fixed sqlite_append_insight empty-insight error response using message instead of error field for {success: false} responses — now consistent with the structured error convention used by all other tools.
  • Test Prompt: Fixed test-tools.md item 9 annotation verification instruction from uncallable tools/list protocol method to the existing test-tool-annotations.mjs terminal script. Fixed duplicate item numbering (two item 9s) and broke items out of the CAUTION blockquote where they were incorrectly nested.
  • Validation Leak: Fixed sqlite_execute_code({}) producing a raw MCP error by moving ExecuteCodeSchema.parse() inside the try/catch block — Zod validation errors now return structured {success: false} responses. Also made metrics optional in ExecuteCodeOutputSchema so error responses without metrics pass output schema validation.
  • Input Coercion: Added z.preprocess() coercion for enum parameters in introspection tool schemas — operation (sqlite_cascade_simulator), direction (sqlite_topological_sort), sections array (sqlite_schema_snapshot), and checks array (sqlite_constraint_analysis). Invalid enum values now coerce to defaults or are filtered out instead of producing raw MCP -32602 validation frames.
  • Payload Optimization: Added excludeSystemTables parameter (default: true) to sqlite_schema_snapshot, sqlite_storage_analysis, sqlite_index_audit, and sqlite_constraint_analysis. SpatiaLite system tables, views, indexes, and triggers are now excluded by default, reducing response sizes by 47–91% in databases with SpatiaLite loaded. Pass excludeSystemTables: false to restore the previous behavior.
  • Error Message Leak: Fixed sqlite_spatialite_query exposing internal better-sqlite3 implementation detail ("This statement does not return data. Use run() instead") when called with non-SELECT statements — now returns a clear "This tool only supports SELECT queries" message with QUERY_NOT_SELECT error code.
  • Silent Enum Coercion: Fixed sqlite_spatialite_index silently coercing invalid action values (e.g., "invalid_action") to the default "create" instead of returning a validation error. Replaced z.preprocess(coerceIndexAction, z.enum(...)) with z.string() + handler-level validation, consistent with the pattern used by analysisType, operation, and format in other SpatiaLite tools.
  • Output Schema Leak: Fixed sqlite_cascade_simulator with compact: true producing a raw MCP -32602 output validation error — the path field in the output schema was required but compact mode strips it from affected entries. Made path optional in CascadeSimulatorOutputSchema.
  • Payload Optimization: Added excludeSystemTables parameter (default: true) to sqlite_dependency_graph and sqlite_topological_sort. SpatiaLite system tables are now excluded by default, reducing dependency_graph from 8KB→1.5KB and topological_sort from 3.5KB→0.7KB in databases with SpatiaLite loaded. Pass excludeSystemTables: false to restore the previous behavior.
  • Output Schema Leak: Fixed sqlite_geo_distance returning from and to coordinate objects not declared in GeoDistanceOutputSchema — the additionalProperties: false constraint caused the MCP framework to reject all successful responses with -32602. Removed redundant coordinate echo fields.
  • Field Naming: Fixed sqlite_geo_nearby using _distance field name on result items instead of distance declared in GeoWithinRadiusOutputSchema — clients relying on the schema-declared field would find it absent.
  • Strict Schema Leak: Removed .strict() from all tool input schemas across all groups — core (10), json (14), stats/window (6), admin/transactions (7+1), geo/SpatiaLite (7), migration (2). additionalProperties: false caused the MCP SDK to reject unrecognized keys with raw -32602 errors before handlers could catch them.
  • Error Consistency: Standardized ~20 error return paths across SpatiaLite tool handlers (tools.ts, analysis.ts) to include code, category, and recoverable fields — previously returned bare {success: false, error: "..."} without the structured metadata used by all other tool groups. Fixed sqlite_spatialite_load failure response using message field instead of error field.
  • Output Schema Leak: Fixed sqlite_json_valid and sqlite_json_validate_path returning raw MCP -32602 output validation errors on every call — output schemas were missing success, message, path, and issues fields that the handlers return.
  • Output Schema Leak: Fixed sqlite_optimize, sqlite_vacuum, and sqlite_analyze_csv_schema returning raw MCP -32602 output validation errors — output schemas were missing durationMs, message, and wasmLimitation fields that the handlers return.
  • Phantom Tool Names: Fixed 11 non-existent tool names in help resource source files (stats.md, text.md, geo.md) that would mislead agents into calling tools that don't exist. Removed sqlite_stats_covariance, sqlite_stats_z_score, sqlite_stats_moving_average, sqlite_text_pad, sqlite_text_template, sqlite_text_similarity, sqlite_text_word_count, sqlite_fts_count, sqlite_spatialite_status. Renamed sqlite_window_lead_lagsqlite_window_lag_lead. Added missing real tools to help content.
  • Code Mode Groups: Fixed gotchas.md listing only 7 Code Mode API groups — added missing sqlite.introspection and sqlite.migration which are real groups exposed by the sandbox API.
  • Validation Leak: Fixed sqlite_json_normalize_column producing a raw MCP -32602 error when outputFormat receives an invalid enum value (e.g., "invalid_format"). Replaced z.enum() in the schema with z.string() and handler-side validation, consistent with the established pattern for enum coercion.
  • Output Schema Alignment: Added missing warning field to JsonSetOutputSchema and JsonRemoveOutputSchema — handlers return a warning property when 0 rows are affected, but the output schema did not declare it. Added missing firstErrorDetail field to JsonNormalizeColumnOutputSchema. Changed outputFormat in JsonNormalizeColumnOutputSchema from z.enum() to z.string() to match the input schema change.
  • Missing Value Guards: Added explicit undefined guards for payload parameters (value in sqlite_json_set, sqlite_json_array_append, sqlite_json_update; mergeData in sqlite_json_merge; data in sqlite_json_insert) — the SDK's .partial() makes all params optional, so omitting these previously caused a cryptic "Cannot read properties of undefined" error instead of a clear "Missing required parameter: <name>" structured response.
  • Input Coercion: Fixed sqlite_text_substring start parameter producing a raw MCP -32602 error when receiving wrong-type input (e.g., "abc"). Changed inner schema from required z.number() to z.number().optional() and added handler-side validation so the preprocess coercion-to-undefined path returns a structured error.
  • Output Schema Leak: Fixed sqlite_text_validate returning undeclared truncated field when invalid results exceed maxInvalid — added truncated: z.boolean().optional() to the inline output schema.
  • Silent Enum Coercion: Fixed sqlite_vector_search and sqlite_vector_distance silently coercing invalid metric values (e.g., "invalid_metric") to the default "cosine" instead of returning a validation error. Replaced z.preprocess(coerceMetric, z.enum(...)) with z.string() + handler-level validation, consistent with the pattern used for SpatiaLite action and JSON outputFormat.
  • E2E Test Flakiness: Fixed intermittent 429 rate-limit and timeout failures in the Playwright test suite by bumping MCP_RATE_LIMIT_MAX from 1000 to 10000 (5× headroom), increasing global test timeout to 60s, and adding retry-with-backoff logic to the createClient() helper.
  • Raw MCP Error: Fixed sqlite_analyze_csv_schema propagating a raw MCP error when the CSV file does not exist at an absolute path — the try block had no catch, only a finally. Added a catch block returning structured {success: false, error: "..."}. Also changed messageerror in relative-path and WASM-unavailable error returns for field consistency.
  • Output Schema Wiring: Wired outputSchema for 6 window function tools (sqlite_window_row_number, sqlite_window_rank, sqlite_window_lag_lead, sqlite_window_running_total, sqlite_window_moving_avg, sqlite_window_ntile) — schemas were defined in native.ts but never referenced. Updated 6 named schemas to match handler return shapes (added rankType, direction, valueColumn, windowSize, buckets; made rowCount/rows optional).
  • Output Schema Wiring: Created 7 new SpatiaLite output schemas (SpatialiteLoadOutputSchema, SpatialiteCreateTableOutputSchema, SpatialiteQueryOutputSchema, SpatialiteIndexOutputSchema, SpatialiteAnalyzeOutputSchema, SpatialiteTransformOutputSchema, SpatialiteImportOutputSchema) and wired them into all 7 SpatiaLite tool definitions — these were the only tool group without output schema enforcement.
  • Inline Schema Consolidation: Replaced 5 inline z.object() output schemas with named imports from output-schemas/sqlite_fuzzy_match, sqlite_phonetic_match, sqlite_text_normalize, sqlite_stats_regression, sqlite_stats_outliers. Updated the corresponding named schemas (FuzzySearchOutputSchema, SoundexOutputSchema, TextNormalizeOutputSchema, StatsRegressionOutputSchema, StatsOutliersOutputSchema) to match actual handler return shapes.
  • Dead Schema Removal: Deleted 25 orphaned output schemas that had no corresponding tools: 9 vector (VectorCreate, VectorInsert, VectorUpsert, CosineSimilarity, EuclideanDistance, DotProduct, VectorMagnitude, HybridSearch + result), 3 stats (StatsDescribe, StatsMode, StatsMedian), 3 virtual (GenerateDates, CteRecursive, PivotTable), 3 geo (GeoNearest + result, GeoPolygonContains, GeoEncode), 2 text (Levenshtein, TrigramSimilarity), 2 JSON (JsonTree, JsonPatch), 1 FTS (FtsOptimize), 3 server (ServerInfo, ServerHealth, ListAdapters — built-in tools use content pattern, not structuredContent).
  • API Consistency: Renamed valueColumncolumn in RunningTotalSchema and MovingAverageSchema input schemas (and all handler references) for consistency with the other 4 window function tools which all use column. Updated unit tests accordingly.
  • Input Coercion: Added case-insensitive coercion to TextNormalizeSchema.mode — uppercase values like "NFC" now coerce to "nfc" instead of failing Zod enum validation.
  • Payload Optimization: Changed sqlite_list_tables and sqlite_get_indexes defaults for excludeSystemTables / excludeSystemIndexes from false to true — SpatiaLite system tables (27 entries) and system indexes (4 entries) are now excluded by default, reducing list_tables from 38→11 entries and get_indexes from 8→4 entries. Pass excludeSystemTables: false / excludeSystemIndexes: false to restore the previous behavior.
  • Validation Leak: Added missing try/catch around ListTablesSchema.parse() in sqlite_list_tables handler — the only core tool handler without the defensive wrapper. Zod parse errors now return structured {success: false} responses instead of propagating as uncaught exceptions.
  • Payload Optimization: Filtered internal _mcp_migrations table from sqlite_list_tables default results — the db-mcp migration tracking table is now excluded alongside SpatiaLite system tables when excludeSystemTables: true (default). Tables prefixed with _mcp_ are internal and not relevant to user workflows.
  • API Consistency: Renamed tableNametable in core tool input schemas (sqlite_create_table, sqlite_describe_table, sqlite_drop_table, sqlite_get_indexes, sqlite_create_index) to match the field naming convention used by all other tool groups (json, text, stats, vector, admin).
  • Backward Compatibility: Added resolveAliases() parameter alias support to all 8 core tool handlers and 2 window function handlers — legacy parameter names (tableName, sql, name, valueColumn) are transparently mapped to canonical names (table, query, indexName, column) before Zod parsing. Canonical names take precedence when both are supplied. Applied via handler-level preprocess (not schema-level z.preprocess() which would break the SDK's .partial() call). Also changed registerToolImpl to use .partial().passthrough() so unknown alias keys survive Zod's default strip mode.
  • Stale References: Fixed sqlite://help/stats referencing valueColumn instead of column in running_total and moving_avg examples (both stats.md source and compiled server-instructions.ts). Fixed codemode POSITIONAL_PARAM_MAP and GROUP_EXAMPLES still using tableName for core tools after the rename to table.
  • Raw MCP Error: Fixed sqlite_create_table propagating a raw MCP error when ifNotExists: false and the table already exists — adapter.executeQuery() was outside any try/catch, so the SQLite error escaped as an uncaught exception instead of returning a structured {success: false} response.
  • Error Quality: Added sqlite_master table existence validation and pragma_table_info column existence validation to all 6 window function tools (sqlite_window_row_number, sqlite_window_rank, sqlite_window_lag_lead, sqlite_window_running_total, sqlite_window_moving_avg, sqlite_window_ntile) — previously relied on SQL execution errors which leaked raw SQL in the error details field. Now returns clean TABLE_NOT_FOUND / COLUMN_NOT_FOUND structured errors consistent with all other tool groups.
  • Chi-Square Validation: Fixed sqlite_stats_hypothesis with testType: "chi_square" incorrectly rejecting non-numeric columns — the validateNumericColumn() check ran unconditionally for all test types before branching, but chi-square tests operate on categorical data. Numeric validation now only runs for ttest_one and ttest_two.
  • OrderBy Validation: Added validateOrderByColumns() pre-validation to all 6 window function tools — parses column names from ORDER BY expressions (handling price DESC, multi-column a, b DESC, and expression skipping), then validates each against the table schema. Previously, nonexistent orderBy columns produced raw SQL errors with internal query leakage in details.sql.
  • Test Prompt: Fixed test-group-tools.md checklist item 19 missing required direction: "lag" parameter for sqlite_window_lag_lead.
  • Output Schema Alignment: Added missing message field to VectorBatchStoreOutputSchema — handler returns message: "No items provided" on empty-items path but the output schema did not declare it.
  • Dimension Validation: Fixed sqlite_vector_store and sqlite_vector_batch_store silently accepting mismatched vector dimensions when the table lacks a dimensions column (e.g., tables not created via sqlite_vector_create_table). Added a third fallback to validateDimensions() that samples an existing vector from the actual vector column to infer expected dimensions.
  • Inline Schema Consolidation: Relocated AppendInsightOutputSchema from handler helpers (tools/admin/helpers.ts) to the centralized output-schemas/admin.ts — consistent with the project convention that all output schemas live in the output-schemas/ directory with named exports.
  • Output Schema Wiring: Created DbstatOutputSchema (polymorphic — supports summarized, raw, and fallback return shapes) and wired it to the sqlite_dbstat tool definition — the only admin tool without output schema enforcement.
  • Output Schema Alignment: Fixed sqlite_list_views error path returning bare formatHandlerError(error) without required output schema fields (count, views) — now merges {count: 0, views: []} to pass ListViewsOutputSchema validation on error paths.
  • Output Schema Alignment: Added missing skipped and warning fields to VectorSearchOutputSchema — handler returns these fields when unparseable vectors are encountered during search, but the output schema did not declare them, causing raw MCP -32602 errors on direct tool calls that trigger the skip path.
  • Missing Annotations: Added MCP annotations to all 7 SpatiaLite tools (spatialite_load, spatialite_create_table, spatialite_query, spatialite_index, spatialite_analyze, spatialite_transform, spatialite_import) — these were the only tools without annotations, causing the code mode readonly guard to classify write tools as read-safe.
  • Readonly Guard: Fixed code mode isWriteTool() using fail-open logic (readOnlyHint !== false) that treated unannotated tools as read-safe. Inverted to fail-closed (readOnlyHint === true) — tools are now assumed to be write tools unless explicitly marked as read-only. Removed redundant READ_SAFE_PATTERNS heuristic. Added defense-in-depth warning logging for any unannotated tool blocked in readonly mode.
  • Validation Leak: Fixed sqlite_text_case, sqlite_text_normalize, and sqlite_text_validate producing raw MCP -32602 errors when required enum params (mode, pattern) receive empty or invalid values. Replaced z.enum() in schemas with z.string() and handler-side validation against exported const arrays (VALID_TEXT_CASE_MODES, VALID_NORMALIZE_MODES, VALID_VALIDATE_PATTERNS). Fixed sqlite_phonetic_match algorithm param leaking on explicit empty string by adding a preprocess coercer.
  • Output Schema Wiring: Created 4 new text output schemas (TextConcatOutputSchema, TextTrimOutputSchema, TextCaseOutputSchema, TextSubstringOutputSchema) and wired them to their tool definitions. Relocated inline AdvancedSearchOutputSchema from search.ts to centralized output-schemas/text.ts.
  • Validation Leak: Fixed sqlite_stats_group_by and sqlite_stats_hypothesis producing raw MCP -32602 errors when required enum params (stat, testType) receive empty or invalid values. Replaced z.enum() in schemas with z.string() and handler-side validation against exported const arrays (VALID_STAT_TYPES, VALID_TEST_TYPES).
  • Enum Coercion: Added z.preprocess(coerceEnum, ...) to 6 optional z.enum() params that leaked raw MCP -32602 on explicit empty strings: orderBy and stat in GroupByStatsSchema, orderDirection in TopNSchema, method in OutlierSchema, mode in TextTrimSchema, tokenizer in FtsCreateSchema, format in FtsMatchInfoSchema. Empty strings now coerce to undefined so .default() kicks in.
  • Validation Leak: Fixed sqlite_text_trim and sqlite_phonetic_match producing raw MCP -32602 errors when optional enum params (mode, algorithm) receive invalid non-empty values. Replaced z.enum() in schemas with z.string() and handler-side validation against exported const arrays (VALID_TRIM_MODES, VALID_PHONETIC_ALGORITHMS), consistent with the pattern used by text_case, text_normalize, and text_validate.
  • Enum Coercion: Replaced coerceEnum (empty-string-only) with coerceEnumValues factory for 5 optional z.enum() params with defaults — orderBy in GroupByStatsSchema, orderDirection in TopNSchema, method in OutlierSchema, tokenizer in FtsCreateSchema, format in FtsMatchInfoSchema. Invalid non-empty strings (e.g., "invalid", "abc") now coerce to undefined so .default() kicks in, instead of leaking raw MCP -32602 from the inner z.enum() rejection.
  • Validation Leak: Fixed sqlite_advanced_search techniques array parameter producing a raw MCP -32602 error when array elements contain invalid enum values (e.g., ["invalid_technique"]). Replaced z.enum(["exact", "fuzzy", "phonetic"]) inside the array with z.string() and handler-side validation against exported VALID_SEARCH_TECHNIQUES constant, consistent with the pattern used by all other enum params in text tools.
  • Payload Optimization: sqlite_stats_top_n now auto-excludes long-content TEXT/BLOB columns (matching names like description, body, notes, content, summary, etc.) when selectColumns is not specified. Short identifier columns (name, category, email, etc.) are preserved. A hint field in the response lists excluded columns. Use selectColumns to override and include specific text columns.
  • Misleading Stats: Fixed sqlite_stats_summary returning misleading avg: 0 with null min/max when the user explicitly requests text columns via the columns parameter. Now returns {column, error: "Not numeric"} per-column (using the existing error field in the summary schema) instead of running SQL aggregates that produce meaningless results on text data.
  • Code Mode Alias: Changed sqlite.stats.describe() alias mapping from statsBasicstatsSummary — calling describe({table: 'foo'}) now returns a table-level summary of all numeric columns, matching the intuitive expectation of "describe a table" rather than requiring a column parameter.
  • Error Field Consistency: Fixed sqlite_create_csv_table using message instead of error for failure text in two early-return paths (relative path rejection and WASM/CSV unavailability) — now consistent with the structured error convention used by all other tools.
  • Raw MCP Error: Fixed sqlite_vacuum with into parameter propagating a raw MCP error instead of a structured response. Added early WASM guard for VACUUM INTO (file system access not supported in WASM mode) and wrapped executeQuery() in try/catch so SQL failures (e.g., invalid target paths) return structured {success: false} responses. Added wasmLimitation field to VacuumOutputSchema.
  • Input Coercion: Fixed required numeric parameters in geo tools (lat1, lon1, lat2, lon2, centerLat, centerLon, radius, minLat, maxLat, minLon, maxLon) producing raw MCP -32602 errors when receiving wrong-type string inputs (e.g., "abc"). Changed schema inner types from required z.number() to z.number().optional() so coerceNumber's undefined fallback passes the SDK boundary, then added requireCoordinate() and requireNumber() handler-level validators that return structured {success: false} errors with GEO_INVALID_COORDINATES code.
  • Misleading Suggestion: Fixed sqlite_query_plan classifying SCAN CONSTANT ROW as a full table scan on synthetic table "CONSTANT" and suggesting adding an index — constant-row, subquery, list, and materialized EXPLAIN plan entries are now excluded from fullScans/indexScans/coveringIndexes lists and optimization suggestions.
  • Validation Leak: Fixed sqlite_window_rank and sqlite_window_lag_lead producing raw MCP -32602 errors when enum params (rankType, direction) receive invalid values. rankType (optional with default) now uses coerceEnumValues coercer so invalid values fall to the "rank" default. direction (required, no default) changed from z.enum() to z.string() with handler-side validation against VALID_DIRECTIONS constant, returning a structured error.
  • Error Quality: Added table existence pre-validation to sqlite_fts_search, sqlite_fts_rebuild, and sqlite_fts_match_info — previously, querying a nonexistent FTS table produced a generic DB_QUERY_FAILED error with leaked SQL. Now returns a clean TABLE_NOT_FOUND structured error consistent with all other text group tools. Extracted reusable validateTableExists() from column-validation.ts.
  • Case Sensitivity: Fixed sqlite_window_lag_lead rejecting uppercase "LAG"/"LEAD" direction values despite the schema description suggesting them. The handler now normalizes direction to lowercase before validation, so "LAG", "lag", and "Lag" are all accepted.
  • Error Code Refinement: Fixed DbMcpError subclasses (e.g., QueryError) always using their generic constructor code (e.g., DB_QUERY_FAILED) even when the error message matches a more specific suggestion pattern (e.g., TABLE_NOT_FOUND, COLUMN_NOT_FOUND). The constructor now auto-refines generic codes (DB_QUERY_FAILED, DB_WRITE_FAILED, QUERY_ERROR, RESOURCE_ERROR, UNKNOWN_ERROR) to the suggestion's specific code when available. This fixes all vector, stats, and other tools that delegate to executeReadQuery/executeWriteQuery — they now return TABLE_NOT_FOUND instead of DB_QUERY_FAILED for missing tables.
  • Error Code Consistency: Added missing code: "DIMENSION_MISMATCH" to sqlite_vector_distance dimension mismatch error — sqlite_vector_store and sqlite_vector_batch_store already return this code, but vector_distance returned a bare {success: false, error: "..."} without it.
  • Error Code Consistency: Added missing code: "VECTOR_NOT_FOUND" to sqlite_vector_get not-found error — both {success: false} return paths now include a specific error code for programmatic handling.
  • Error Code Refinement: Added VIEW_NOT_FOUND and FILE_NOT_FOUND error suggestion patterns — sqlite_drop_view on a nonexistent view and sqlite_create_csv_table on a nonexistent file now return specific codes instead of generic DB_WRITE_FAILED. Both patterns also provide actionable suggestions.
  • Error Field Consistency: Added missing code: "VALIDATION_ERROR" and category: "validation" to sqlite_create_csv_table and sqlite_analyze_csv_schema relative path rejection responses — previously returned bare {success: false, error: "..."} without structured error metadata.
  • Error Code Consistency: Added missing error codes to 5 admin tool error responses: sqlite_pragma_table_info (TABLE_NOT_FOUND), sqlite_pragma_settings (VALIDATION_ERROR for invalid/unknown pragma names), sqlite_verify_backup (FILE_NOT_FOUND for missing files, VALIDATION_ERROR for empty paths, ATTACH_FAILED for attach errors), sqlite_virtual_table_info (TABLE_NOT_FOUND). Added error field and VALIDATION_ERROR code to sqlite_drop_virtual_table when attempting to drop a regular table (previously used message field only).
  • Error Code Consistency: Fixed sqlite_transaction_execute failure response missing structured error metadata (code, category, suggestion, recoverable) — now uses formatHandlerError() and spreads the formatted error, so failures return specific codes like TABLE_NOT_FOUND instead of bare {success: false, error: "..."}.
  • Error Suggestion: Added TRANSACTION_CONFLICT error suggestion pattern for "cannot start a transaction within a transaction" errors — advises committing/rolling back the active transaction or using sqlite_transaction_execute for atomic multi-statement operations.
  • Graph Semantics: Fixed sqlite_dependency_graph rootTables and leafTables overlapping for tables with no FK relationships. Root now means "referenced by others but doesn't reference anything" and leaf means "references others but isn't referenced by anything." Isolated tables (no FK relationships at all) are excluded from both, making the sets properly disjoint.
  • Error Code Consistency: Added missing code: "TABLE_NOT_FOUND" and structured error metadata to sqlite_constraint_analysis and sqlite_cascade_simulator nonexistent table responses — previously returned bare {success: false, error: "..."} without error codes.
  • Error Code Consistency: Added missing code: "VALIDATION_ERROR" and structured error metadata to sqlite_query_plan non-SELECT rejection response — previously returned bare {success: false, error: "..."} without error codes.
  • FK Awareness: Enhanced sqlite_migration_risks DROP TABLE analysis to check for FK dependents — when a table that other tables reference via foreign keys is dropped, the risk description now lists the dependent tables and the mitigation suggests handling them first.
  • Limit After Filter: Fixed sqlite_storage_analysis limit parameter being applied at the SQL level before SpatiaLite system table filtering — limit: 3 with excludeSystemTables: true could return fewer tables than requested because system tables consumed slots in the SQL result set before being filtered out. Limit is now applied via .slice() after filtering in both the dbstat and fallback code paths.
  • Error Code Consistency: Added missing structured error codes to all migration tool error responses: sqlite_migration_apply (DUPLICATE_MIGRATION, MIGRATION_NOT_INITIALIZED, MIGRATION_EXECUTION_FAILED), sqlite_migration_record (DUPLICATE_MIGRATION, MIGRATION_NOT_INITIALIZED), sqlite_migration_rollback (VALIDATION_ERROR, MIGRATION_NOT_FOUND, ROLLBACK_SQL_MISSING, MIGRATION_NOT_INITIALIZED), sqlite_migration_history (MIGRATION_NOT_INITIALIZED) — previously returned bare {success: false, error: "..."} without error codes for programmatic handling.
  • Migration Status Semantics: sqlite_migration_record now inserts with status: 'recorded' instead of 'applied' — distinguishes externally-recorded migrations from those actually executed by sqlite_migration_apply. Added recorded count to sqlite_migration_status output. Status output schema updated to include the new count field.
  • Rollback Safety: sqlite_migration_rollback now rejects re-rolling back an already rolled_back migration with ALREADY_ROLLED_BACK error code — previously would silently re-execute the rollback SQL, which could cause errors for non-idempotent rollback statements.
  • Duplicate Version Blocking: sqlite_migration_record and sqlite_migration_apply now reject duplicate version identifiers with DUPLICATE_VERSION error code — previously migrationRecord only warned and migrationApply had no version check at all. Duplicate versions caused ambiguity with migrationRollback which looks up by version and would silently target only the latest record.
  • Rollback SQL Validation: sqlite_migration_rollback now detects comment-only rollback SQL (e.g., "-- Cannot drop column") and returns ROLLBACK_SQL_INVALID error — previously attempted to execute the comments, producing a confusing DB_WRITE_FAILED error with "The supplied SQL string contains no statements". Strips single-line (--) and multi-line (/* */) comments before checking for executable content.
  • Migration Dedup Scope: Fixed sqlite_migration_apply SHA-256 dedup check blocking the record → apply workflow — the dedup previously matched against ALL migration statuses, so recording a migration with migrationRecord then applying the same SQL with migrationApply was rejected as a duplicate. Dedup now only blocks against applied migrations, allowing: (1) record then apply with the same SQL, (2) re-apply after rollback. Also fixed post-insert SELECT in both apply.ts and record.ts fetching by migration_hash (returns wrong row when multiple rows share a hash) — now fetches by version (unique).
  • History Filter Completeness: Added "recorded" to MigrationHistorySchema.status enum — previously only ["applied", "rolled_back", "failed"] were available, making it impossible to filter history by recorded status.
  • Rollback on Recorded-Only Migrations: sqlite_migration_rollback now handles recorded-only migrations (never applied) by marking them as rolled_back without executing rollback SQL — previously would blindly execute the rollback SQL even though the migration was never applied, which could cause errors or unintended side effects. Returns warning explaining the behavior.
  • Error Suggestion: Added MALFORMED_JSON error suggestion pattern for "malformed JSON" errors — commonly triggered when json_extract() receives a nonexistent column name (SQLite treats the unresolved identifier as a string literal and attempts to parse it as JSON). The suggestion now guides the agent to verify the column exists with sqlite_describe_table, instead of returning a generic DB_QUERY_FAILED with no guidance.
  • Error Field Consistency: Added missing code: "VALIDATION_ERROR" and category: "validation" to WASM limitation error responses in sqlite_verify_backup, sqlite_create_rtree_table, sqlite_create_csv_table, and sqlite_analyze_csv_schema — previously returned bare {success: false, error: "...", wasmLimitation: true} without structured error metadata, inconsistent with sqlite_backup and sqlite_restore which used formatHandlerError(new ValidationError(...)).
  • Code Quality Audit — Magic JSON-RPC Error Code — Replaced 4 remaining inline -32000 literals with JSONRPC_SERVER_ERROR constant in session.ts
  • Code Quality Audit — Removed unused deprecated SERVER_INSTRUCTIONS export from server-instructions.ts (zero consumers)
  • Code Quality AuditexecuteGeneral() in query-executor.ts now throws QueryError with logging (was bare Error)
  • Code Quality AuditvalidateQuery() in database-adapter.ts now throws ValidationError instead of bare Error
  • Code Quality AuditensureConnected() / ensureDb() in both adapters now throw ConnectionError instead of bare Error
  • Transport Feature Backport — Changed Referrer-Policy from strict-origin-when-cross-origin to no-referrer (API server has no referrer to share)
  • Version SSoT Mismatch — Synced hardcoded 0.1.0 to 1.0.2 (matching package.json) in index.ts, McpServer.ts, and cli.ts
  • Duplicate Error Class Hierarchy — Removed 6 duplicate error classes from types/index.ts (simple constructor) and consolidated into utils/errors.ts (enhanced: category, suggestions, recoverable, toResponse()); types/index.ts now re-exports from utils/errors.ts; auth/errors.ts updated to extend enhanced DbMcpError; added AUTHENTICATION/AUTHORIZATION to ErrorCategory enum
  • Bare z.object({}) Schemas — Added .strict() to 5 schemas (transaction_commit, transaction_rollback, MigrationInitSchema, MigrationStatusSchema, pragma_database_list) to reject extraneous properties
  • sqlite_migration_risks DROP INDEX Detection — Now returns medium risk for DROP INDEX statements
    • Previously no risk entry was generated for DROP INDEX (fell through all pattern checks)
    • Now detects DROP INDEX with riskLevel: "medium", category: "index_removal", and actionable mitigation advice
  • ERROR_SUGGESTIONS Insufficient Data Pattern — Regression tool's "Insufficient data" error now returns VALIDATION_ERROR instead of UNKNOWN_ERROR
    • sqlite_stats_regression throws Error("Insufficient data for degree N regression") when data points < degree+1
    • Message didn't match any ERROR_SUGGESTIONS pattern and fell through to ErrorCategory.INTERNALUNKNOWN_ERROR
    • Added /insufficient data/i pattern mapping to ErrorCategory.VALIDATION with actionable suggestion
  • sqlite_json_set / sqlite_json_remove No-Match Warning — Returns warning field when rowsAffected: 0
    • Previously returned {success: true, rowsAffected: 0} with no indication that nothing was changed
    • Now includes warning: "No rows matched the WHERE clause — no changes were made"
    • Mirrors the same pattern already applied to sqlite_json_update and sqlite_json_merge
  • ERROR_SUGGESTIONS Column Name Pattern Coverage — Added has no column named pattern for INSERT/UPDATE column errors
    • SQLite uses "has no column named X" for INSERT/UPDATE column errors, distinct from "no such column" used by SELECT
    • Previously classified as UNKNOWN_ERROR (no pattern match); now returns RESOURCE_ERROR with actionable suggestion
  • sqlite_text_validate Missing customPattern Error Code — Now returns VALIDATION_ERROR instead of UNKNOWN_ERROR
    • Handler threw generic Error for missing customPattern when pattern='custom'; formatError() classified it as UNKNOWN_ERROR
    • Changed to throw ValidationError with proper VALIDATION_ERROR code and validation category
  • sqlite_vector_store / sqlite_vector_batch_store DDL-Based Dimension Check — Dimension validation now reads table schema DDL as primary source
    • Previously read dimensions from existing rows only — bypassed on empty tables or tables with mismatched row data
    • Now parses DEFAULT N from CREATE TABLE SQL via sqlite_master for authoritative validation
    • Falls back to existing row data when DDL lacks a DEFAULT clause
    • INSERT now explicitly sets dimensions column to actual vector length
  • sqlite_vector_search Skipped Vector Reporting — Response now includes skipped count and warning when vectors fail similarity calculation
    • Previously, vectors with dimension mismatches or parse errors were silently dropped (try/catch returned null)
    • Now surfaces a warning: "N vector(s) skipped due to dimension mismatch or parse errors" field in the response
    • Helps callers diagnose why count may be less than expected
  • sqlite_json_update / sqlite_json_merge No-Match Warning — Returns warning field when rowsAffected: 0
    • Now includes warning: "No rows matched the WHERE clause — nothing was updated/merged"
    • Helps callers distinguish between a successful no-op and an actual problem
  • sqlite_stats_histogram Empty Table Phantom Bucket — Histogram on empty table no longer returns a phantom {min: 0, max: 0, count: 1} bucket
    • Root cause: MIN()/MAX() return NULL on empty tables, which defaulted to 0 via ?? 0, making bucketSize === 0 and returning a hardcoded count: 1
    • Now counts non-null rows via COUNT(column) and returns empty buckets: [] when no data exists
    • Uniform data (all values identical) now returns actual row count instead of hardcoded 1
  • sqlite_vector_store / sqlite_vector_batch_store Dimension Mismatch Validation — Storing vectors with wrong dimensions now returns a structured error
    • Previously accepted any vector length regardless of table's configured dimensions column (e.g., storing 2-dim vector in 4-dim table succeeded silently)
    • Now reads the table's dimensions column and returns {success: false, code: "DIMENSION_MISMATCH"} when vector length doesn't match
    • sqlite_vector_search already validated dimensions at comparison time (via helper functions), so this adds write-side enforcement
  • Introspection Tools WASM FTS5 Crash — 5 introspection tools no longer crash when the database contains FTS5 virtual tables in WASM mode
    • sqlite_dependency_graph, sqlite_topological_sort, sqlite_cascade_simulator, sqlite_schema_snapshot, sqlite_constraint_analysis all failed with "no such module: fts5" because internal queries (SELECT COUNT(*), PRAGMA table_info, PRAGMA foreign_key_list) hit FTS5 virtual tables that WASM SQLite can't resolve
    • Added try/catch around per-table queries in buildForeignKeyGraph() (graph.ts) and schemaSnapshot/constraintAnalysis handlers (analysis.ts)
    • FTS5 tables are still included in results (with rowCount 0 and columnCount 0) but no longer crash the entire operation
  • sqlite_json_normalize_column WASM Compatibility — Fixed all rows silently failing in WASM mode
    • Root cause: SELECT rowid, ... doesn't expose rowid as a named column in sql-js when the table has an INTEGER PRIMARY KEY
    • Handler received undefined for row["rowid"], causing all per-row UPDATE queries to fail in the inner try/catch
    • Fix: Changed to SELECT _rowid_ AS _rid_ which SQLite guarantees to work across all backends
    • Added firstErrorDetail field to response when errors occur, making per-row failures diagnosable without reading source code
  • Security Test Assertion Migration — Updated 11 tests from .rejects.toThrow() to structured error assertions
    • pragma-security.test.ts: 3 sqlite_pragma_table_info injection tests now assert {success: false, error: /invalid/i}
    • identifier-integration.test.ts: 6 FTS tool injection tests and 2 admin tool injection tests (pragma_table_info, index_stats) updated
    • These tests were stale after handlers were migrated to return structured {success: false} instead of throwing
  • sqlite_index_stats Structured Error Handling — Handler now wrapped in try/catch with formatError()
    • sanitizeIdentifier() and Schema.parse() were outside any try/catch, causing raw InvalidIdentifierError throws
    • Now returns {success: false, indexes: [], error: "Invalid identifier..."} consistent with all other admin tools
  • FTS Security Test Assertion Migration — Updated 7 FTS injection tests from .rejects.toThrow() to structured error assertions
    • fts-injection.test.ts: 4 sqlite_fts_create, 1 sqlite_fts_search, 1 sqlite_fts_rebuild, 1 sqlite_fts_match_info injection tests updated
  • Core Query Tool Validation Hardeningsqlite_read_query and sqlite_write_query handlers now catch Zod validation errors as structured {success: false} responses
    • Wrapped Schema.parse(params) inside try/catch blocks in both createReadQueryTool and createWriteQueryTool handlers
    • sqlite_read_query: Added empty query guard — empty string "" previously returned {success: true, rowCount: 0} instead of a validation error
    • Now returns {success: false, error: "Query cannot be empty. Provide a valid SELECT, PRAGMA, EXPLAIN, or WITH statement."}
  • Text/FTS Tool Zod Validation Error Handling — All 17 text and FTS tool handlers now catch Zod validation errors as structured {success: false} responses
    • 13 text tools (regex.ts, formatting.ts, search.ts): Moved Schema.parse(params) inside try/catch blocks with formatError()
    • 4 FTS tools (fts.ts): Moved Schema.parse(params) plus FTS5 availability checks and identifier validation inside try/catch blocks
    • Previously, calling these tools with invalid parameters returned raw MCP error frames instead of structured handler errors
  • Introspection Tool Zod Validation Error Handling — All 9 introspection tool handlers now catch Zod validation errors as structured {success: false} responses
    • sqlite_dependency_graph, sqlite_topological_sort, sqlite_cascade_simulator, sqlite_schema_snapshot, sqlite_constraint_analysis, sqlite_migration_risks, sqlite_storage_analysis, sqlite_index_audit, sqlite_query_plan: Moved Schema.parse(params) inside try/catch blocks with formatError()
    • Previously, calling tools with invalid parameters (wrong types, missing required fields, out-of-range values) returned raw MCP error frames instead of structured handler errors
  • sqlite_query_plan min(1) Refinement Leak — Removed .min(1) from QueryPlanSchema.sql and added handler-level validation
    • .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
    • Now validates empty sql inside the handler and returns structured {success: false, error: "Parameter 'sql' is required..."}
  • Geo Tool Zod Validation Error Handling — All 4 Haversine geo tool handlers now catch Zod validation errors as structured {success: false} responses
    • sqlite_geo_distance, sqlite_geo_nearby, sqlite_geo_bounding_box, sqlite_geo_cluster: Moved Schema.parse(params) inside try/catch blocks with formatError()
    • Previously, calling these tools with empty or invalid parameters returned raw MCP error frames instead of structured handler errors
  • Geo Tool Coordinate Range Validation — Moved .min(-90).max(90) / .min(-180).max(180) refinements from Zod schemas to handler-level validation
    • sqlite_geo_distance: lat1, lon1, lat2, lon2 range validation via validateCoordinates() helper
    • sqlite_geo_nearby: centerLat, centerLon range validation
    • sqlite_geo_bounding_box: minLat, maxLat, minLon, maxLon range validation
    • Previously, out-of-range coordinates (e.g., lat1: 91) triggered raw MCP -32602 errors at the SDK boundary before the handler ran
    • Now returns structured {success: false, error: "Invalid lat1: 91. Must be between -90 and 90."}
  • Admin Tool Zod Validation Error Handling — 11 admin tool handlers now catch Zod/sanitizeIdentifier errors as structured {success: false} responses
    • sqlite_pragma_table_info, sqlite_virtual_table_info, sqlite_create_csv_table, sqlite_create_rtree_table, sqlite_create_series_table, sqlite_append_insight: Added try/catch around Schema.parse(params) and sanitizeIdentifier() calls
    • sqlite_backup, sqlite_restore, sqlite_generate_series, sqlite_analyze_csv_schema, sqlite_transaction_execute: Added try/catch around Schema.parse(params) calls
    • AppendInsightSchema.insight now requires .min(1) to reject empty strings (previously accepted "" silently)
  • Migration Tool Zod Validation Error Handlingsqlite_migration_record and sqlite_migration_apply handlers now catch Zod validation errors as structured {success: false} responses
    • Moved Schema.parse(params) inside existing try/catch blocks in tracking.ts
    • Previously, calling these tools with empty {} params returned raw MCP error frames instead of structured handler errors
  • Code Mode log Alias Mapping — Fixed sqlite.migration.log() pointing to migrationRecord instead of migrationHistory
    • log semantically means "show the log of migrations", not "record a new migration"
    • Calling sqlite.migration.log() previously required version and migrationSql params (record) — now correctly returns migration history with no required params
  • JSON Tool Zod Validation Error Handling — All 23 JSON tool handlers now catch Zod validation errors as structured {success: false} responses
    • Previously, calling any JSON tool with empty or invalid parameters returned raw MCP error -32602 instead of a structured handler error
    • Root cause: MCP SDK validates inputSchema at the transport layer before the handler runs, rejecting required-field violations as -32602
    • Fix: DatabaseAdapter.registerTool() now wraps inputSchema with .partial() so the SDK accepts any param subset; handler-level Schema.parse() validates strictly and returns structured errors via formatError()
    • Added try/catch around Schema.parse(params) in all 23 JSON handlers across 4 files: crud.ts (7), query.ts (4), transform.ts (4), json-helpers.ts (8)
  • Core Table Tool Zod Validation Error Handling — 3 table handlers (sqlite_create_table, sqlite_describe_table, sqlite_drop_table) now catch Zod validation errors as structured {success: false} responses
    • Previously, calling these tools with missing required parameters (e.g., empty {}) threw raw MCP errors instead of returning structured handler errors
    • Added try/catch around Schema.parse(params) in all 3 handlers in tables.ts with formatError() for consistent error responses
  • Index Tool Zod Validation Error Handling — All 3 index handlers (sqlite_get_indexes, sqlite_create_index, sqlite_drop_index) now catch Zod validation errors as structured {success: false} responses
    • Root cause: CreateIndexSchema.columns had .min(1) which the MCP SDK validates before the handler runs, surfacing as raw MCP error -32602
    • Moved min(1) check to handler-level validation returning {success: false, message: "At least one column is required..."}
    • Wrapped all Schema.parse() calls in try/catch blocks with formatError() for defense-in-depth
  • Multi-Session Streamable HTTP Crash — Fixed Already connected to a transport error when creating 2+ concurrent sessions
    • SDK's McpServer.connect() only supports one active transport; second connect() threw
    • Added close-before-reconnect pattern wrapping server.connect() in try-catch
  • sqlite_spatialite_index Check Returns valid: false for Valid Indexes — Now treats CheckSpatialIndex null result as indeterminate
    • SpatiaLite 5.x's CheckSpatialIndex() commonly returns null instead of 1 for valid indexes
    • Previously interpreted null as false, producing misleading message "Spatial index exists but may be invalid"
    • Now returns valid: null with message "Spatial index exists (validation inconclusive — common in SpatiaLite 5.x)"
    • Explicit valid: false now only shown when CheckSpatialIndex returns 0 (actually invalid index)
  • sqlite_spatialite_create_table Misleading Success on Existing Table — Now returns alreadyExists: true when table already exists
    • Previously used CREATE TABLE IF NOT EXISTS and always reported "Spatial table 'X' created" even when table already existed
    • Now pre-checks table existence and returns accurate message: "Spatial table 'X' already exists" with alreadyExists: true flag
    • Prevents confusion about whether data was reset or preserved
  • sqlite_spatialite_index Create/Drop/Check Idempotency — All 3 index actions now report accurate state
    • create: Returns alreadyExists: true when index already exists instead of silently running CreateSpatialIndex again
    • drop: Returns alreadyDropped: true when no index exists instead of misleadingly reporting "Spatial index dropped"
    • check: Returns { indexed: false } when no index exists, or { indexed: true, valid: true/false } when index exists — previously returned raw { result: [{ "CheckSpatialIndex(...)": null }] }
    • Index existence checked via idx_{table}_{column} in sqlite_master
  • sqlite_spatialite_analyze Distance Matrix targetTable Support — Now uses targetTable parameter when provided
    • Previously, the distance_matrix analysis type always used sourceTable for both sides of the cross-join, ignoring targetTable
    • Now uses targetTable (defaulting to sourceTable when omitted) and only applies a.id < b.id dedup filter for same-table queries
  • SpatiaLite Tool Structured Error Responses — All 7 SpatiaLite handlers now return structured errors instead of throwing raw MCP exceptions
    • Added formatError import and try/catch blocks to all 7 handlers: sqlite_spatialite_load, sqlite_spatialite_create_table, sqlite_spatialite_query, sqlite_spatialite_analyze, sqlite_spatialite_index, sqlite_spatialite_transform, sqlite_spatialite_import
    • sqlite_spatialite_query: Nonexistent table errors now return {success: false, error, code, suggestion} instead of propagating as raw MCP exceptions
    • sqlite_spatialite_analyze: Same fix — structured error response for nonexistent tables and invalid table names
    • sqlite_spatialite_index: Added table existence validation — previously returned {success: true} for nonexistent tables; now returns {success: false, error: "Table 'x' does not exist"}
    • sqlite_spatialite_transform: Added null-result validation — previously returned {success: true, result: null} for invalid WKT geometry; now returns {success: false, error: "Invalid geometry..."}
    • sqlite_spatialite_import: Added WKT pre-validation via GeomFromText() — previously silently accepted invalid WKT strings like "INVALID_WKT"; now returns {success: false, error: "Invalid WKT geometry..."}
    • sqlite_spatialite_create_table: Validation errors (invalid table/column names) now return structured responses instead of throwing
    • Tests updated to expect structured error responses instead of catching thrown errors; 11 tests covering all 7 tools
    • Previously threw raw MCP exception when called with a nonexistent table
    • Now returns {success: false, error, code, suggestion} consistent with all other tool groups
    • Security test updated to assert structured error response instead of .rejects.toThrow()
  • sqlite_restore Relative Path Resolution — Now resolves relative paths to absolute before file existence check
    • Previously used raw input.sourcePath with fs.existsSync, which resolved against the MCP server's CWD (e.g., Antigravity IDE directory)
    • Stale 0-byte files left by SQLite ATTACH DATABASE at the server CWD could cause false-positive {success: true} responses
    • Now uses nodePath.resolve() consistent with the existing sqlite_verify_backup handler
  • sqlite_backup Relative Path Resolution — Now resolves relative paths to absolute before VACUUM INTO
    • Previously used raw input.targetPath for VACUUM INTO, causing backups to be written to the MCP server's CWD instead of the expected location
    • Now uses nodePath.resolve() consistent with sqlite_verify_backup and sqlite_restore
  • sqlite_drop_view Misleading Success Message — Now reports "did not exist (no action taken)" for nonexistent views
    • Previously always returned View 'x' dropped regardless of whether the view existed (when ifExists: true)
    • Now checks view existence before dropping, consistent with sqlite_drop_virtual_table pattern
  • sqlite_verify_backup Relative Path False Positive — Now resolves relative paths to absolute before fs.existsSync check
    • Previously, relative paths like "nonexistent_file.db" bypassed the file existence check (resolved against MCP server CWD, not database directory) and ATTACH DATABASE silently created an empty DB, returning {success: true, valid: true, pageCount: 0}
    • Now uses nodePath.resolve() to convert to absolute path before checking, ensuring consistent behavior regardless of server CWD
  • sqlite_pragma_settings Nonexistent PRAGMA Error Message — Returns user-friendly error for unknown PRAGMAs
    • Previously, querying a nonexistent PRAGMA like nonexistent_pragma_xyz returned the confusing better-sqlite3 internal error: "This statement does not return data. Use run() instead" with UNKNOWN_ERROR code
    • Now detects this specific error pattern and returns {success: false, error: "Unknown or write-only PRAGMA: 'nonexistent_pragma_xyz'"}
    • input parsing moved before try/catch block to ensure PRAGMA name is accessible in error handler
  • sqlite_pragma_settings Structured Error Response — Handler now wrapped in try/catch with formatError()
    • Previously, invalid PRAGMA names threw raw MCP exceptions instead of structured error responses
    • Now returns {success: false, error: "Invalid PRAGMA name"} for validation failures
    • Catches all SQLite errors and returns structured {success: false, error, code, suggestion} responses
  • sqlite_verify_backup Nonexistent File Validation — Now pre-validates file existence before ATTACH
    • Previously, ATTACH silently created an empty DB for nonexistent files, returning false-positive {success: true, valid: true, pageCount: 0}
    • Now returns {success: false, message: "Backup file not found: ..."} when file doesn't exist
    • Outer try/catch with formatError() added for unexpected errors
  • sqlite_restore Nonexistent File Validation — Now pre-validates source file existence before ATTACH
    • Previously, ATTACH silently created an empty DB for nonexistent files, returning false-positive {success: true}
    • Now returns {success: false, message: "Source file not found: ..."} when file doesn't exist
  • Transaction Tool Structured Error Responses — All 6 transaction handlers now return structured errors instead of throwing raw MCP exceptions
    • sqlite_transaction_begin, sqlite_transaction_commit, sqlite_transaction_rollback: Errors like double-begin and no-active-transaction now return {success: false, error, code, suggestion} instead of propagating as unhandled exceptions
    • sqlite_transaction_savepoint, sqlite_transaction_release, sqlite_transaction_rollback_to: Invalid savepoint names return {success: false, error: "Invalid savepoint name"} instead of throwing; nonexistent savepoint errors return structured responses
    • Added formatError import to transactions.ts
    • Security tests updated to assert structured error responses instead of .rejects.toThrow()
  • sqlite_vector_distance Missing Error Handling — Handler now wrapped in try/catch with formatError()
    • Previously, Zod validation errors from malformed input threw raw MCP exceptions instead of structured error responses
    • Now consistent with sqlite_vector_normalize and all other vector tool handlers
  • sqlite_vector_batch_store Empty Items Table Validation — Now validates table existence even when items array is empty
    • Previously, batch_store({table: "nonexistent", items: []}) returned {success: true, stored: 0} without checking if the table exists
    • Now queries sqlite_master to verify table existence before returning the empty-items early response
    • Returns {success: false, error: "Table 'x' does not exist"} for nonexistent tables
  • sqlite_vector_get Column Not Found Error — Provides clear error when vector column doesn't exist in row data
    • Previously returned misleading "Invalid vector format" with UNKNOWN_ERROR code when the specified vector column was not found in the row
    • Now returns descriptive error: "Column 'x' not found or contains NULL. Available columns: ..." listing actual column names
  • sqlite_vector_count Dimensions Filterdimensions parameter now filters results instead of being silently ignored
    • Previously sqlite_vector_count({table: "t", dimensions: 8}) returned total row count regardless of dimensions value
    • Now adds WHERE dimensions = N clause when dimensions parameter is specified
  • sqlite_vector_normalize Error Handling — Handler now wrapped in try/catch with formatError()
    • Previously threw raw Zod validation errors instead of returning structured error responses
    • Now consistent with all other vector tool handlers
  • sqlite_vector_batch_store Empty Items Validation — Returns early with {stored: 0, message: "No items provided"} for empty items array
    • Previously, empty items array on a nonexistent table silently returned {success: true, stored: 0} without touching the database
    • Now short-circuits before any SQL execution, preventing misleading success responses
  • Vector Tool Structured Error Responses — All 11 vector handlers now return structured errors instead of throwing raw MCP exceptions
    • sqlite_vector_create_table, sqlite_vector_store, sqlite_vector_batch_store, sqlite_vector_search, sqlite_vector_get, sqlite_vector_delete, sqlite_vector_count, sqlite_vector_stats, sqlite_vector_dimensions, sqlite_vector_normalize, sqlite_vector_distance: Errors like nonexistent tables, invalid identifiers, and invalid input now return {success: false, error, code, suggestion} instead of propagating as unhandled exceptions
    • Added formatError import from utils/errors.js and wrapped all 11 handlers in try/catch blocks
    • Security tests in identifier-integration.test.ts updated to assert structured error responses instead of .rejects.toThrow()
    • Consistent with the structured error pattern already used by all other tool groups
  • sqlite_vector_search Negative Cosine Similarity Filter — Search no longer silently drops results with negative cosine similarity
    • Previously, the search filter _similarity >= 0 excluded rows with negative cosine similarity (dissimilar vectors)
    • Negative cosine similarity is valid (ranges from -1 to 1) and should be returned when within the limit
    • Now filters only rows where vector parsing failed (returns null), preserving all valid similarity scores
  • sqlite_vector_create_table Dimensions Validation — Now rejects dimensions < 1 with structured error
    • Previously accepted dimensions: 0 creating a table with meaningless DEFAULT 0 dimension column
  • sqlite_vector_distance Cosine Metric — Now returns cosine distance (1 - similarity) instead of raw cosine similarity
    • Previously returned cosine similarity (0 for orthogonal, 1 for identical) despite the tool being named "distance"
    • Now returns cosine distance (1.0 for orthogonal, 0 for identical) consistent with euclidean distance semantics
    • Does not affect sqlite_vector_search which correctly uses _similarity as a ranking score
  • Window Function Structured Error Responses — All 6 window function handlers now return structured errors instead of throwing raw MCP exceptions
    • sqlite_window_row_number, sqlite_window_rank, sqlite_window_lag_lead, sqlite_window_running_total, sqlite_window_moving_avg, sqlite_window_ntile: Errors like nonexistent tables, invalid identifiers, and bad SQL now return {success: false, error, code, suggestion} instead of propagating as unhandled exceptions
    • Added formatError import from utils/errors.js and wrapped all 6 handlers in try/catch blocks
    • Window function tests updated to assert structured error responses instead of .rejects.toThrow()
    • Consistent with the structured error pattern already used by all 13 stats tools
  • server_health FTS5 Detection False Negative — Health check now correctly reports fts5: true when FTS5 is compiled in
    • hasFts5() previously created a _fts5_test virtual table as a probe, which silently failed when SpatiaLite extensions were loaded
    • Replaced with lightweight PRAGMA compile_options check for ENABLE_FTS5 flag
    • More reliable and efficient than the virtual table creation/drop approach
  • FTS5 Tool Structured Error Responses — All 4 FTS5 handlers now return structured errors instead of throwing raw MCP exceptions
    • sqlite_fts_create, sqlite_fts_search, sqlite_fts_rebuild, sqlite_fts_match_info: Errors like nonexistent tables, bad SQL, and invalid columns now return {success: false, error, code, suggestion} instead of propagating as unhandled exceptions
    • Previously, only isFts5UnavailableError (WASM mode) was caught; all other errors were re-thrown
    • Consistent with the structured error pattern already used by all 13 text tools, core tools, stats tools, and JSON tools
    • Security tests in fts-injection.test.ts updated to assert structured error responses instead of .rejects.toThrow()
  • sqlite_execute_code Per-Call Timeout Enforcement — The timeout parameter is now respected per-call instead of being silently ignored
    • Previously, timeout was parsed from input but never passed to the sandbox pool; all executions used the fixed 30000ms default
    • Added timeoutMs?: number parameter to ISandbox.execute() and ISandboxPool.execute() interfaces
    • All 4 implementations updated: CodeModeSandbox, SandboxPool, WorkerSandbox, WorkerSandboxPool
    • codemode.ts now passes the user-specified timeout through to pool.execute(code, bindings, timeoutMs)
  • sqlite_create_index Table Existence Pre-Validation — Now returns TABLE_NOT_FOUND error instead of raw SQL error for nonexistent tables
    • Previously returned {success: false, message: "Write query failed: no such table: main.xyz"} (leaking implementation detail)
    • Now pre-validates table existence and returns {success: false, message: "Table 'xyz' does not exist", code: "TABLE_NOT_FOUND"}
    • Consistent with sqlite_describe_table and sqlite_get_indexes which already pre-validate table existence
  • sqlite_create_index Empty Columns ValidationCreateIndexSchema.columns now requires .min(1)
    • Previously, an empty columns array passed Zod validation and produced invalid SQL CREATE INDEX ... ON table ()
    • Now rejected at schema validation level with clear "Array must contain at least 1 element(s)" message
  • formatError Specific Resource Error Codes — Native SQLite errors now return precise error codes instead of generic RESOURCE_ERROR
    • no such table errors now return TABLE_NOT_FOUND code (previously RESOURCE_ERROR)
    • no such column and has no column named errors now return COLUMN_NOT_FOUND code (previously RESOURCE_ERROR)
    • Added optional code field to ERROR_SUGGESTIONS entries; formatError prefers match.code over category default
    • Consistent across all tool groups: core read_query/write_query, text fts_search, vector search, JSON extract
    • findSuggestion return type extended with code?: string field
    • Category-level fallback codes still apply for patterns without specific code overrides
  • ERROR_SUGGESTIONS Query Error Pattern Coverage — 3 new patterns added for query errors that previously fell through to UNKNOWN_ERROR
    • incomplete inputQUERY_ERROR with suggestion to check for missing clauses or closing parentheses
    • more than one statementQUERY_ERROR with suggestion to split into separate calls or use sqlite_execute_code
    • too few parameterQUERY_ERROR with suggestion to match params array to placeholder count
  • sqlite_read_query Statement Type Validation — Now rejects non-SELECT statements with clear error messages
    • Previously, INSERT/UPDATE/DELETE/DDL passed to read_query leaked internal better-sqlite3 message: "This statement does not return data. Use run() instead"
    • Now validates upfront and returns: "Statement type not allowed: INSERT is not a SELECT query. Use sqlite_write_query for INSERT/UPDATE/DELETE, or appropriate admin tools for DDL."
    • Allows SELECT, PRAGMA, EXPLAIN, and WITH statements; mirrors write_query validation pattern
  • reset-database.ps1 Verification Table List — Removed orphaned temp_text_test entry from expected tables map
    • temp_text_test is not created by the seed SQL and was dead code (verification query only checks test_% tables)
  • Native Adapter Missing Codemode Toolsqlite_execute_code was not registered in Native mode
    • NativeSqliteAdapter.getToolDefinitions() was missing getCodeModeTools() from its tool list
    • WASM adapter (SqliteAdapter) already included it via getAllToolDefinitions()
    • Tool filter correctly auto-injected codemode into enabled groups, but the tool definition was never produced so it couldn't be registered
  • Core Tool Input Validation — 5 core tool handlers now return structured errors for invalid identifiers instead of throwing raw MCP exceptions
    • sqlite_create_table: Added sanitizeIdentifier validation for table names and empty columns array check (previously accepted empty string names and empty columns, causing orphaned tables or SQL syntax errors)
    • sqlite_drop_table, sqlite_drop_index: Wrapped existing sanitizeIdentifier calls in try/catch to return {success: false, message: "..."} instead of propagating InvalidIdentifierError
    • sqlite_get_indexes, sqlite_create_index: Same try/catch wrapping for identifier validation
    • All 5 handlers now follow the structured error response pattern: {success: false, message: "Invalid ... name"}
  • sqlite_geo_nearby returnColumns Column Leakage — Lat/lon columns no longer leak into results when returnColumns is specified
    • Previously, internally-added lat/lon columns (needed for Haversine distance calculation) were included in the response even when the user didn't request them
    • Now strips lat/lon columns from results unless the user explicitly includes them in returnColumns
    • Consistent with sqlite_geo_bounding_box which already respected returnColumns exactly
  • Geo Tool Structured Error Responses — All 3 database-accessing geo handlers now return structured errors instead of throwing raw MCP errors
    • sqlite_geo_nearby, sqlite_geo_bounding_box, sqlite_geo_cluster: Wrap handler logic in try-catch with formatError() for consistent {success: false, error: "..."} responses
    • Added validateColumnExists() to validate lat/lon column existence before query execution; previously nonexistent columns silently returned 0 results
    • 6 new error path tests added for nonexistent table and column scenarios
  • Admin Tool Structured Error Responses — 4 admin tool handlers now return structured errors instead of throwing raw MCP errors
    • sqlite_virtual_table_info: Returns {success: false, error: "Virtual table 'x' not found"} instead of throwing for nonexistent virtual tables
    • sqlite_create_view: Catches duplicate view errors, invalid SQL, and identifier validation failures; returns {success: false, message: "..."} with context
    • sqlite_drop_view: Catches nonexistent view errors (when ifExists: false) and identifier validation failures
    • sqlite_drop_virtual_table: Catches nonexistent table errors (when ifExists: false) and returns structured response
    • Security tests updated to assert {success: false, message: /invalid/i} instead of .rejects.toThrow()
  • sqlite_verify_backup WASM False Positive — Now returns WASM limitation error upfront before attempting ATTACH
    • Previously, ATTACH succeeded silently in WASM (creating empty DB in virtual filesystem), causing verify to return {success: true, valid: true} for any path including nonexistent files
    • Now checks isNativeBackend() first and returns {success: false, wasmLimitation: true} immediately
  • sqlite_restore WASM False Positive — Now returns WASM limitation error upfront before attempting ATTACH
    • Previously, ATTACH succeeded silently in WASM, causing restore to "succeed" by copying empty tables from a nonexistent backup
  • sqlite_pragma_table_info Nonexistent Table Detection — Returns {success: false} for nonexistent tables
    • Previously returned {success: true, columns: []} for tables that don't exist
    • Now checks if columns array is empty and returns {success: false, error: "Table 'x' not found or has no columns"}
  • Admin Code Mode Positional Parameters — Added 12 missing entries in api.ts for admin group methods
    • generateSeries, createView, dropView, createSeriesTable, virtualTableInfo, dropVirtualTable, verifyBackup, pragmaCompileOptions, createRtreeTable, createCsvTable, analyzeCsvSchema now support positional arg syntax
    • Example: sqlite.admin.createView("my_view", "SELECT 1") now works instead of requiring object syntax
  • Code Mode normalizeParams Primitive Type Handling — Fixed single number/boolean args being passed raw to tool handlers
    • Previously, sqlite.admin.generateSeries(1, 5, 1) passed 1 directly instead of {start: 1, stop: 5, step: 1}
    • normalizeParams now wraps number and boolean single args using the positional parameter mapping, same as strings
    • Affects any method with non-string first positional params (e.g., generateSeries, dbstat)
    • sqlite_stats_correlation Non-Numeric Column Validation — Now returns structured error for non-numeric columns
    • Previously returned {success: true, correlation: null} when correlating text columns (e.g., name, description)
    • Now validates column types via PRAGMA table_info() and returns {success: false, code: "INVALID_INPUT"} with suggestion to use numeric columns
    • Correlation description says "numeric columns" — behavior now enforces this
  • Stats Tool Zod Refinement Leak Fixes — Moved .min()/.max() refinements from Zod schemas to handler-level validation for 3 tools
    • sqlite_stats_histogram: Removed .min(1) from buckets schema parameter; handler now returns {success: false, error: "'buckets' must be at least 1"} for invalid values
    • sqlite_stats_percentile: Removed .min(0).max(100) from percentiles array element schema; handler now validates each percentile value is between 0 and 100
    • sqlite_stats_regression: Removed .min(1).max(3) from degree schema parameter; handler now returns structured error for values outside 1-3 range
    • Previously, out-of-range values triggered raw MCP -32602 errors at the SDK boundary before the handler ran
  • Stats Code Mode Positional Parameters — Fixed statsGroupBy and added 5 missing entries in api.ts
    • statsGroupBy: Was mapped to ["table", "column"] but actual params are ["table", "valueColumn", "groupByColumn", "stat"]
    • Added missing positional mappings for statsDistinct, statsSummary, statsFrequency, statsOutliers, statsHypothesis
    • All 13 stats methods now support positional arg syntax in sqlite_execute_code
  • Code Mode help() Write Method Discoverabilityhelp() now lists all methods regardless of readonly flag
    • Previously, readonly: true filtered write tools before API construction, hiding them from help() output
    • Now builds full API surface first, then wraps write methods with readonly guards returning CODEMODE_READONLY_VIOLATION errors
    • Users can discover all available methods via sqlite.core.help() and get clear error messages when invoking write methods in readonly mode
  • Text Tool Code Mode Positional Parameters — Fixed 8 broken positional parameter mappings for text tools in api.ts
    • textSplit, textConcat, textReplace renamed to split, concat, replace (matching actual method names after prefix stripping)
    • Added 5 missing entries: trim, case, substring, validate, normalize
    • All text tools now support positional arg syntax in sqlite_execute_code (e.g., sqlite.text.split("table", "col", "@"))
  • Text Tool Code Mode Alias — Removed broken normalize → textNormalize alias from METHOD_ALIASES
    • The canonical method name is normalize (not textNormalize), so the alias was a no-op pointing to nothing
  • sqlite_advanced_search Error Code — Changed from executeQuery to executeReadQuery for consistent error codes
    • Nonexistent table errors now return DB_QUERY_FAILED code instead of UNKNOWN_ERROR
  • Security Integration Tests — Updated 4 text tool injection tests in identifier-integration.test.ts
    • Tests now check for {success: false, error: /invalid/i} pattern instead of .rejects.toThrow()
    • Consistent with structured error handling across all tool groups
    • Fixed text_replace test to use correct parameter names (searchPattern/replaceWith instead of search/replace)
  • createIndex Code Mode Positional Parameter — Added missing indexName to positional parameter mapping
    • createIndex was mapped as ["tableName", "columns"] but indexName is required
    • Code mode calls like sqlite.core.createIndex("table", ["col"], "idx_name") now work correctly
  • Text Tool TABLE_NOT_FOUND Error PriorityvalidateColumnExists now checks table existence before column existence
    • Previously returned COLUMN_NOT_FOUND when table didn't exist (because pragma_table_info returns empty for nonexistent tables)
    • Now returns TABLE_NOT_FOUND with suggestion to run sqlite_list_tables
    • Gives users a more actionable error message for the root cause
  • sqlite_phonetic_match Word-Level Matching — Now splits column values into words and matches any word
    • Previously computed soundex/metaphone on the entire column value, missing multi-word matches (e.g., "Mouse" didn't match "Mouse Pad XL")
    • Now consistent with sqlite_advanced_search phonetic behavior which already matched per-word
    • Both Soundex and Metaphone paths updated; native SQLite soundex query replaced with JS-based word splitting
    • Documentation updated from "compares FIRST word only" to "matches against any word in value"
  • Stats Tool Output Schema Error Responses — All 13 stats output schemas now accommodate {success: false} error responses
    • 10 exported schemas in output-schemas.ts and 3 inline schemas in stats.ts (outliers, regression, hypothesis) updated
    • Success-specific fields made optional; error, code, suggestion fields added
    • Previously, formatError() responses failed Zod output validation because required fields like column, stats, count were missing
    • Mirrors the pattern already used by JSON tool schemas for structured error handling
  • Stats Tools Non-Numeric Column Validationsqlite_stats_percentile, sqlite_stats_outliers, and sqlite_stats_hypothesis now validate column types upfront
    • sqlite_stats_percentile: Previously produced raw MCP output validation error (string values in numeric schema); now returns {success: false, code: "INVALID_INPUT"}
    • sqlite_stats_outliers: Previously generated SQL with NaN values causing DB_QUERY_FAILED; now returns structured error before query execution
    • sqlite_stats_hypothesis: Previously returned UNKNOWN_ERROR with vague message; now returns INVALID_INPUT with clear suggestion
    • Shared validateNumericColumn() helper extracted from createCorrelationTool for reuse across all three handlers
  • Stats Code Mode Positional Parameters (Round 2) — Fixed 2 remaining positional parameter mappings in api.ts
    • statsTopN: Was ["table", "column"], missing n and orderDirection — fixed to ["table", "column", "n", "orderDirection"]
    • statsHypothesis: Had column and testType swapped — fixed to ["table", "column", "testType"]
    • statsHypothesis: Added missing expectedMean as 4th positional param — enables sqlite.stats.statsHypothesis("table", "col", "ttest_one", 25) without object syntax
  • Stats Code Mode Positional Parameters (Round 3) — Added whereClause and selectColumns to positional parameter mappings in api.ts
    • 12 stats methods (statsBasic, statsCount, statsGroupBy, statsHistogram, statsPercentile, statsCorrelation, statsRegression, statsDistinct, statsSummary, statsFrequency, statsOutliers, statsHypothesis) now accept trailing whereClause positional arg
    • statsTopN: Added selectColumns as 5th positional param — enables sqlite.stats.statsTopN("table", "col", 3, "desc", ["id", "name"]) without object syntax
    • Previously, trailing positional args for whereClause and selectColumns were silently dropped
  • Stats Code Mode Help Examples — Fixed incorrect method names in GROUP_EXAMPLES for stats group
    • sqlite.stats.basic()sqlite.stats.statsBasic(), .histogram().statsHistogram(), .percentile().statsPercentile()
    • Stats group uses KEEP_PREFIX_GROUPS so methods retain the stats prefix; examples now match actual API
  • Stats Tools Numeric Column Validation (Round 2) — Added validateNumericColumn to 4 additional stats tools
    • sqlite_stats_basic: Previously returned meaningless results (sum: 0, avg: 0, min/max: null) for text columns; now returns structured INVALID_INPUT error
    • sqlite_stats_histogram: Previously generated corrupt SQL with NaN bucket boundaries for text columns; now returns structured error before query execution
    • sqlite_stats_regression: Previously returned raw MCP output validation error (NaN coefficients) for text columns; now validates both xColumn and yColumn upfront
    • sqlite_stats_group_by: Previously returned stat_value: 0 for AVG/SUM/MIN/MAX on text columns; now validates valueColumn is numeric for non-count aggregations (count stat remains unrestricted)
  • Stats Code Mode Positional Parameters (Round 4) — Fixed statsCount missing distinct in positional parameter mapping
    • Was ["table", "column", "whereClause"]distinct boolean passed as 3rd arg was mapped to whereClause, causing Zod validation error
    • Fixed to ["table", "column", "distinct", "whereClause"] — enables sqlite.stats.statsCount("table", "col", true) syntax
  • Codemode Positional Parameter Mapping — Fixed incorrect parameter name mappings in api.ts
    • readQuery and writeQuery mapped to "sql" but actual schema uses "query" — corrected
    • describeTable, dropTable, getIndexes mapped to "table" but actual schema uses "tableName" — corrected
    • createTable, createIndex first positional param mapped to "table" instead of "tableName" — corrected
    • ServerInstructions.ts examples updated to match corrected mappings
  • Codemode JSON Positional Parameter Mapping — Fixed 16 incorrect parameter mappings for JSON code mode methods
    • validatePath, pretty, valid were mismapped to ["table", "column", ...] instead of "path", "json", "json" respectively
    • extract, set, remove, type, arrayLength, arrayAppend, keys, each, update, merge were missing whereClause positional param
    • insert missing data, select missing paths, query missing filterPaths params
    • Calling sqlite.json.extract("table", "col", "$.path", "id = 1") now correctly maps the 4th arg to whereClause
  • sqlite_create_index Misleading Message for Duplicate Index Name — Fixed IF NOT EXISTS returning false "created" message
    • When an index name already exists, CREATE INDEX IF NOT EXISTS silently does nothing but the handler always reported "created on table(column)"
    • Now checks index existence before executing and returns "already exists (no changes made)" when the index is pre-existing
    • Mirrors the pattern already used by sqlite_create_table for duplicate table names
  • sqlite_execute_code Negative memoryUsedMb Values — Clamped memory metric to Math.max(0, ...)
    • Both worker-sandbox.ts and sandbox.ts measured heap delta on the main thread, which could go negative due to GC during worker execution
    • Values like -4.76 MB are now reported as 0 MB instead
  • sqlite_write_query Statement Type Validation — Now rejects non-DML statements with structured errors
    • Only allows INSERT, UPDATE, DELETE, and REPLACE statements
    • SELECT, PRAGMA, EXPLAIN, and DDL (CREATE, ALTER, DROP, TRUNCATE) are rejected with clear error messages
    • Prevents accidental data loss from DDL via write_query (previously accepted and executed DROP TABLE)
  • WASM FTS5 Tool Exclusion — FTS5 tools no longer registered in WASM mode
    • Removed getFtsTools() from shared WASM tool index (tools/index.ts)
    • FTS5 tools (sqlite_fts_create, sqlite_fts_search, sqlite_fts_rebuild, sqlite_fts_match_info) remain available in native mode only
    • Previously, 4 FTS5 tools were registered in WASM but always returned {success: false, error: "FTS5 module unavailable"}
    • WASM tool counts corrected: starter 48→44, search 36→32, full 102→98, text group 17→13
    • Updated README.md, DOCKER_README.md, ToolConstants.ts, ServerInstructions.ts
    • Updated fts.test.ts and index.test.ts to verify exclusion
  • sqlite_create_json_collection Non-Atomic Table Creation — Index path validation now runs before table creation
    • Previously, the table was created first, then index paths were validated one-by-one
    • An invalid index path returned {success: false} but left the table behind (partial creation)
    • Now validates all index paths upfront before executing CREATE TABLE
    • DOCKER_README Documentation Sync — Synchronized Docker Hub README with main README content
    • Added Resources (8) table with efficiency tip and Prompts (10) table
    • Added SQLite Extensions section with Docker-specific SpatiaLite/CSV instructions
    • Added OAuth 2.1 supported scopes table and Docker quick start example
    • Added stateless mode section for serverless Docker deployments
    • Added performance tuning tip for schema cache TTL configuration
    • Expanded HTTP endpoints from bullet list to table format with session management details
    • Fixed formatting bug: unclosed 4-backtick code block in legacy syntax section
  • README Streamlining — Removed redundant sections to reduce README from 712 to ~590 lines
    • Removed Table of Contents (GitHub renders one natively)
    • Merged Quick Test into Quick Start as a "Verify It Works" substep
    • Removed Security Features checklist (duplicated by "What Sets Us Apart" table)
    • Removed Tool Categories table (redundant with Tool Groups table in Tool Filtering)
    • Removed Backend Options table and Transaction/Window tool listings (reference-level detail for Wiki)
    • Merged standalone Configuration section into OAuth section as a one-liner
    • Promoted Extensions, Resources, and Prompts to top-level sections
  • ESLint v10 Compatibility — Fixed 11 new lint errors introduced by the ESLint v10 major upgrade
    • Added { cause } to re-thrown errors in NativeSqliteAdapter.ts, spatialite.ts, SqliteAdapter.ts (preserve-caught-error)
    • Removed useless initial assignments in SchemaManager.ts, SqliteAdapter.ts, admin.ts, stats.ts (no-useless-assignment)
    • Fixed unsafe express.json() call in http.ts (no-unsafe-call)
  • Added lint:json npm script for agent-readable ESLint output (eslint-results.json)
  • Added .gitattributes to normalize line endings to LF on all platforms
  • Added test suite badges (941 tests, 80% coverage) to both READMEs
  • Query Normalization: Strip trailing whitespace and semicolons before injecting safety LIMIT, preventing invalid SQL like SELECT ...; LIMIT 1000
  • CTE Write Support: sqlite_write_query now correctly accepts CTE-prefixed DML (WITH ... INSERT/UPDATE/DELETE/REPLACE) by parsing past parenthesized CTE bodies to find the main DML keyword
  • Statement Validation: Removed UPSERT from allowed write prefixes — it is not a valid SQLite leading keyword
  • SQL Injection Hardening: Replaced string interpolation with parameterized queries for table name filters in sqlite_get_indexes and sqlite_index_stats
  • Column Validation: Optimized validateColumnsExist to fetch all columns in a single pragma_table_info query and check membership in-memory, eliminating N+1 query roundtrips
  • Structured Errors: All 3 native transaction savepoint handlers (savepoint, release, rollback_to) now return formatHandlerError(ValidationError) for invalid names instead of bare {success: false} objects
  • WASM Capability: Corrected fullTextSearch capability flag to false for WASM/sql.js builds (FTS5 is not available)
  • Constraint Analysis: Removed redundant no-op .replace(/_/g, "_") in foreign key column inference
  • Encoding: Fixed mojibake em dash (â€") in admin barrel index JSDoc
  • CodeQL: Fixed missing regex anchor in icon URL test assertion
  • CodeQL: Removed 10 unused imports across 8 test files
  • SQL Injection: Replaced string interpolation with parameter binding in column validation queries (validateTableExists, validateColumnExists, validateColumnsExist)
  • SQL Injection: Replaced string interpolation with parameter binding in schema fallback fallBackGetIndexes table filter
  • Read Query: Deny-by-default for sqlite_read_query — unrecognized statement types are now blocked instead of falling through to the adapter
  • Verify Backup: Use structured formatHandlerError in sqlite_verify_backup early-return error paths (empty path, file not found, ATTACH failure)
  • Transaction Methods: Throw ValidationError instead of generic Error for invalid savepoint names in native transaction methods
  • Index Detection: Case-insensitive UNIQUE detection in sqlite_get_indexes (normalize DDL to uppercase before matching)
  • Metadata: Updated server.json tool count from 122 to 139
  • CodeQL: Removed unused calledPragma variable in vtable test
  • SQL Injection: Narrowed UNION SELECT / UNION ALL SELECT dangerous-pattern regexes to require semicolon-delimited context (;\\s*UNION), allowing legitimate UNION queries
  • PRAGMA Safety: Block mutating PRAGMAs (assignment form with =) in sqlite_read_query to prevent privilege escalation via writable_schema, journal_mode, etc.
  • Verify Backup: Wrapped DETACH DATABASE in finally block with try/catch to prevent detach failures from overriding successful verification results
  • Optimize Tool: Added try/catch + formatHandlerError to sqlite_optimize handler for consistent structured error responses on parse or runtime failures
  • Structured Errors: Added structuredContent to error responses in the tool registration wrapper when tools have outputSchema, ensuring clients receive machine-readable error payloads
  • PRAGMA Safety: Block mutating PRAGMAs in sqlite_read_query — assignment form (=) always blocked; function-call form (PRAGMA name(...)) checked against read-only allowlist (table_info, index_list, foreign_key_list, etc.)
  • Optimize Progress: Fixed off-by-one progress tracking in analyze branch (step + 1++step)
  • Adapter Version: Updated SqliteAdapter.version from 1.0.0 to 1.1.0 to match package.json
  • Error Codes: Aligned schema-manager error codes with canonical tool-level codes (SQLITE_INVALID_TABLEINVALID_TABLE, SQLITE_TABLE_NOT_FOUNDTABLE_NOT_FOUND)
  • Transaction Methods: Removed local ValidationError class in favor of plain Error — callers already wrap with formatHandlerError
  • Transaction Rollback: Preserved formatted.error in rollback catch block instead of overwriting with generic rollback message
  • SpatiaLite Loader: Windows PATH resolution now derives directory from customPath (when provided) instead of only SPATIALITE_PATH env var; renamed shadow path variable
  • CI E2E: Added database seeding step (sqlite3 test.db < test-database.sql) to e2e.ymltest.db is gitignored and absent on fresh CI checkout, causing WASM E2E tests to fail with empty database
  • Transaction Mode: Normalized transaction mode input to lowercase — IMMEDIATE and Immediate now correctly resolve to immediate instead of silently defaulting to deferred
  • Transaction Rollback: Wrapped rollbackTransaction() in try/catch to preserve original error context if rollback itself fails
  • Verify Backup Errors: Error codes (FILE_NOT_FOUND, ATTACH_FAILED) now passed through ValidationError constructor instead of overriding after formatHandlerError spread
  • Dockerfile Healthcheck: Transport-aware healthcheck — only runs curl /health in HTTP mode; falls back to lightweight Node.js check for stdio to prevent false-healthy status
  • E2E: CSV payload test now reads payload.error (not payload.message) for extension-unavailable skip detection, fixing CI failures on Linux where the Windows-only CSV extension is absent

Security

  • CTE Write-Bypass: sqlite_read_query now blocks WITH ... INSERT/UPDATE/DELETE — parses past CTE preamble to verify main statement is SELECT or EXPLAIN
  • PRAGMA Hardening: Assignment detection uses anchored regex (^PRAGMA\s+name\s*=) instead of includes("=") to avoid false positives in string literals; function-call regex handles schema-qualified names (PRAGMA main.table_info(...))
  • SQL Comment Injection: Comment-style patterns (--, /* */) now tested against string-literal-stripped SQL to prevent false positives on quoted values like SELECT 'a--b'
  • Log Injection (CodeQL): Logger taint-break uses char-code round-trip (String.fromCharCode) to sever CodeQL data-flow tracking chain for sanitized output
  • Strict Validation: Removed .strict() from all Zod tool input schemas across all tool groups. .strict() maps to additionalProperties: false in JSON Schema, which causes the MCP SDK to reject unrecognized keys at the framework boundary before handlers can catch, producing raw -32602 errors instead of structured responses. Handler-level validation (regex, enum checks) already guards against malformed input.
  • SQL Injection: Added strong regex validation to savepoint names in the Native SQLite transaction methods to prevent potential arbitrary SQL injection.
  • CORS Advisory: Updated README.md and DOCKER_README.md to explicitly warn about the permissive ["*"] default CORS property in production HTTP deployments.
  • Unified Audit: SHA-pinned all GitHub Actions in lint-and-test.yml and e2e.yml for supply chain safety. Updated stale v4 SHAs to current v6 in e2e.yml. Removed manually-maintained LABEL version from Dockerfile to prevent version drift. Fixed flatted dependency vulnerability (GHSA-25h7-pfq9-p65f).
  • DNS Rebinding: Added localhostHostValidation() middleware from MCP SDK to the HTTP transport to prevent DNS rebinding attacks.
  • Supply Chain: SHA-pinned remaining 2 un-pinned CI actions (actions/checkout, actions/setup-node) in the benchmarks job of lint-and-test.yml.
  • Supply Chain: Bumped GitHub Actions to latest major versions (Node 24 runtime):
    • docker/login-action v3 → v4
    • docker/build-push-action v6 → v7
    • docker/metadata-action v5 → v6
    • docker/setup-buildx-action v3 → v4
    • actions/upload-artifact v6 → v7
    • actions/download-artifact v7 → v8
  • Transitive Updates: Fixed multiple vulnerabilities in transitive dependencies by updating package-lock.json via npm update:
    • minimatch: ReDoS in matchOne() combinatorial backtracking via multiple non-adjacent GLOBSTAR segments.
    • hono and @hono/node-server: Arbitrary file access via serveStatic, authorization bypass for protected static paths, SSE Control Field Injection, Cookie Attribute Injection, and Prototype Pollution in parseBody.
    • express-rate-limit: IPv4-mapped IPv6 addresses bypassing per-client rate limiting on dual-stack networks.
  • Code Quality Audit — Table Name Validation — Added regex guard (/^[a-zA-Z_][a-zA-Z0-9_]*$/) to native adapter's describeTable fallback
    • WASM adapter already had this guard; native adapter's fallback path was missing it
  • Code Quality Audit — Missing WHERE Clause Validation — Added validateWhereClause() to 15 SQL interpolation points across 5 JSON tool files
    • json-operations/crud.ts (7 handlers), json-operations/query.ts (5 handlers), json-operations/transform.ts (2 handlers)
    • json-helpers/read.ts (1 handler), json-helpers/write.ts (2 handlers)
    • These tools interpolated input.whereClause directly into SQL without validation, unlike text/stats/vector/window tools which all called validateWhereClause()
  • Security Audit Remediation — Addressed 4 findings from comprehensive security audit
    • Fixed transitive hono vulnerability (GHSA-v8w9-8mx6-g223) via npm audit fix
    • Added HTTP server timeouts: setTimeout(120s), keepAliveTimeout(65s), headersTimeout(66s) to prevent slowloris-style DoS attacks
    • SHA-pinned all GitHub Actions across 4 CI workflows (lint-and-test.yml, codeql.yml, publish-npm.yml, docker-publish.yml) to prevent supply chain attacks via tag hijacking
    • Hardened Docker Scout security gate to fail-fast on non-timeout scan errors instead of silently continuing
  • NPM Audit Remediation — Patched high severity vulnerabilities in transitive dependencies
    • @hono/node-server: updated to 1.19.11
    • hono: updated to 4.12.5
  • Docker CVE Remediation — Patched npm-bundled transitive dependencies in Dockerfile (both stages)
    • tar: 7.5.7 → 7.5.8 (CVE-2026-26960: path traversal, HIGH 7.1)
    • minimatch: 10.1.2 → 10.2.4 (CVE-2026-26996: ReDoS, HIGH 8.7)
  • Security Audit Remediation — Addressed findings from exhaustive codebase security audit
    • CI npm audit gate now hard-fails on moderate+ vulnerabilities (removed continue-on-error)
    • Added Referrer-Policy and Strict-Transport-Security HTTP security headers (5 → 7 total)
    • WHERE clause validation now blocks ; SELECT stacked query injection
    • Removed dead new InvalidTokenError() construction in auth middleware
    • Updated SECURITY.md supported versions to 1.x.x
    • Fixed Dockerfile labels (version 1.0.2, tool count 124)

[1.0.2] - 2026-02-04

Added

  • GitHub Release badge to READMEs (dynamic version display)

[1.0.1] - 2026-02-04

Added

  • npm Publishing — Automated npm publishing workflow on GitHub releases
    • publish-npm.yml: NPM publish workflow triggered on release events
    • .npmignore: Reduces npm package size from 2.5MB to ~200KB
  • README Badges — npm version, Docker pulls, MCP Registry badges
  • MCP Registry Integrationserver.json with npm + Docker packages

Fixed

  • MIT license badge color (yellow → blue) for consistency

[1.0.0] - 2026-02-04

Added

  • Docker Release Infrastructure — Complete CI/CD pipeline for Docker Hub publishing

    • lint-and-test.yml: CI workflow with Node.js 22/24/25 matrix testing, ESLint, TypeScript checks
    • docker-publish.yml: Docker deploy workflow with security scanning, multi-platform builds (amd64/arm64), manifest merge
    • Dockerfile: Multi-stage build with better-sqlite3 native compilation, non-root user, security patches
    • .dockerignore: Excludes dev files, tests, and databases from image
    • DOCKER_README.md: Docker Hub README with quick start, tool filtering, security documentation
    • DOCKER_DEPLOYMENT_SETUP.md: Setup guide for GitHub secrets and deployment workflow
  • Security Test Coverage Expansion — 12 new/enhanced test files improving coverage for security-critical utilities

    • tests/utils/quoteIdentifier.test.ts: 32 tests for identifier sanitization edge cases (empty, whitespace, control chars, quotes)
    • tests/security/validateQuery.test.ts: 23 tests for DatabaseAdapter.validateQuery security patterns
    • tests/adapters/sqlite/resources.test.ts: 10 tests for all 8 MCP resource handlers
    • tests/adapters/sqlite/prompts.test.ts: 16 tests for all 10 MCP prompt handlers
    • tests/utils/insightsManager.test.ts: 16 tests for the insights memo singleton
    • tests/utils/progress-utils.test.ts: 17 tests for MCP progress notification utilities
    • tests/utils/annotations.test.ts: 21 tests for tool and resource annotation presets
    • tests/adapters/sqlite/json-utils.test.ts: 67 tests for JSON normalization, JSONB support, SQL generation, validation
    • tests/adapters/sqlite-native/NativeSqliteAdapter.test.ts: 39 tests for native adapter (connection, queries, schema, capabilities)
    • Enhanced logger.test.ts with 7 additional ModuleLogger convenience method tests (notice, warn, warning, critical, alert, emergency)
    • Enhanced security-injection.test.ts with sanitizeWhereClause tests
    • Enhanced ToolFilter.test.ts with edge case tests (comma-only strings, meta-group exclusion, summary generation)
    • Coverage improvements: identifiers.ts 65→97%, where-clause.ts 80→100%, ToolFilter.ts 91→96%, resources.ts 22→97%, prompts.ts 23→87%, insightsManager.ts 22→100%, progress-utils.ts 0→100%, annotations.ts 90→100%, resourceAnnotations.ts 66→100%, json-utils.ts 43→97%, logger.ts 85→97%, NativeSqliteAdapter.ts 49→65%+
  • sqlite_spatialite_analyze Geometry Output Control — New includeGeometry parameter to reduce payload size

    • When false (default), omits full WKT geometry from nearest_neighbor and point_in_polygon results
    • When true, includes source_geom and target_geom WKT fields as before
    • Significantly reduces payload size for proximity analysis (geometry can be 100+ characters per row)
  • sqlite_dbstat System Table Filter — New excludeSystemTables parameter to hide SpatiaLite metadata

    • When true, filters out SpatiaLite system tables from storage statistics (57 tables → ~12 user tables)
    • Applies to both summarize mode and default raw page-level mode
    • Provides parity with sqlite_list_tables and sqlite_get_indexes system table filtering
    • Default is false to preserve backward compatibility
  • sqlite_list_tables Tool Description — Fixed misleading "row counts" description

    • Changed tool description in core.ts from "row counts" to "column counts" to match actual output
    • Tool returns columnCount per table, not row counts
  • sqlite_json_normalize_column Output Format Control — New outputFormat parameter for normalization output

    • preserve (default): Keeps original format (text→text, JSONB→JSONB)
    • text: Always outputs normalized JSON as text
    • jsonb: Outputs normalized JSON in JSONB binary format
    • Enables normalizing JSONB columns without losing binary format efficiency
    • Response includes outputFormat field indicating which format was applied
  • sqlite_list_views System View Filter — New excludeSystemViews parameter to hide SpatiaLite views

    • When true (default), filters out SpatiaLite system views (geom_cols_ref_sys, spatial_ref_sys_all, vector_layers, etc.)
    • Reduces noise in view listings for spatial databases (7 views → 1 user view)
    • Set to false to include all views
  • sqlite_get_indexes System Index Filter — New excludeSystemIndexes parameter to hide SpatiaLite indexes

    • When true, filters out SpatiaLite system indexes (idx_spatial_ref_sys, idx_srid_geocols, idx_viewsjoin, idx_virtssrid, etc.)
    • Provides parity with sqlite_list_tables parameter excludeSystemTables
  • sqlite_list_tables System Table Filter — New excludeSystemTables parameter to hide SpatiaLite metadata

    • When true, filters out SpatiaLite system tables (geometry_columns, spatial_ref_sys, spatialite_history, vector_layers, etc.)
    • Reduces noise in table listings for spatial databases (38 tables → 12 user tables)
  • WASM vs Native Documentation — Added feature comparison table to ServerInstructions.ts

    • Lists FTS5, transactions, window functions, SpatiaLite, and soundex availability
    • Token-efficient format optimized for AI agent consumption
  • Polynomial Regression Supportsqlite_stats_regression now supports degree 1-3 polynomial fits

    • Linear (degree=1), quadratic (degree=2), and cubic (degree=3) regression via OLS normal equation
    • Matrix operations (transpose, multiply, Gauss-Jordan inverse) implemented in pure TypeScript
    • Output includes named coefficients (intercept, linear, quadratic, cubic) instead of generic slope
    • R² calculation uses sum of squared residuals for accurate goodness-of-fit measurement
    • Equation string displays polynomial terms (e.g., y = 2.0000x² + 3.0000x + 5.0000)
  • WASM Mode Core Tool Compatibility — Fixed issues discovered during WASM mode testing

    • server_health now correctly reports filePath from connectionString when filePath is not set
    • sqlite_list_tables now gracefully handles FTS5 virtual tables in WASM mode (sql.js lacks FTS5 module)
    • FTS5 shadow tables (_fts_*) are automatically skipped in table listings
    • Tables that fail PRAGMA table_info() are skipped rather than failing the entire operation
    • COUNT(*) errors on virtual tables return rowCount: 0 instead of throwing
  • MCP Resource Template Registration — Fixed sqlite_table_schema templated resource not matching client requests

    • Updated registerResource() in NativeSqliteAdapter to detect URI templates (containing {param} placeholders)
    • Template resources now use MCP SDK's ResourceTemplate class for proper URI matching
    • Static resources continue using simple string URI registration
    • Allows clients to request resources like sqlite://table/test_products/schema and have them matched correctly
  • Missing getAllIndexes() Method — Added getAllIndexes() to NativeSqliteAdapter

    • Required by sqlite_indexes resource but was missing in native adapter
    • Returns all user-created indexes with table name, column list, and uniqueness info
    • Queries sqlite_master and PRAGMA index_info() for complete index metadata
  • PRAGMA Compile Options Filtersqlite_pragma_compile_options now supports filter parameter

    • Case-insensitive substring match to limit returned options (e.g., filter: "FTS" returns only FTS-related options)
    • Reduces payload size for targeted queries (58 options → filtered subset)
  • Database Stats Summarize Modesqlite_dbstat now supports summarize parameter

    • When summarize: true, returns aggregated per-table stats instead of raw page-level data
    • Summary includes: pageCount, totalPayload, totalUnused, totalCells, maxPayload per table
    • Reduces response size (27 rows → 1 row per table) while providing actionable storage metrics
  • Stats Tool Column Selectionsqlite_stats_top_n now supports selectColumns parameter

    • Limits returned columns to only those specified (reduces payload size for large tables)
    • Default behavior unchanged: returns all columns when selectColumns is not provided
    • Columns are validated and sanitized for SQL injection protection
  • FTS5 Auto-Sync Triggerssqlite_fts_create now automatically creates sync triggers

    • INSERT/UPDATE/DELETE triggers keep FTS5 index synchronized with source table in real-time
    • New createTriggers option (default: true) to control trigger creation
    • FTS tables are automatically populated with existing data on creation via rebuild
    • Trigger naming convention: {ftsTable}_ai (insert), {ftsTable}_ad (delete), {ftsTable}_au (update)
    • Response includes triggersCreated array listing created trigger names
  • FTS5 Wildcard Query Supportsqlite_fts_search now supports list-all queries

    • Query * or empty string returns all FTS table contents without MATCH filtering
    • Useful for browsing FTS index contents or debugging FTS configuration
    • Returns rows ordered by rowid with rank: null
  • Phonetic Match Verbosity Controlsqlite_phonetic_match now supports includeRowData option

    • New includeRowData parameter (default: true) to control full row data inclusion
    • Set to false for compact responses with only value and phoneticCode per match
    • Backward compatible: existing calls behave identically
  • SQLite Extension Support — Added CLI flags and configuration for loadable SQLite extensions

    • --csv flag to load CSV extension for CSV virtual tables
    • --spatialite flag to load SpatiaLite extension for GIS capabilities
    • CSV_EXTENSION_PATH and SPATIALITE_PATH environment variables for custom extension paths
    • Platform-aware extension binary detection (Windows/Linux/macOS)
    • README documentation for built-in vs loadable extensions with installation instructions
  • Test Infrastructure — Migrated tests to native SQLite adapter for full feature coverage

    • Added tests/utils/test-adapter.ts factory for centralized adapter instantiation
    • All 9 SQLite test files now use NativeSqliteAdapter (better-sqlite3) instead of sql.js WASM
    • FTS5 tests now execute properly (previously skipped due to WASM limitations)
  • Comprehensive Test Infrastructure — Test database setup for systematic tool group testing

    • test-server/test-database.sql: Seed data with 10 tables and 409 rows covering all 7 tool groups
    • test-server/reset-database.ps1: PowerShell script to reset database to clean state with verification
    • test-server/test-groups/: Individual test guides for each tool group (core, json, text, stats, vector, admin, geo)
    • Uses ESM-compatible Node.js scripts with better-sqlite3 for cross-platform reset
    • Test tables: products, orders, json_docs, articles, users, measurements, embeddings, locations, categories, events
  • HTTP/SSE Streaming Transport — Enhanced HTTP transport with session management and SSE

    • Stateful mode (default): Multi-session management with SSE streaming for notifications
    • Stateless mode (--stateless): Lightweight serverless-compatible mode for Lambda/Workers
    • POST /mcp: JSON-RPC requests with session management
    • GET /mcp: SSE stream for server-to-client notifications
    • DELETE /mcp: Session termination endpoint
    • Enhanced CORS headers for mcp-session-id and Last-Event-ID
    • Health endpoint reports active session count and transport mode
  • Business Insights Memo — New tool and resource for capturing analysis insights

    • sqlite_append_insight tool: Add business insights discovered during data analysis
    • memo://insights resource: Synthesized memo of all captured insights
    • Insights manager singleton for in-memory insight storage
  • Summarize Table Prompt — Intelligent table analysis workflow

    • sqlite_summarize_table prompt with configurable analysis depth
    • Supports basic, detailed, and comprehensive analysis modes
  • Advanced Search Tool — Multi-mode text search

    • sqlite_advanced_search tool combining exact, fuzzy (Levenshtein), and phonetic (Soundex) matching
    • Configurable threshold and technique selection
  • Hybrid Search Workflow Prompt — Combined FTS5 + vector search

    • sqlite_hybrid_search_workflow prompt for hybrid search implementation
    • Guides through schema setup, query structure, and weight tuning
  • Interactive Demo Prompt — Flagship MCP demonstration

    • sqlite_demo prompt for interactive capability walkthrough
    • Guides through data creation, querying, and insight capture
  • MCP Progress Notifications (2025-11-25) — Real-time progress updates for long-running operations

    • New src/utils/progress-utils.ts module with sendProgress() and buildProgressContext() utilities
    • Extended RequestContext interface with optional server and progressToken fields
    • sqlite_restore: 3-phase progress (prepare → restore → verify)
    • sqlite_optimize: Dynamic multi-phase progress (start → reindex → analyze → complete)
    • sqlite_vacuum: 2-phase progress (start → complete)
    • Notifications are best-effort and require client support for progressToken in _meta
  • Modern Tool Registration — Migrated from deprecated server.tool() to server.registerTool() API

    • Both SqliteAdapter and NativeSqliteAdapter now use modern pattern
    • Full inputSchema/outputSchema passed (not just .shape)
    • MCP 2025-11-25 structuredContent returned when outputSchema is present
    • Progress token extraction from extra._meta enables progress notifications
    • Removed all eslint-disable comments for deprecated API usage
  • Metadata Caching Pattern — TTL-based schema caching ported from mysql-mcp

    • New SchemaManager.ts module with configurable cache TTL (default: 5s)
    • Schema, tables, and indexes cached to reduce repeated introspection queries
    • Auto-invalidation on DDL operations (CREATE/ALTER/DROP) in all query methods
    • Fixed N+1 query pattern in sqlite://indexes resource
    • ToolFilter caching for O(1) tool group lookups
    • METADATA_CACHE_TTL_MS environment variable for tuning (documented in README)
  • SpatiaLite Geospatial Tools (Native-only) — 7 new tools for GIS capabilities

    • sqlite_spatialite_load — Load SpatiaLite extension
    • sqlite_spatialite_create_table — Create tables with geometry columns
    • sqlite_spatialite_query — Execute spatial SQL (ST_Distance, ST_Within, etc.)
    • sqlite_spatialite_analyze — Spatial analysis (nearest neighbor, point-in-polygon)
    • sqlite_spatialite_index — Create/manage spatial R-Tree indexes
    • sqlite_spatialite_transform — Geometry operations (buffer, union, intersection)
    • sqlite_spatialite_import — Import WKT/GeoJSON data
    • Tools gracefully fail with helpful error if SpatiaLite extension not installed
  • Geo Tool Group — New dedicated group for geospatial tools

    • Moved 4 Haversine-based geo tools from admin to geo group
    • SpatiaLite tools also in geo group (7 Native-only tools)
    • New spatial shortcut: Core + Geo + Vector (23 WASM / 30 Native tools)
    • 7 tool groups now available (was 6)
  • Admin/PRAGMA Tools — Added 8 new database administration tools (100 total)

    • sqlite_restore: Restore database from backup file
    • sqlite_verify_backup: Verify backup file integrity without restoring
    • sqlite_index_stats: Get detailed index statistics with column info
    • sqlite_pragma_compile_options: List SQLite compile-time options
    • sqlite_pragma_database_list: List all attached databases
    • sqlite_pragma_optimize: Run PRAGMA optimize for performance tuning
    • sqlite_pragma_settings: Get or set PRAGMA values
    • sqlite_pragma_table_info: Get detailed table column metadata
  • MCP Tool Annotations (2025-11-25 spec) — Added behavioral hints to all 73 tools

    • readOnlyHint: Indicates read-only tools (SELECT queries, schema inspection)
    • destructiveHint: Warns about irreversible operations (DROP, DELETE, TRUNCATE)
    • idempotentHint: Marks safe-to-retry operations (CREATE IF NOT EXISTS)
    • Annotation presets in src/utils/annotations.ts: READ_ONLY, WRITE, DESTRUCTIVE, IDEMPOTENT, ADMIN
    • Helper functions: readOnly(), write(), destructive(), idempotent(), admin()
  • MCP Resource Annotations (2025-11-25 spec) — Added metadata hints to all 7 resources

    • audience: Intended consumer (user, assistant, or both)
    • priority: Display ordering hint (0-1 range)
    • lastModified: ISO 8601 timestamp for cache invalidation
    • Annotation presets in src/utils/resourceAnnotations.ts: HIGH_PRIORITY, MEDIUM_PRIORITY, LOW_PRIORITY
  • Whitelist-Style Tool Filtering — Enhanced tool filtering to match postgres-mcp syntax

    • Whitelist mode: Specify only the groups you want (e.g., core,json,text)
    • Shortcuts: Predefined bundles (starter, analytics, search, spatial, minimal, full)
    • Mixed mode: Combine whitelist with exclusions (e.g., starter,-fts5)
    • Backward compatible: Legacy exclusion syntax (-vector,-geo) still works
    • See README "Tool Filtering" section for documentation
  • ServerInstructions for AI Agents — Added automated instruction delivery to MCP clients

    • New src/constants/ServerInstructions.ts with tiered instruction levels (essential/standard/full)
    • Instructions automatically passed to MCP server during initialization
    • Includes usage examples for JSON, Vector, FTS5, Stats, Geo, Window Functions, and Transactions
    • Following patterns from memory-journal-mcp and postgres-mcp
  • MCP Enhanced Logging — Full MCP protocol-compliant structured logging

    • RFC 5424 severity levels: debug, info, notice, warning, error, critical, alert, emergency
    • Module-prefixed error codes (e.g., DB_CONNECT_FAILED, AUTH_TOKEN_INVALID)
    • Structured log format: [timestamp] [LEVEL] [MODULE] [CODE] message {context}
    • Module-scoped loggers via logger.forModule() and logger.child()
    • Sensitive data redaction for OAuth 2.1 configuration fields
    • Stack trace inclusion for error-level logs with sanitization
    • Log injection prevention via control character sanitization
  • Initial repository setup

  • Project documentation (README, CONTRIBUTING, CODE_OF_CONDUCT, SECURITY)

  • GitHub workflows (CodeQL, Dependabot)

  • Issue and PR templates

Changed

  • ServerInstructions.ts Admin Tool Documentation — Improved admin tool documentation clarity

    • sqlite_dbstat: Clarified JS fallback provides counts only (not per-table stats); updated WASM vs Native table
    • sqlite_pragma_compile_options: Added note that WASM may show FTS3, not FTS5
    • R-Tree and CSV tools: Clarified these return graceful errors with wasmLimitation: true in WASM mode
  • ServerInstructions.ts Text Tool Documentation — Improved fuzzy_match and phonetic_match examples

    • Clarified tokenize behavior: tokenize:false for full-string matching vs default token mode
    • Added includeRowData:false tip for phonetic matching to reduce payload size
    • Fixed example search term ("laptop" instead of "laptp" for clearer demonstration)
  • sqlite_dbstat Response Field Naming — Renamed response fields for clarity when using summarize: true

    • Changed tableCount to objectCount and tables to objects
    • dbstat returns storage stats for all database objects (tables and indexes), not just tables
    • More accurately reflects the actual content of the response
  • sqlite_spatialite_transform Adaptive Buffer Simplification — Buffer tolerance now scales with buffer distance

    • Default tolerance changed from fixed 0.0001 to adaptive max(0.0001, distance * 0.01)
    • Larger buffers (e.g., 0.1 degrees) now produce ~50 vertices instead of 96+ for more compact WKT
    • Smaller buffers retain precision with the 0.0001 floor
  • sqlite_index_stats System Index Filter — New excludeSystemIndexes parameter to hide SpatiaLite system indexes

    • When true (default), filters out SpatiaLite system indexes (idx_spatial_ref_sys, idx_srid_geocols, idx_viewsjoin, idx_virtssrid)
    • Provides parity with sqlite_dbstat and sqlite_list_tables system table filtering
    • Set to false to include all indexes
  • sqlite_pragma_compile_options Description — Enhanced tool description to mention filter parameter

    • Description now notes "Use the filter parameter to reduce output (~50+ options by default)"
    • Helps agents know upfront how to avoid large payloads
  • sqlite_dbstat Parameter Clarification — Updated excludeSystemTables description for accuracy

    • Description now clarifies it filters "SpatiaLite system tables and indexes" (not just tables)
    • Reflects actual filtering behavior which includes SpatiaLite indexes in dbstat output
  • sqlite_dbstat FTS5 Shadow Table Filtering — Now filters FTS5 shadow tables when excludeSystemTables: true

    • Previously excludeSystemTables only filtered SpatiaLite system tables/indexes
    • Now also filters FTS5 shadow tables (*_fts_data, *_fts_config, *_fts_docsize, *_fts_idx, etc.)
    • Applies to both summarize mode and raw page-level mode
  • JSON Tool Naming Consistency — Renamed sqlite_analyze_json_schema to sqlite_json_analyze_schema

    • Aligns with the sqlite_json_* prefix pattern used by all other tools in the JSON group
    • Updated ToolConstants.ts, ServerInstructions.ts, json-helpers.ts, and output-schemas.ts
  • ServerInstructions.ts Core Tools Documentation — Removed confusing sqlite_list_views reference from sqlite_list_tables description

    • sqlite_list_views is in the admin group, not core; reference was misleading in core tools table
    • Simplified description to: "List tables with column counts (excludeSystemTables hides SpatiaLite tables)"
  • Modern MCP SDK API Migration — Removed all eslint-disable comments

    • McpServer.ts: Migrated built-in tools (server_info, server_health, list_adapters) from deprecated server.tool() to server.registerTool() API
    • SqliteAdapter.ts and NativeSqliteAdapter.ts: Migrated from deprecated server.resource() and server.prompt() to modern server.registerResource() and server.registerPrompt() APIs
    • middleware.ts: Replaced global namespace extension with proper Express module augmentation pattern (declare module "express-serve-static-core")
    • progress-utils.ts: Replaced deprecated Server type import with structural interface (NotificationSender)
    • logger.ts: Replaced control character regex literals with dynamically constructed RegExp using String.fromCharCode() to satisfy no-control-regex rule
  • sqlite_generate_series Pure JS Implementation — Removed unnecessary native SQLite attempt

    • better-sqlite3's bundled SQLite lacks SQLITE_ENABLE_SERIES compile option
    • Native generate_series() virtual table was always failing, wasting a database call
    • Now generates directly in JavaScript, eliminating the failed native attempt overhead
  • ServerInstructions.ts sqlite_stats_top_n Documentation — Strengthened payload optimization guidance

    • Changed comment from passive note to explicit ⚠️ warning: "Always use selectColumns to avoid returning all columns (large payloads with text fields)"
    • Emphasizes importance of column selection to reduce token usage
  • sqlite_json_normalize_column Default Behavior — Changed default outputFormat from text to preserve

    • Prevents accidental JSONB-to-text conversion when normalizing columns that were previously converted to JSONB
    • Use explicit outputFormat: "text" when text output is specifically needed
  • ServerInstructions.ts sqlite_json_each Payload Warning — Added explicit warning about output row multiplication

    • Comment now reads: "Note: json_each multiplies output rows—use limit param for large arrays"
    • Example updated to include limit: 50 parameter to demonstrate payload control
  • ServerInstructions.ts SpatiaLite Analyze Documentation — Improved tool documentation clarity

    • Added explicit analysisType options: spatial_extent | point_in_polygon | nearest_neighbor | distance_matrix
    • Documented excludeSelf parameter for same-table nearest_neighbor/distance_matrix queries
    • Added note clarifying that distances are returned in Cartesian (degrees), not geodetic (km/miles)
  • sqlite_drop_virtual_table Regular Table Validation — Now validates target is actually a virtual table

    • Returns helpful error message if attempting to drop a regular table, directing to use sqlite_drop_table instead
    • Prevents accidental misuse of virtual table drop tool on regular tables
  • sqlite_dbstat WASM Fallback Enhancement — Added table count to basic stats in WASM mode

    • When dbstat virtual table is unavailable, now returns tableCount in addition to pageCount
    • Provides more useful context about database contents
  • CSV Tool Messages WASM Clarity — Improved error messages for sqlite_create_csv_table and sqlite_analyze_csv_schema

    • When running in WASM mode, now explicitly states "CSV extension not available in WASM mode"
    • Previously showed generic message about loading extension, which was misleading in WASM context
    • wasmLimitation flag is now dynamic based on actual runtime environment
  • ServerInstructions.ts CSV Documentation — Added WASM limitation note to CSV tool examples

    • Comment now reads "Native only - not available in WASM" for clarity
  • ServerInstructions.ts sqlite_list_tables Documentation — Clarified that views are listed via sqlite_list_views

    • Updated description to note that views require sqlite_list_views from admin group
  • sqlite_vector_search Payload Optimization — Vector data now excluded from results when not explicitly requested

    • When returnColumns is specified without the vector column, results omit vector data for smaller payloads
    • Reduces response size significantly for high-dimensional vectors (e.g., 384+ dimensions)
    • Vector data still included when returnColumns is empty or explicitly includes the vector column
  • ServerInstructions.ts Vector Tool Documentation — Expanded vector section with all 11 tool examples

    • Added missing tools: sqlite_vector_batch_store, sqlite_vector_get, sqlite_vector_delete, sqlite_vector_count, sqlite_vector_dimensions
    • Added documentation note about returnColumns payload optimization
  • ServerInstructions.ts Admin Tool Documentation — Expanded Database Administration section with all admin tool examples

    • Added 20+ missing examples: views (sqlite_create_view/drop_view/list_views), virtual tables, backup/restore/verify
    • Added PRAGMA utilities (sqlite_pragma_compile_options/database_list/optimize), sqlite_index_stats, sqlite_dbstat
    • Added sqlite_generate_series, sqlite_create_series_table, sqlite_create_rtree_table, sqlite_append_insight
  • sqlite_pragma_database_list Configured Path Visibility — Added configuredPath field to output

    • WASM mode shows internal virtual filesystem paths (e.g., /dbfile_3503536817) which can confuse users
    • Now includes configuredPath showing the user's original database file path
    • Adds explanatory note when internal path differs from configured path
  • Dependency Updates — Updated npm dependencies to latest versions

    • @types/node: 25.1.0 → 25.2.0
    • globals: 17.2.0 → 17.3.0
    • pg: 8.17.2 → 8.18.0
  • ServerInstructions.ts FTS5 Documentation — Added note that FTS5 virtual tables and shadow tables are hidden from sqlite_list_tables for cleaner output

  • sqlite_fuzzy_match Token-Based Matching — Now matches against word tokens by default instead of entire column value

    • New tokenize parameter (default: true) splits column values into words for per-token comparison
    • "laptop" now matches "Laptop Pro 15" (distance 0 on first token)
    • Output includes matchedToken and tokenDistance for transparency
    • Set tokenize: false to restore legacy behavior (match entire column value)
    • Removed full row data from output for token efficiency (just value and match info)
    • Updated ServerInstructions.ts documentation with new behavior
  • ServerInstructions.ts generate_series Documentation — Clarified JS fallback behavior

    • Changed WASM vs Native table entry from "✅ native | ❌ | JS" to "JS fallback | JS fallback | —"
    • The generate_series extension is not compiled into SQLite, so both environments use the JavaScript fallback
  • sqlite_phonetic_match Documentation — Updated matching behavior description

    • Changed from "compares FIRST word only" to "matches against any word in value"
  • sqlite_json_keys Documentation — Clarified distinct key behavior

    • Updated description to note tool returns unique keys across all matching rows, not per-row keys
  • ServerInstructions.ts Stats Group Documentation — Clarified window function grouping

    • Line 70: Changed "Window functions (6 tools)" to "Window functions (6 tools in stats group)"
    • Line 89: Changed "Stats(13-19)" to "Stats(19: 13 core + 6 window)" for clearer tool count breakdown
  • CSV Tools Path Validation — Improved error messages for sqlite_create_csv_table and sqlite_analyze_csv_schema

    • Now validates that file paths are absolute before attempting to create virtual table
    • Returns helpful error message with suggested absolute path when relative path is provided
    • Example: "Relative path not supported. Please use an absolute path. Example: C:\\path\\to\\file.csv"
  • ServerInstructions.ts FTS5 Documentation — Fixed incomplete FTS5 example

    • Added required sqlite_fts_rebuild call after sqlite_fts_create (indexes are empty until rebuild)
    • Fixed parameter names: tabletableName/sourceTable to match actual tool schema
    • Added clarifying comment explaining that triggers sync future changes but don't populate existing data
  • sqlite_list_tables Documentation — Updated tool description in ServerInstructions.ts

    • Now mentions excludeSystemTables parameter for filtering SpatiaLite metadata
  • ServerInstructions.ts SpatiaLite Tool Count — Improved documentation clarity

    • Changed "SpatiaLite GIS (7 of 11 geo tools)" to "SpatiaLite GIS (7 tools; 4 basic geo always work)"
    • Clarifies that 7 tools require SpatiaLite while 4 basic Haversine-based tools work in any mode
  • sqlite_json_normalize_column JSONB Conversion Consistency — JSONB rows now always converted to normalized text format

    • Previously, JSONB rows with already-normalized content were left unchanged (still in JSONB binary format)
    • Handler now detects original storage format and forces text output for all JSONB rows
    • Ensures uniform text JSON format after normalization, avoiding mixed format scenarios
  • sqlite_stats_hypothesis Chi-Square Validation — Added validation for insufficient categories

    • Chi-square test now throws descriptive error when df=0 (fewer than 2 categories in either column)
    • Previously returned mathematically meaningless results (p=1, df=0) without warning
    • Error message includes actual category counts for both columns to help users diagnose the issue
  • sqlite_json_storage_info Mixed Format Recommendation — Fixed misleading recommendation when column has both text and JSONB rows

    • Now detects mixed format scenarios and recommends running sqlite_jsonb_convert to unify storage
    • Previously reported "Column already uses JSONB format" even when 50% of rows were still text JSON
  • sqlite_spatialite_transform Buffer Auto-Simplification — Buffer operation now auto-simplifies output by default

    • Reduces verbose WKT payload from ~2KB (64-point circle) to ~200 bytes
    • Default tolerance 0.0001 is suitable for lat/lon coordinates
    • Set simplifyTolerance: 0 to disable auto-simplification for full precision output
    • Updated ServerInstructions.ts with clarified documentation on distance parameter usage
  • sqlite_transaction_execute SELECT Row Data — SELECT statements now return actual row data

    • Results include rowCount and rows fields for SELECT statements instead of just rowsAffected: 0
    • Enables read-modify-read patterns within atomic transactions
    • Write statements continue to return rowsAffected as before
  • sqlite_dbstat Limit Parameter — Added configurable limit parameter (default: 100)

    • Controls maximum number of tables/pages returned in both summarized and raw modes
    • Helps reduce payload size for large databases
    • Previously hardcoded to 100; now user-configurable
  • sqlite_fuzzy_match Documentation — Clarified that Levenshtein distance is computed against entire column values

    • Updated description to note comparison is against whole values, not word tokens
    • Added guidance to use maxDistance 1-3 for similar-length strings
    • This is expected behavior; documentation now makes it explicit
  • sqlite_advanced_search Parameter Guidance — Added threshold tuning guidance for fuzzyThreshold

    • Parameter description now includes: "0.3-0.4 for loose matching, 0.6-0.8 for strict matching"
    • Added inline example: "e.g., 'laptob' matches 'laptop'"
    • Helps users understand how to tune the similarity threshold for their use case
  • ServerInstructions.ts Stats Tool Documentation — Added selectColumns example for sqlite_stats_top_n

    • Documents payload optimization pattern for retrieving only required columns
    • Helps reduce response size when querying tables with large text fields
  • ServerInstructions.ts Text Processing Documentation — Expanded TOOL_REFERENCE examples

    • Added sqlite_regex_extract example with capture groups
    • Added sqlite_text_split, sqlite_text_concat, sqlite_text_normalize examples
    • Added sqlite_phonetic_match example with soundex algorithm
    • Clarified fuzzy match behavior: "compares against ENTIRE column value, not word tokens"
    • Added fuzzyThreshold tuning guidance comment in sqlite_advanced_search example
  • sqlite_spatialite_analyze Self-Match Filtering — Added excludeSelf parameter (default: true)

    • When sourceTable equals targetTable in nearest_neighbor analysis, self-matches (distance=0) are now filtered
    • Set excludeSelf: false to include self-matches in results
    • Reduces noise in proximity analysis results
  • sqlite_spatialite_transform Buffer Simplification — Added simplifyTolerance parameter

    • Optional simplification applied to buffer operation output to reduce vertex count
    • Recommended values: 0.0001-0.001 for lat/lon coordinates
    • Reduces payload size for large buffer polygons (96+ vertices → fewer)
  • sqlite_spatialite_analyze Documentation — Improved tool description

    • Clarified that point_in_polygon requires POINTs in sourceTable and POLYGONs in targetTable
    • Updated targetTable parameter description with geometry type guidance
  • ServerInstructions.ts Vector Tool Documentation — Expanded vector section with utility tool examples

    • Added sqlite_vector_normalize, sqlite_vector_distance, and sqlite_vector_stats examples
    • Utility tools help with pre-processing embeddings before storage
  • sqlite_text_split Per-Row Output Structure — Improved output for row traceability

    • Changed from flat parts[] array to structured per-row results
    • Each row now includes rowid, original value, and parts array
    • Enables correlation between split results and source rows
  • ServerInstructions.ts WASM Tool Count — Corrected starter preset count for WASM mode

    • Changed from 48 to 44 (4 FTS5 tools unavailable in WASM)
    • Added footnote: "17 = 13 in WASM (4 FTS5 tools require native)"
  • ServerInstructions.ts JSONB Documentation — Added note that sqlite_json_normalize_column converts JSONB back to text format

    • The json() function used for normalization returns text JSON, not JSONB binary
    • Users should run sqlite_jsonb_convert after normalization if JSONB format is desired
  • ServerInstructions.ts Text Processing Documentation — Added inline comment for regex escaping clarity

    • Explains that regex patterns require double-escaping backslashes (\\\\) when passing through JSON/MCP transport
  • ServerInstructions.ts CSV Path Documentation — Added absolute path requirement note for CSV tools

    • Updated WASM vs Native table: CSV virtual tables now note "(requires absolute paths)"
    • Added CSV Virtual Tables examples to Database Administration section showing sqlite_analyze_csv_schema and sqlite_create_csv_table with absolute path usage
  • ServerInstructions.ts Statistical Analysis Examples — Added missing stats tool examples to TOOL_REFERENCE

    • Added sqlite_stats_outliers example with IQR/Z-score method options
    • Added sqlite_stats_hypothesis example with one-sample t-test usage
  • JSON Aggregation Tool Documentation — Clarified groupByColumn usage for JSON collection tables

    • Updated sqlite_json_group_array and sqlite_json_group_object parameter descriptions
    • For JSON collections, must use allowExpressions: true with json_extract(data, '$.field') for groupByColumn
    • Updated ServerInstructions.ts examples to show both regular table and JSON collection patterns
  • Tool Count Documentation Accuracy — Fixed tool counts across all documentation files

    • text group: 16 → 17 (added fuzzy_match, phonetic_match, text_normalize, text_validate, advanced_search, fts_rebuild, fts_match_info)
    • admin group: 32 → 33
    • starter preset: 47 → 48
    • search preset: 35 → 36
    • full preset: 120 → 122 Native, 100 → 102 WASM
    • Updated ToolConstants.ts, ServerInstructions.ts, and README.md
  • ServerInstructions.ts Text Processing Examples — Updated TOOL_REFERENCE section

    • Fixed sqlite_fuzzy_search example to correct tool name sqlite_fuzzy_match with proper parameters
    • Replaced generic sqlite_text_similarity example with practical sqlite_text_validate (email/phone/url/uuid/ipv4)
    • Added sqlite_advanced_search example demonstrating multi-technique search (exact/fuzzy/phonetic)
  • ServerInstructions.ts Documentation Improvements — Updated tool filtering reference for accuracy

    • Corrected tool counts to match README (was showing outdated single-column counts)
    • Added WASM/Native columns to shortcut table showing accurate counts per backend
    • Added spatial shortcut (23 WASM / 30 Native tools)
    • Added geo to groups list (was missing from documentation)
    • Added Fallback column to WASM vs Native table documenting JS fallback availability
    • Documented generate_series, dbstat, soundex JS fallbacks vs extension tools with no fallback
    • Added Database Administration examples section with 6 common admin tools
  • WASM Mode FTS5 Graceful Handling — FTS5 tools now return helpful errors instead of crashes in WASM mode

    • All 4 FTS5 tools (sqlite_fts_create, sqlite_fts_search, sqlite_fts_rebuild, sqlite_fts_match_info) detect "no such module: fts5" errors
    • Returns structured error with hint directing to native SQLite backend (--sqlite-native)
    • Prevents tool failures when running in WASM mode (sql.js) which lacks FTS5 module
  • WASM Mode Soundex Fallbacksqlite_phonetic_match now works with soundex algorithm in WASM mode

    • JavaScript-based soundex implementation used as fallback when SQLite's native soundex() function unavailable
    • Behavior matches metaphone algorithm path (fetch rows, filter in JS)
    • Same output format and accuracy as native soundex
    • Gracefully handles "no such function: soundex" error without user intervention
  • SQLite-Focused Branding — Updated project descriptions to reflect SQLite-only focus

    • package.json: Updated description and removed unused database keywords (postgresql, mysql, mongodb, redis)
    • src/cli.ts: Updated help text, removed dead CLI options and environment variable parsing for unsupported databases
    • Updated header comments in src/index.ts, src/server/McpServer.ts, src/adapters/DatabaseAdapter.ts
  • Simplified SpatiaLite Instructions — Removed manual sqlite_spatialite_load step requirement

    • SpatiaLite extension and metadata tables are now auto-initialized on first use of any spatial tool
    • Removed "IMPORTANT" warning and step numbering from ServerInstructions.ts
    • Added GeoJSON import example to instructions
  • Node.js 24 LTS Baseline — Upgraded from Node 20 to Node 24 LTS as the project baseline

    • package.json now requires Node.js >=24.0.0 in engines field
    • README prerequisites updated to specify Node.js 24+ (LTS)
    • @modelcontextprotocol/sdk: 1.24.3 → 1.25.3
    • @types/node: 25.0.2 → 25.1.0
    • better-sqlite3: 12.5.0 → 12.6.2
    • cors: 2.8.5 → 2.8.6
    • globals: 16.5.0 → 17.2.0 (major version bump)
    • pg: 8.16.3 → 8.17.2
    • typescript-eslint: 8.49.0 → 8.54.0
    • vitest: 4.0.15 → 4.0.18
    • zod: 4.1.13 → 4.3.6
  • OAuth 2.1 Implementation — Tested with Keycloak 26.4.7

    • Token validation with JWKS endpoint verified
    • Scope enforcement (read, write, admin) working correctly
    • RFC 9728 Protected Resource Metadata endpoint operational
    • Added OAuth Quick Start section to README with usage examples

Fixed

  • sqlite_vector_search returnColumns Consistency — Fixed returnColumns being ignored for euclidean/dot metrics

    • Previously, returnColumns only filtered output when using cosine similarity; euclidean and dot returned all columns
    • Now consistently applies column filtering after similarity calculation for all three metrics
    • Reduces payload size for non-cosine searches (previously ~3x larger due to full embedding vectors in output)
  • sqlite_backup WASM Consistent Error Response — Backup now returns success: false upfront in WASM mode

    • Previously, backup attempted VACUUM INTO then caught errors, leading to inconsistent behavior: sometimes succeeding to ephemeral VFS, sometimes failing on path resolution
    • Now checks isNativeBackend() first and returns {success: false, wasmLimitation: true} immediately
    • Consistent with sqlite_restore and sqlite_verify_backup which already had upfront WASM checks
    • Native mode behavior unchanged: backup still uses VACUUM INTO and returns structured errors on failure
  • Stats Tool Group Bug Fixes — Resolved 6 issues from comprehensive tool testing

    • sqlite_stats_histogram: Fixed off-by-one bucket boundary that excluded max values (now uses <= for final bucket)
    • sqlite_stats_summary: Auto-filters to numeric columns when no columns specified (prevents string min/max errors)
    • sqlite_stats_correlation: Returns null instead of NaN for invalid correlations (schema-safe)
    • sqlite_stats_hypothesis: Validates t-statistic is finite before returning (catches zero variance/non-numeric columns)
    • sqlite_stats_basic: Ensures numeric type coercion for all stat values (converts strings to numbers or null)
    • sqlite_stats_group_by: Validates both valueColumn and groupByColumn exist in table before execution
  • NativeSqliteAdapter Missing Method — Added getConfiguredPath() to match SqliteAdapter interface

    • sqlite_pragma_database_list tool was failing in native mode due to missing method
    • Now returns configured database path consistently across WASM and Native adapters
  • sqlite_dbstat Table-Specific WASM Fallback — Improved fallback when dbstat virtual table unavailable

    • Previously, the table parameter was ignored in WASM mode, returning only total database page count
    • Now provides table-specific estimates: rowCount, estimatedPages (~100 rows/page), and totalDatabasePages
    • Returns success: false with appropriate message if specified table doesn't exist
  • sqlite_drop_virtual_table Accurate Messaging — Fixed misleading success message for non-existent tables

    • Previously, dropping a non-existent table with ifExists: true reported "Dropped virtual table 'x'"
    • Now returns accurate message: "Virtual table 'x' did not exist (no action taken)"
    • Helps distinguish between actual drops and no-op operations
  • FTS5 Tools WASM Upfront Checksqlite_fts_search, sqlite_fts_rebuild, sqlite_fts_match_info now check FTS5 availability upfront

    • Previously, these tools threw raw "no such table" SQL errors in WASM mode when FTS tables couldn't be created
    • Now return graceful error response with hint before attempting any SQL execution
    • Consistent with sqlite_fts_create which already had upfront FTS5 detection
  • WASM Adapter Templated Resource Support — Fixed sqlite://table/{name}/schema resource returning "not found" in WASM mode

    • Ported ResourceTemplate handling from NativeSqliteAdapter to SqliteAdapter
    • Templated resources now properly register with MCP SDK's ResourceTemplate class
    • Both static and templated resources now work consistently across WASM and Native backends
  • Index Column Population in WASM Adapter — Fixed sqlite://indexes resource returning empty columns array

    • Added PRAGMA index_info() queries to populate column names for each index
    • Updated both SchemaManager.getAllIndexes() and SqliteAdapter.getIndexes() fallback
    • Index metadata now matches Native adapter behavior
  • sqlite_list_tables KNN2 Virtual Table — KNN2 SpatiaLite virtual table now filtered by excludeSystemTables

    • Added "KNN2" to the SpatiaLite system table exclusion list
    • Previously KNN2 was shown despite excludeSystemTables=true
  • sqlite_json_group_object Aggregate Function Support — New aggregateFunction parameter for aggregate values

    • Enables COUNT(*), SUM(amount), AVG(price), and other aggregate functions as object values
    • Uses subquery pattern to pre-aggregate results before wrapping in json_group_object()
    • Example: sqlite_json_group_object({ table: "events", keyColumn: "event_type", aggregateFunction: "COUNT(*)" })
    • allowExpressions parameter clarified: supports column extraction only, NOT aggregate functions
    • New: Returns hint warning when using allowExpressions without groupByColumn (duplicate keys may result if key values aren't unique)
  • server_health SpatiaLite Status — Health check now reports accurate SpatiaLite extension status

    • Previously hardcoded spatialite: false regardless of actual extension state
    • Now calls exported isSpatialiteLoaded() to reflect runtime extension status
    • Helps users confirm SpatiaLite is loaded before using spatial tools
  • sqlite_text_split WASM Rowid Bug — Fixed rows returning rowid: 0 for all results

    • Changed SQL query from SELECT rowid, column to SELECT rowid as id, column for consistent behavior
    • SQL.js (WASM) does not handle unaliased rowid column correctly; aliasing ensures proper value retrieval
    • Native SQLite (better-sqlite3) was unaffected, but now uses consistent query pattern
  • sqlite_list_tables FTS5 Table Visibility — FTS5 virtual tables and shadow tables now hidden

    • Virtual tables ending with _fts (e.g., articles_fts) are now filtered from output
    • Shadow tables containing _fts_ (e.g., articles_fts_config, articles_fts_data) already filtered
    • Internal FTS5 implementation details no longer clutter table listings in native mode
  • sqlite_text_validate Null Value Display — Improved accuracy for invalid null/empty values

    • Null/undefined values now display as null instead of artificial "(empty)" placeholder
    • Long values (>100 chars) are truncated with "..." for readability
  • sqlite_json_group_array and sqlite_json_group_object groupByColumn Expressions — Extended allowExpressions to also apply to groupByColumn parameter

    • Previously allowExpressions: true only bypassed validation for valueColumn/keyColumn, not groupByColumn
    • Now enables grouping by JSON path expressions like json_extract(data, '$.type')
    • When using expressions for groupByColumn, output uses group_key alias for clarity
  • sqlite_json_group_array Expression Support — Added allowExpressions option for consistency with sqlite_json_group_object

    • When allowExpressions: true, SQL expressions like json_extract(data, '$.name') are accepted for valueColumn
    • Default behavior unchanged (validates as simple column identifier for security)
    • Enables advanced aggregation patterns combining JSON extraction with grouping
  • sqlite_json_update String Value Escaping — Fixed "malformed JSON" error when updating string values

    • String values now wrapped with JSON.stringify() before SQL escaping to produce valid JSON
    • Previously 'New Title' (invalid JSON) was passed to json() instead of '"New Title"'
  • sqlite_spatialite_analyze Error Message Clarity — Improved error messages for required parameter validation

    • Changed "Target table required" to "Missing required parameter 'targetTable'" for nearest_neighbor and point_in_polygon analysis types
    • Clearer messaging helps users identify which parameter they need to provide
  • sqlite_json_group_array and sqlite_json_group_object Column Naming — Fixed quoted identifier names appearing in output

    • When using groupByColumn, the result column was showing "type" (with escaped quotes) instead of type
    • Added explicit column aliases (e.g., "type" AS type) to produce clean column names in output
    • Affects both tools when groupByColumn is specified
  • sqlite_dbstat Page Count Inconsistency — Fixed JS fallback returning inconsistent page counts

    • Properly extracts page_count from PRAGMA result (handles both named and indexed column access)
    • Ensures consistent numeric return value via explicit type coercion
  • False WASM Limitation Detection in Native Mode — Fixed backup/restore/verify tools incorrectly reporting WASM limitations when running in native mode

    • Added isNativeBackend() method to both SqliteAdapter (returns false) and NativeSqliteAdapter (returns true)
    • sqlite_backup, sqlite_restore, sqlite_verify_backup now only return wasmLimitation: true when actually running in WASM mode
    • sqlite_restore now attempts to recreate virtual tables (FTS5, R-Tree) in native mode instead of unconditionally skipping them
    • In native mode, actual file system errors are now properly thrown instead of being masked as WASM limitations
  • sqlite_create_table SQL Expression Default Values — Fixed syntax error when using SQL expressions as default values

    • Expressions like datetime('now'), CURRENT_TIMESTAMP, CURRENT_DATE, CURRENT_TIME now wrapped in parentheses
    • Literal string values continue to be properly single-quoted with escape handling for embedded quotes
    • Added regex detection for function calls (pattern function_name(...)) and SQL keywords
  • JSONB Normalize Corruption Fix — Fixed sqlite_json_normalize_column corrupting JSONB columns

    • Changed query to use json(${column}) SQL function to convert JSONB binary to text before JavaScript processing
    • Previously, JSONB binary blobs were being serialized as numbered-key objects ({"0":204,"1":95,...})
    • Now properly handles both text JSON and JSONB binary format without data loss
  • ServerInstructions.ts Core Tools Table — Added missing tools to documentation

    • Added sqlite_drop_table and sqlite_get_indexes to Core Tools table (was only showing 6 of 8 tools)
  • WASM Mode Admin Tool Graceful Handling — 4 admin tools now return structured errors instead of throwing in WASM mode

    • sqlite_virtual_table_info: Returns moduleAvailable: false with partial metadata when module unavailable (e.g., FTS5)
    • sqlite_backup: Returns wasmLimitation: true when file system access unavailable
    • sqlite_restore: Returns wasmLimitation: true when file system access unavailable
    • sqlite_verify_backup: Returns wasmLimitation: true when file system access unavailable
    • Added wasmLimitation field to BackupOutputSchema, RestoreOutputSchema, VerifyBackupOutputSchema
    • Updated ServerInstructions.ts WASM vs Native table with backup/restore, R-Tree, CSV limitations
  • Restore Tool Security Bypasssqlite_restore now bypasses SQL validation for internal operations

    • Added skipValidation optional parameter to executeWriteQuery() method signature
    • Internal restore operations (ATTACH, DROP, CREATE, INSERT, DETACH, PRAGMA) pass skipValidation=true
    • Prevents false-positive "dangerous patterns" errors from internal SQL comments or multi-statement patterns
    • Security remains intact: bypass only applies to trusted internal operations, not user-provided queries
  • WASM Mode R-Tree/CSV/Restore Graceful Handling — 4 additional admin tools now return structured errors instead of throwing

    • sqlite_create_rtree_table: Returns success: false with wasmLimitation: true when R-Tree module unavailable
    • sqlite_analyze_csv_schema: Returns success: false with wasmLimitation: true when CSV extension not loaded
    • sqlite_create_csv_table: Returns success: false with wasmLimitation: true when CSV extension not loaded
    • sqlite_restore: Now skips virtual tables with unavailable modules (FTS5, R-Tree) instead of failing entire restore
    • Added skippedTables and note fields to RestoreOutputSchema for partial restore reporting
  • SpatiaLite Analyze WKT Output — Fixed sqlite_spatialite_analyze binary geometry output

    • nearest_neighbor and point_in_polygon analysis types now return WKT via AsText() instead of raw binary blobs
    • Changed from s.* wildcard select to explicit source_id, source_geom, target_id, target_geom columns
    • Reduces payload size and improves readability (binary arrays → human-readable WKT strings)
  • Restore Virtual Table Handling — Fixed sqlite_restore failing with virtual table shadow tables

    • Added pre-restore phase to drop existing virtual tables before attempting restore
    • Virtual table deletion automatically cleans up associated shadow tables (R-Tree: _node, _rowid, _parent)
    • Excludes R-Tree shadow tables from copy list in addition to FTS5 shadow tables
    • Prevents "may not be dropped" error when backup contains virtual table artifacts
  • Custom Regex Validation Double-Escaping Fix — Fixed sqlite_text_validate custom pattern handling

    • Normalizes double-escaped backslashes (\\\\\\) from JSON transport
    • Patterns like .*@.*\.com$ now work correctly as expected
    • Added error message with both original and normalized pattern for debugging invalid regex
  • JSON Each Ambiguous Column Fix — Fixed sqlite_json_each "ambiguous column name: id" error

    • Added table alias (t) and CROSS JOIN syntax to prevent column name conflicts with json_each() TVF output
    • json_each() returns columns: key, value, type, atom, id, parent, fullkey, path
    • Source table columns (especially id) now properly qualified with table alias
    • Added automatic id =t.id = rewriting for user-provided WHERE clauses
    • Updated JsonEachOutputSchema to include optional row_id field for row identification
  • JSON Group Object Expression Support — Added allowExpressions option to sqlite_json_group_object

    • When allowExpressions: true, SQL expressions like json_extract(data, '$.name') are accepted for keyColumn and valueColumn
    • Default behavior unchanged (validates as simple column identifiers for security)
  • JSONB Text Serialization Fix — Fixed sqlite_json_select returning binary Buffer for JSONB data

    • Wrapped column selection with json() function to convert JSONB binary to readable text JSON
    • Works seamlessly with both text JSON (no-op) and JSONB (converts to text)
    • API consumers now receive readable JSON instead of raw binary buffers
  • JSONB Schema Analysis Fix — Fixed sqlite_analyze_json_schema returning byte indexes for JSONB columns

    • Wrapped column with json() function to decode JSONB binary before schema inference
    • Was returning numeric keys (0, 1, 2, ..., 100) representing blob bytes instead of actual JSON structure
    • Now correctly infers object properties, types, and nullability for JSONB-formatted data
  • Core Tool Bug Fixes — Resolved 3 issues discovered during comprehensive MCP tool testing

    • sqlite_describe_table now correctly returns an error for non-existent tables (was returning success: true with empty columns)
    • sqlite_write_query and other query methods now auto-convert boolean parameters (true/false) to integers (1/0) since SQLite doesn't have native boolean type
    • sqlite_create_table message now accurately indicates when table already exists (using IF NOT EXISTS): "Table 'x' already exists (no changes made)"
    • sqlite_list_tables now correctly returns columnCount for each table (was always returning 0 in native adapter because PRAGMA table_info() was not being called)
  • JSON Path Column Naming — Fixed column naming in json_select and json_query tools

    • Columns now use meaningful names extracted from JSONPath expressions (e.g., $.user.emailemail)
    • Was returning generic indexed names (path_0, result_0)
    • Added extractColumnNameFromPath() and getUniqueColumnNames() helpers in json-helpers.ts
    • Duplicate path segments get numeric suffixes (e.g., name, name_2)
  • Text Tool Output Schema Fixes — Fixed 6 tools with output validation errors

    • sqlite_regex_extract: Added safe rowid coercion (Number/String/undefined → Number) to prevent NaN in output
    • sqlite_regex_match: Added safe rowid coercion (Number/String/undefined → Number) to prevent NaN in output
    • sqlite_text_split: Changed rowCount/results to parts/count to match schema
    • sqlite_advanced_search: Fixed NaN bug when coercing rowid to number
    • sqlite_fts_create: Changed sql to tableName in response to match schema
    • sqlite_fts_rebuild: Added missing tableName field to response
  • Text Tool Bug Fixes — Resolved issues discovered during comprehensive MCP tool testing

    • sqlite_text_concat: Fixed SQL generation to use || operator for concatenation (was generating comma-separated SELECT which only returns last column)
    • sqlite_regex_extract, sqlite_regex_match, sqlite_advanced_search: Fixed rowid extraction by aliasing rowid as id in SQL queries (was returning 0 for all rows)
    • sqlite_phonetic_match: Fixed empty searchCode for soundex algorithm by computing locally upfront (was only extracting from matches, returning empty when no matches found)
  • Test Database FTS5 Table — Added pre-built FTS5 table for testing

    • test_articles_fts: FTS5 virtual table indexing test_articles (title, body)
    • Updated test-database.sql to create and populate the FTS index
    • Updated reset-database.md documentation with new table
  • JSONB Support in Native Adapter — Fixed JSONB detection missing in NativeSqliteAdapter

    • NativeSqliteAdapter.connect() now detects SQLite version and sets JSONB support flag
    • sqlite_jsonb_convert and other JSONB tools now work correctly with better-sqlite3 backend
    • better-sqlite3 includes SQLite 3.51.2 which fully supports JSONB (requires 3.45+)
  • JSONB-Compatible Collection Tables — Updated sqlite_create_json_collection CHECK constraint

    • Changed from CHECK(json_valid("data")) to CHECK(json_type("data") IS NOT NULL)
    • json_valid() only works on text JSON; json_type() works on both text and JSONB formats
    • Collections can now store JSONB data after sqlite_jsonb_convert
  • JSON Tool Output Schema Fixes — Fixed 6 tools with output validation errors

    • sqlite_json_keys: Added missing rowCount field and fixed keys array type
    • sqlite_json_group_array: Changed results to rows to match schema
    • sqlite_json_group_object: Changed results to rows to match schema
    • sqlite_jsonb_convert: Created dedicated JsonbConvertOutputSchema
    • sqlite_json_storage_info: Created dedicated JsonStorageInfoOutputSchema
    • sqlite_json_normalize_column: Created dedicated JsonNormalizeColumnOutputSchema
    • Added JsonPrettyOutputSchema for sqlite_json_pretty
    • Updated ToolConstants.ts with correct list of all 23 JSON tool names
  • Stats Tool Output Schema Fixes — Fixed 8 tools with output validation errors

    • Created dedicated output schemas: StatsBasicOutputSchema, StatsCountOutputSchema, StatsGroupByOutputSchema, StatsTopNOutputSchema, StatsDistinctOutputSchema, StatsSummaryOutputSchema, StatsFrequencyOutputSchema
    • Updated StatsPercentileOutputSchema to support array of percentiles (was single value)
    • Updated StatsHistogramOutputSchema with optional range, bucketSize, and bucket fields
    • Updated StatsCorrelationOutputSchema with optional n and message fields
    • Tools fixed: sqlite_stats_basic, sqlite_stats_count, sqlite_stats_group_by, sqlite_stats_percentile, sqlite_stats_top_n, sqlite_stats_distinct, sqlite_stats_summary, sqlite_stats_frequency
  • Vector Tool Output Schema Fixes — Fixed 10 tools with output validation errors

    • Created dedicated output schemas: VectorStoreOutputSchema, VectorBatchStoreOutputSchema, VectorGetOutputSchema, VectorDeleteOutputSchema, VectorCountOutputSchema, VectorStatsOutputSchema, VectorDimensionsOutputSchema, VectorNormalizeOutputSchema, VectorDistanceOutputSchema
    • Updated VectorSearchOutputSchema to match handler return structure (metric, count, results with _similarity)
    • Tools fixed: sqlite_vector_store, sqlite_vector_batch_store, sqlite_vector_get, sqlite_vector_search, sqlite_vector_delete, sqlite_vector_count, sqlite_vector_stats, sqlite_vector_dimensions, sqlite_vector_normalize, sqlite_vector_distance
  • Admin Tool Bug Fixes — Fixed 4 tools with output schema and logic errors

    • sqlite_create_view: Fixed syntax error by using DROP+CREATE pattern (SQLite doesn't support CREATE OR REPLACE VIEW)
    • sqlite_list_views: Created dedicated ListViewsOutputSchema (was using ListTablesOutputSchema expecting tables instead of views)
    • sqlite_optimize: Added required message field to handler return object
    • sqlite_restore: Fixed PRAGMA query that caused "no such table: 1" error (simplified to PRAGMA integrity_check(1))
  • Geo Tool Output Schema Fixes — Fixed 3 tools with output validation errors

    • sqlite_geo_nearby: Changed count field to rowCount, removed extra metadata fields
    • sqlite_geo_bounding_box: Changed count field to rowCount, removed extra metadata fields
    • sqlite_geo_cluster: Restructured return to match schema with clusterId, center: {latitude, longitude}, pointCount
  • SpatiaLite Windows DLL Loading — Fixed extension loading on Windows

    • Added runtime PATH modification to prepend SpatiaLite directory before loadExtension() call
    • Windows requires dependency DLLs (libgeos, libproj, etc.) to be discoverable via PATH
    • Applied to both NativeSqliteAdapter.ts (startup) and spatialite.ts (on-demand loading)
    • Following pattern from Python sqlite-mcp-server implementation
  • SpatiaLite Tool Bug Fixes — Fixed 3 tools that silently failed due to incorrect method usage

    • sqlite_spatialite_create_table: Changed executeWriteQuery to executeReadQuery for AddGeometryColumn() call
    • sqlite_spatialite_index (create/drop): Changed to executeReadQuery for CreateSpatialIndex() and DisableSpatialIndex() calls
    • Root cause: better-sqlite3's .run() method only works for INSERT/UPDATE/DELETE, not SELECT statements
    • Added verification step after geometry column creation to ensure column exists before reporting success
    • Cascading fix enables sqlite_spatialite_import and sqlite_spatialite_analyze to work correctly
  • SpatiaLite Metadata Initialization — Fixed missing geometry_columns table on pre-loaded databases

    • isSpatialiteLoaded() now calls InitSpatialMetaData(1) when detecting a pre-loaded SpatiaLite extension
    • Ensures SpatiaLite metadata tables (geometry_columns, spatial_ref_sys) exist even if extension was loaded in previous session
    • Fixes sqlite_spatialite_analyze "no such table: geometry_columns" error
    • Fixes sqlite_spatialite_create_table returning 0 from AddGeometryColumn() call
  • SpatiaLite GeoJSON Import Fix — Fixed SRID constraint violation when importing GeoJSON data

    • Wrapped GeomFromGeoJSON() with SetSRID(..., srid) to ensure SRID is set correctly
    • GeoJSON import now supports additionalData columns (was only available for WKT import)
    • Fixes "geom violates Geometry constraint [geom-type or SRID not allowed]" error
  • MCP SDK 1.25.2 Compatibility — Fixed stricter transport type requirements

    • Added onclose handler to StreamableHTTPServerTransport before connecting
    • Used type assertion to satisfy SDK's narrower Transport type constraints

Security

  • Identifier Validation Centralization — Migrated 83 tool handlers to use centralized sanitizeIdentifier() utility

    • Replaced inline regex validations with type-safe InvalidIdentifierError handling
    • Consistent security pattern across 10 files: geo.ts, admin.ts, text.ts, vector.ts, virtual.ts, stats.ts, fts.ts, json-operations.ts, json-helpers.ts, core.ts
    • Updated security tests to expect new error message format
  • Transitive Dependency Fixes — Resolved vulnerabilities via npm audit fix

    • hono: 4.11.5 → 4.11.7 (moderate severity fix via @modelcontextprotocol/sdk)
  • Log Injection Prevention — Control character sanitization for log messages

    • Strips all ASCII control characters (0x00-0x1F) and DEL (0x7F) from messages
    • Prevents log forging and escape sequence attacks
    • Dedicated sanitizeStack() function replaces newlines with arrow delimiters for safe stack trace logging
  • Sensitive Data Redaction — Automatic redaction of security-sensitive fields in log context

    • Sensitive keys redacted: password, secret, token, authorization, apikey, access_token, refresh_token, credential, client_secret
    • OAuth 2.1 fields redacted: issuer, audience, jwks_uri, oauth_config, scopes_supported, bearer_format
    • Supports recursive sanitization for nested configuration objects
    • Prevents exposure of OAuth configuration data in log output
  • CodeQL Taint Tracking Fix — Resolved static analysis alerts in logger

    • Fixed js/clear-text-logging by breaking data-flow path in writeToStderr()
    • Fixed js/log-injection by reconstructing output from static character codes
    • Implemented the "Static Classification" pattern for taint-breaking sanitization
  • SQL Injection Protection — WHERE clause validation and identifier sanitization (adapted from postgres-mcp)

    • New src/utils/where-clause.ts utility with SQLite-specific dangerous pattern detection
    • Blocks: ATTACH DATABASE, load_extension, PRAGMA, fileio functions, hex literals, comments, UNION attacks
    • New src/utils/identifiers.ts with centralized identifier validation and quoting
    • Integrated validateWhereClause into 36 tool handlers (text, window, vector, stats, geo)
    • New tests/security/security-injection.test.ts test suite (49 comprehensive test cases)
    • New tests/security/tool-integration.test.ts test suite (67 end-to-end handler tests)
  • Handler Security Hardening — Added missing WHERE clause validation to tool handlers

    • geo.ts: Added validateWhereClause() to sqlite_geo_cluster
    • stats.ts: Added validateWhereClause() to sqlite_stats_outliers, sqlite_stats_top_n, sqlite_stats_distinct, sqlite_stats_frequency