Skip to main content
Glama
MSPbotsAI

covedataprotection-mcp

by MSPbotsAI
README.md
# covedataprotection-mcp

MCP server for **Cove Data Protection** (N-able's backup/BDR platform,
formerly N-able Backup / Backup Manager). Exposes the Backup Manager
JSON-RPC **Management Service** API as MCP tools.

## Overview

- Stateless HTTP service. No credentials are ever persisted — each request
  supplies its own credentials via headers, used only for the lifetime of
  that single request.
- Supports concurrent requests; per-request credential isolation is done via
  Python `contextvars`, not a global/shared client instance.
- Entry points: `POST /mcp` (MCP protocol) and `GET /health` (health check).
- Default port: `8080` (configurable via `MCP_HTTP_PORT`).

## Scope

**26 tools**, trimmed down from an original 247-tool full-schema build
(2026-08-04). MSPbots' own Cove Data Protection integration (confirmed live
via `/web/int/sys/integration/api/list` against the production platform) is
configured with exactly 6 APIs, mapped to these underlying JSON-RPC methods:

| MSPbots-configured API | JSON-RPC method | Covered here? |
|---|---|---|
| Cove Data Protection Devices | `EnumerateAccounts` | ✅ |
| Cove Data Protection Devices Detail | `GetAccountInfoById` | ✅ |
| Cove Data Protection Device Statistics | `EnumerateAccountStatistics` | ✅ |
| Cove Data Protection Users | `EnumerateUsers` | ✅ |
| Cove Data Protection Customers | `EnumeratePartners` | ✅ |
| Cove Data Protection Query Sessions | `QuerySessions` | ❌ Reporting Service, not Management Service — see Known Gaps |

The other 5 confirmed-real methods above were kept as-is, plus **same-category
core CRUD** (`Add`/`Get`/`Modify`/`Remove`) for each of the three resource
types they touch — `accounts` (9 tools), `partners` (9 tools), `users` (7
tools) — plus `GetServerInfo` (1 tool, connectivity self-test, used for the
original live-verification below). Every other category from the original
247-tool build (`notifications`, `storage_nodes`, `contacts`, `storage`,
`view_delivery`, `labels`, `jobs`, `custom_columns`, `branding`, `products`,
`eula`, `locations`, `countries`, `audit`, `email`, `regions`, `features`,
`permissions`, `templates` — 19 categories, ~221 tools) was removed entirely
as unused by MSPbots and out of scope for this server's purpose.

## Authentication

Cove has no static long-lived API key. Instead, every session starts with a
**Login** call (`partner` + `username` + `password`) that returns a
short-lived **visa** token (valid ~15 minutes), which must accompany every
subsequent call.

This server does **not** cache a visa across requests — caching one would
mean persisting session state, which conflicts with the "no credential
persistence" requirement. Instead, `api_client.CoveClient.call()` performs a
fresh Login on *every* tool invocation and discards the resulting visa
afterward, trading one extra HTTP round trip per call for full statelessness.

### HEADER 授权参数说明

| Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
|---|---|---|---|---|---|---|
| `X-CoveDataProtection-Partner` | string | 是 | 无 | 无 | Login 的 `partner` 字段(登录所属的租户/合作伙伴名) | `Acme MSP (admin@example.com)` |
| `X-CoveDataProtection-Username` | string | 是 | 无 | 无 | Login 的 `username` 字段 | `mspbots` |
| `X-CoveDataProtection-Password` | string | 是 | 无 | 无 | Login 的 `password` 字段 | `••••••••` |

Missing any of the three headers returns `401`:
```json
{
  "error": "Missing credentials",
  "message": "This server requires the X-CoveDataProtection-Partner, X-CoveDataProtection-Username, and X-CoveDataProtection-Password headers",
  "required_headers": ["X-CoveDataProtection-Partner", "X-CoveDataProtection-Username", "X-CoveDataProtection-Password"],
  "optional_headers": []
}
```

## Environment Variables

| Variable | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `MCP_HTTP_PORT` | int | 否 | `8080` | HTTP 监听端口 |
| `MCP_HTTP_HOST` | string | 否 | `0.0.0.0` | HTTP 监听地址 |
| `COVEDATAPROTECTION_BASE_URL` | string | 否 | `https://api.backup.management/jsonapi` | Cove Management Service JSON-RPC 端点 |

## MCP Endpoint

- `POST /mcp` — MCP protocol (streamable HTTP transport)
- `GET /health` — health check, returns exactly `{"status": "ok"}` (pure local liveness probe; does not call the Cove API)

## Tool List

Tool names follow `covedataprotection_<snake_case_method_name>` — e.g. the
JSON-RPC method `EnumerateAccountStatistics` becomes
`covedataprotection_enumerate_account_statistics`. Parameter names mirror
the JSON-RPC method's own parameter names (camelCase → snake_case); complex
struct/enum-typed parameters are accepted as a `dict`/`str` and passed
through to the vendor API as-is — see **Known Gaps** for what that means in
practice.

| Category | Tool | JSON-RPC Method | Params |
|---|---|---|---|
| accounts | `covedataprotection_add_account` | AddAccount | account_info(required), home_node_info(required) |
| accounts | `covedataprotection_enumerate_account_statistics` | EnumerateAccountStatistics | query(required) |
| accounts | `covedataprotection_enumerate_accounts` | EnumerateAccounts | partner_id(required) |
| accounts | `covedataprotection_get_account_features` | GetAccountFeatures | account_id(required) |
| accounts | `covedataprotection_get_account_info` | GetAccountInfo | name(required), password(required) |
| accounts | `covedataprotection_get_account_info_by_id` | GetAccountInfoById | account_id(required) |
| accounts | `covedataprotection_modify_account` | ModifyAccount | account_info(required), force_remove_custom_column_values_in_old_scope(required) |
| accounts | `covedataprotection_remove_account` | RemoveAccount | account_id(required) |
| accounts | `covedataprotection_set_account_features` | SetAccountFeatures | account_id(required), features(required) |
| misc | `covedataprotection_get_server_info` | GetServerInfo | none |
| partners | `covedataprotection_add_partner` | AddPartner | partner_info(required), create_default_account(required) |
| partners | `covedataprotection_enumerate_child_partners` | EnumerateChildPartners | partner_id(required), fields(required), partner_filter(required), range(optional) |
| partners | `covedataprotection_enumerate_partners` | EnumeratePartners | parent_partner_id(required), fetch_recursively(required), fields(required) |
| partners | `covedataprotection_get_partner_info` | GetPartnerInfo | name(required) |
| partners | `covedataprotection_get_partner_info_by_id` | GetPartnerInfoById | partner_id(required) |
| partners | `covedataprotection_get_partner_tree` | GetPartnerTree | partner_id(required), fields(required), filter(required), children_limit(required), partner_filter(required) |
| partners | `covedataprotection_get_root_partner_name` | GetRootPartnerName | none |
| partners | `covedataprotection_modify_partner` | ModifyPartner | partner_info(required), force_remove_custom_column_values_in_old_scope(required) |
| partners | `covedataprotection_remove_partner` | RemovePartner | partner_id(required) |
| users | `covedataprotection_add_user` | AddUser | user_info(required) |
| users | `covedataprotection_enumerate_user_roles` | EnumerateUserRoles | none |
| users | `covedataprotection_enumerate_users` | EnumerateUsers | partner_ids(required) |
| users | `covedataprotection_get_user_info` | GetUserInfo | partner_id(required), name_or_email(required), password(required) |
| users | `covedataprotection_get_user_info_by_id` | GetUserInfoById | user_id(required) |
| users | `covedataprotection_modify_user` | ModifyUser | user_info(required) |
| users | `covedataprotection_remove_user` | RemoveUser | user_id(required) |

## 测试示例

```bash
# Health check
curl -s http://localhost:8080/health

# Call a tool via the MCP protocol (streamable HTTP) — requires an
# initialize handshake first per the MCP spec; abbreviated example below
# shows the tool-call request body only:
curl -s -X POST http://localhost:8080/mcp \
  -H "X-CoveDataProtection-Partner: <your-partner-name>" \
  -H "X-CoveDataProtection-Username: <your-username>" \
  -H "X-CoveDataProtection-Password: <your-password>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: <session-id-from-initialize>" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "covedataprotection_get_server_info",
      "arguments": {}
    }
  }'
```

Expected: `200` with the server version on valid credentials; on invalid
credentials, the `Login` call itself fails and every tool returns a
structured JSON error envelope, e.g.:

```json
{"error":{"code":"unauthorized","message":"<vendor error message>","retryable":false}}
```

`code` is one of the fixed values `not_configured` / `unauthorized` /
`not_found` / `invalid_argument` / `rate_limited` / `upstream_error`;
`retryable` tells the caller whether retrying the same call could succeed
(true only for `rate_limited` and `upstream_error`). Tools never raise
exceptions for business/vendor errors — this envelope is returned as the
normal tool result string.

**Live-verified** (2026-07-29): `covedataprotection_get_server_info` (zero
parameters) was called end-to-end through this running server with a real
partner/username/password and returned the actual Cove server version —
confirming the Login → visa → method-call pipeline works against the live
API, not just structurally.

## API Reference

- Getting Started: https://developer.n-able.com/n-able-cove/docs/getting-started
- Authorization: https://developer.n-able.com/n-able-cove/docs/authorization
- Constructing a call: https://developer.n-able.com/n-able-cove/docs/construct-a-json-rpc-api-call
- Full method/struct/enum schema (JSON): https://documentation.n-able.com/covedataprotection/Schema_23.3.json

## Known Gaps

- **Trimmed from 247 to 26 tools on 2026-08-04.** The original build covered
  every method in the Management Service schema. Per a later scope decision,
  this was cut down to what MSPbots' own production integration config
  actually calls (verified live via `/web/int/sys/integration/api/list`
  against `app.mspbots.ai`, integration id `2026570354981494786`) plus
  same-category core CRUD — see the Scope section above for the exact
  API→method mapping and the full list of removed categories. The removed
  ~221 tools (`notifications`, `storage_nodes`, `contacts`, `storage`,
  `view_delivery`, `labels`, `jobs`, `custom_columns`, `branding`,
  `products`, `eula`, `locations`, `countries`, `audit`, `email`, `regions`,
  `features`, `permissions`, `templates`) are not in this build at all; if a
  future need requires one of them, the original schema
  (`Schema_23.3.json`, linked below) still documents its exact method
  signature and it can be re-added the same way the kept tools were
  generated.
- **This covers the Management Service only.** Cove's Getting Started guide
  describes a second, separate **Reporting Service** (`{host}/repserv_json`,
  runs per storage node) that provides backup/restore session statistics.
  MSPbots' own configuration calls a "Query Sessions" report against this
  Reporting Service — it is **not** part of the Management Service schema
  this MCP is generated from, and no public schema for the Reporting
  Service was found. This is the one MSPbots-configured endpoint this MCP
  does not cover; it can be added if the Reporting Service's method
  list/schema becomes available.
- **Complex struct/enum parameters are untyped (`dict`/`str`) rather than
  fully modeled.** The schema defines 106 structs and 78 enums; fully
  reproducing each one as a typed Python parameter was out of scope for a
  mechanically-generated server. Callers need to shape these dict
  arguments to match the vendor's schema (see the Structs section of
  `Schema_23.3.json` for exact field names) — each such parameter's
  description names the struct it maps to and points at that schema file.
- **No visa caching** — see the Authentication section above. Every tool
  call performs its own Login, which is simple and fully stateless but
  means 2 HTTP requests to the vendor per tool call instead of 1.
- All 26 tools were code-generated directly from the vendor's own schema
  file, not hand-written — parameter names/types are only as accurate as
  that schema. `covedataprotection_get_server_info` was the one tool
  live-verified end-to-end; the rest are structurally correct (schema
  validated, MCP-protocol tools/list confirmed) but not individually
  smoke-tested against real data.

## Vendor MCP SOP Compliance Notes

- **Tool count (26) exceeds the SOP's "should be ≤20" guideline.** Already
  trimmed 247 → 26 (see above); the remaining 26 map 1:1 to distinct
  JSON-RPC methods across 3 resource domains (accounts/partners/users) that
  cannot be merged without losing required-parameter distinctions (e.g.
  `get_*_info` by name+password vs. `get_*_info_by_id` by numeric ID are
  different lookup keys, not the same tool with an optional parameter).
- **No `limit` / `page_size` scalar parameter exists on any tool.** None of
  the 26 methods expose a first-class numeric page-size parameter — the one
  pagination-shaped field (`range` on `EnumerateChildPartners`) is an opaque
  vendor struct passed through as-is, and `children_limit` on
  `GetPartnerTree` is likewise passed straight to the vendor uninterpreted.
  There is nothing for this server to clamp against the SOP's default-50 /
  hard-cap-200 guidance; if the vendor schema's `range`/limit structs turn
  out to have their own documented per-page maximum, that should be
  enforced here instead of the SOP's generic fallback ceiling.
- **No credential env-var fallback.** `config.Settings` has no
  partner/username/password field; `get_client_from_context` returns `None`
  (→ `not_configured` envelope) whenever the per-request contextvar is
  unset. There is no code path that falls back to an environment variable.
- **Tool annotations**: every read tool (`get_*`, `enumerate_*`) is marked
  `readOnlyHint=True, idempotentHint=True`; `add_*` tools are
  `readOnlyHint=False, idempotentHint=False` (creating twice is not a
  no-op); `modify_*`/`set_*`/`remove_*` tools are
  `readOnlyHint=False, destructiveHint=True, idempotentHint=True`.