wasabi-mcp
by MSPbotsAI
README.md
# wasabi-mcp
MCP server for **Wasabi** (S3-compatible hot cloud storage). Exposes the
Wasabi **Stats API**'s bucket utilization data as an MCP tool.
## 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`).
## Authentication
The Wasabi Stats API (`stats.wasabisys.com`) — a separate, simpler API
from the S3-compatible object storage API — uses a single static header,
with no login/token exchange:
```
Authorization: <AccessKey>:<SecretKey>
```
The keys used must be Wasabi Root keys, or sub-user keys with an attached
billing/stats policy (`WasabiAccountStatsAccess` or
`WasabiBucketStatsAccess`) — plain storage-only keys are rejected. This is
already fully stateless by the vendor's own design; nothing is cached
across MCP calls.
### HEADER 授权参数说明
| Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
|---|---|---|---|---|---|---|
| `X-Wasabi-Access-Key` | string | 是 | 无 | 无 | Wasabi API Access Key(需为 Root key 或带 billing/stats 权限策略的 key) | `AGWZ1234567890ABCDEF` |
| `X-Wasabi-Secret-Key` | string | 是 | 无 | 无 | 对应 Secret Key | `a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8g9h0` |
Missing either header returns `401`:
```json
{
"error": "Missing credentials",
"message": "This server requires the X-Wasabi-Access-Key and X-Wasabi-Secret-Key headers",
"required_headers": ["X-Wasabi-Access-Key", "X-Wasabi-Secret-Key"],
"optional_headers": []
}
```
## Environment Variables
| Variable | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `MCP_HTTP_PORT` | int | 否 | `8080` | HTTP 监听端口 |
| `MCP_HTTP_HOST` | string | 否 | `0.0.0.0` | HTTP 监听地址 |
| `WASABI_STATS_BASE_URL` | string | 否 | `https://stats.wasabisys.com` | Wasabi Stats API 基础 URL(与 bucket 所在 region 无关,固定不变) |
## MCP Endpoint
- `POST /mcp` — MCP protocol (streamable HTTP transport)
- `GET /health` — health check, returns `{"status": "ok"}` (pure local probe, does not call the Wasabi API)
## Tool List
| Tool | 功能 | 参数 |
|---|---|---|
| `wasabi_get_bucket_utilizations` | 列出账号下所有 bucket 的每日存储/API 调用用量记录 | `page_size`(可选,默认 100,硬上限 100 — Wasabi Stats API 本身的每页上限)、`page_num`、`from_date`、`to_date`(均可选) |
Responses are the vendor's raw JSON (`{"PageInfo": {...}, "Records": [...]}`), serialized compactly (no indentation, `ensure_ascii=False`) and capped at 20,000 characters — if the `Records` list would push the response past that, it is truncated with `truncated`/`truncated_field`/`original_count` markers added to the payload.
## Error Handling
On failure, tools return a JSON error envelope (as a string, not a protocol-level error) instead of raising:
```json
{"error": {"code": "upstream_error", "message": "...", "retryable": true}}
```
`code` is one of a fixed vocabulary: `not_configured`, `unauthorized`, `not_found`, `invalid_argument`, `rate_limited`, `upstream_error`. `retryable` tells the caller whether retrying is worthwhile. Empty result sets (no usage records for the requested range) are returned as a normal empty result, not as an error.
## 测试示例
```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-Wasabi-Access-Key: <your-access-key>" \
-H "X-Wasabi-Secret-Key: <your-secret-key>" \
-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": "wasabi_get_bucket_utilizations",
"arguments": {}
}
}'
```
**Live-verified** (2026-07-30) against a real Wasabi account:
`wasabi_get_bucket_utilizations` called end-to-end through this running
server returned real data — 540 real bucket-utilization records across
270 pages, including real bucket names (e.g. "oraclegroup",
"centrewestib") in the `ap-southeast-2` region, with real storage/API-call
metrics.
## API Reference
- Public, no login required:
- Overview: https://docs.wasabi.com/apidocs/wasabi-stats-api
- Authentication: https://docs.wasabi.com/apidocs/authentication-with-wasabi-stats-api
- This endpoint: https://docs.wasabi.com/apidocs/stats-api-get-v1standalone-bucket-utilizations
## Known Gaps
- **Scope is exactly MSPbots' 1 configured endpoint, not the vendor's full
API surface** — the Wasabi Stats API also offers an account-level
summary endpoint (`GET /v1/standalone/utilizations`) and per-bucket
detail lookups by name or number; those are out of scope here. The
Wasabi S3-compatible object storage API (bucket/object CRUD) is an
entirely separate API and also out of scope.
- **The `region` field MSPbots also stores for this integration is not
used by this server** — the one endpoint MSPbots actually uses (Stats
API bucket utilizations) has a fixed base URL
(`https://stats.wasabisys.com`) regardless of which Wasabi region a
given bucket lives in; each returned record already includes its own
`Region` field. `region` would only matter for direct S3-compatible
object storage calls, which this server does not make.
- **`from`/`to` date range defaults are vendor-controlled** — if omitted,
Wasabi defaults to "one month ago" through "today"; this server does not
apply its own default and simply omits the parameter when not provided.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues