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.
- mysql_aiops-0.1.0/.github/workflows/mcp-publish.yml +55 -0
- mysql_aiops-0.1.0/.github/workflows/publish.yml +26 -0
- mysql_aiops-0.1.0/.gitignore +8 -0
- mysql_aiops-0.1.0/CHANGELOG.md +78 -0
- mysql_aiops-0.1.0/LICENSE +21 -0
- mysql_aiops-0.1.0/PKG-INFO +164 -0
- mysql_aiops-0.1.0/README.md +148 -0
- mysql_aiops-0.1.0/RELEASE_NOTES.md +60 -0
- mysql_aiops-0.1.0/SECURITY.md +95 -0
- mysql_aiops-0.1.0/mcp_server/__init__.py +1 -0
- mysql_aiops-0.1.0/mcp_server/_shared.py +102 -0
- mysql_aiops-0.1.0/mcp_server/server.py +38 -0
- mysql_aiops-0.1.0/mcp_server/tools/__init__.py +1 -0
- mysql_aiops-0.1.0/mcp_server/tools/activity.py +62 -0
- mysql_aiops-0.1.0/mcp_server/tools/analysis.py +124 -0
- mysql_aiops-0.1.0/mcp_server/tools/indexes.py +46 -0
- mysql_aiops-0.1.0/mcp_server/tools/queries.py +60 -0
- mysql_aiops-0.1.0/mcp_server/tools/remediation.py +256 -0
- mysql_aiops-0.1.0/mcp_server/tools/replication.py +34 -0
- mysql_aiops-0.1.0/mcp_server/tools/server.py +101 -0
- mysql_aiops-0.1.0/mcp_server/tools/tables.py +48 -0
- mysql_aiops-0.1.0/mcp_server/tools/undo.py +121 -0
- mysql_aiops-0.1.0/mysql_aiops/__init__.py +14 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/__init__.py +9 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/_common.py +78 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/_root.py +70 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/activity.py +66 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/analyze.py +68 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/doctor.py +21 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/index.py +45 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/init.py +163 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/overview.py +16 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/query.py +78 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/remediate.py +157 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/replication.py +35 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/secret.py +103 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/server.py +82 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/table.py +45 -0
- mysql_aiops-0.1.0/mysql_aiops/cli/undo.py +62 -0
- mysql_aiops-0.1.0/mysql_aiops/config.py +187 -0
- mysql_aiops-0.1.0/mysql_aiops/connection.py +201 -0
- mysql_aiops-0.1.0/mysql_aiops/doctor.py +120 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/__init__.py +40 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/audit.py +377 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/budget.py +225 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/decorators.py +482 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/paths.py +23 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/patterns.py +378 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/policy.py +430 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/sanitize.py +45 -0
- mysql_aiops-0.1.0/mysql_aiops/governance/undo.py +218 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/__init__.py +1 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/_util.py +116 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/activity.py +209 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/analysis.py +448 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/indexes.py +142 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/overview.py +59 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/queries.py +137 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/remediation.py +297 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/replication.py +104 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/server.py +138 -0
- mysql_aiops-0.1.0/mysql_aiops/ops/tables.py +142 -0
- mysql_aiops-0.1.0/mysql_aiops/secretstore.py +304 -0
- mysql_aiops-0.1.0/pyproject.toml +60 -0
- mysql_aiops-0.1.0/server.json +21 -0
- mysql_aiops-0.1.0/skills/mysql-aiops/SKILL.md +125 -0
- mysql_aiops-0.1.0/skills/mysql-aiops/references/capabilities.md +82 -0
- mysql_aiops-0.1.0/skills/mysql-aiops/references/cli-reference.md +78 -0
- mysql_aiops-0.1.0/skills/mysql-aiops/references/setup-guide.md +116 -0
- mysql_aiops-0.1.0/smithery.yaml +9 -0
- mysql_aiops-0.1.0/tests/conftest.py +65 -0
- mysql_aiops-0.1.0/tests/test_analysis.py +198 -0
- mysql_aiops-0.1.0/tests/test_cli_writes.py +102 -0
- mysql_aiops-0.1.0/tests/test_connection.py +166 -0
- mysql_aiops-0.1.0/tests/test_doctor.py +240 -0
- mysql_aiops-0.1.0/tests/test_governance_persistence.py +180 -0
- mysql_aiops-0.1.0/tests/test_init.py +140 -0
- mysql_aiops-0.1.0/tests/test_reads.py +267 -0
- mysql_aiops-0.1.0/tests/test_secretstore.py +99 -0
- mysql_aiops-0.1.0/tests/test_smoke.py +267 -0
- mysql_aiops-0.1.0/tests/test_undo_executor.py +138 -0
- mysql_aiops-0.1.0/tests/test_undo_replay.py +111 -0
- mysql_aiops-0.1.0/tests/test_writes.py +212 -0
- 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,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."""
|