# tractorbeeam-mcp

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/Ringosystems/TractorBeeam-MCP  
**Views:** 0  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/tractorbeeam-mcp

## Description
MCP server for Veeam Backup for Microsoft 365: read-only review + gated, audited restore tier.

## Claude Desktop Quick Installation
Heuristic fallback — verify the package name and runner against the repository README before running it. Uses `npx` (confidence: low):

```json
"mcpServers": {
  "tractorbeeam-mcp": {
    "command": "npx",
    "args": ["-y","tractorbeeam-mcp"]
  }
}
```

## Documentation & README

# TractorBeeam365 MCP

A Model Context Protocol server for **Veeam Backup for Microsoft 365 (VB365)**.
It talks **directly** to the VB365 REST API so an MCP client (Claude Code / Claude
Desktop) can **review your backup configuration, find protection gaps, spot
trends, verify cloud immutability — and, when you explicitly opt in, run jobs and
orchestrate restores.**

> **Independent project — not affiliated with, endorsed by, or supported by Veeam
> Software.** "Veeam" is a registered trademark of Veeam Software; the "Beeam"
> spelling is a deliberate, distinct play on words. Use at your own risk.
>
> 🔱 The name: a *tractor beam* pulls your data back in — and *Beeam* winks at the
> backup product underneath. Read-only review is the safe default; the "pull"
> (restore/actions) is opt-in.

## Two tiers

| Tier | Default | What it can do |
|------|---------|----------------|
| **Read-only review** | ✅ always on | GET-only. Cannot change anything. Config/health, gap-analysis, trends, cloud-lock cross-check. |
| **Action / Restore** | ⛔ off | Opt-in via `TB_*` env flags. Run/stop jobs, generate reports, sync orgs, **define + execute restores**. Every write is confirm-token gated and audited. |

If you never set the `TB_*` flags, this is a pure read-only reviewer that
*physically cannot* modify your environment — the action/restore tools aren't even
registered.

## Quick deploy (prebuilt image)

No clone or build required. From v2.2.0 the image is published **multi-arch
(amd64 + arm64)** to GitHub Container Registry and Docker Hub, so it runs
natively on x86 servers, Apple Silicon, and ARM boxes (Raspberry Pi, ARM cloud).
On an ARM host, pin the `:2.2.0` (or later) tag until a multi-arch `:latest` has
been published.

### Persistent HTTP service (Docker Compose)

Grab two files and start it:

```bash
curl -fsSLO https://raw.githubusercontent.com/Ringosystems/TractorBeeam-MCP/main/docker-compose.deploy.yml
curl -fsSL  https://raw.githubusercontent.com/Ringosystems/TractorBeeam-MCP/main/.env.example -o .env
# Edit .env: set VB365_HOST / VB365_USERNAME / VB365_PASSWORD and a long MCP_AUTH_TOKEN.
docker compose -f docker-compose.deploy.yml up -d
```

MCP is then live at `http://<host>:8766/mcp`. Attach a client with the bearer
token you set:

```bash
claude mcp add --transport http tractorbeeam365 http://<host>:8766/mcp \
  --header "Authorization: Bearer <your MCP_AUTH_TOKEN>"
```

Update later:

```bash
docker compose -f docker-compose.deploy.yml pull && docker compose -f docker-compose.deploy.yml up -d
```

### Unraid (one click)

In Unraid open **Docker → Add Container**, and paste this template URL into the
**Template** field:

```text
https://raw.githubusercontent.com/Ringosystems/TractorBeeam-MCP/main/deploy/unraid/tractorbeeam365.xml
```

Fill in `VB365_HOST`, `VB365_USERNAME`, `VB365_PASSWORD`, and a long
`MCP_AUTH_TOKEN`, then Apply. The audit and downloads folders map under
`/mnt/user/appdata/tractorbeeam365/`.

### Single MCP client, no service (stdio)

For a client that launches the server itself, run the image on demand over stdio:

```bash
docker run -i --rm \
  -e VB365_HOST=... -e VB365_USERNAME=... -e VB365_PASSWORD=... \
  ghcr.io/ringosystems/tractorbeeam-mcp:latest
```

## Read-only tools (always available)

| Tool | What it returns |
|------|-----------------|
| `vb365_health_summary` | One-shot review: orgs, jobs + last status, repos, **cloud storage (B2/S3/Azure)**, proxies, license, **trend anomalies**, and a `flags` list. **Start here.** |
| `vb365_trends` | Per-job success/failure **drift**, repo **capacity-full projection**, **restore-test cadence** per org, **RPO compliance**. |
| `gap_coverage_summary` / `gap_unprotected_objects` | **Backup coverage %** and **unprotected** live M365 objects, by comparing Microsoft Graph against what jobs protect *(needs `GRAPH_*`)*. |
| `cloud_lock_audit` | Cross-checks **Object Lock** mode/retention/versioning at the **bucket** vs what VB365 reports *(needs `B2_*`/`S3_*`)*. |
| `vb365_api_root` | Resource list + version (confirms connectivity). |
| `vb365_list_organizations` / `vb365_org_inventory` | Protected orgs; an org's users/groups/sites/teams. |
| `vb365_list_jobs` / `vb365_get_job` / `vb365_job_scope` | Jobs, one job's config, and exactly what a job protects (selected/excluded). |
| `vb365_list_job_sessions` | Recent run results (optionally per job). |
| `vb365_list_repositories` / `vb365_list_restore_points` | Repos (capacity/retention/immutability); restore points. |
| `vb365_list_object_storage` / `vb365_get_object_storage` | Cloud/object storage (B2/S3/Azure/Wasabi/IBM/Glacier). |
| `vb365_list_proxies` / `vb365_license` | Proxies + status; license/edition/expiry. |
| `vb365_get` | Read-only GET to any other `/<version>/...` resource. |

## Action / Restore tools (opt-in, gated)

Registered only when the matching flag is set. **Two-call confirm pattern:** call
once to get a preview + a one-time `confirm_token`; call again with
`confirm=<token>` to execute. Every execution is appended to `TB_AUDIT_LOG`.

| Tool (flag) | What it does |
|-------------|--------------|
| `action_job` (`TB_ALLOW_JOB_CONTROL`) | start / stop / enable / disable a backup job |
| `action_generate_report` (`TB_ALLOW_REPORTS`) | mailbox/onedrive/sharepoint/teams/user protection, license, storage reports → file |
| `action_org_sync` (`TB_ALLOW_ORG_SYNC`) | trigger a directory resync for an org |
| `action_proxy` (`TB_ALLOW_PROXY`) | rescan / maintenance-mode a proxy |
| `restore_session_start` → `restore_browse` / `restore_search` → `restore_define` → `restore_execute` → `restore_status` → `restore_session_stop` (`TB_ALLOW_RESTORE`) | **Full restore orchestration** across Exchange / OneDrive / SharePoint / Teams: open a point-in-time session, browse/search restorable items, then **define** (pick items + target + options) and **execute** a restore. |

### Restore: define **what**, **where**, **how**

```text
restore_session_start(scope="job", scope_id="<jobId>", workload="exchange")
   → { session_id }                         # opens a point-in-time explore session
restore_browse(session_id)                  # list mailboxes
restore_browse(session_id, parent_id=<mailboxId>)   # list items in a mailbox
restore_define(session_id, parent_id=<mailboxId>, item_ids=[...], target="export")
   → { confirm_token, preview }             # DRY RUN — nothing changed
restore_execute(session_id, confirm=<confirm_token>)   # executes + audits
restore_session_stop(session_id)
```

- **target** = `export` (safest — reads backup to a local file; no M365 creds),
  `alternate` (writes to a *different* M365 location), or `original` (writes back
  to the **original** location — destructive; also pass `confirm_overwrite_original=True`).
- **options** may carry an alternate `mailbox`/`folder` and the M365 target
  credentials VB365 uses to write back (`userName`/`userPassword`/`applicationId`),
  or set `VB365_RESTORE_*` in `.env`.
- **PST export requires 64-bit Outlook 2010+ installed on the VB365 server**
  (a Veeam requirement); without it, `exportToPst` returns a server-side error.

## Setup

1. **Install Python 3.10+** where Claude Code runs.
2. From this folder:
   ```powershell
   python -m venv .venv
   .\.venv\Scripts\Activate.ps1
   pip install -r requirements.txt
   ```
3. Copy `.env.example` to `.env` and fill in `VB365_HOST`, `VB365_USERNAME`,
   `VB365_PASSWORD` (keep `VB365_PORT=4443`, `VB365_API_VERSION=v8` unless yours
   differ). Optionally add `GRAPH_*`, `B2_*`/`S3_*`, and the `TB_*` flags.

   > The REST API account needs to be a VB365 administrator (or restore
   > operator) — VB365 has no read-only API role. The read-only **review** tools
   > are GET-only regardless. `New-VB365ReviewAccount.ps1` creates a dedicated
   > service account on the VB365 server. Keep `.env` out of source control.

## Register with Claude Code

```powershell
# Replace <repo> with the absolute path to your clone.
claude mcp add tractorbeeam365 --scope user -- "<repo>\.venv\Scripts\python.exe" "<repo>\server.py"
```

> On Linux/macOS use forward slashes and `<repo>/.venv/bin/python`.

It is also published to the [MCP Registry](https://registry.modelcontextprotocol.io)
as `io.github.Ringosystems/tractorbeeam-mcp` (an OCI image on GHCR), so MCP
clients that support the registry can install it directly. To run the published
image as a stdio server:

```bash
docker run -i --rm \
  -e VB365_HOST=... -e VB365_USERNAME=... -e VB365_PASSWORD=... \
  ghcr.io/ringosystems/tractorbeeam-mcp:latest
```

Then ask: **"Run a VB365 health summary and tell me if anything is misconfigured."**

## Enabling the action / restore tier

The action/restore tools stay hidden until you opt in. In `.env`:

```ini
TB_ENABLE_ACTIONS=true        # master switch
TB_ALLOW_JOB_CONTROL=true     # + any of the per-category flags you want
TB_ALLOW_RESTORE=true
TB_AUDIT_LOG=audit/actions.jsonl
```

> The action/restore tools are **not** registered over an HTTP transport unless
> you also set `TB_ALLOW_WRITE_OVER_HTTP=true`, because that transport has no
> per-caller identity. Run the operator tier over stdio, or only behind your own
> authenticating reverse proxy.

Safety model: tools are **only registered when enabled**, every mutation needs a
**second call with a one-time confirm token**, restores **default to a safe
target** (original-location overwrite needs an explicit acknowledgement), and
**every action is written to an append-only audit log**. Recommended: run a
separate "operator" instance with the flags on, and the default instance
read-only.

## Run as a persistent service (Docker / UNRAID)

The image itself defaults to the stdio transport (so MCP clients can `docker run
-i` it). Via `docker compose` it runs `streamable-http` on `0.0.0.0:8000` inside
the container, **read-only** (no `TB_*` flags). No credentials are baked in. The
HTTP transport **fails closed**: it refuses to start unless you set
`MCP_AUTH_TOKEN` (clients then send `Authorization: Bearer <token>`), or you
explicitly accept the risk with `MCP_ALLOW_UNAUTHENTICATED_HTTP=true`.

```bash
# Put MCP_AUTH_TOKEN=<a long random secret> in .env first.
docker compose up -d --build          # builds locally and runs read-only
# MCP is live at http://<host>:8766/mcp ; attach with:
claude mcp add --transport http tractorbeeam365 http://<host>:8766/mcp \
  --header "Authorization: Bearer <token>"
```

### Prebuilt images

Each GitHub Release publishes a multi-arch, multi-tag image via CI
([.github/workflows/publish.yml](.github/workflows/publish.yml)) to GHCR, Docker
Hub, and the MCP Registry. The full release runbook is in
[PUBLISHING.md](PUBLISHING.md).

```bash
# GitHub Container Registry (published automatically on every release):
docker pull ghcr.io/ringosystems/tractorbeeam-mcp:latest
# Docker Hub (published when the DOCKERHUB_USERNAME / DOCKERHUB_TOKEN repo
# secrets are configured):
docker pull ringosystems/tractorbeeam365-mcp:latest
```

To publish manually instead:

```bash
docker build -t <dockerhubuser>/tractorbeeam365-mcp:latest .
docker push <dockerhubuser>/tractorbeeam365-mcp:latest
```

> **Security:** the MCP HTTP transport has no per-caller identity. This build
> binds loopback by default, requires `MCP_AUTH_TOKEN` before it will serve HTTP,
> and hides the write/restore tools over HTTP unless `TB_ALLOW_WRITE_OVER_HTTP=true`.
> Still keep the port on a trusted network and front it with TLS + auth. The audit
> log and any generated PST/report files live in the mounted `audit/` and
> `downloads/` volumes. See [SECURITY.md](SECURITY.md).

## Quick connectivity test (no MCP client needed)

```powershell
.\.venv\Scripts\Activate.ps1
python -c "import server; print(server.vb365_api_root())"
```

## Notes

- `.gitignore` excludes `.env`, the venv, and the operator-tier `audit/`,
  `downloads/`, `*.pst` artifacts. Never commit credentials or restored data.
- VB365 ships a self-signed cert, so `VB365_VERIFY_SSL` defaults to `false`. That
  leaves the link to VB365 open to an active man-in-the-middle, so prefer setting
  `VB365_CA_BUNDLE` to the server's certificate (verification on against it), or
  `VB365_VERIFY_SSL=true` with a trusted cert. The server warns at startup when
  the channel is unverified.
- Endpoint names vary slightly by VB365 version. If a curated tool 404s, call
  `vb365_api_root` and use `vb365_get` with the exact resource name.

## Trademarks

This is an independent project and is not affiliated with, endorsed by, or
sponsored by any of the companies below. Product names are used only for
identification (nominative use).

- "Veeam" is a registered trademark of Veeam Software. The "Beeam" spelling is a
  deliberate, distinct wordplay and is not the trademark.
- Microsoft, Microsoft 365, Microsoft Graph, Outlook, and the Office Deployment
  Tool are trademarks of the Microsoft group of companies.
- Backblaze and B2 are trademarks of Backblaze, Inc.
- Amazon Web Services, AWS, Amazon S3, and S3 Glacier are trademarks of
  Amazon.com, Inc. or its affiliates.
- Wasabi, IBM and IBM Cloud, Azure, and Google Cloud are trademarks of their
  respective owners.

## License

Released under the [MIT License](LICENSE). See [SECURITY.md](SECURITY.md) for the
security model and reporting, [CONTRIBUTING.md](CONTRIBUTING.md) to contribute, and
[PUBLISHING.md](PUBLISHING.md) for how releases are built and published.

