io.github.AIops-tools/ceph-aiops
This MCP server lets an agent inspect and manage a Ceph cluster through governed read/write tools, with risk levels, dry-run previews for destructive actions, and undo recording.
Read cluster health/status, monitor and mgr status, slow ops, capacity forecasts, CephFS/RGW status.
Inspect OSDs, placement groups, pools, and RBD images.
Perform reversible writes such as cluster flags, OSD reweight/mark-in, recovery throttling, pool quota/PG/autoscale changes, and RBD snapshots.
Perform high-risk/destructive writes with dry-run support: OSD mark-out/purge, pool delete/resize, RBD image/snapshot delete.
Trigger shallow/deep scrubs and create pools or RBD images.
List recorded undo tokens and apply them, with dry-run preview.
Every tool carries risk metadata, and writes are recorded through the project’s audit/governance harness.
Provides governance-enhanced AIOps for Ceph clusters, allowing health analysis, OSD management, pool operations, RBD management, and more via the Ceph Dashboard API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@io.github.AIops-tools/ceph-aiops What's the root cause of the cluster health warning?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Ceph AIops
Audit availability: Real writes require a committed
pendingaudit row and stop before contacting the platform if storage is unavailable. Reads and previews may continue with a warning; new audit rows store outcome summaries rather than full responses.
Disclaimer: Community-maintained open-source project. Not affiliated with, endorsed by, or sponsored by the Ceph project or any storage vendor. Product and trademark names belong to their owners. MIT licensed.
Governed AI-ops for Ceph — talks to a vanilla ceph-mgr Dashboard REST API
(HTTPS :8443, username + password exchanged for a short-lived JWT at
POST /api/auth) with a built-in governance harness: unified audit log,
token/runaway budget guard, undo-token recording, and descriptive risk tiers.
Works against stock ceph-mgr — cephadm,
hypervisor-bundled Ceph, or MicroCeph — with no croit and no Kubernetes
dependency. Self-contained: no external skill-family dependency.
What it does
The flagship analysis, plus the guarded reads and writes around it:
cluster_health— HEALTH_WARN/ERR root-cause analysis. Instead of echoing raw check codes (PG_DEGRADED,OSD_NEARFULL,SLOW_OPS,MON_DOWN,LARGE_OMAP_OBJECTS, …), it turns each active check into plain language: what it means, the likely cause, and the suggested next action. This is the differentiator vs the hobby Ceph MCPs that just proxyceph -s.Governed destructive ops. The operations operators actually fear —
osd_purge,pool_delete,set_pool_size,rbd_image_delete— carry dry-run + double-confirm and a high risk tier; reversible tuning (osd_reweight,throttle_recovery,cluster_flag_set, pool quota/pg_num/ autoscale) records an undo descriptor capturing the prior state.
Related MCP server: OpenShift SRE Copilot
What this tool does, and does not, decide
It delivers Ceph operations — reads and writes — accurately and efficiently, and records every one of them. It does not decide whether a write is allowed to happen. That is the agent's judgement, or the permission of the account you connect it with: give it a ceph-mgr Dashboard account with a read-only role and the writes fail at the mgr — the place that actually owns the permission.
So there is no read-only switch, no policy file, no approval gate to configure.
The one thing the tool guarantees is that nothing is silent: every call, over
MCP and over the CLI alike, lands an audit row in ~/.ceph-aiops/audit.db,
and destructive writes still capture their before-state and record an inverse
where one exists.
Each tool declares a
risk_level, kept in agreement with its[READ]/[WRITE]documentation tag by a test, and carried into the audit row as a descriptive tier — so a reviewer can see at a glance that a row was a high-risk delete. It is a label, not a gate.
What works
CLI (
ceph-aiops ...):init,overview,health detail/health status,osd tree/df/reweight/out/purge,secret set/list/rm/migrate/rotate-password,doctor,mcp.osd outandosd purgerequire--dry-run+ double confirm.MCP server (
ceph-aiops mcporceph-aiops-mcp): the full 37 tools (17 read, 18 write, 2 undo), every one wrapped with the bundled@governed_toolharness. The CLI is a convenience subset; the MCP surface is the whole tool.Encrypted credentials: the Dashboard password lives in an encrypted store
~/.ceph-aiops/secrets.enc(Fernet + scrypt) — never plaintext on disk. Unlock with a master password fromCEPH_AIOPS_MASTER_PASSWORD(MCP/CI) or an interactive prompt (CLI).Reversibility: reversible writes capture the prior state and record an inverse undo descriptor (e.g.
osd_reweight→ prior weight,set_pool_quota→ prior quota,throttle_recovery→ prior backfill/recovery settings).Safety: destructive ops (
osd_purge,osd_mark_out,pool_delete,set_pool_size,rbd_image_delete,rbd_snapshot_delete) arehighrisk withdry_runand CLI double confirmation.
Capability matrix (37 MCP tools)
Group | Tools | Count | R/W |
Health |
| 2 | read |
OSD |
| 3 | read |
| 3 | write | |
| 2 | write | |
PG |
| 3 | read |
| 2 | write | |
Pool |
| 2 | read |
| 4 | write | |
| 2 | write | |
RBD |
| 1 | read |
| 2 | write | |
| 2 | write | |
CephFS / RGW |
| 2 | read |
Cluster-ops |
| 4 | read |
| 1 | write | |
Undo |
| 2 | undo |
Totals: 37 tools — 17 read, 18 write, 2 undo.
Quick start
As a Claude Code plugin
One install gives an agent both the skill and the MCP server:
/plugin marketplace add AIops-tools/marketplace
/plugin install ceph-aiops@aiops-toolsThe MCP server is fetched with uv and pinned to the
package version this plugin declares, so an audit row can be traced back to the
code that wrote it. Credentials are still configured with ceph-aiops init — see below.
As an OpenClaw plugin
The same bundle is published on ClawHub, where one install delivers the skill and its MCP server together:
openclaw plugins install clawhub:@zw008/ceph-aiops
openclaw skills info ceph-aiops # expect: Visible to model: yesRestart the OpenClaw gateway afterwards so it loads the plugin. The MCP server is
fetched with uv, pinned to this exact release, so
uvx has to be on PATH — without it the skill still installs but reports
Visible to model: no. Credentials are configured exactly as below.
As a CLI or standalone MCP server
uv tool install ceph-aiops # or: pipx install ceph-aiops
ceph-aiops init # wizard: add a mgr target + store the Dashboard password (encrypted)
ceph-aiops doctor # JWT login + mgr-dashboard reachability
ceph-aiops overview # HEALTH status + active checks + OSD up/in
ceph-aiops health detail # decode the active HEALTH_WARN/ERR checks (RCA)
ceph-aiops osd df # per-OSD utilization, most-full first, near/backfill-full flagsRun as an MCP server (stdio):
export CEPH_AIOPS_MASTER_PASSWORD=... # unlock secrets non-interactively
ceph-aiops-mcpWhere that password then lives: an exported variable is readable by every process this shell starts and is recorded by shell history. On a shared or long-lived host, prefer the interactive prompt, or inject it from a secret manager for the life of the one command that needs it.
Governance
Every operation — MCP and CLI — passes through the bundled @governed_tool
harness. It records; it does not authorize (see above).
Audit — every call (params, outcome summary, status, duration, risk tier, and any operator-supplied approver/rationale) is logged to
~/.ceph-aiops/audit.db(relocatable viaCEPH_AIOPS_HOME). The CLI writes the same row the MCP path does — there is no unaudited entry point.Runaway guard — a safety backstop, not an authorization gate: the same call hammered in a tight loop trips a circuit breaker so a stuck agent can't burn unbounded calls/time. Disable with
CEPH_RUNAWAY_MAX=0; optional hard ceilings viaCEPH_MAX_TOOL_CALLS/CEPH_MAX_TOOL_SECONDS.Undo recording — reversible writes record an inverse descriptor built from the fetched before-state.
Risk tier — a descriptive label on the audit row derived from
risk_level; it gates nothing.
Supported scope & limitations
Deployments: vanilla ceph-mgr with the dashboard module enabled — cephadm, hypervisor-bundled Ceph, or MicroCeph. No croit, no Kubernetes dependency.
Ceph has no ETag / pagination on the Dashboard API, so this tool exposes none — nothing is missing, the upstream API simply doesn't offer them.
Validation status: behaviour is exercised against mocked Dashboard responses by the test suite; multi-node rebalance and the write ops have not been run against a live cluster. The cheapest live check is a single-node MicroCeph (
snap install microceph→ bootstrap → loop-file OSDs) runningceph-aiops doctor; a 3-node Vagrant cluster exercises real rebalance behaviour. Seedocs/VERIFICATION.mdfor the full live-verification checklist.
Missing a capability?
RGW multisite, per-daemon config sprawl, NFS-Ganesha exports, orchestrator (cephadm) host management — not here yet. Open an issue or send a PR — feedback and contributions are welcome.
Available Tools
37 toolscapacity_forecastARead-only
[READ] Capacity usage + a deterministic days-to-nearfull projection.
Pass an observed daily growth in bytes to get daysToNearfull; without it the forecast is "insufficient-data". Nearfull is 85% of total. No clock is read — the projection is pure arithmetic.
Args: daily_growth_bytes: Observed daily growth in bytes; omit for a usage-only view. target: Ceph target name from config; omit for the default.
Inputs: target, daily_growth_bytes.
cephfs_statusARead-only
[READ] Per-filesystem MDS ranks with the behind-on-trimming backpressure signal.
Surfaces each MDS rank's state, the client/standby counts, and the notorious "MDS behind on trimming" flag that quietly precedes metadata stalls.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
cluster_flag_setADestructive
[WRITE][risk=medium] Set/unset a cluster flag (noout/nobackfill/norecover/noscrub…).
Heavily used before maintenance (e.g. set noout while rebooting a host). Reversible — records an undo that toggles the flag back.
Args: flag: Flag name, e.g. "noout", "noscrub", "nobackfill", "norecover". enable: True to set the flag, False to clear it. target: Ceph target name from config; omit for the default.
Inputs: flag (required), enable, target.
cluster_healthARead-only
[READ] HEALTH status with a plain-language cause + suggested action per active check.
Call this first on any "the cluster is unhealthy" question — it decodes raw HEALTH_WARN/ERR check codes (PG_DEGRADED, OSD_NEARFULL, …) into what's wrong and what to do next.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
cluster_statusARead-only
[READ] Compact ceph -s summary: mons, OSDs up/in, PGs, usage, objects.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
mgr_statusBRead-only
[READ] Active mgr, its standbys, and the enabled mgr modules.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
mon_statusARead-only
[READ] Monitor quorum: mons in/out of quorum and the monmap epoch.
Call this when health flags MON_DOWN or a clock-skew warn — it shows which monitors are actually holding quorum.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
osd_dfARead-only
[READ] Per-OSD utilisation (most-full first) with near/backfill-full flags.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
osd_mark_inADestructive
[WRITE][risk=medium] Mark an OSD 'in' (return a drained/repaired OSD to service).
Args: osd_id: Numeric OSD id (from osd_tree). target: Ceph target name from config; omit for the default.
Inputs: osd_id (required), target.
osd_mark_outADestructive
[WRITE][risk=high] Mark an OSD 'out' — drains its data (recovery storm / min_size risk).
Destructive to redundancy — pass dry_run=True to preview.
Args: osd_id: Numeric OSD id (from osd_tree). dry_run: If True, preview without marking out. target: Ceph target name from config; omit for the default.
Inputs: osd_id (required), target, dry_run.
osd_perfARead-only
[READ] Per-OSD commit/apply latency (slowest first) — find the slow disk.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
osd_purgeADestructive
[WRITE][risk=high] Purge an OSD (destroy + crush rm + auth del). Irreversible.
Pass dry_run=True to preview. Drain first (osd_reweight 0 → mark out → wait active+clean) before purging.
Args: osd_id: Numeric OSD id (from osd_tree). dry_run: If True, preview without purging. target: Ceph target name from config; omit for the default.
Inputs: osd_id (required), target, dry_run.
osd_reweightADestructive
[WRITE][risk=medium] Set an OSD's reweight (0.0 drains it). Reversible → prior weight.
Pass dry_run=True to preview the current→target weight without applying it.
Args: osd_id: Numeric OSD id (from osd_tree). weight: New reweight 0.0–1.0 (0.0 = full drain). dry_run: If True, read the current weight and preview without reweighting. target: Ceph target name from config; omit for the default.
Inputs: osd_id (required), weight (required), target, dry_run.
osd_treeBRead-only
[READ] All OSDs: up/in state, weight, host, device class.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
pg_dump_stuckARead-only
[READ] Stuck PGs (inactive/unclean/stale/undersized/degraded) with implicated OSDs.
Use this when a PG is not recovering — it surfaces the OSD ids to investigate.
Returns {"stuck": [...], "returned": N, "limit": L, "truncated": bool};
when truncated is true there are more stuck PGs than were returned.
Args: target: Ceph target name from config; omit for the default. limit: Maximum stuck-PG rows to return. Default 200.
Inputs: limit, target.
pg_summaryARead-only
[READ] PG state histogram + every PG that is not active+clean.
Call this to answer "are my PGs healthy?" — it counts PGs by state and lists
the ones needing attention. unhealthyCount is the true total; the
unhealthy list is capped at limit and sets truncated: true when
there were more. Re-run with a higher limit rather than treating a truncated
result as complete.
Args: target: Ceph target name from config; omit for the default. limit: Maximum unhealthy PG rows to return. Default 200.
Inputs: limit, target.
pool_createADestructive
[WRITE][risk=medium] Create a replicated pool.
Args: pool_name: Name for the new pool. pg_num: Initial placement-group count (default 32). size: Replica count (default 3). application: Pool application tag: "rbd", "cephfs", or "rgw" (default "rbd"). target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), size, pg_num, target, +1 more.
pool_deleteADestructive
[WRITE][risk=high] Delete a pool — destroys all of its data. Irreversible.
Pass dry_run=True to preview. The classic footgun: there is no undo once the data is gone.
Refuses .mgr / .rgw.root and any mgr-owned pool: ceph-mgr serves the Dashboard REST API this tool speaks, so deleting its pool severs the transport for every later call. Enforced under dry_run too.
Args: pool_name: Pool name (from pool_ls). dry_run: If True, preview without deleting. target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), target, dry_run.
pool_dfARead-only
[READ] Per-pool usage: used/avail bytes, percent, objects, usable capacity.
Returns {"pools": [...], "returned": N, "error": str | None}. A non-null "error" means the query failed — that is NOT the same as a cluster with no pools, so do not report it as "nothing to worry about".
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
pool_lsARead-only
[READ] All pools: size/min_size, pg_num, autoscale mode, application, quota.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
rbd_image_createADestructive
[WRITE][risk=medium] Create a new RBD image in a pool.
Args: pool_name: Pool the image lives in (from a pool listing). name: New image name. size_bytes: Image size in bytes. target: Ceph target name from config; omit for the default.
Inputs: name (required), pool_name (required), size_bytes (required), target.
rbd_image_deleteADestructive
[WRITE][risk=high] Delete an RBD image and ALL its data. Irreversible.
Pass dry_run=True to preview.
Args: pool_name: Pool the image lives in. image_name: Image to delete (from rbd_ls). dry_run: If True, preview without deleting. target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), image_name (required), target, dry_run.
rbd_lsARead-only
[READ] RBD images (optionally one pool): size, features, snapshot count.
Args: pool: Restrict to a single pool name; omit for all pools. target: Ceph target name from config; omit for the default.
Inputs: pool, target.
rbd_snapshot_createADestructive
[WRITE][risk=medium] Snapshot an RBD image. Reversible → delete the snapshot.
Args: pool_name: Pool the image lives in. image_name: Image to snapshot (from rbd_ls). snap_name: Name for the new snapshot. target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), snap_name (required), image_name (required), target.
rbd_snapshot_deleteADestructive
[WRITE][risk=high] Delete an RBD image snapshot. Irreversible.
Pass dry_run=True to preview.
Args: pool_name: Pool the image lives in. image_name: Image the snapshot belongs to. snap_name: Snapshot to delete. dry_run: If True, preview without deleting. target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), snap_name (required), image_name (required), target, +1 more.
rgw_statusARead-only
[READ] RGW daemons plus a large-omap (unsharded bucket index) scan.
Flags buckets whose index is unsharded/oversized — the LARGE_OMAP signal and the top RGW performance foot-gun. Partial-safe if the bucket call fails.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
scrub_statusARead-only
[READ] PGs overdue for shallow / deep scrub (decodes PG_NOT(_DEEP)_SCRUBBED).
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
set_pool_autoscaleADestructive
[WRITE][risk=medium] Set a pool's PG autoscale mode (on/off/warn). Reversible → prior.
Args: pool_name: Pool name (from pool_ls). mode: Autoscale mode: "on", "off", or "warn". target: Ceph target name from config; omit for the default.
Inputs: mode (required), pool_name (required), target.
set_pool_pg_numADestructive
[WRITE][risk=medium] Set a pool's pg_num. Reversible → prior pg_num.
Args: pool_name: Pool name (from pool_ls). pg_num: New placement-group count. target: Ceph target name from config; omit for the default.
Inputs: pg_num (required), pool_name (required), target.
set_pool_quotaADestructive
[WRITE][risk=medium] Set a pool's byte/object quota. Reversible → prior quota.
Args: pool_name: Pool name (from pool_ls). max_bytes: New byte quota (0 clears it); omit to leave unchanged. max_objects: New object quota (0 clears it); omit to leave unchanged. target: Ceph target name from config; omit for the default.
Inputs: pool_name (required), target, max_bytes, max_objects.
set_pool_sizeADestructive
[WRITE][risk=high] Set a pool's replica size — forces mass data movement on a live pool.
Pass dry_run=True to preview. Reversible → prior size.
Refuses a size REDUCTION on .mgr / .rgw.root and any mgr-owned pool: fewer replicas degrades ceph-mgr, which serves the Dashboard REST API this tool speaks — so the recorded undo would have no transport to travel over. RAISING the size on those pools is allowed. Enforced under dry_run too.
Args: pool_name: Pool name (from pool_ls). size: New replica count. dry_run: If True, preview without changing the size. target: Ceph target name from config; omit for the default.
Inputs: size (required), pool_name (required), target, dry_run.
slow_opsARead-only
[READ] Blocked/slow requests per OSD (decodes the SLOW_OPS health check).
Use this to find the OSD sitting on blocked ops when clients report stalls.
Args: target: Ceph target name from config; omit for the default.
Inputs: target.
throttle_recoveryADestructive
[WRITE][risk=medium] Tune osd_max_backfills / osd_recovery_max_active.
The #1 tuning ask: turn recovery/backfill down so a recovery storm stops starving client IO (or back up once it's calm). Reversible — records an undo restoring the prior config values.
Args: max_backfills: New osd_max_backfills value; omit to leave it unchanged. recovery_max_active: New osd_recovery_max_active value; omit to leave unchanged. target: Ceph target name from config; omit for the default.
Inputs: target, max_backfills, recovery_max_active.
trigger_deep_scrubADestructive
[WRITE][risk=medium] Schedule a deep (data-integrity) scrub on a PG.
Args: pgid: Placement group id, e.g. "2.1a" (from pg_summary / scrub_status). target: Ceph target name from config; omit for the default.
Inputs: pgid (required), target.
trigger_scrubADestructive
[WRITE][risk=medium] Schedule a shallow scrub on a PG (clears a PG_NOT_SCRUBBED warn).
Args: pgid: Placement group id, e.g. "2.1a" (from pg_summary / scrub_status). target: Ceph target name from config; omit for the default.
Inputs: pgid (required), target.
undo_applyADestructive
[WRITE][risk=medium] Apply a recorded undo by dispatching its inverse tool.
The inverse runs through its own governed tool, so its real risk tier is recorded there. Pass dry_run=True to preview the inverse call without executing it. A token can only be applied once.
Args:
undo_id: The undoId from undo_list (or an _undo_id in a write result).
dry_run: If True, preview the inverse tool + params without running it.
target: Passed through to the inverse tool when it accepts a target.
Inputs: undo_id (required), target, dry_run.
undo_listARead-only
[READ] List recorded, not-yet-applied undo tokens (most recent first).
Each entry names the original tool, the inverse tool that undo_apply
would run, and a human note. Use the undoId with undo_apply.
Returns {"undos": [...], "returned": N, "limit": L, "truncated": bool}.
truncated is measured (one extra row is fetched), not guessed from a
length coincidence: when it is true there are MORE tokens than shown, so
re-run with a higher limit rather than reporting the list as complete.
Each entry carries effectVerified. False means the original write lost
its response, so the change it reverses is PROBABLE, not confirmed — check
the live state before applying, and do not report the result as a restore
of a state that may never have been reached.
Args: limit: Max rows to return (default 50, capped at 500). target: Unused (undo state is host-local); accepted for CLI uniformity.
Inputs: limit, target.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 37 tools
Most tools target clearly distinct resources and actions (mon vs mgr vs osd vs pg vs pool vs rbd), and descriptions reinforce the boundaries. A few pairs are close enough to risk confusion: cluster_health vs cluster_status, pool_ls vs pool_df, and pg_summary vs pg_dump_stuck, but the prose distinguishes them well.
Everything is snake_case and consistently resource-prefixed (osd_, pool_, pg_, rbd_, cluster_, cephfs_, rgw_, mon_, mgr_, undo_), which makes grouping very readable. Verb placement varies though: set_pool_quota/set_pool_size are verb-first while pool_create/pool_delete and osd_mark_out are noun/action-first, a minor but real deviation.
37 tools is well past the 'heavy' threshold, and while the Ceph domain genuinely spans cluster, mon, mgr, osd, pg, pool, rbd, cephfs, rgw, and an undo subsystem, the surface still feels broad. Each tool maps to a distinct operation so little is truly wasted, but the count is on the bloated side for the observable scope.
Coverage is strong for an AIOps server: rich read diagnostics plus write/remediation for pools, OSDs, RBD, scrubs, throttle, cluster flags, and a reversible-undo pattern. Gaps remain — no CephFS provisioning, no RGW user/bucket management, no RBD resize/clone/flatten, no OSD add or CRUSH editing — but these are minor for a monitoring-and-remediation focus.
Maintenance
Related MCP Connectors
Autonomous and governed SRE & MLOps control plane for AI agent platforms.
Runtime AI governance: decision gates, human approval, hash-chained audit, compliance mapping.
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
Fail-closed policy guardrails for AI agents running kubectl, terraform, helm, and argocd.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA Model Context Protocol server that enables AI assistants to interact with Ceph storage clusters through natural language, making storage management more accessible and intuitive.6MIT
- AlicenseAqualityDmaintenanceAI-powered MCP server for enterprise OpenShift/Kubernetes cluster management, providing diagnostic tools, RAG knowledge retrieval, and autonomous remediation recommendations.9MIT
- AlicenseAqualityBmaintenanceAI-powered MCP server for TrueNAS SCALE storage operations with governance and safety features, enabling management of pools, datasets, snapshots, disks, alerts, and services.251MIT
- AlicenseAqualityBmaintenanceGoverned AI-ops for managed-endpoint fleets, providing login-storm analysis and patch/config drift detection with built-in audit, budget, and risk-tier governance.13MIT