@neverinfamous/mysql-mcp 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.dockerignore +1 -0
- package/.gitattributes +18 -0
- package/.github/workflows/codeql.yml +2 -10
- package/.github/workflows/docker-publish.yml +15 -13
- package/CHANGELOG.md +287 -1
- package/DOCKER_README.md +100 -265
- package/Dockerfile +5 -0
- package/README.md +124 -59
- package/VERSION +1 -1
- package/dist/__tests__/mocks/adapter.d.ts.map +1 -1
- package/dist/__tests__/mocks/adapter.js +2 -0
- package/dist/__tests__/mocks/adapter.js.map +1 -1
- package/dist/adapters/DatabaseAdapter.d.ts.map +1 -1
- package/dist/adapters/DatabaseAdapter.js +50 -9
- package/dist/adapters/DatabaseAdapter.js.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.d.ts +6 -0
- package/dist/adapters/mysql/MySQLAdapter.d.ts.map +1 -1
- package/dist/adapters/mysql/MySQLAdapter.js +8 -0
- package/dist/adapters/mysql/MySQLAdapter.js.map +1 -1
- package/dist/adapters/mysql/SchemaManager.js +16 -15
- package/dist/adapters/mysql/SchemaManager.js.map +1 -1
- package/dist/adapters/mysql/prompts/index.js +10 -20
- package/dist/adapters/mysql/prompts/index.js.map +1 -1
- package/dist/adapters/mysql/prompts/proxysqlSetup.js +1 -1
- package/dist/adapters/mysql/resources/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/docstore.js +10 -7
- package/dist/adapters/mysql/resources/docstore.js.map +1 -1
- package/dist/adapters/mysql/resources/events.js +11 -8
- package/dist/adapters/mysql/resources/events.js.map +1 -1
- package/dist/adapters/mysql/resources/indexes.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/indexes.js +12 -15
- package/dist/adapters/mysql/resources/indexes.js.map +1 -1
- package/dist/adapters/mysql/resources/innodb.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/innodb.js +20 -17
- package/dist/adapters/mysql/resources/innodb.js.map +1 -1
- package/dist/adapters/mysql/resources/locks.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/locks.js +9 -6
- package/dist/adapters/mysql/resources/locks.js.map +1 -1
- package/dist/adapters/mysql/resources/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/performance.js +15 -15
- package/dist/adapters/mysql/resources/performance.js.map +1 -1
- package/dist/adapters/mysql/resources/spatial.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/spatial.js +9 -6
- package/dist/adapters/mysql/resources/spatial.js.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.d.ts.map +1 -1
- package/dist/adapters/mysql/resources/sysschema.js +12 -9
- package/dist/adapters/mysql/resources/sysschema.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/backup.js +170 -121
- package/dist/adapters/mysql/tools/admin/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/maintenance.js +106 -57
- package/dist/adapters/mysql/tools/admin/maintenance.js.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/admin/monitoring.js +183 -101
- package/dist/adapters/mysql/tools/admin/monitoring.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/group-replication.js +164 -120
- package/dist/adapters/mysql/tools/cluster/group-replication.js.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js +212 -145
- package/dist/adapters/mysql/tools/cluster/innodb-cluster.js.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/codemode/index.js +6 -4
- package/dist/adapters/mysql/tools/codemode/index.js.map +1 -1
- package/dist/adapters/mysql/tools/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/core.js +152 -29
- package/dist/adapters/mysql/tools/core.js.map +1 -1
- package/dist/adapters/mysql/tools/docstore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/docstore.js +340 -163
- package/dist/adapters/mysql/tools/docstore.js.map +1 -1
- package/dist/adapters/mysql/tools/events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/events.js +284 -198
- package/dist/adapters/mysql/tools/events.js.map +1 -1
- package/dist/adapters/mysql/tools/json/core.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/core.js +11 -39
- package/dist/adapters/mysql/tools/json/core.js.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/enhanced.js +15 -33
- package/dist/adapters/mysql/tools/json/enhanced.js.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/json/helpers.js +13 -24
- package/dist/adapters/mysql/tools/json/helpers.js.map +1 -1
- package/dist/adapters/mysql/tools/partitioning.js +3 -0
- package/dist/adapters/mysql/tools/partitioning.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/analysis.js +89 -60
- package/dist/adapters/mysql/tools/performance/analysis.js.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/performance/optimization.js +151 -127
- package/dist/adapters/mysql/tools/performance/optimization.js.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts +1 -1
- package/dist/adapters/mysql/tools/proxysql.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/proxysql.js +289 -176
- package/dist/adapters/mysql/tools/proxysql.js.map +1 -1
- package/dist/adapters/mysql/tools/replication.js +75 -49
- package/dist/adapters/mysql/tools/replication.js.map +1 -1
- package/dist/adapters/mysql/tools/roles.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/roles.js +224 -182
- package/dist/adapters/mysql/tools/roles.js.map +1 -1
- package/dist/adapters/mysql/tools/router.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/router.js +168 -67
- package/dist/adapters/mysql/tools/router.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/constraints.js +21 -3
- package/dist/adapters/mysql/tools/schema/constraints.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/management.js +61 -14
- package/dist/adapters/mysql/tools/schema/management.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/routines.js +27 -4
- package/dist/adapters/mysql/tools/schema/routines.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/scheduled_events.js +24 -3
- package/dist/adapters/mysql/tools/schema/scheduled_events.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/triggers.js +23 -2
- package/dist/adapters/mysql/tools/schema/triggers.js.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/schema/views.js +47 -7
- package/dist/adapters/mysql/tools/schema/views.js.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/audit.js +102 -34
- package/dist/adapters/mysql/tools/security/audit.js.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/data-protection.js +264 -205
- package/dist/adapters/mysql/tools/security/data-protection.js.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/security/encryption.js +137 -104
- package/dist/adapters/mysql/tools/security/encryption.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/backup.js +71 -59
- package/dist/adapters/mysql/tools/shell/backup.js.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/shell/restore.js +61 -47
- package/dist/adapters/mysql/tools/shell/restore.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/geometry.js +19 -5
- package/dist/adapters/mysql/tools/spatial/geometry.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/operations.js +42 -17
- package/dist/adapters/mysql/tools/spatial/operations.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/queries.js +109 -57
- package/dist/adapters/mysql/tools/spatial/queries.js.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/spatial/setup.js +103 -50
- package/dist/adapters/mysql/tools/spatial/setup.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/comparative.js +128 -79
- package/dist/adapters/mysql/tools/stats/comparative.js.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/stats/descriptive.js +174 -102
- package/dist/adapters/mysql/tools/stats/descriptive.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/activity.js +50 -25
- package/dist/adapters/mysql/tools/sysschema/activity.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/performance.js +121 -66
- package/dist/adapters/mysql/tools/sysschema/performance.js.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/sysschema/resources.js +101 -64
- package/dist/adapters/mysql/tools/sysschema/resources.js.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/text/fulltext.js +18 -32
- package/dist/adapters/mysql/tools/text/fulltext.js.map +1 -1
- package/dist/adapters/mysql/tools/transactions.d.ts.map +1 -1
- package/dist/adapters/mysql/tools/transactions.js +48 -23
- package/dist/adapters/mysql/tools/transactions.js.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.d.ts +15 -0
- package/dist/adapters/mysql/types/proxysql-types.d.ts.map +1 -1
- package/dist/adapters/mysql/types/proxysql-types.js +33 -1
- package/dist/adapters/mysql/types/proxysql-types.js.map +1 -1
- package/dist/adapters/mysql/types/router-types.d.ts +1 -1
- package/dist/adapters/mysql/types/router-types.js +1 -1
- package/dist/adapters/mysql/types/router-types.js.map +1 -1
- package/dist/adapters/mysql/types/shell-types.js +2 -2
- package/dist/adapters/mysql/types/shell-types.js.map +1 -1
- package/dist/adapters/mysql/types.d.ts +485 -21
- package/dist/adapters/mysql/types.d.ts.map +1 -1
- package/dist/adapters/mysql/types.js +546 -19
- package/dist/adapters/mysql/types.js.map +1 -1
- package/dist/auth/scopes.js +1 -1
- package/dist/auth/scopes.js.map +1 -1
- package/dist/codemode/api.d.ts +3 -2
- package/dist/codemode/api.d.ts.map +1 -1
- package/dist/codemode/api.js +80 -5
- package/dist/codemode/api.js.map +1 -1
- package/dist/codemode/sandbox-factory.js +1 -1
- package/dist/codemode/sandbox-factory.js.map +1 -1
- package/dist/codemode/types.d.ts +26 -0
- package/dist/codemode/types.d.ts.map +1 -1
- package/dist/codemode/types.js +2 -0
- package/dist/codemode/types.js.map +1 -1
- package/dist/codemode/worker-sandbox.d.ts +4 -2
- package/dist/codemode/worker-sandbox.d.ts.map +1 -1
- package/dist/codemode/worker-sandbox.js +66 -7
- package/dist/codemode/worker-sandbox.js.map +1 -1
- package/dist/codemode/worker-script.d.ts +3 -0
- package/dist/codemode/worker-script.d.ts.map +1 -1
- package/dist/codemode/worker-script.js +128 -75
- package/dist/codemode/worker-script.js.map +1 -1
- package/dist/constants/ServerInstructions.d.ts +1 -1
- package/dist/constants/ServerInstructions.d.ts.map +1 -1
- package/dist/constants/ServerInstructions.js +37 -31
- package/dist/constants/ServerInstructions.js.map +1 -1
- package/dist/filtering/ToolConstants.d.ts +1 -1
- package/dist/filtering/ToolConstants.d.ts.map +1 -1
- package/dist/filtering/ToolConstants.js +1 -2
- package/dist/filtering/ToolConstants.js.map +1 -1
- package/dist/pool/ConnectionPool.d.ts.map +1 -1
- package/dist/pool/ConnectionPool.js.map +1 -1
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +6 -0
- package/dist/transports/http.js.map +1 -1
- package/dist/utils/validators.d.ts +1 -1
- package/dist/utils/validators.d.ts.map +1 -1
- package/dist/utils/validators.js.map +1 -1
- package/package.json +4 -4
- package/releases/v2.3.0-release-notes.md +20 -20
- package/releases/v2.3.1-release-notes.md +34 -0
- package/releases/v3.0.0-release-notes.md +81 -0
- package/src/__tests__/mocks/adapter.ts +3 -0
- package/src/__tests__/perf.test.ts +6 -6
- package/src/adapters/DatabaseAdapter.ts +58 -9
- package/src/adapters/__tests__/DatabaseAdapter.test.ts +89 -8
- package/src/adapters/mysql/MySQLAdapter.ts +17 -2
- package/src/adapters/mysql/SchemaManager.ts +21 -21
- package/src/adapters/mysql/__tests__/MySQLAdapter.test.ts +1 -1
- package/src/adapters/mysql/prompts/index.ts +12 -22
- package/src/adapters/mysql/prompts/proxysqlSetup.ts +1 -1
- package/src/adapters/mysql/resources/docstore.ts +13 -10
- package/src/adapters/mysql/resources/events.ts +12 -12
- package/src/adapters/mysql/resources/indexes.ts +17 -19
- package/src/adapters/mysql/resources/innodb.ts +23 -22
- package/src/adapters/mysql/resources/locks.ts +9 -7
- package/src/adapters/mysql/resources/performance.ts +23 -18
- package/src/adapters/mysql/resources/spatial.ts +9 -7
- package/src/adapters/mysql/resources/sysschema.ts +12 -11
- package/src/adapters/mysql/tools/__tests__/core.test.ts +126 -55
- package/src/adapters/mysql/tools/__tests__/docstore.test.ts +459 -88
- package/src/adapters/mysql/tools/__tests__/events.test.ts +281 -103
- package/src/adapters/mysql/tools/__tests__/proxysql.test.ts +128 -28
- package/src/adapters/mysql/tools/__tests__/replication.test.ts +48 -2
- package/src/adapters/mysql/tools/__tests__/roles.test.ts +15 -18
- package/src/adapters/mysql/tools/__tests__/router.test.ts +32 -5
- package/src/adapters/mysql/tools/__tests__/security.test.ts +126 -2
- package/src/adapters/mysql/tools/__tests__/security_injection.test.ts +84 -76
- package/src/adapters/mysql/tools/__tests__/security_integration.test.ts +47 -50
- package/src/adapters/mysql/tools/__tests__/spatial.test.ts +11 -10
- package/src/adapters/mysql/tools/__tests__/spatial_handler.test.ts +54 -38
- package/src/adapters/mysql/tools/__tests__/stats.test.ts +285 -152
- package/src/adapters/mysql/tools/__tests__/transactions.test.ts +13 -13
- package/src/adapters/mysql/tools/admin/__tests__/backup.test.ts +171 -25
- package/src/adapters/mysql/tools/admin/__tests__/maintenance.test.ts +240 -4
- package/src/adapters/mysql/tools/admin/__tests__/monitoring-summary.test.ts +274 -0
- package/src/adapters/mysql/tools/admin/__tests__/monitoring.test.ts +94 -5
- package/src/adapters/mysql/tools/admin/backup.ts +193 -143
- package/src/adapters/mysql/tools/admin/maintenance.ts +118 -69
- package/src/adapters/mysql/tools/admin/monitoring.ts +201 -125
- package/src/adapters/mysql/tools/cluster/__tests__/group-replication.test.ts +69 -0
- package/src/adapters/mysql/tools/cluster/__tests__/innodb-cluster.test.ts +141 -0
- package/src/adapters/mysql/tools/cluster/group-replication.ts +172 -132
- package/src/adapters/mysql/tools/cluster/innodb-cluster.ts +231 -157
- package/src/adapters/mysql/tools/codemode/__tests__/codemode-tool.test.ts +227 -0
- package/src/adapters/mysql/tools/codemode/index.ts +5 -3
- package/src/adapters/mysql/tools/core.ts +152 -38
- package/src/adapters/mysql/tools/docstore.ts +422 -205
- package/src/adapters/mysql/tools/events.ts +334 -233
- package/src/adapters/mysql/tools/json/__tests__/core.test.ts +20 -0
- package/src/adapters/mysql/tools/json/__tests__/enhanced.test.ts +82 -50
- package/src/adapters/mysql/tools/json/__tests__/helpers.test.ts +42 -3
- package/src/adapters/mysql/tools/json/core.ts +21 -42
- package/src/adapters/mysql/tools/json/enhanced.ts +22 -37
- package/src/adapters/mysql/tools/json/helpers.ts +21 -25
- package/src/adapters/mysql/tools/partitioning.ts +3 -0
- package/src/adapters/mysql/tools/performance/__tests__/analysis.test.ts +98 -5
- package/src/adapters/mysql/tools/performance/__tests__/optimization-coverage.test.ts +515 -0
- package/src/adapters/mysql/tools/performance/__tests__/optimization.test.ts +187 -0
- package/src/adapters/mysql/tools/performance/analysis.ts +95 -69
- package/src/adapters/mysql/tools/performance/optimization.ts +182 -153
- package/src/adapters/mysql/tools/proxysql.ts +314 -209
- package/src/adapters/mysql/tools/replication.ts +84 -57
- package/src/adapters/mysql/tools/roles.ts +274 -226
- package/src/adapters/mysql/tools/router.ts +181 -85
- package/src/adapters/mysql/tools/schema/__tests__/constraints.test.ts +13 -0
- package/src/adapters/mysql/tools/schema/__tests__/management.test.ts +60 -25
- package/src/adapters/mysql/tools/schema/__tests__/scheduled_events.test.ts +11 -0
- package/src/adapters/mysql/tools/schema/__tests__/triggers.test.ts +25 -4
- package/src/adapters/mysql/tools/schema/__tests__/views.test.ts +46 -14
- package/src/adapters/mysql/tools/schema/constraints.ts +22 -3
- package/src/adapters/mysql/tools/schema/management.ts +60 -15
- package/src/adapters/mysql/tools/schema/routines.ts +26 -4
- package/src/adapters/mysql/tools/schema/scheduled_events.ts +25 -3
- package/src/adapters/mysql/tools/schema/triggers.ts +27 -2
- package/src/adapters/mysql/tools/schema/views.ts +46 -8
- package/src/adapters/mysql/tools/security/__tests__/audit.test.ts +90 -4
- package/src/adapters/mysql/tools/security/audit.ts +113 -39
- package/src/adapters/mysql/tools/security/data-protection.ts +293 -233
- package/src/adapters/mysql/tools/security/encryption.ts +172 -139
- package/src/adapters/mysql/tools/shell/__tests__/backup.test.ts +29 -0
- package/src/adapters/mysql/tools/shell/backup.ts +90 -73
- package/src/adapters/mysql/tools/shell/restore.ts +62 -48
- package/src/adapters/mysql/tools/spatial/__tests__/operations.test.ts +22 -14
- package/src/adapters/mysql/tools/spatial/__tests__/queries.test.ts +65 -51
- package/src/adapters/mysql/tools/spatial/geometry.ts +23 -7
- package/src/adapters/mysql/tools/spatial/operations.ts +60 -31
- package/src/adapters/mysql/tools/spatial/queries.ts +142 -65
- package/src/adapters/mysql/tools/spatial/setup.ts +121 -55
- package/src/adapters/mysql/tools/stats/__tests__/comparative.test.ts +12 -10
- package/src/adapters/mysql/tools/stats/comparative.ts +150 -98
- package/src/adapters/mysql/tools/stats/descriptive.ts +204 -127
- package/src/adapters/mysql/tools/sysschema/__tests__/error-paths.test.ts +222 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/performance.test.ts +45 -0
- package/src/adapters/mysql/tools/sysschema/__tests__/resources.test.ts +6 -3
- package/src/adapters/mysql/tools/sysschema/activity.ts +52 -27
- package/src/adapters/mysql/tools/sysschema/performance.ts +132 -68
- package/src/adapters/mysql/tools/sysschema/resources.ts +105 -67
- package/src/adapters/mysql/tools/text/__tests__/fulltext.test.ts +45 -17
- package/src/adapters/mysql/tools/text/fulltext.ts +27 -38
- package/src/adapters/mysql/tools/transactions.ts +49 -24
- package/src/adapters/mysql/types/proxysql-types.ts +38 -1
- package/src/adapters/mysql/types/router-types.ts +1 -1
- package/src/adapters/mysql/types/shell-types.ts +2 -2
- package/src/adapters/mysql/types.ts +632 -19
- package/src/auth/__tests__/scopes.test.ts +2 -2
- package/src/auth/scopes.ts +1 -1
- package/src/codemode/__tests__/api.test.ts +417 -0
- package/src/codemode/__tests__/sandbox-factory.test.ts +158 -0
- package/src/codemode/__tests__/sandbox.test.ts +301 -0
- package/src/codemode/__tests__/security.test.ts +368 -0
- package/src/codemode/__tests__/worker-sandbox.test.ts +179 -0
- package/src/codemode/__tests__/worker-script.test.ts +226 -0
- package/src/codemode/api.ts +89 -5
- package/src/codemode/sandbox-factory.ts +1 -1
- package/src/codemode/types.ts +34 -0
- package/src/codemode/worker-sandbox.ts +74 -7
- package/src/codemode/worker-script.ts +157 -86
- package/src/constants/ServerInstructions.ts +37 -31
- package/src/filtering/ToolConstants.ts +1 -2
- package/src/filtering/__tests__/ToolFilter.test.ts +9 -9
- package/src/pool/ConnectionPool.ts +4 -1
- package/src/transports/__tests__/http.test.ts +15 -3
- package/src/transports/http.ts +12 -0
- package/src/utils/validators.ts +2 -1
- package/vitest.config.ts +3 -1
- package/CODE_MODE.md +0 -245
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mysql-mcp - Code Mode Tool Unit Tests
|
|
3
|
+
*
|
|
4
|
+
* Tests for createExecuteCodeTool, getCodeModeTools, and cleanupCodeMode.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
8
|
+
import {
|
|
9
|
+
createExecuteCodeTool,
|
|
10
|
+
getCodeModeTools,
|
|
11
|
+
cleanupCodeMode,
|
|
12
|
+
} from "../index.js";
|
|
13
|
+
import type { MySQLAdapter } from "../../../MySQLAdapter.js";
|
|
14
|
+
import type { ToolDefinition } from "../../../../../types/index.js";
|
|
15
|
+
|
|
16
|
+
// Suppress logger
|
|
17
|
+
vi.mock("../../../../../utils/logger.js", () => ({
|
|
18
|
+
logger: { info: vi.fn(), warning: vi.fn(), error: vi.fn() },
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a mock adapter sufficient for Code Mode usage
|
|
23
|
+
*/
|
|
24
|
+
function createCodeModeMockAdapter(): MySQLAdapter {
|
|
25
|
+
const mockTools: ToolDefinition[] = [
|
|
26
|
+
{
|
|
27
|
+
name: "mysql_read_query",
|
|
28
|
+
group: "core",
|
|
29
|
+
title: "Read Query",
|
|
30
|
+
description: "Execute a read query",
|
|
31
|
+
inputSchema: { parse: (v: unknown) => v } as never,
|
|
32
|
+
requiredScopes: ["read"],
|
|
33
|
+
annotations: { readOnlyHint: true },
|
|
34
|
+
handler: vi
|
|
35
|
+
.fn()
|
|
36
|
+
.mockResolvedValue({ rows: [{ id: 1 }], rowsAffected: 0 }),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "mysql_write_query",
|
|
40
|
+
group: "core",
|
|
41
|
+
title: "Write Query",
|
|
42
|
+
description: "Execute a write query",
|
|
43
|
+
inputSchema: { parse: (v: unknown) => v } as never,
|
|
44
|
+
requiredScopes: ["write"],
|
|
45
|
+
annotations: {},
|
|
46
|
+
handler: vi.fn().mockResolvedValue({ rows: [], rowsAffected: 1 }),
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
type: "mysql",
|
|
52
|
+
getToolDefinitions: vi.fn().mockReturnValue(mockTools),
|
|
53
|
+
createContext: vi.fn().mockReturnValue({
|
|
54
|
+
timestamp: new Date(),
|
|
55
|
+
requestId: "test-ctx",
|
|
56
|
+
}),
|
|
57
|
+
getActiveTransactionIds: vi.fn().mockReturnValue([]),
|
|
58
|
+
rollbackTransaction: vi.fn().mockResolvedValue(undefined),
|
|
59
|
+
} as unknown as MySQLAdapter;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("Code Mode Tool", () => {
|
|
63
|
+
let mockAdapter: MySQLAdapter;
|
|
64
|
+
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
vi.clearAllMocks();
|
|
67
|
+
process.env["CODEMODE_ISOLATION"] = "vm";
|
|
68
|
+
mockAdapter = createCodeModeMockAdapter();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
afterEach(() => {
|
|
72
|
+
cleanupCodeMode();
|
|
73
|
+
delete process.env["CODEMODE_ISOLATION"];
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// ===========================================================================
|
|
77
|
+
// createExecuteCodeTool
|
|
78
|
+
// ===========================================================================
|
|
79
|
+
describe("createExecuteCodeTool", () => {
|
|
80
|
+
it("should create tool with correct definition", () => {
|
|
81
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
82
|
+
expect(tool.name).toBe("mysql_execute_code");
|
|
83
|
+
expect(tool.group).toBe("codemode");
|
|
84
|
+
expect(tool.requiredScopes).toContain("admin");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should have proper annotations", () => {
|
|
88
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
89
|
+
expect(tool.annotations?.destructiveHint).toBe(true);
|
|
90
|
+
expect(tool.annotations?.readOnlyHint).toBe(false);
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("should reject invalid code (blocked patterns)", async () => {
|
|
94
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
95
|
+
const result = (await tool.handler(
|
|
96
|
+
{ code: 'require("fs")' },
|
|
97
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
98
|
+
)) as { success: boolean; error: string };
|
|
99
|
+
|
|
100
|
+
expect(result.success).toBe(false);
|
|
101
|
+
expect(result.error).toContain("validation failed");
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("should reject empty code", async () => {
|
|
105
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
106
|
+
const result = (await tool.handler(
|
|
107
|
+
{ code: "" },
|
|
108
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
109
|
+
)) as { success: boolean; error: string };
|
|
110
|
+
|
|
111
|
+
expect(result.success).toBe(false);
|
|
112
|
+
expect(result.error).toContain("validation failed");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("should execute valid code successfully", async () => {
|
|
116
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
117
|
+
const result = (await tool.handler(
|
|
118
|
+
{ code: "return 42" },
|
|
119
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
120
|
+
)) as { success: boolean; result: unknown; hint: string };
|
|
121
|
+
|
|
122
|
+
expect(result.success).toBe(true);
|
|
123
|
+
expect(result.result).toBe(42);
|
|
124
|
+
expect(result.hint).toContain("mysql.help()");
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should handle execution errors gracefully", async () => {
|
|
128
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
129
|
+
const result = (await tool.handler(
|
|
130
|
+
{ code: 'throw new Error("test fail")' },
|
|
131
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
132
|
+
)) as { success: boolean; error: string };
|
|
133
|
+
|
|
134
|
+
expect(result.success).toBe(false);
|
|
135
|
+
expect(result.error).toContain("test fail");
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it("should cleanup orphaned transactions", async () => {
|
|
139
|
+
// Simulate a transaction that starts during execution
|
|
140
|
+
const getActiveIds = mockAdapter.getActiveTransactionIds as ReturnType<
|
|
141
|
+
typeof vi.fn
|
|
142
|
+
>;
|
|
143
|
+
getActiveIds
|
|
144
|
+
.mockReturnValueOnce([]) // before execution
|
|
145
|
+
.mockReturnValueOnce(["orphan-txn-1"]); // after execution
|
|
146
|
+
|
|
147
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
148
|
+
await tool.handler(
|
|
149
|
+
{ code: "return 'done'" },
|
|
150
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(mockAdapter.rollbackTransaction).toHaveBeenCalledWith(
|
|
154
|
+
"orphan-txn-1",
|
|
155
|
+
);
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("should handle rollback errors gracefully during cleanup", async () => {
|
|
159
|
+
const getActiveIds = mockAdapter.getActiveTransactionIds as ReturnType<
|
|
160
|
+
typeof vi.fn
|
|
161
|
+
>;
|
|
162
|
+
getActiveIds.mockReturnValueOnce([]).mockReturnValueOnce(["bad-txn"]);
|
|
163
|
+
|
|
164
|
+
(
|
|
165
|
+
mockAdapter.rollbackTransaction as ReturnType<typeof vi.fn>
|
|
166
|
+
).mockRejectedValueOnce(new Error("rollback failed"));
|
|
167
|
+
|
|
168
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
169
|
+
// Should not throw even though rollback fails
|
|
170
|
+
const result = (await tool.handler(
|
|
171
|
+
{ code: "return 'done'" },
|
|
172
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
173
|
+
)) as { success: boolean };
|
|
174
|
+
|
|
175
|
+
expect(result.success).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// ===========================================================================
|
|
180
|
+
// getCodeModeTools
|
|
181
|
+
// ===========================================================================
|
|
182
|
+
describe("getCodeModeTools", () => {
|
|
183
|
+
it("should return array with execute code tool", () => {
|
|
184
|
+
const tools = getCodeModeTools(mockAdapter);
|
|
185
|
+
expect(tools).toHaveLength(1);
|
|
186
|
+
expect(tools[0].name).toBe("mysql_execute_code");
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// ===========================================================================
|
|
191
|
+
// cleanupCodeMode
|
|
192
|
+
// ===========================================================================
|
|
193
|
+
describe("cleanupCodeMode", () => {
|
|
194
|
+
it("should clean up without error when not initialized", () => {
|
|
195
|
+
expect(() => cleanupCodeMode()).not.toThrow();
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("should clean up after initialization", async () => {
|
|
199
|
+
// Initialize by executing
|
|
200
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
201
|
+
await tool.handler(
|
|
202
|
+
{ code: "return 1" },
|
|
203
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
204
|
+
);
|
|
205
|
+
// Clean up
|
|
206
|
+
expect(() => cleanupCodeMode()).not.toThrow();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should allow re-initialization after cleanup", async () => {
|
|
210
|
+
const tool = createExecuteCodeTool(mockAdapter);
|
|
211
|
+
await tool.handler(
|
|
212
|
+
{ code: "return 1" },
|
|
213
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
214
|
+
);
|
|
215
|
+
cleanupCodeMode();
|
|
216
|
+
|
|
217
|
+
// Re-execute should work
|
|
218
|
+
const result = (await tool.handler(
|
|
219
|
+
{ code: "return 2" },
|
|
220
|
+
{ timestamp: new Date(), requestId: "test" },
|
|
221
|
+
)) as { success: boolean; result: unknown };
|
|
222
|
+
|
|
223
|
+
expect(result.success).toBe(true);
|
|
224
|
+
expect(result.result).toBe(2);
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
} from "../../../../types/index.js";
|
|
14
14
|
import {
|
|
15
15
|
createSandboxPool,
|
|
16
|
+
getDefaultSandboxMode,
|
|
16
17
|
type ISandboxPool,
|
|
17
18
|
type SandboxMode,
|
|
18
19
|
} from "../../../../codemode/sandbox-factory.js";
|
|
@@ -68,7 +69,8 @@ let securityManager: CodeModeSecurityManager | null = null;
|
|
|
68
69
|
function getIsolationMode(): SandboxMode {
|
|
69
70
|
const envMode = process.env["CODEMODE_ISOLATION"];
|
|
70
71
|
if (envMode === "worker") return "worker";
|
|
71
|
-
return "vm";
|
|
72
|
+
if (envMode === "vm") return "vm";
|
|
73
|
+
return getDefaultSandboxMode();
|
|
72
74
|
}
|
|
73
75
|
|
|
74
76
|
/**
|
|
@@ -162,8 +164,8 @@ return results;
|
|
|
162
164
|
};
|
|
163
165
|
}
|
|
164
166
|
|
|
165
|
-
// Create mysql API bindings
|
|
166
|
-
const mysqlApi = createMysqlApi(adapter);
|
|
167
|
+
// Create mysql API bindings (readonly filtering applied when readonly: true)
|
|
168
|
+
const mysqlApi = createMysqlApi(adapter, readonly);
|
|
167
169
|
const bindings = mysqlApi.createSandboxBindings();
|
|
168
170
|
|
|
169
171
|
// Validate bindings are populated
|
|
@@ -24,6 +24,14 @@ import {
|
|
|
24
24
|
GetIndexesSchemaBase,
|
|
25
25
|
ListTablesSchema,
|
|
26
26
|
} from "../types.js";
|
|
27
|
+
import { ZodError } from "zod";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extract human-readable messages from a ZodError instead of raw JSON array
|
|
31
|
+
*/
|
|
32
|
+
function formatZodError(error: ZodError): string {
|
|
33
|
+
return error.issues.map((i) => i.message).join("; ");
|
|
34
|
+
}
|
|
27
35
|
|
|
28
36
|
/**
|
|
29
37
|
* Pre-compiled identifier validation patterns (hoisted for performance)
|
|
@@ -83,11 +91,15 @@ function createReadQueryTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
83
91
|
idempotentHint: true,
|
|
84
92
|
},
|
|
85
93
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
params
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
let parsed;
|
|
95
|
+
try {
|
|
96
|
+
parsed = ReadQuerySchema.parse(params);
|
|
97
|
+
} catch (err: unknown) {
|
|
98
|
+
if (err instanceof ZodError)
|
|
99
|
+
return { success: false, error: formatZodError(err) };
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
const { query, params: queryParams, transactionId } = parsed;
|
|
91
103
|
try {
|
|
92
104
|
const result = await adapter.executeReadQuery(
|
|
93
105
|
query,
|
|
@@ -123,11 +135,15 @@ function createWriteQueryTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
123
135
|
readOnlyHint: false,
|
|
124
136
|
},
|
|
125
137
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
params
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
let parsed;
|
|
139
|
+
try {
|
|
140
|
+
parsed = WriteQuerySchema.parse(params);
|
|
141
|
+
} catch (err: unknown) {
|
|
142
|
+
if (err instanceof ZodError)
|
|
143
|
+
return { success: false, error: formatZodError(err) };
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
const { query, params: queryParams, transactionId } = parsed;
|
|
131
147
|
try {
|
|
132
148
|
const result = await adapter.executeWriteQuery(
|
|
133
149
|
query,
|
|
@@ -163,18 +179,47 @@ function createListTablesTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
163
179
|
idempotentHint: true,
|
|
164
180
|
},
|
|
165
181
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
182
|
+
let parsed;
|
|
183
|
+
try {
|
|
184
|
+
parsed = ListTablesSchema.parse(params);
|
|
185
|
+
} catch (err: unknown) {
|
|
186
|
+
if (err instanceof ZodError)
|
|
187
|
+
return { success: false, error: formatZodError(err) };
|
|
188
|
+
throw err;
|
|
189
|
+
}
|
|
190
|
+
const { database } = parsed;
|
|
191
|
+
|
|
192
|
+
// P154: Pre-check database existence when explicitly provided
|
|
193
|
+
if (database) {
|
|
194
|
+
const dbCheck = await adapter.executeReadQuery(
|
|
195
|
+
`SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = ?`,
|
|
196
|
+
[database],
|
|
197
|
+
);
|
|
198
|
+
if (!dbCheck.rows || dbCheck.rows.length === 0) {
|
|
199
|
+
return {
|
|
200
|
+
exists: false,
|
|
201
|
+
database,
|
|
202
|
+
message: `Database '${database}' does not exist`,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
try {
|
|
208
|
+
const tables = await adapter.listTables(database);
|
|
209
|
+
return {
|
|
210
|
+
tables: tables.map((t) => ({
|
|
211
|
+
name: t.name,
|
|
212
|
+
type: t.type,
|
|
213
|
+
engine: t.engine,
|
|
214
|
+
rowCount: t.rowCount,
|
|
215
|
+
comment: t.comment,
|
|
216
|
+
})),
|
|
217
|
+
count: tables.length,
|
|
218
|
+
};
|
|
219
|
+
} catch (err: unknown) {
|
|
220
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
221
|
+
return { success: false, error: message };
|
|
222
|
+
}
|
|
178
223
|
},
|
|
179
224
|
};
|
|
180
225
|
}
|
|
@@ -196,7 +241,15 @@ function createDescribeTableTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
196
241
|
idempotentHint: true,
|
|
197
242
|
},
|
|
198
243
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
199
|
-
|
|
244
|
+
let parsed;
|
|
245
|
+
try {
|
|
246
|
+
parsed = DescribeTableSchema.parse(params);
|
|
247
|
+
} catch (err: unknown) {
|
|
248
|
+
if (err instanceof ZodError)
|
|
249
|
+
return { success: false, error: formatZodError(err) };
|
|
250
|
+
throw err;
|
|
251
|
+
}
|
|
252
|
+
const { table } = parsed;
|
|
200
253
|
const tableInfo = await adapter.describeTable(table);
|
|
201
254
|
// Graceful handling for non-existent tables
|
|
202
255
|
if (!tableInfo.columns || tableInfo.columns.length === 0) {
|
|
@@ -227,8 +280,32 @@ function createCreateTableTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
227
280
|
readOnlyHint: false,
|
|
228
281
|
},
|
|
229
282
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
283
|
+
let parsed;
|
|
284
|
+
try {
|
|
285
|
+
parsed = CreateTableSchema.parse(params);
|
|
286
|
+
} catch (err: unknown) {
|
|
287
|
+
if (err instanceof ZodError)
|
|
288
|
+
return { success: false, error: formatZodError(err) };
|
|
289
|
+
throw err;
|
|
290
|
+
}
|
|
230
291
|
const { name, columns, engine, charset, collate, comment, ifNotExists } =
|
|
231
|
-
|
|
292
|
+
parsed;
|
|
293
|
+
|
|
294
|
+
// Pre-check existence for skipped indicator when ifNotExists is true
|
|
295
|
+
if (ifNotExists) {
|
|
296
|
+
const checkName = name.includes(".")
|
|
297
|
+
? (name.split(".")[1] ?? name)
|
|
298
|
+
: name;
|
|
299
|
+
const tableInfo = await adapter.describeTable(checkName);
|
|
300
|
+
if (tableInfo.columns && tableInfo.columns.length > 0) {
|
|
301
|
+
return {
|
|
302
|
+
success: true,
|
|
303
|
+
skipped: true,
|
|
304
|
+
tableName: name,
|
|
305
|
+
reason: "Table already exists",
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
}
|
|
232
309
|
|
|
233
310
|
// Build column definitions
|
|
234
311
|
const columnDefs = columns.map((col) => {
|
|
@@ -310,12 +387,13 @@ function createCreateTableTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
310
387
|
if (message.includes("already exists")) {
|
|
311
388
|
return {
|
|
312
389
|
success: false,
|
|
313
|
-
|
|
390
|
+
error: `Table '${name}' already exists`,
|
|
314
391
|
};
|
|
315
392
|
}
|
|
316
|
-
|
|
393
|
+
return { success: false, error: message };
|
|
317
394
|
}
|
|
318
395
|
|
|
396
|
+
adapter.clearSchemaCache();
|
|
319
397
|
return { success: true, tableName: name };
|
|
320
398
|
},
|
|
321
399
|
};
|
|
@@ -337,11 +415,19 @@ function createDropTableTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
337
415
|
destructiveHint: true,
|
|
338
416
|
},
|
|
339
417
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
340
|
-
|
|
418
|
+
let parsed;
|
|
419
|
+
try {
|
|
420
|
+
parsed = DropTableSchema.parse(params);
|
|
421
|
+
} catch (err: unknown) {
|
|
422
|
+
if (err instanceof ZodError)
|
|
423
|
+
return { success: false, error: formatZodError(err) };
|
|
424
|
+
throw err;
|
|
425
|
+
}
|
|
426
|
+
const { table, ifExists } = parsed;
|
|
341
427
|
|
|
342
428
|
// Validate table name
|
|
343
429
|
if (!isValidId(table)) {
|
|
344
|
-
|
|
430
|
+
return { success: false, error: "Invalid table name" };
|
|
345
431
|
}
|
|
346
432
|
|
|
347
433
|
// Pre-check existence for skipped indicator when ifExists is true
|
|
@@ -363,12 +449,14 @@ function createDropTableTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
363
449
|
if (message.includes("Unknown table")) {
|
|
364
450
|
return {
|
|
365
451
|
success: false,
|
|
366
|
-
|
|
452
|
+
error: `Table '${table}' does not exist`,
|
|
367
453
|
};
|
|
368
454
|
}
|
|
369
|
-
|
|
455
|
+
return { success: false, error: message };
|
|
370
456
|
}
|
|
371
457
|
|
|
458
|
+
adapter.clearSchemaCache();
|
|
459
|
+
|
|
372
460
|
if (tableAbsent) {
|
|
373
461
|
return {
|
|
374
462
|
success: true,
|
|
@@ -400,7 +488,15 @@ function createGetIndexesTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
400
488
|
idempotentHint: true,
|
|
401
489
|
},
|
|
402
490
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
403
|
-
|
|
491
|
+
let parsed;
|
|
492
|
+
try {
|
|
493
|
+
parsed = GetIndexesSchema.parse(params);
|
|
494
|
+
} catch (err: unknown) {
|
|
495
|
+
if (err instanceof ZodError)
|
|
496
|
+
return { success: false, error: formatZodError(err) };
|
|
497
|
+
throw err;
|
|
498
|
+
}
|
|
499
|
+
const { table } = parsed;
|
|
404
500
|
// First check if table exists by describing it
|
|
405
501
|
const tableInfo = await adapter.describeTable(table);
|
|
406
502
|
if (!tableInfo.columns || tableInfo.columns.length === 0) {
|
|
@@ -433,16 +529,22 @@ function createCreateIndexTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
433
529
|
readOnlyHint: false,
|
|
434
530
|
},
|
|
435
531
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
436
|
-
|
|
437
|
-
|
|
532
|
+
let parsed;
|
|
533
|
+
try {
|
|
534
|
+
parsed = CreateIndexSchema.parse(params);
|
|
535
|
+
} catch (err: unknown) {
|
|
536
|
+
if (err instanceof ZodError)
|
|
537
|
+
return { success: false, error: formatZodError(err) };
|
|
538
|
+
throw err;
|
|
539
|
+
}
|
|
540
|
+
const { name, table, columns, unique, type, ifNotExists } = parsed;
|
|
438
541
|
|
|
439
542
|
// Validate names
|
|
440
543
|
if (!VALID_INDEX_NAME_PATTERN.test(name)) {
|
|
441
|
-
|
|
442
|
-
throw new Error("Invalid index name");
|
|
544
|
+
return { success: false, error: "Invalid index name" };
|
|
443
545
|
}
|
|
444
546
|
if (!isValidId(table)) {
|
|
445
|
-
|
|
547
|
+
return { success: false, error: "Invalid table name" };
|
|
446
548
|
}
|
|
447
549
|
|
|
448
550
|
const columnList = columns.map((c) => `\`${c}\``).join(", ");
|
|
@@ -478,15 +580,27 @@ function createCreateIndexTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
478
580
|
if (message.includes("Duplicate key name")) {
|
|
479
581
|
return {
|
|
480
582
|
success: false,
|
|
481
|
-
|
|
583
|
+
error: `Index '${name}' already exists on table '${table}'`,
|
|
584
|
+
};
|
|
585
|
+
}
|
|
586
|
+
// Distinguish column errors from table errors
|
|
587
|
+
if (message.includes("Key column")) {
|
|
588
|
+
const colMatch = /Key column '([^']+)'/.exec(message);
|
|
589
|
+
return {
|
|
590
|
+
success: false,
|
|
591
|
+
error: colMatch
|
|
592
|
+
? `Column '${colMatch[1]}' does not exist in table '${table}'`
|
|
593
|
+
: `Column does not exist in table '${table}'`,
|
|
482
594
|
};
|
|
483
595
|
}
|
|
484
596
|
if (message.includes("doesn't exist")) {
|
|
485
597
|
return { exists: false, table };
|
|
486
598
|
}
|
|
487
|
-
|
|
599
|
+
return { success: false, error: message };
|
|
488
600
|
}
|
|
489
601
|
|
|
602
|
+
adapter.clearSchemaCache();
|
|
603
|
+
|
|
490
604
|
// Warn if HASH was requested on a non-MEMORY engine (InnoDB silently converts to BTREE)
|
|
491
605
|
if (type === "HASH") {
|
|
492
606
|
return {
|