Metadata-Version: 2.4
Name: mcp-server-kubestash
Version: 0.1.0
Summary: MCP server for inspecting KubeStash backup health on any Kubernetes cluster via the Kubernetes API
Project-URL: Homepage, https://github.com/margus/kubestash-mcp
Project-URL: Repository, https://github.com/margus/kubestash-mcp
Project-URL: Issues, https://github.com/margus/kubestash-mcp/issues
Author-email: Margus <margus@imargus.net>
License-Expression: MIT
License-File: LICENSE
Keywords: backup,claude,kubernetes,kubestash,mcp,model-context-protocol
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: System Administrators
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: System :: Monitoring
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.11
Requires-Dist: kubernetes>=29.0
Requires-Dist: mcp>=1.2.0
Requires-Dist: python-dotenv>=1.0
Requires-Dist: requests>=2.31
Description-Content-Type: text/markdown

# kubestash-mcp

An [MCP](https://modelcontextprotocol.io) server for inspecting **[KubeStash](https://kubestash.com)** backup health on any Kubernetes cluster. It connects through your kubeconfig — exactly like `kubectl` — and exposes read-only tools that an AI assistant (Claude Code, Claude Desktop, etc.) can call in natural language.

Its headline capability is **stuck-repository detection**: KubeStash's `Repository.status.lastBackupTime` can freeze while backups keep succeeding, which silently breaks any alert that reads that field. This server computes the *true* backup freshness from `status.recentSnapshots` and tells you when the two disagree.

No vendor lock-in: no hardcoded endpoints, clusters, metrics backend, or auth. If `kubectl` can reach your cluster, so can this.

## Install

```bash
# run straight from PyPI, no install
uvx mcp-server-kubestash

# or install into a tool environment
uv tool install mcp-server-kubestash
```

Requires Python 3.11+ and a kubeconfig with access to the KubeStash CRDs
(`core.kubestash.com`, `storage.kubestash.com`).

## Configure an MCP client

Add to your MCP client config (e.g. `~/.mcp.json`):

```jsonc
{
  "mcpServers": {
    "kubestash": {
      "type": "stdio",
      "command": "uvx",
      "args": ["mcp-server-kubestash"],
      "env": {
        "KUBESTASH_CONTEXTS": "all",
        "KUBESTASH_STALE_HOURS": "24"
      }
    }
  }
}
```

All settings are optional — see [`.env.example`](.env.example):

| Variable | Default | Meaning |
|---|---|---|
| `KUBESTASH_CONTEXTS` | `all` | `all` / `` (current) / CSV of context names or unique short ids |
| `KUBESTASH_CONTEXTS_EXCLUDE` | — | fnmatch globs dropped after resolution |
| `KUBESTASH_NAMESPACES` | — | namespaces to search (empty = whole cluster) |
| `KUBESTASH_STALE_HOURS` | `24` | freshness threshold for "stale" |
| `KUBESTASH_STUCK_THRESHOLD_MINUTES` | `60` | tolerance before a repo counts as "stuck" |
| `KUBECONFIG` | — | standard kubeconfig path override |

## Tools

| Tool | What it does |
|---|---|
| `list_clusters` | The kubeconfig contexts that will be queried, and any that didn't resolve |
| `backup_health` | Fleet rollup: session phase counts, repo counts, stuck/stale, overall verdict |
| `list_repositories` | Repositories with freshness + stuck check |
| `detect_stuck_repositories` | **Only** the repositories whose `lastBackupTime` has frozen |
| `list_backup_sessions` | BackupSessions, optionally filtered by phase |
| `list_backup_configurations` | What's configured to back up: target, schedule, history limit |
| `repository_detail` | One repository, including the raw `recentSnapshots` |
| `diagnose_failed_session` | Triage a failed BackupSession + remediation hints |

All tools are **read-only** — the server never mutates cluster state.

## How "stuck" is determined

For each `Repository`, the server compares `status.lastBackupTime` against the newest
`status.recentSnapshots[].snapshotTime` whose `phase == "Succeeded"`. If the newest succeeded
snapshot is more than `KUBESTASH_STUCK_THRESHOLD_MINUTES` newer than `lastBackupTime` — or
snapshots exist but `lastBackupTime` is unset — the repository is **stuck**: backups are
healthy, but the status field (and anything alerting on it) is not.

## Development

```bash
uv sync --all-extras --dev
uv run ruff check .
uv run pytest -q
```

The suite is fully offline (the Kubernetes client is mocked). A small opt-in end-to-end check
runs against a real cluster when `RUN_E2E=1` and a kubeconfig are present.

## License

MIT
