@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
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, it, expect, vi, beforeEach, type Mock } from "vitest";
|
|
2
2
|
import {
|
|
3
3
|
createGRStatusTool,
|
|
4
|
+
createGRMembersTool,
|
|
5
|
+
createGRPrimaryTool,
|
|
6
|
+
createGRTransactionsTool,
|
|
4
7
|
createGRFlowControlTool,
|
|
5
8
|
} from "../group-replication.js";
|
|
6
9
|
import { MySQLAdapter } from "../../../MySQLAdapter.js";
|
|
@@ -216,3 +219,69 @@ describe("Group Replication Tools", () => {
|
|
|
216
219
|
});
|
|
217
220
|
});
|
|
218
221
|
});
|
|
222
|
+
|
|
223
|
+
describe("Group Replication Tools - Error Handling", () => {
|
|
224
|
+
let mockAdapter: MySQLAdapter;
|
|
225
|
+
let mockExecuteQuery: Mock;
|
|
226
|
+
|
|
227
|
+
beforeEach(() => {
|
|
228
|
+
mockExecuteQuery = vi.fn();
|
|
229
|
+
mockAdapter = {
|
|
230
|
+
executeQuery: mockExecuteQuery,
|
|
231
|
+
} as unknown as MySQLAdapter;
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it("mysql_gr_status should return structured error when query fails", async () => {
|
|
235
|
+
const tool = createGRStatusTool(mockAdapter);
|
|
236
|
+
mockExecuteQuery.mockRejectedValue(new Error("Connection refused"));
|
|
237
|
+
|
|
238
|
+
const result = (await tool.handler({}, {} as any)) as any;
|
|
239
|
+
|
|
240
|
+
expect(result.enabled).toBe(false);
|
|
241
|
+
expect(result.error).toBe("Connection refused");
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it("mysql_gr_members should return structured error when query fails", async () => {
|
|
245
|
+
const tool = createGRMembersTool(mockAdapter);
|
|
246
|
+
mockExecuteQuery.mockRejectedValue(new Error("Access denied"));
|
|
247
|
+
|
|
248
|
+
const result = (await tool.handler({}, {} as any)) as any;
|
|
249
|
+
|
|
250
|
+
expect(result.members).toEqual([]);
|
|
251
|
+
expect(result.count).toBe(0);
|
|
252
|
+
expect(result.error).toBe("Access denied");
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("mysql_gr_primary should return structured error when query fails", async () => {
|
|
256
|
+
const tool = createGRPrimaryTool(mockAdapter);
|
|
257
|
+
mockExecuteQuery.mockRejectedValue(new Error("Connection lost"));
|
|
258
|
+
|
|
259
|
+
const result = (await tool.handler({}, {} as any)) as any;
|
|
260
|
+
|
|
261
|
+
expect(result.hasPrimary).toBe(false);
|
|
262
|
+
expect(result.error).toBe("Connection lost");
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
it("mysql_gr_transactions should return structured error when query fails", async () => {
|
|
266
|
+
const tool = createGRTransactionsTool(mockAdapter);
|
|
267
|
+
mockExecuteQuery.mockRejectedValue(new Error("Permission denied"));
|
|
268
|
+
|
|
269
|
+
const result = (await tool.handler({}, {} as any)) as any;
|
|
270
|
+
|
|
271
|
+
expect(result.memberStats).toEqual([]);
|
|
272
|
+
expect(result.gtid).toEqual({ executed: "", purged: "" });
|
|
273
|
+
expect(result.error).toBe("Permission denied");
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
it("mysql_gr_flow_control should return structured error when query fails", async () => {
|
|
277
|
+
const tool = createGRFlowControlTool(mockAdapter);
|
|
278
|
+
mockExecuteQuery.mockRejectedValue(new Error("Timeout"));
|
|
279
|
+
|
|
280
|
+
const result = (await tool.handler({}, {} as any)) as any;
|
|
281
|
+
|
|
282
|
+
expect(result.configuration).toEqual({});
|
|
283
|
+
expect(result.memberQueues).toEqual([]);
|
|
284
|
+
expect(result.isThrottling).toBe(false);
|
|
285
|
+
expect(result.error).toBe("Timeout");
|
|
286
|
+
});
|
|
287
|
+
});
|
|
@@ -125,6 +125,22 @@ describe("InnoDB Cluster Tools", () => {
|
|
|
125
125
|
});
|
|
126
126
|
|
|
127
127
|
describe("createClusterInstancesTool", () => {
|
|
128
|
+
it("should include primaryError when both queries fail", async () => {
|
|
129
|
+
mockAdapter.executeQuery
|
|
130
|
+
.mockRejectedValueOnce(new Error("Metadata query failed")) // Primary fails
|
|
131
|
+
.mockRejectedValueOnce(new Error("GR query also failed")); // Fallback fails
|
|
132
|
+
|
|
133
|
+
const tool = createClusterInstancesTool(
|
|
134
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
135
|
+
);
|
|
136
|
+
const result = (await tool.handler({ limit: 10 }, mockContext)) as any;
|
|
137
|
+
|
|
138
|
+
expect(result.instances).toEqual([]);
|
|
139
|
+
expect(result.count).toBe(0);
|
|
140
|
+
expect(result.error).toBe("GR query also failed");
|
|
141
|
+
expect(result.primaryError).toBe("Metadata query failed");
|
|
142
|
+
});
|
|
143
|
+
|
|
128
144
|
it("should fallback to GR members when InnoDB Cluster metadata query fails", async () => {
|
|
129
145
|
mockAdapter.executeQuery
|
|
130
146
|
.mockRejectedValueOnce(new Error("Table not found")) // First query fails
|
|
@@ -388,11 +404,36 @@ describe("InnoDB Cluster Tools", () => {
|
|
|
388
404
|
|
|
389
405
|
expect(result.canSwitchover).toBe(false);
|
|
390
406
|
expect(result.candidates).toHaveLength(0);
|
|
407
|
+
expect(result.currentPrimary).toBeDefined();
|
|
391
408
|
expect(result.warning).toBe(
|
|
392
409
|
"No online secondaries available for switchover.",
|
|
393
410
|
);
|
|
394
411
|
});
|
|
395
412
|
|
|
413
|
+
it("should return currentPrimary as null when no primary exists", async () => {
|
|
414
|
+
mockAdapter.executeQuery.mockResolvedValueOnce(
|
|
415
|
+
createMockQueryResult([
|
|
416
|
+
{
|
|
417
|
+
memberId: "uuid1",
|
|
418
|
+
host: "node1",
|
|
419
|
+
port: 3306,
|
|
420
|
+
state: "OFFLINE",
|
|
421
|
+
role: "SECONDARY",
|
|
422
|
+
version: "9.2.0",
|
|
423
|
+
txQueue: 0,
|
|
424
|
+
applierQueue: 0,
|
|
425
|
+
},
|
|
426
|
+
]),
|
|
427
|
+
);
|
|
428
|
+
|
|
429
|
+
const tool = createClusterSwitchoverTool(
|
|
430
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
431
|
+
);
|
|
432
|
+
const result = (await tool.handler({}, mockContext)) as any;
|
|
433
|
+
|
|
434
|
+
expect(result.currentPrimary).toBeNull();
|
|
435
|
+
});
|
|
436
|
+
|
|
396
437
|
it("should recommend good switchover candidate", async () => {
|
|
397
438
|
mockAdapter.executeQuery.mockResolvedValueOnce(
|
|
398
439
|
createMockQueryResult([
|
|
@@ -431,4 +472,104 @@ describe("InnoDB Cluster Tools", () => {
|
|
|
431
472
|
expect(result.warning).toBeUndefined();
|
|
432
473
|
});
|
|
433
474
|
});
|
|
475
|
+
|
|
476
|
+
describe("createClusterTopologyTool - error handling", () => {
|
|
477
|
+
it("should return structured error when first query fails", async () => {
|
|
478
|
+
mockAdapter.executeQuery.mockRejectedValue(
|
|
479
|
+
new Error("Connection refused"),
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
const tool = createClusterTopologyTool(
|
|
483
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
484
|
+
);
|
|
485
|
+
const result = (await tool.handler({}, mockContext)) as any;
|
|
486
|
+
|
|
487
|
+
expect(result.topology).toEqual({
|
|
488
|
+
primary: [],
|
|
489
|
+
secondaries: [],
|
|
490
|
+
recovering: [],
|
|
491
|
+
offline: [],
|
|
492
|
+
});
|
|
493
|
+
expect(result.visualization).toBe("");
|
|
494
|
+
expect(result.totalMembers).toBe(0);
|
|
495
|
+
expect(result.onlineMembers).toBe(0);
|
|
496
|
+
expect(result.error).toBe("Connection refused");
|
|
497
|
+
});
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
describe("createClusterSwitchoverTool - error handling", () => {
|
|
501
|
+
it("should return structured error when query fails", async () => {
|
|
502
|
+
mockAdapter.executeQuery.mockRejectedValue(new Error("Access denied"));
|
|
503
|
+
|
|
504
|
+
const tool = createClusterSwitchoverTool(
|
|
505
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
506
|
+
);
|
|
507
|
+
const result = (await tool.handler({}, mockContext)) as any;
|
|
508
|
+
|
|
509
|
+
expect(result.candidates).toEqual([]);
|
|
510
|
+
expect(result.canSwitchover).toBe(false);
|
|
511
|
+
expect(result.error).toBe("Access denied");
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
describe("Zod validation leak prevention", () => {
|
|
516
|
+
it("cluster_status should return structured error for invalid summary type", async () => {
|
|
517
|
+
const tool = createClusterStatusTool(
|
|
518
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
519
|
+
);
|
|
520
|
+
const result = (await tool.handler(
|
|
521
|
+
{ summary: "yes" },
|
|
522
|
+
mockContext,
|
|
523
|
+
)) as any;
|
|
524
|
+
|
|
525
|
+
expect(result.isInnoDBCluster).toBe(false);
|
|
526
|
+
expect(result.error).toBeDefined();
|
|
527
|
+
expect(result.error).toContain("expected boolean");
|
|
528
|
+
});
|
|
529
|
+
|
|
530
|
+
it("cluster_instances should return structured error for invalid limit type", async () => {
|
|
531
|
+
const tool = createClusterInstancesTool(
|
|
532
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
533
|
+
);
|
|
534
|
+
const result = (await tool.handler({ limit: "abc" }, mockContext)) as any;
|
|
535
|
+
|
|
536
|
+
expect(result.instances).toEqual([]);
|
|
537
|
+
expect(result.count).toBe(0);
|
|
538
|
+
expect(result.error).toBeDefined();
|
|
539
|
+
expect(result.error).toContain("expected number");
|
|
540
|
+
});
|
|
541
|
+
|
|
542
|
+
it("cluster_instances should return structured error for negative limit", async () => {
|
|
543
|
+
const tool = createClusterInstancesTool(
|
|
544
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
545
|
+
);
|
|
546
|
+
const result = (await tool.handler({ limit: -5 }, mockContext)) as any;
|
|
547
|
+
|
|
548
|
+
expect(result.instances).toEqual([]);
|
|
549
|
+
expect(result.count).toBe(0);
|
|
550
|
+
expect(result.error).toBeDefined();
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
it("cluster_instances should return structured error for float limit", async () => {
|
|
554
|
+
const tool = createClusterInstancesTool(
|
|
555
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
556
|
+
);
|
|
557
|
+
const result = (await tool.handler({ limit: 0.5 }, mockContext)) as any;
|
|
558
|
+
|
|
559
|
+
expect(result.instances).toEqual([]);
|
|
560
|
+
expect(result.count).toBe(0);
|
|
561
|
+
expect(result.error).toBeDefined();
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
it("cluster_router_status should return structured error for invalid summary type", async () => {
|
|
565
|
+
const tool = createClusterRouterStatusTool(
|
|
566
|
+
mockAdapter as unknown as MySQLAdapter,
|
|
567
|
+
);
|
|
568
|
+
const result = (await tool.handler({ summary: 123 }, mockContext)) as any;
|
|
569
|
+
|
|
570
|
+
expect(result.available).toBe(false);
|
|
571
|
+
expect(result.error).toBeDefined();
|
|
572
|
+
expect(result.error).toContain("expected boolean");
|
|
573
|
+
});
|
|
574
|
+
});
|
|
434
575
|
});
|
|
@@ -41,18 +41,19 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
41
41
|
idempotentHint: true,
|
|
42
42
|
},
|
|
43
43
|
handler: async (_params: unknown, _context: RequestContext) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
try {
|
|
45
|
+
// Check if GR is running
|
|
46
|
+
const pluginResult = await adapter.executeQuery(
|
|
47
|
+
"SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
|
|
48
|
+
);
|
|
49
|
+
if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
|
|
50
|
+
return {
|
|
51
|
+
enabled: false,
|
|
52
|
+
message: "Group Replication plugin is not active",
|
|
53
|
+
};
|
|
54
|
+
}
|
|
54
55
|
|
|
55
|
-
|
|
56
|
+
const statusResult = await adapter.executeQuery(`
|
|
56
57
|
SELECT
|
|
57
58
|
@@group_replication_group_name as groupName,
|
|
58
59
|
@@group_replication_single_primary_mode as singlePrimaryMode,
|
|
@@ -61,10 +62,10 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
61
62
|
@@group_replication_bootstrap_group as bootstrapGroup
|
|
62
63
|
`);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
const config = statusResult.rows?.[0];
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
// Get member status from performance_schema
|
|
68
|
+
const memberResult = await adapter.executeQuery(`
|
|
68
69
|
SELECT
|
|
69
70
|
CHANNEL_NAME,
|
|
70
71
|
MEMBER_ID,
|
|
@@ -76,35 +77,41 @@ export function createGRStatusTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
76
77
|
FROM performance_schema.replication_group_members
|
|
77
78
|
`);
|
|
78
79
|
|
|
79
|
-
|
|
80
|
-
|
|
80
|
+
// Get local member info
|
|
81
|
+
const localResult = await adapter.executeQuery(`
|
|
81
82
|
SELECT @@server_uuid as serverUuid
|
|
82
83
|
`);
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
const localUuid = localResult.rows?.[0]?.["serverUuid"] as string;
|
|
86
|
+
const members = memberResult.rows ?? [];
|
|
87
|
+
const localMember = members.find((m) => m["MEMBER_ID"] === localUuid);
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
return {
|
|
90
|
+
enabled: members.length > 0,
|
|
91
|
+
groupName: config?.["groupName"] ?? null,
|
|
92
|
+
singlePrimaryMode: config?.["singlePrimaryMode"] === 1,
|
|
93
|
+
localAddress: config?.["localAddress"] ?? null,
|
|
94
|
+
localMember: localMember ?? null,
|
|
95
|
+
memberCount: members.length,
|
|
96
|
+
members: members.map((m) => {
|
|
97
|
+
const member = m;
|
|
98
|
+
return {
|
|
99
|
+
id: member["MEMBER_ID"],
|
|
100
|
+
host: member["MEMBER_HOST"],
|
|
101
|
+
port: member["MEMBER_PORT"],
|
|
102
|
+
state: member["MEMBER_STATE"],
|
|
103
|
+
role: member["MEMBER_ROLE"],
|
|
104
|
+
version: member["MEMBER_VERSION"],
|
|
105
|
+
isLocal: member["MEMBER_ID"] === localUuid,
|
|
106
|
+
};
|
|
107
|
+
}),
|
|
108
|
+
};
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
enabled: false,
|
|
112
|
+
error: error instanceof Error ? error.message : String(error),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
108
115
|
},
|
|
109
116
|
};
|
|
110
117
|
}
|
|
@@ -126,21 +133,22 @@ export function createGRMembersTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
126
133
|
idempotentHint: true,
|
|
127
134
|
},
|
|
128
135
|
handler: async (params: unknown, _context: RequestContext) => {
|
|
129
|
-
|
|
136
|
+
try {
|
|
137
|
+
const { memberId } = MemberSchema.parse(params);
|
|
130
138
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
139
|
+
// Check if GR is running
|
|
140
|
+
const pluginResult = await adapter.executeQuery(
|
|
141
|
+
"SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
|
|
142
|
+
);
|
|
143
|
+
if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
|
|
144
|
+
return {
|
|
145
|
+
members: [],
|
|
146
|
+
count: 0,
|
|
147
|
+
message: "Group Replication not active",
|
|
148
|
+
};
|
|
149
|
+
}
|
|
142
150
|
|
|
143
|
-
|
|
151
|
+
let query = `
|
|
144
152
|
SELECT
|
|
145
153
|
m.MEMBER_ID as memberId,
|
|
146
154
|
m.MEMBER_HOST as host,
|
|
@@ -157,17 +165,24 @@ export function createGRMembersTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
157
165
|
ON m.MEMBER_ID = s.MEMBER_ID
|
|
158
166
|
`;
|
|
159
167
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
168
|
+
const queryParams: unknown[] = [];
|
|
169
|
+
if (memberId) {
|
|
170
|
+
query += " WHERE m.MEMBER_ID = ?";
|
|
171
|
+
queryParams.push(memberId);
|
|
172
|
+
}
|
|
165
173
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
const result = await adapter.executeQuery(query, queryParams);
|
|
175
|
+
return {
|
|
176
|
+
members: result.rows ?? [],
|
|
177
|
+
count: result.rows?.length ?? 0,
|
|
178
|
+
};
|
|
179
|
+
} catch (error) {
|
|
180
|
+
return {
|
|
181
|
+
members: [],
|
|
182
|
+
count: 0,
|
|
183
|
+
error: error instanceof Error ? error.message : String(error),
|
|
184
|
+
};
|
|
185
|
+
}
|
|
171
186
|
},
|
|
172
187
|
};
|
|
173
188
|
}
|
|
@@ -189,7 +204,8 @@ export function createGRPrimaryTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
189
204
|
idempotentHint: true,
|
|
190
205
|
},
|
|
191
206
|
handler: async (_params: unknown, _context: RequestContext) => {
|
|
192
|
-
|
|
207
|
+
try {
|
|
208
|
+
const result = await adapter.executeQuery(`
|
|
193
209
|
SELECT
|
|
194
210
|
MEMBER_ID as memberId,
|
|
195
211
|
MEMBER_HOST as host,
|
|
@@ -200,19 +216,25 @@ export function createGRPrimaryTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
200
216
|
WHERE MEMBER_ROLE = 'PRIMARY'
|
|
201
217
|
`);
|
|
202
218
|
|
|
203
|
-
|
|
219
|
+
const primary = result.rows?.[0];
|
|
204
220
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
221
|
+
// Check if we are the primary
|
|
222
|
+
const localResult = await adapter.executeQuery(
|
|
223
|
+
"SELECT @@server_uuid as serverUuid",
|
|
224
|
+
);
|
|
225
|
+
const localUuid = localResult.rows?.[0]?.["serverUuid"];
|
|
210
226
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
227
|
+
return {
|
|
228
|
+
primary: primary ?? null,
|
|
229
|
+
hasPrimary: !!primary,
|
|
230
|
+
isLocalPrimary: primary?.["memberId"] === localUuid,
|
|
231
|
+
};
|
|
232
|
+
} catch (error) {
|
|
233
|
+
return {
|
|
234
|
+
hasPrimary: false,
|
|
235
|
+
error: error instanceof Error ? error.message : String(error),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
216
238
|
},
|
|
217
239
|
};
|
|
218
240
|
}
|
|
@@ -236,20 +258,21 @@ export function createGRTransactionsTool(
|
|
|
236
258
|
idempotentHint: true,
|
|
237
259
|
},
|
|
238
260
|
handler: async (_params: unknown, _context: RequestContext) => {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
261
|
+
try {
|
|
262
|
+
// Check if GR is running
|
|
263
|
+
const pluginResult = await adapter.executeQuery(
|
|
264
|
+
"SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
|
|
265
|
+
);
|
|
266
|
+
if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
|
|
267
|
+
return {
|
|
268
|
+
memberStats: [],
|
|
269
|
+
gtid: { executed: "", purged: "" },
|
|
270
|
+
message: "Group Replication not active",
|
|
271
|
+
};
|
|
272
|
+
}
|
|
250
273
|
|
|
251
|
-
|
|
252
|
-
|
|
274
|
+
// Get transaction statistics
|
|
275
|
+
const statsResult = await adapter.executeQuery(`
|
|
253
276
|
SELECT
|
|
254
277
|
MEMBER_ID as memberId,
|
|
255
278
|
COUNT_TRANSACTIONS_IN_QUEUE as txInQueue,
|
|
@@ -263,22 +286,29 @@ export function createGRTransactionsTool(
|
|
|
263
286
|
FROM performance_schema.replication_group_member_stats
|
|
264
287
|
`);
|
|
265
288
|
|
|
266
|
-
|
|
267
|
-
|
|
289
|
+
// Get GTID info
|
|
290
|
+
const gtidResult = await adapter.executeQuery(`
|
|
268
291
|
SELECT
|
|
269
292
|
@@gtid_executed as gtidExecuted,
|
|
270
293
|
@@gtid_purged as gtidPurged
|
|
271
294
|
`);
|
|
272
295
|
|
|
273
|
-
|
|
296
|
+
const gtid = gtidResult.rows?.[0];
|
|
274
297
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
298
|
+
return {
|
|
299
|
+
memberStats: statsResult.rows ?? [],
|
|
300
|
+
gtid: {
|
|
301
|
+
executed: gtid?.["gtidExecuted"] ?? "",
|
|
302
|
+
purged: gtid?.["gtidPurged"] ?? "",
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
} catch (error) {
|
|
306
|
+
return {
|
|
307
|
+
memberStats: [],
|
|
308
|
+
gtid: { executed: "", purged: "" },
|
|
309
|
+
error: error instanceof Error ? error.message : String(error),
|
|
310
|
+
};
|
|
311
|
+
}
|
|
282
312
|
},
|
|
283
313
|
};
|
|
284
314
|
}
|
|
@@ -300,21 +330,22 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
300
330
|
idempotentHint: true,
|
|
301
331
|
},
|
|
302
332
|
handler: async (_params: unknown, _context: RequestContext) => {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
333
|
+
try {
|
|
334
|
+
// Check if GR is running
|
|
335
|
+
const pluginResult = await adapter.executeQuery(
|
|
336
|
+
"SELECT PLUGIN_STATUS FROM information_schema.PLUGINS WHERE PLUGIN_NAME = 'group_replication'",
|
|
337
|
+
);
|
|
338
|
+
if (pluginResult.rows?.[0]?.["PLUGIN_STATUS"] !== "ACTIVE") {
|
|
339
|
+
return {
|
|
340
|
+
configuration: {},
|
|
341
|
+
memberQueues: [],
|
|
342
|
+
isThrottling: false,
|
|
343
|
+
message: "Group Replication not active",
|
|
344
|
+
};
|
|
345
|
+
}
|
|
315
346
|
|
|
316
|
-
|
|
317
|
-
|
|
347
|
+
// Get flow control configuration
|
|
348
|
+
const configResult = await adapter.executeQuery(`
|
|
318
349
|
SELECT
|
|
319
350
|
@@group_replication_flow_control_mode as flowControlMode,
|
|
320
351
|
@@group_replication_flow_control_certifier_threshold as certifierThreshold,
|
|
@@ -324,10 +355,10 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
324
355
|
@@group_replication_flow_control_max_quota as maxQuota
|
|
325
356
|
`);
|
|
326
357
|
|
|
327
|
-
|
|
358
|
+
const config = configResult.rows?.[0];
|
|
328
359
|
|
|
329
|
-
|
|
330
|
-
|
|
360
|
+
// Get current queue depths
|
|
361
|
+
const queueResult = await adapter.executeQuery(`
|
|
331
362
|
SELECT
|
|
332
363
|
MEMBER_ID as memberId,
|
|
333
364
|
COUNT_TRANSACTIONS_IN_QUEUE as certifyQueue,
|
|
@@ -335,25 +366,34 @@ export function createGRFlowControlTool(adapter: MySQLAdapter): ToolDefinition {
|
|
|
335
366
|
FROM performance_schema.replication_group_member_stats
|
|
336
367
|
`);
|
|
337
368
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
369
|
+
// Determine if flow control is active
|
|
370
|
+
const isThrottling = (queueResult.rows ?? []).some((row) => {
|
|
371
|
+
const r = row;
|
|
372
|
+
const certQueue = r["certifyQueue"] as number;
|
|
373
|
+
const appQueue = r["applierQueue"] as number;
|
|
374
|
+
const certThreshold =
|
|
375
|
+
(config?.["certifierThreshold"] as number) ?? 25000;
|
|
376
|
+
const appThreshold =
|
|
377
|
+
(config?.["applierThreshold"] as number) ?? 25000;
|
|
378
|
+
return certQueue > certThreshold || appQueue > appThreshold;
|
|
379
|
+
});
|
|
348
380
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
381
|
+
return {
|
|
382
|
+
configuration: config ?? {},
|
|
383
|
+
memberQueues: queueResult.rows ?? [],
|
|
384
|
+
isThrottling,
|
|
385
|
+
recommendation: isThrottling
|
|
386
|
+
? "Flow control is active. Consider investigating slow members or adjusting thresholds."
|
|
387
|
+
: "Flow control is not currently throttling.",
|
|
388
|
+
};
|
|
389
|
+
} catch (error) {
|
|
390
|
+
return {
|
|
391
|
+
configuration: {},
|
|
392
|
+
memberQueues: [],
|
|
393
|
+
isThrottling: false,
|
|
394
|
+
error: error instanceof Error ? error.message : String(error),
|
|
395
|
+
};
|
|
396
|
+
}
|
|
357
397
|
},
|
|
358
398
|
};
|
|
359
399
|
}
|