Skip to main content
Glama
io.github.AIops-tools/ceph-aiops

io.github.AIops-tools/ceph-aiops

Ceph AIops

Audit availability: Real writes require a committed pending audit 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 proxy ceph -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 out and osd purge require --dry-run + double confirm.

  • MCP server (ceph-aiops mcp or ceph-aiops-mcp): the full 37 tools (17 read, 18 write, 2 undo), every one wrapped with the bundled @governed_tool harness. 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 from CEPH_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) are high risk with dry_run and CLI double confirmation.

Capability matrix (37 MCP tools)

Group

Tools

Count

R/W

Health

cluster_health (flagship RCA), cluster_status

2

read

OSD

osd_tree, osd_df, osd_perf

3

read

cluster_flag_set (low, undo), osd_reweight (med, undo), osd_mark_in (med, undo)

3

write

osd_mark_out (high, dry-run), osd_purge (high, dry-run)

2

write

PG

pg_summary, pg_dump_stuck, scrub_status

3

read

trigger_scrub (low), trigger_deep_scrub (low)

2

write

Pool

pool_ls, pool_df

2

read

set_pool_quota (med, undo), set_pool_pg_num (med, undo), set_pool_autoscale (med, undo), pool_create (med)

4

write

set_pool_size (high, dry-run), pool_delete (high, dry-run)

2

write

RBD

rbd_ls

1

read

rbd_image_create (med), rbd_snapshot_create (low)

2

write

rbd_image_delete (high, dry-run), rbd_snapshot_delete (high, dry-run)

2

write

CephFS / RGW

cephfs_status, rgw_status

2

read

Cluster-ops

mon_status, mgr_status, slow_ops, capacity_forecast

4

read

throttle_recovery (med, undo)

1

write

Undo

undo_list, undo_apply

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-tools

The 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: yes

Restart 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 flags

Run as an MCP server (stdio):

export CEPH_AIOPS_MASTER_PASSWORD=...   # unlock secrets non-interactively
ceph-aiops-mcp

Where 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 via CEPH_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 via CEPH_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) running ceph-aiops doctor; a 3-node Vagrant cluster exercises real rebalance behaviour. See docs/VERIFICATION.md for 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 tools
capacity_forecastA
Read-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_statusA
Read-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_setA
Destructive

[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_healthA
Read-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_statusA
Read-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_statusB
Read-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_statusA
Read-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_dfA
Read-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_inA
Destructive

[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_outA
Destructive

[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_perfA
Read-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_purgeA
Destructive

[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_reweightA
Destructive

[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_treeB
Read-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_stuckA
Read-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_summaryA
Read-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_createA
Destructive

[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_deleteA
Destructive

[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_dfA
Read-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_lsA
Read-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_createA
Destructive

[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_deleteA
Destructive

[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_lsA
Read-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_createA
Destructive

[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_deleteA
Destructive

[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_statusA
Read-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_statusA
Read-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_autoscaleA
Destructive

[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_numA
Destructive

[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_quotaA
Destructive

[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_sizeA
Destructive

[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_opsA
Read-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_recoveryA
Destructive

[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_scrubA
Destructive

[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_scrubA
Destructive

[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_applyA
Destructive

[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_listA
Read-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

    A3.8/5.0

    Scored across 37 tools

    Disambiguation4/5

    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.

    Naming Consistency4/5

    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.

    Tool Count3/5

    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.

    Completeness4/5

    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

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A Model Context Protocol server that enables AI assistants to interact with Ceph storage clusters through natural language, making storage management more accessible and intuitive.
      6
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      AI-powered MCP server for TrueNAS SCALE storage operations with governance and safety features, enabling management of pools, datasets, snapshots, disks, alerts, and services.
      25
      1
      MIT