mysql-aiops 0.1.0__tar.gz

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.
Files changed (84) hide show
  1. mysql_aiops-0.1.0/.github/workflows/mcp-publish.yml +55 -0
  2. mysql_aiops-0.1.0/.github/workflows/publish.yml +26 -0
  3. mysql_aiops-0.1.0/.gitignore +8 -0
  4. mysql_aiops-0.1.0/CHANGELOG.md +78 -0
  5. mysql_aiops-0.1.0/LICENSE +21 -0
  6. mysql_aiops-0.1.0/PKG-INFO +164 -0
  7. mysql_aiops-0.1.0/README.md +148 -0
  8. mysql_aiops-0.1.0/RELEASE_NOTES.md +60 -0
  9. mysql_aiops-0.1.0/SECURITY.md +95 -0
  10. mysql_aiops-0.1.0/mcp_server/__init__.py +1 -0
  11. mysql_aiops-0.1.0/mcp_server/_shared.py +102 -0
  12. mysql_aiops-0.1.0/mcp_server/server.py +38 -0
  13. mysql_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
  14. mysql_aiops-0.1.0/mcp_server/tools/activity.py +62 -0
  15. mysql_aiops-0.1.0/mcp_server/tools/analysis.py +124 -0
  16. mysql_aiops-0.1.0/mcp_server/tools/indexes.py +46 -0
  17. mysql_aiops-0.1.0/mcp_server/tools/queries.py +60 -0
  18. mysql_aiops-0.1.0/mcp_server/tools/remediation.py +256 -0
  19. mysql_aiops-0.1.0/mcp_server/tools/replication.py +34 -0
  20. mysql_aiops-0.1.0/mcp_server/tools/server.py +101 -0
  21. mysql_aiops-0.1.0/mcp_server/tools/tables.py +48 -0
  22. mysql_aiops-0.1.0/mcp_server/tools/undo.py +121 -0
  23. mysql_aiops-0.1.0/mysql_aiops/__init__.py +14 -0
  24. mysql_aiops-0.1.0/mysql_aiops/cli/__init__.py +9 -0
  25. mysql_aiops-0.1.0/mysql_aiops/cli/_common.py +78 -0
  26. mysql_aiops-0.1.0/mysql_aiops/cli/_root.py +70 -0
  27. mysql_aiops-0.1.0/mysql_aiops/cli/activity.py +66 -0
  28. mysql_aiops-0.1.0/mysql_aiops/cli/analyze.py +68 -0
  29. mysql_aiops-0.1.0/mysql_aiops/cli/doctor.py +21 -0
  30. mysql_aiops-0.1.0/mysql_aiops/cli/index.py +45 -0
  31. mysql_aiops-0.1.0/mysql_aiops/cli/init.py +163 -0
  32. mysql_aiops-0.1.0/mysql_aiops/cli/overview.py +16 -0
  33. mysql_aiops-0.1.0/mysql_aiops/cli/query.py +78 -0
  34. mysql_aiops-0.1.0/mysql_aiops/cli/remediate.py +157 -0
  35. mysql_aiops-0.1.0/mysql_aiops/cli/replication.py +35 -0
  36. mysql_aiops-0.1.0/mysql_aiops/cli/secret.py +103 -0
  37. mysql_aiops-0.1.0/mysql_aiops/cli/server.py +82 -0
  38. mysql_aiops-0.1.0/mysql_aiops/cli/table.py +45 -0
  39. mysql_aiops-0.1.0/mysql_aiops/cli/undo.py +62 -0
  40. mysql_aiops-0.1.0/mysql_aiops/config.py +187 -0
  41. mysql_aiops-0.1.0/mysql_aiops/connection.py +201 -0
  42. mysql_aiops-0.1.0/mysql_aiops/doctor.py +120 -0
  43. mysql_aiops-0.1.0/mysql_aiops/governance/__init__.py +40 -0
  44. mysql_aiops-0.1.0/mysql_aiops/governance/audit.py +377 -0
  45. mysql_aiops-0.1.0/mysql_aiops/governance/budget.py +225 -0
  46. mysql_aiops-0.1.0/mysql_aiops/governance/decorators.py +482 -0
  47. mysql_aiops-0.1.0/mysql_aiops/governance/paths.py +23 -0
  48. mysql_aiops-0.1.0/mysql_aiops/governance/patterns.py +378 -0
  49. mysql_aiops-0.1.0/mysql_aiops/governance/policy.py +430 -0
  50. mysql_aiops-0.1.0/mysql_aiops/governance/sanitize.py +45 -0
  51. mysql_aiops-0.1.0/mysql_aiops/governance/undo.py +218 -0
  52. mysql_aiops-0.1.0/mysql_aiops/ops/__init__.py +1 -0
  53. mysql_aiops-0.1.0/mysql_aiops/ops/_util.py +116 -0
  54. mysql_aiops-0.1.0/mysql_aiops/ops/activity.py +209 -0
  55. mysql_aiops-0.1.0/mysql_aiops/ops/analysis.py +448 -0
  56. mysql_aiops-0.1.0/mysql_aiops/ops/indexes.py +142 -0
  57. mysql_aiops-0.1.0/mysql_aiops/ops/overview.py +59 -0
  58. mysql_aiops-0.1.0/mysql_aiops/ops/queries.py +137 -0
  59. mysql_aiops-0.1.0/mysql_aiops/ops/remediation.py +297 -0
  60. mysql_aiops-0.1.0/mysql_aiops/ops/replication.py +104 -0
  61. mysql_aiops-0.1.0/mysql_aiops/ops/server.py +138 -0
  62. mysql_aiops-0.1.0/mysql_aiops/ops/tables.py +142 -0
  63. mysql_aiops-0.1.0/mysql_aiops/secretstore.py +304 -0
  64. mysql_aiops-0.1.0/pyproject.toml +60 -0
  65. mysql_aiops-0.1.0/server.json +21 -0
  66. mysql_aiops-0.1.0/skills/mysql-aiops/SKILL.md +125 -0
  67. mysql_aiops-0.1.0/skills/mysql-aiops/references/capabilities.md +82 -0
  68. mysql_aiops-0.1.0/skills/mysql-aiops/references/cli-reference.md +78 -0
  69. mysql_aiops-0.1.0/skills/mysql-aiops/references/setup-guide.md +116 -0
  70. mysql_aiops-0.1.0/smithery.yaml +9 -0
  71. mysql_aiops-0.1.0/tests/conftest.py +65 -0
  72. mysql_aiops-0.1.0/tests/test_analysis.py +198 -0
  73. mysql_aiops-0.1.0/tests/test_cli_writes.py +102 -0
  74. mysql_aiops-0.1.0/tests/test_connection.py +166 -0
  75. mysql_aiops-0.1.0/tests/test_doctor.py +240 -0
  76. mysql_aiops-0.1.0/tests/test_governance_persistence.py +180 -0
  77. mysql_aiops-0.1.0/tests/test_init.py +140 -0
  78. mysql_aiops-0.1.0/tests/test_reads.py +267 -0
  79. mysql_aiops-0.1.0/tests/test_secretstore.py +99 -0
  80. mysql_aiops-0.1.0/tests/test_smoke.py +267 -0
  81. mysql_aiops-0.1.0/tests/test_undo_executor.py +138 -0
  82. mysql_aiops-0.1.0/tests/test_undo_replay.py +111 -0
  83. mysql_aiops-0.1.0/tests/test_writes.py +212 -0
  84. mysql_aiops-0.1.0/uv.lock +1130 -0
@@ -0,0 +1,55 @@
1
+ name: mcp-publish
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ release:
6
+ types: [published]
7
+
8
+ permissions:
9
+ id-token: write
10
+ contents: read
11
+
12
+ jobs:
13
+ publish-mcp:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: Wait for PyPI
18
+ # The release event also triggers the PyPI publish workflow; the MCP
19
+ # registry validates that the package version exists on PyPI, so poll
20
+ # until it has propagated (every 15s, up to 10 minutes).
21
+ run: |
22
+ python3 - <<'EOF'
23
+ import json
24
+ import sys
25
+ import time
26
+ import urllib.error
27
+ import urllib.request
28
+
29
+ with open("server.json", encoding="utf-8") as f:
30
+ package = json.load(f)["packages"][0]
31
+ name, version = package["identifier"], package["version"]
32
+ url = f"https://pypi.org/pypi/{name}/{version}/json"
33
+ deadline = time.monotonic() + 600
34
+ while True:
35
+ try:
36
+ with urllib.request.urlopen(url, timeout=10):
37
+ print(f"{name}=={version} is available on PyPI.")
38
+ sys.exit(0)
39
+ except (urllib.error.URLError, OSError) as exc:
40
+ print(f"{name}=={version} not on PyPI yet ({exc}); "
41
+ "retrying in 15s...")
42
+ if time.monotonic() >= deadline:
43
+ sys.exit(f"Timed out after 10 minutes waiting for "
44
+ f"{name}=={version} to appear on PyPI. "
45
+ "Check the PyPI publish workflow, then re-run "
46
+ "this workflow via workflow_dispatch.")
47
+ time.sleep(15)
48
+ EOF
49
+ - name: Install mcp-publisher
50
+ run: |
51
+ curl -sL "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher
52
+ - name: Login to MCP Registry (GitHub OIDC)
53
+ run: ./mcp-publisher login github-oidc
54
+ - name: Publish server.json
55
+ run: ./mcp-publisher publish
@@ -0,0 +1,26 @@
1
+ name: Publish to PyPI
2
+
3
+ # Trusted Publishing (OIDC) — publishes from GitHub's runners with no API token,
4
+ # sidestepping the local-IP / account new-project rate limit. Configure a matching
5
+ # "trusted publisher" for this package on PyPI (see the repo release notes).
6
+ on:
7
+ release:
8
+ types: [published]
9
+ workflow_dispatch:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ publish:
16
+ runs-on: ubuntu-latest
17
+ permissions:
18
+ id-token: write # required for PyPI Trusted Publishing (OIDC)
19
+ steps:
20
+ - uses: actions/checkout@v4
21
+ - name: Set up uv
22
+ uses: astral-sh/setup-uv@v5
23
+ - name: Build sdist + wheel
24
+ run: uv build
25
+ - name: Publish to PyPI (Trusted Publishing)
26
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,8 @@
1
+ .venv/
2
+ dist/
3
+ __pycache__/
4
+ *.pyc
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ *.egg-info/
8
+ .coverage
@@ -0,0 +1,78 @@
1
+ # Changelog
2
+
3
+ All notable changes to mysql-aiops are documented here. Format loosely follows
4
+ [Keep a Changelog](https://keepachangelog.com/); this project uses semantic
5
+ versioning (currently 0.x preview — the API may change).
6
+
7
+ ## v0.1.0 — 2026-07-17
8
+
9
+ Initial preview release: governed AI-ops for **MySQL 8.x and MariaDB 10.6+ DBA
10
+ operations** — connecting via **PyMySQL** and reading `information_schema` /
11
+ `performance_schema` — with a bundled governance harness. **Mock-validated only
12
+ — not run against a live server.** Community-maintained; not affiliated with
13
+ Oracle or the MariaDB Foundation.
14
+
15
+ ### Added
16
+
17
+ - **PyMySQL connection layer** (`mysql_aiops.connection`) — parameterised reads
18
+ with a `DictCursor`, autocommit for maintenance statements (OPTIMIZE /
19
+ ANALYZE / KILL), 30s connect/read/write timeouts, an injectable connection
20
+ for tests, teaching error translation (`MySQLError`, with connect / privilege
21
+ / missing-performance_schema hints), and **flavor detection** (mysql vs
22
+ mariadb from `version()`) so flavor-dependent statements branch
23
+ (`SHOW REPLICA STATUS` vs `SHOW SLAVE STATUS`;
24
+ `performance_schema.data_lock_waits` vs `information_schema.innodb_lock_waits`).
25
+ - **33 governed MCP tools**, every one wrapped with `@governed_tool`:
26
+ - **Overview** — `overview` (one-shot server health snapshot incl. flavor,
27
+ connection headroom, replica role).
28
+ - **Server** — `server_version`, `show_variables`, `show_status`,
29
+ `list_databases`, `list_engines`, `connection_stats`.
30
+ - **Activity** — `list_sessions`, `long_running_queries`,
31
+ `list_transactions`, `lock_waits`.
32
+ - **Queries** — `top_queries` (statement digests), `explain_query`
33
+ (EXPLAIN FORMAT=JSON).
34
+ - **Indexes** — `unused_indexes`, `redundant_indexes`, `index_stats`.
35
+ - **Tables** — `table_sizes`, `table_fragmentation`, `table_status`.
36
+ - **Replication** — `replica_status`, `binlog_status`.
37
+ - **Analysis (flagship)** — `slow_query_rca`, `lock_wait_rca` (incl. last
38
+ deadlock parsed from `SHOW ENGINE INNODB STATUS`), `replication_lag_rca`,
39
+ `fragmentation_analysis`.
40
+ - **Writes** — `kill_session` (high), `kill_query` (high), `drop_index`
41
+ (high), `optimize_table` (medium), `analyze_table` (medium), `create_index`
42
+ (medium), `set_global_variable` (medium), `reset_query_stats` (medium).
43
+ - **Guarded writes** — every write supports a `dry_run` preview and (at the
44
+ CLI) double confirmation. Reversible writes fetch the **real before-state**
45
+ and record a faithful inverse: `create_index`↔`drop_index` (drop rebuilds the
46
+ index definition from `SHOW CREATE TABLE` so undo recreates it exactly;
47
+ the descriptor replays through `create_index(definition=...)`);
48
+ `set_global_variable` captures the prior value from `SHOW GLOBAL VARIABLES`.
49
+ Irreversible ops record prior state for audit but no undo.
50
+ - **SQL-injection defenses** — all values are bound query parameters; the few
51
+ identifiers that cannot be parameterised (schema/table/index/column/variable
52
+ names, ORDER BY columns) are validated against a strict charset / allow-lists
53
+ and backtick-quoted before interpolation. EXPLAIN rejects multi-statement
54
+ input.
55
+ - **Bundled governance harness** (`mysql_aiops.governance`) — audit log, policy
56
+ engine, token/runaway budget guard, undo-token recording, graduated risk
57
+ tiers (secure by default: high-risk needs a named approver), output
58
+ `sanitize`. State under `~/.mysql-aiops/` (relocatable via
59
+ `MYSQL_AIOPS_HOME`).
60
+ - **Encrypted secret store** — account passwords in `~/.mysql-aiops/secrets.enc`
61
+ (Fernet + scrypt); legacy `MYSQL_<TARGET>_PASSWORD` env fallback +
62
+ `secret migrate`.
63
+ - **CLI** — `init` wizard (targets, TLS mode with verify_ca/verify_identity,
64
+ encrypted password, seeded rules.yaml), `overview`, `server`, `activity`,
65
+ `query`, `index`, `table`, `repl`, `analyze`, `remediate`, `secret`,
66
+ `doctor` (connectivity + flavor + performance_schema + replica-role probes),
67
+ `mcp`.
68
+
69
+ ### Known limitations
70
+
71
+ - Preview / mock-only: the `information_schema` / `performance_schema` queries
72
+ need live verification against MySQL 8.x and MariaDB 10.6+.
73
+ - `top_queries` / `slow_query_rca` require `performance_schema=ON`.
74
+ - `SET GLOBAL` changes are runtime-only (persist in my.cnf / SET PERSIST
75
+ yourself).
76
+ - Coverage is a curated subset of MySQL's surface; open an issue/PR for gaps.
77
+
78
+ [v0.1.0]: https://github.com/AIops-tools/MySQL-AIops/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wei <zhouwei008@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: mysql-aiops
3
+ Version: 0.1.0
4
+ Summary: Governed AI-ops for MySQL/MariaDB DBA operations: slow-query RCA, InnoDB lock-wait & deadlock analysis, replication-lag RCA and fragmentation analysis with a built-in governance harness (audit, budget, undo, risk tiers)
5
+ Author-email: wei <zhouwei008@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Requires-Python: >=3.11
9
+ Requires-Dist: cryptography>=42.0
10
+ Requires-Dist: mcp[cli]<2.0,>=1.10
11
+ Requires-Dist: pymysql<2.0,>=1.1
12
+ Requires-Dist: pyyaml<7.0,>=6.0
13
+ Requires-Dist: rich<16.0,>=13.0
14
+ Requires-Dist: typer<1.0,>=0.12
15
+ Description-Content-Type: text/markdown
16
+
17
+ <!-- mcp-name: io.github.AIops-tools/mysql-aiops -->
18
+
19
+ # MySQL AIops (preview)
20
+
21
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Oracle Corporation or the MariaDB Foundation.** "MySQL" is a trademark of Oracle Corporation; "MariaDB" is a trademark of MariaDB plc; all product/trademark names belong to their respective owners. MIT licensed.
22
+
23
+ Governed AI-ops for **MySQL 8.x and MariaDB 10.6+ DBA operations** — connecting
24
+ to a server with **PyMySQL** and reading `information_schema` /
25
+ `performance_schema` — with a **built-in governance harness**: unified audit
26
+ log, policy engine, token/runaway budget guard, undo-token recording, and
27
+ graduated-autonomy risk tiers. The server **flavor** (mysql vs mariadb) is
28
+ detected from `version()` and flavor-dependent statements branch automatically
29
+ (`SHOW REPLICA STATUS` vs `SHOW SLAVE STATUS`).
30
+ **Preview — mock-validated only, not run against a live server.**
31
+
32
+ ## What it does
33
+
34
+ Four flagship signature analyses, plus the guarded reads and writes around them:
35
+
36
+ - **Slow-query RCA** — take the worst `events_statements_summary_by_digest`
37
+ entry (plus an optional `EXPLAIN FORMAT=JSON` plan) and map its numbers —
38
+ no-index share (`SUM_NO_INDEX_USED`), lock-time share, rows-examined/sent
39
+ ratio, tmp-disk spill, call count, plan access types — to a cited cause and a
40
+ concrete action. Every finding carries its measured number, not a black-box
41
+ verdict.
42
+ - **InnoDB lock-wait & deadlock chain RCA** — build the wait-for tree from
43
+ `performance_schema.data_lock_waits` (MariaDB:
44
+ `information_schema.innodb_lock_waits`), name the **root blocker** (blocks
45
+ others, waits on none), and parse the **last deadlock** out of
46
+ `SHOW ENGINE INNODB STATUS`.
47
+ - **Replication lag RCA** — map the replica's IO/SQL thread state,
48
+ `Seconds_Behind_Source` and error fields to a cited cause + action
49
+ (stopped IO thread, failed applier statement, lagging applier, intentional
50
+ `SQL_Delay`).
51
+ - **Table fragmentation analysis** — rank tables by reclaimable `data_free`
52
+ from `information_schema.tables` into cited `OPTIMIZE TABLE` candidates.
53
+
54
+ ## What works
55
+
56
+ - **CLI** (`mysql-aiops ...`): `init`, `overview`, `server`, `activity`, `query`, `index`, `table`, `repl`, `analyze`, `remediate`, `secret`, `doctor`, `mcp`.
57
+ - **MCP server** (`mysql-aiops mcp` or `mysql-aiops-mcp`): **33 tools** (25 read, 8 write), every one wrapped with the bundled `@governed_tool` harness.
58
+ - **Encrypted credentials**: the account password lives in an encrypted store `~/.mysql-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `MYSQL_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
59
+ - **Reversibility**: mutating writes fetch the **real before-state first** and record a faithful inverse — `create_index`↔`drop_index`; `drop_index` captures the index definition out of `SHOW CREATE TABLE` so undo recreates it exactly; `set_global_variable` captures the prior value from `SHOW GLOBAL VARIABLES` so undo sets it back. Irreversible ops (`kill_session`, `kill_query`, `optimize_table`, `analyze_table`, `reset_query_stats`) record prior state for audit but declare no undo.
60
+ - **Safety**: every state-changing CLI op supports `--dry-run` and requires double confirmation; every write MCP tool takes a `dry_run` preview. All identifiers that cannot be parameterised (schema/table/index/column/variable names) are validated against a strict charset and backtick-quoted; all values are bound query parameters.
61
+
62
+ ## Capability matrix (33 MCP tools)
63
+
64
+ | Domain | Tools | Count | R/W |
65
+ |--------|-------|:-----:|:---:|
66
+ | **Overview** | `overview` | 1 | read |
67
+ | **Server** | `server_version`, `show_variables`, `show_status`, `list_databases`, `list_engines`, `connection_stats` | 6 | read |
68
+ | **Activity** | `list_sessions`, `long_running_queries`, `list_transactions`, `lock_waits` | 4 | read |
69
+ | **Queries** | `top_queries`, `explain_query` | 2 | read |
70
+ | **Indexes** | `unused_indexes`, `redundant_indexes`, `index_stats` | 3 | read |
71
+ | **Tables** | `table_sizes`, `table_fragmentation`, `table_status` | 3 | read |
72
+ | **Replication** | `replica_status`, `binlog_status` | 2 | read |
73
+ | **Analysis (flagship)** | `slow_query_rca`, `lock_wait_rca`, `replication_lag_rca`, `fragmentation_analysis` | 4 | read |
74
+ | **Writes** | `kill_session`, `kill_query`, `drop_index` | 3 | write (high) |
75
+ | | `optimize_table`, `analyze_table`, `create_index`, `set_global_variable`, `reset_query_stats` | 5 | write (medium) |
76
+
77
+ The flagship analyses accept injected records for pure/offline analysis, or pull
78
+ live from a configured target. `top_queries`/`slow_query_rca` require
79
+ `performance_schema=ON`; the read account should have `PROCESS`,
80
+ `REPLICATION CLIENT` and `SELECT` on `performance_schema`.
81
+
82
+ ## Support scope
83
+
84
+ | Platform | Status |
85
+ |----------|--------|
86
+ | MySQL 8.0 / 8.4 | supported (preview; `SHOW REPLICA STATUS`, `performance_schema.data_lock_waits`) |
87
+ | MariaDB 10.6+ / 11.x | supported (preview; `SHOW SLAVE STATUS`, `information_schema.innodb_lock_waits`) |
88
+ | MySQL 5.7 and older | not targeted (EOL; pre-8.0 digest/lock views untested) |
89
+ | Cloud-managed MySQL (RDS/Aurora/Cloud SQL flavors) | wire-compatible reads should work; managed restrictions (KILL, SET GLOBAL) apply — untested |
90
+
91
+ ## Quick start
92
+
93
+ ```bash
94
+ uv tool install mysql-aiops # or: pipx install mysql-aiops
95
+ mysql-aiops init # wizard: add a target + store the password (encrypted)
96
+ mysql-aiops doctor # verify config, secrets, connectivity, flavor, perf-schema
97
+ mysql-aiops overview # one-shot server health snapshot
98
+ mysql-aiops analyze slow-query # RCA the worst statement digest
99
+ mysql-aiops analyze fragmentation # OPTIMIZE TABLE candidates
100
+ ```
101
+
102
+ Run as an MCP server (stdio):
103
+
104
+ ```bash
105
+ export MYSQL_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
106
+ mysql-aiops-mcp
107
+ ```
108
+
109
+ Claude Desktop / MCP client config:
110
+
111
+ ```json
112
+ {
113
+ "mcpServers": {
114
+ "mysql-aiops": {
115
+ "command": "uvx",
116
+ "args": ["--from", "mysql-aiops", "mysql-aiops-mcp"],
117
+ "env": { "MYSQL_AIOPS_MASTER_PASSWORD": "your-master-password" }
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ > **Env-block caveat**: the `env` block above is the only environment the MCP
124
+ > server sees — GUI-launched clients do **not** inherit your shell profile. Put
125
+ > `MYSQL_AIOPS_MASTER_PASSWORD` (and `MYSQL_AIOPS_HOME` / `MYSQL_AUDIT_APPROVED_BY`
126
+ > if you use them) there, or the server cannot unlock the secret store.
127
+
128
+ ## Governance
129
+
130
+ Every MCP tool passes through the bundled `@governed_tool` harness:
131
+
132
+ - **Audit** — every call (params, result, status, duration, risk tier, approver,
133
+ rationale) is logged to `~/.mysql-aiops/audit.db` (relocatable via
134
+ `MYSQL_AIOPS_HOME`).
135
+ - **Budget / runaway guard** — token and call budgets trip a circuit breaker
136
+ (`MYSQL_MAX_TOOL_CALLS`, `MYSQL_MAX_TOOL_SECONDS`, `MYSQL_RUNAWAY_MAX`).
137
+ - **Risk tiers** — graduated autonomy, **secure by default**: with no
138
+ `rules.yaml`, high-risk writes require a named approver
139
+ (`MYSQL_AUDIT_APPROVED_BY` / `MYSQL_AUDIT_RATIONALE`); `mysql-aiops init`
140
+ seeds an explicit starter `rules.yaml` with that dual-control tier.
141
+ - **Undo recording** — reversible writes record an inverse descriptor built from
142
+ the fetched before-state, replayable through the tool it names.
143
+
144
+ ## Scope
145
+
146
+ This is the **MySQL / MariaDB DBA-ops** member of the AIops-tools family
147
+ (governed AI-ops with audit + budget + undo + risk tiers). Do **NOT** use it
148
+ for PostgreSQL — use **postgres-aiops**. Do **NOT** use it for OT / industrial
149
+ edge — see the separate `industrial-aiops` line — nor for application-schema
150
+ migrations or ORM management.
151
+
152
+ ## Missing a capability?
153
+
154
+ Coverage is intentionally a curated subset of MySQL's catalogs and maintenance
155
+ surface. Missing a view, a metric, or a maintenance command? **Open an issue or
156
+ PR** — contributions welcome. 缺功能提 issue/PR 欢迎留言。
157
+
158
+ ## Status
159
+
160
+ **Preview — mock-validated only, not run against a live server.** The catalog
161
+ queries are modelled from the documented `information_schema` /
162
+ `performance_schema` shapes for MySQL 8.x and MariaDB 10.6+ and need live
163
+ verification. `mysql-aiops doctor` is the fastest live check (connectivity,
164
+ flavor, performance_schema, replica role).
@@ -0,0 +1,148 @@
1
+ <!-- mcp-name: io.github.AIops-tools/mysql-aiops -->
2
+
3
+ # MySQL AIops (preview)
4
+
5
+ > **Disclaimer**: Community-maintained open-source project. **Not affiliated with, endorsed by, or sponsored by Oracle Corporation or the MariaDB Foundation.** "MySQL" is a trademark of Oracle Corporation; "MariaDB" is a trademark of MariaDB plc; all product/trademark names belong to their respective owners. MIT licensed.
6
+
7
+ Governed AI-ops for **MySQL 8.x and MariaDB 10.6+ DBA operations** — connecting
8
+ to a server with **PyMySQL** and reading `information_schema` /
9
+ `performance_schema` — with a **built-in governance harness**: unified audit
10
+ log, policy engine, token/runaway budget guard, undo-token recording, and
11
+ graduated-autonomy risk tiers. The server **flavor** (mysql vs mariadb) is
12
+ detected from `version()` and flavor-dependent statements branch automatically
13
+ (`SHOW REPLICA STATUS` vs `SHOW SLAVE STATUS`).
14
+ **Preview — mock-validated only, not run against a live server.**
15
+
16
+ ## What it does
17
+
18
+ Four flagship signature analyses, plus the guarded reads and writes around them:
19
+
20
+ - **Slow-query RCA** — take the worst `events_statements_summary_by_digest`
21
+ entry (plus an optional `EXPLAIN FORMAT=JSON` plan) and map its numbers —
22
+ no-index share (`SUM_NO_INDEX_USED`), lock-time share, rows-examined/sent
23
+ ratio, tmp-disk spill, call count, plan access types — to a cited cause and a
24
+ concrete action. Every finding carries its measured number, not a black-box
25
+ verdict.
26
+ - **InnoDB lock-wait & deadlock chain RCA** — build the wait-for tree from
27
+ `performance_schema.data_lock_waits` (MariaDB:
28
+ `information_schema.innodb_lock_waits`), name the **root blocker** (blocks
29
+ others, waits on none), and parse the **last deadlock** out of
30
+ `SHOW ENGINE INNODB STATUS`.
31
+ - **Replication lag RCA** — map the replica's IO/SQL thread state,
32
+ `Seconds_Behind_Source` and error fields to a cited cause + action
33
+ (stopped IO thread, failed applier statement, lagging applier, intentional
34
+ `SQL_Delay`).
35
+ - **Table fragmentation analysis** — rank tables by reclaimable `data_free`
36
+ from `information_schema.tables` into cited `OPTIMIZE TABLE` candidates.
37
+
38
+ ## What works
39
+
40
+ - **CLI** (`mysql-aiops ...`): `init`, `overview`, `server`, `activity`, `query`, `index`, `table`, `repl`, `analyze`, `remediate`, `secret`, `doctor`, `mcp`.
41
+ - **MCP server** (`mysql-aiops mcp` or `mysql-aiops-mcp`): **33 tools** (25 read, 8 write), every one wrapped with the bundled `@governed_tool` harness.
42
+ - **Encrypted credentials**: the account password lives in an encrypted store `~/.mysql-aiops/secrets.enc` (Fernet + scrypt) — **never plaintext on disk**. Unlock with a master password from `MYSQL_AIOPS_MASTER_PASSWORD` (MCP/CI) or an interactive prompt (CLI).
43
+ - **Reversibility**: mutating writes fetch the **real before-state first** and record a faithful inverse — `create_index`↔`drop_index`; `drop_index` captures the index definition out of `SHOW CREATE TABLE` so undo recreates it exactly; `set_global_variable` captures the prior value from `SHOW GLOBAL VARIABLES` so undo sets it back. Irreversible ops (`kill_session`, `kill_query`, `optimize_table`, `analyze_table`, `reset_query_stats`) record prior state for audit but declare no undo.
44
+ - **Safety**: every state-changing CLI op supports `--dry-run` and requires double confirmation; every write MCP tool takes a `dry_run` preview. All identifiers that cannot be parameterised (schema/table/index/column/variable names) are validated against a strict charset and backtick-quoted; all values are bound query parameters.
45
+
46
+ ## Capability matrix (33 MCP tools)
47
+
48
+ | Domain | Tools | Count | R/W |
49
+ |--------|-------|:-----:|:---:|
50
+ | **Overview** | `overview` | 1 | read |
51
+ | **Server** | `server_version`, `show_variables`, `show_status`, `list_databases`, `list_engines`, `connection_stats` | 6 | read |
52
+ | **Activity** | `list_sessions`, `long_running_queries`, `list_transactions`, `lock_waits` | 4 | read |
53
+ | **Queries** | `top_queries`, `explain_query` | 2 | read |
54
+ | **Indexes** | `unused_indexes`, `redundant_indexes`, `index_stats` | 3 | read |
55
+ | **Tables** | `table_sizes`, `table_fragmentation`, `table_status` | 3 | read |
56
+ | **Replication** | `replica_status`, `binlog_status` | 2 | read |
57
+ | **Analysis (flagship)** | `slow_query_rca`, `lock_wait_rca`, `replication_lag_rca`, `fragmentation_analysis` | 4 | read |
58
+ | **Writes** | `kill_session`, `kill_query`, `drop_index` | 3 | write (high) |
59
+ | | `optimize_table`, `analyze_table`, `create_index`, `set_global_variable`, `reset_query_stats` | 5 | write (medium) |
60
+
61
+ The flagship analyses accept injected records for pure/offline analysis, or pull
62
+ live from a configured target. `top_queries`/`slow_query_rca` require
63
+ `performance_schema=ON`; the read account should have `PROCESS`,
64
+ `REPLICATION CLIENT` and `SELECT` on `performance_schema`.
65
+
66
+ ## Support scope
67
+
68
+ | Platform | Status |
69
+ |----------|--------|
70
+ | MySQL 8.0 / 8.4 | supported (preview; `SHOW REPLICA STATUS`, `performance_schema.data_lock_waits`) |
71
+ | MariaDB 10.6+ / 11.x | supported (preview; `SHOW SLAVE STATUS`, `information_schema.innodb_lock_waits`) |
72
+ | MySQL 5.7 and older | not targeted (EOL; pre-8.0 digest/lock views untested) |
73
+ | Cloud-managed MySQL (RDS/Aurora/Cloud SQL flavors) | wire-compatible reads should work; managed restrictions (KILL, SET GLOBAL) apply — untested |
74
+
75
+ ## Quick start
76
+
77
+ ```bash
78
+ uv tool install mysql-aiops # or: pipx install mysql-aiops
79
+ mysql-aiops init # wizard: add a target + store the password (encrypted)
80
+ mysql-aiops doctor # verify config, secrets, connectivity, flavor, perf-schema
81
+ mysql-aiops overview # one-shot server health snapshot
82
+ mysql-aiops analyze slow-query # RCA the worst statement digest
83
+ mysql-aiops analyze fragmentation # OPTIMIZE TABLE candidates
84
+ ```
85
+
86
+ Run as an MCP server (stdio):
87
+
88
+ ```bash
89
+ export MYSQL_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
90
+ mysql-aiops-mcp
91
+ ```
92
+
93
+ Claude Desktop / MCP client config:
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ "mysql-aiops": {
99
+ "command": "uvx",
100
+ "args": ["--from", "mysql-aiops", "mysql-aiops-mcp"],
101
+ "env": { "MYSQL_AIOPS_MASTER_PASSWORD": "your-master-password" }
102
+ }
103
+ }
104
+ }
105
+ ```
106
+
107
+ > **Env-block caveat**: the `env` block above is the only environment the MCP
108
+ > server sees — GUI-launched clients do **not** inherit your shell profile. Put
109
+ > `MYSQL_AIOPS_MASTER_PASSWORD` (and `MYSQL_AIOPS_HOME` / `MYSQL_AUDIT_APPROVED_BY`
110
+ > if you use them) there, or the server cannot unlock the secret store.
111
+
112
+ ## Governance
113
+
114
+ Every MCP tool passes through the bundled `@governed_tool` harness:
115
+
116
+ - **Audit** — every call (params, result, status, duration, risk tier, approver,
117
+ rationale) is logged to `~/.mysql-aiops/audit.db` (relocatable via
118
+ `MYSQL_AIOPS_HOME`).
119
+ - **Budget / runaway guard** — token and call budgets trip a circuit breaker
120
+ (`MYSQL_MAX_TOOL_CALLS`, `MYSQL_MAX_TOOL_SECONDS`, `MYSQL_RUNAWAY_MAX`).
121
+ - **Risk tiers** — graduated autonomy, **secure by default**: with no
122
+ `rules.yaml`, high-risk writes require a named approver
123
+ (`MYSQL_AUDIT_APPROVED_BY` / `MYSQL_AUDIT_RATIONALE`); `mysql-aiops init`
124
+ seeds an explicit starter `rules.yaml` with that dual-control tier.
125
+ - **Undo recording** — reversible writes record an inverse descriptor built from
126
+ the fetched before-state, replayable through the tool it names.
127
+
128
+ ## Scope
129
+
130
+ This is the **MySQL / MariaDB DBA-ops** member of the AIops-tools family
131
+ (governed AI-ops with audit + budget + undo + risk tiers). Do **NOT** use it
132
+ for PostgreSQL — use **postgres-aiops**. Do **NOT** use it for OT / industrial
133
+ edge — see the separate `industrial-aiops` line — nor for application-schema
134
+ migrations or ORM management.
135
+
136
+ ## Missing a capability?
137
+
138
+ Coverage is intentionally a curated subset of MySQL's catalogs and maintenance
139
+ surface. Missing a view, a metric, or a maintenance command? **Open an issue or
140
+ PR** — contributions welcome. 缺功能提 issue/PR 欢迎留言。
141
+
142
+ ## Status
143
+
144
+ **Preview — mock-validated only, not run against a live server.** The catalog
145
+ queries are modelled from the documented `information_schema` /
146
+ `performance_schema` shapes for MySQL 8.x and MariaDB 10.6+ and need live
147
+ verification. `mysql-aiops doctor` is the fastest live check (connectivity,
148
+ flavor, performance_schema, replica role).
@@ -0,0 +1,60 @@
1
+ # MySQL AIops v0.1.0 — preview
2
+
3
+ Governed AI-ops for **MySQL 8.x / MariaDB 10.6+ DBA operations** for AI agents
4
+ — connecting via **PyMySQL** and reading `information_schema` /
5
+ `performance_schema` — with a built-in governance harness (audit, policy,
6
+ token/runaway budget, undo-token recording, graduated risk tiers) and an
7
+ encrypted credential store. Standalone — no external skill-family dependency.
8
+
9
+ > **Preview / mock-only.** All behaviour is validated against a mocked PyMySQL
10
+ > cursor/connection; it has **not** been run against a live MySQL or MariaDB
11
+ > server. The fastest live check is `mysql-aiops doctor`.
12
+ >
13
+ > Community-maintained; **not affiliated with or endorsed by Oracle Corporation
14
+ > or the MariaDB Foundation.** "MySQL" and "MariaDB" trademarks belong to their
15
+ > owners.
16
+
17
+ ## Highlights
18
+
19
+ - **33 MCP tools** (25 read, 8 write), every one wrapped with `@governed_tool`.
20
+ - Read: server `overview`; server reads (6); activity (4); query stats (2);
21
+ index health (3); table health (3); replication (2); and four flagship
22
+ analyses.
23
+ - Write: `kill_session`/`kill_query`/`drop_index` (high);
24
+ `optimize_table`/`analyze_table`/`create_index`/`set_global_variable`/
25
+ `reset_query_stats` (medium).
26
+ - **Four signature analyses** — `slow_query_rca` (worst statement digest +
27
+ EXPLAIN → cited cause/action), `lock_wait_rca` (InnoDB wait-for tree with the
28
+ root blocker named + last deadlock parsed from `SHOW ENGINE INNODB STATUS`),
29
+ `replication_lag_rca` (thread state / lag / error fields → cause + action),
30
+ and `fragmentation_analysis` (`data_free` → OPTIMIZE TABLE candidates).
31
+ - **Flavor-aware** — mysql vs mariadb detected from `version()`;
32
+ `SHOW REPLICA STATUS` vs `SHOW SLAVE STATUS` and the lock-wait source branch
33
+ automatically; doctor and overview report the flavor.
34
+ - **Encrypted password store** (`~/.mysql-aiops/secrets.enc`, Fernet + scrypt)
35
+ — never plaintext on disk; legacy `MYSQL_<TARGET>_PASSWORD` env fallback.
36
+ - **CLI** with an `init` onboarding wizard (TLS modes incl. verify_ca /
37
+ verify_identity), `secret` management, and `doctor`.
38
+ - **PyMySQL connection layer** — parameterised catalog reads, `DictCursor`
39
+ results, autocommit for maintenance commands, 30s timeouts, and teaching
40
+ error translation (`MySQLError`). Reversible writes fetch the real
41
+ before-state first.
42
+
43
+ ## Install
44
+
45
+ ```bash
46
+ uv tool install mysql-aiops
47
+ mysql-aiops init
48
+ mysql-aiops doctor
49
+ ```
50
+
51
+ ## Caveats
52
+
53
+ - The `information_schema` / `performance_schema` queries are modelled from the
54
+ documented MySQL 8.x / MariaDB 10.6+ shapes and need live verification.
55
+ - `top_queries` / `slow_query_rca` require `performance_schema=ON`; the read
56
+ account should have `PROCESS`, `REPLICATION CLIENT` and `SELECT` on
57
+ `performance_schema`.
58
+ - Out of scope by design: application-schema migrations, ORM management,
59
+ logical backup/restore orchestration, and any bulk destructive DDL.
60
+ - Missing a view, metric, or maintenance command? Open an issue or PR.
@@ -0,0 +1,95 @@
1
+ # Security Policy
2
+
3
+ ## Disclaimer
4
+
5
+ Community-maintained open-source project. **Not affiliated with, endorsed by, or
6
+ sponsored by Oracle Corporation or the MariaDB Foundation.** "MySQL" and
7
+ "MariaDB" trademarks belong to their respective owners. Source is publicly
8
+ auditable under the MIT license.
9
+
10
+ ## Reporting Vulnerabilities
11
+
12
+ Report privately via a GitHub Security Advisory on
13
+ [github.com/AIops-tools/MySQL-AIops](https://github.com/AIops-tools/MySQL-AIops/security/advisories)
14
+ or email zhouwei008@gmail.com. Please do not open public issues for security
15
+ reports.
16
+
17
+ ## Security Design
18
+
19
+ ### Credential Management
20
+ - Per-target MySQL account passwords live **encrypted** in
21
+ `~/.mysql-aiops/secrets.enc` (Fernet/AES-128 + scrypt-derived key; chmod
22
+ 600), never in `config.yaml` and never in source. The master password is never
23
+ stored — only a per-store random salt and the ciphertext are on disk.
24
+ - A legacy plaintext env var `MYSQL_<TARGET_NAME_UPPER>_PASSWORD` is still
25
+ honoured as a fallback with a deprecation warning (migrate with
26
+ `mysql-aiops secret migrate`).
27
+ - The password is passed to `pymysql.connect` at connect time and held only in
28
+ memory. It is never logged or echoed; `config.yaml` holds only host, port,
29
+ database, user, `ssl_mode` (and optionally `ssl_ca`). The redacted DSN
30
+ (`dsn_redacted`) masks it.
31
+
32
+ ### SQL-Injection Defenses
33
+ - **All values are bound query parameters** (session ids, thresholds, limits,
34
+ variable values) — never string-formatted into SQL.
35
+ - The few identifiers that cannot be parameterised (schema/table/index/column
36
+ names, global variable names, `ORDER BY` columns) are validated against a
37
+ strict identifier charset / allow-lists (`mysql_aiops.ops._util`) and
38
+ backtick-quoted before the single interpolation site; anything that is not a
39
+ plain identifier is rejected, not interpolated.
40
+ - `EXPLAIN` rejects multi-statement input (an embedded `;` is refused).
41
+ - The `drop_index` undo replay path (`create_index(definition=...)`) is
42
+ shape-gated: single statement, must be `CREATE [UNIQUE] INDEX ... ON ...`.
43
+
44
+ ### Governed Operations
45
+ Every MCP tool runs through the bundled `@governed_tool` harness
46
+ (`mysql_aiops.governance`):
47
+ - **Audit** — every call logged to a local SQLite DB under `~/.mysql-aiops/`
48
+ (relocatable via `MYSQL_AIOPS_HOME`), agent-attributed, secret-redacted.
49
+ - **Token/runaway budget** — hard ceilings (`MYSQL_MAX_TOOL_CALLS` /
50
+ `MYSQL_MAX_TOOL_SECONDS` — the env-var names the bundled harness reads) plus
51
+ an on-by-default guard that trips a tight poll/retry loop.
52
+ - **Graduated risk tiers** — **secure by default**: with no
53
+ `~/.mysql-aiops/rules.yaml`, high/critical writes are denied unless
54
+ `MYSQL_AUDIT_APPROVED_BY` names an approver (`MYSQL_AUDIT_RATIONALE` for
55
+ why); `mysql-aiops init` seeds an explicit starter rules.yaml.
56
+ - **Undo-token recording** — reversible writes fetch the **real before-state
57
+ first** and record a faithful inverse (`create_index`↔`drop_index`, where
58
+ drop rebuilds the definition from `SHOW CREATE TABLE`;
59
+ `set_global_variable` restores the prior value).
60
+
61
+ ### State-Changing Operations
62
+ Every write supports `--dry-run` (CLI) / `dry_run=True` (MCP) and requires double
63
+ confirmation at the CLI layer. Destructive/irreversible ops (`kill_session`,
64
+ `kill_query`, `drop_index`) are `risk_level=high`; mutating maintenance ops
65
+ (`optimize_table`, `analyze_table`, `create_index`, `set_global_variable`,
66
+ `reset_query_stats`) are `medium`. Irreversible ops capture prior state for the
67
+ audit record but record no undo token. `SET GLOBAL` is runtime-only and reports
68
+ (but does not auto-perform) the my.cnf / SET PERSIST persistence step.
69
+
70
+ ### SSL/TLS
71
+ `ssl_mode` follows MySQL client semantics (default `preferred`); set
72
+ `verify_ca` / `verify_identity` (with `ssl_ca`) on untrusted networks;
73
+ `disabled` is for isolated labs only.
74
+
75
+ ### Output Sanitisation
76
+ All catalog- and query-returned text (query text, object names, error strings)
77
+ is passed through a `sanitize()` truncate + control-character strip before
78
+ reaching the agent. This bounds length and strips control/format characters;
79
+ semantic resistance to adversarial text must come from the consuming agent.
80
+
81
+ ### Network Scope
82
+ No webhooks, no telemetry, no outbound calls beyond the configured MySQL
83
+ connection. No post-install scripts or background services.
84
+
85
+ ## Static Analysis
86
+
87
+ ```bash
88
+ uvx bandit -r mysql_aiops/ mcp_server/
89
+ uv run ruff check .
90
+ ```
91
+
92
+ ## Supported Versions
93
+
94
+ The latest released version receives security fixes. This is a preview (0.x);
95
+ pin a version in production.
@@ -0,0 +1 @@
1
+ """MCP server package for mysql-aiops."""