@backblaze-labs/b2-mcp
    Preparing search index...

    @backblaze-labs/b2-mcp

    Backblaze B2 MCP Server

    Backblaze B2 MCP Server — safe Model Context Protocol access to Backblaze B2 buckets, files, keys, Object Lock, and S3-compatible storage

    CI CodeQL npm License: MIT TypeScript Node.js MCP API docs Coverage floors Runtime dependencies

    MCP Registry Smithery LobeHub Glama

    A Model Context Protocol server for Backblaze B2 Cloud Storage. It lets any MCP-compatible AI client (Claude, and others) operate B2 through a focused, safe set of tools, currently incubating in Backblaze-Labs.

    This is the official Backblaze B2 MCP serverbackblaze-labs/b2-mcp, published as @backblaze-labs/b2-mcp on npm and listed in the Official MCP Registry as io.github.backblaze-labs/b2-mcp. Community forks and third-party wrappers are not maintained by Backblaze.

    40 tools, assigned by backing category:

    • Native B2 SDK (@backblaze-labs/b2-sdk) (17) — B2 control-plane operations the S3 API has no equivalent for: buckets, application keys, Object Lock, event notifications, and Partner/Groups operations.
    • AWS S3 SDK (@aws-sdk/client-s3) (19) — the S3-compatible data plane: object upload/download/copy/list/delete, multipart, bucket reachability, lifecycle, and presigned URL paths.
    • Neither SDK (custom MCP code) (4) — repository-owned analytics over B2 reports and bounded live listings: storage growth, egress leaders, largest files, and abandoned uploads.

    Availability is a per-tool annotation, separate from those backing categories: durable-secret-producing tools are sink-backed for local stdio runs and remain non-secret unavailable stubs on HTTP/serverless unless an explicit sink is configured.

    Destructive actions are gated, durable B2 secrets stay out of the model's context in the default/file/off modes, and the unsafe B2_SECRET_SINK=inline escape hatch is explicit. The tool surface is deliberately lean (registration is capability-aware, so a key only ever sees tools it can use).


    Prerequisites: A supported Node.js runtime (22.22.2+, or 24 / 26) and a Backblaze B2 application key. A non-master key is all you need. The package engine range is ^22.22.2 || ^24 || ^26; CI runs on Node.js 22.23.1, 24, and 26.

    The canonical package name is @backblaze-labs/b2-mcp and the canonical binary is b2-mcp (b2-mcp-server is a transition alias). The fastest setup runs it with npx, no clone or build.

    S3-compatible and report tools derive their endpoint region from the authorized B2 account response. B2_REGION is only a fallback/default for paths that need a region before authorization, or when authorization is temporarily unavailable.

    Connect Claude Desktop by editing its config file — claude_desktop_config.json, located per OS:

    • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
    • Windows: %APPDATA%\Claude\claude_desktop_config.json
    • Linux: ~/.config/Claude/claude_desktop_config.json
    {
    "mcpServers": {
    "backblaze-b2": {
    "command": "npx",
    "args": ["-y", "@backblaze-labs/b2-mcp"],
    "env": {
    "B2_APPLICATION_KEY_ID": "your-application-key-id",
    "B2_APPLICATION_KEY": "your-application-key-secret"
    }
    }
    }
    }

    If you need an explicit fallback region before authorization, include B2_REGION in the same env block before restarting Claude Desktop:

    {
    "B2_APPLICATION_KEY_ID": "your-application-key-id",
    "B2_APPLICATION_KEY": "your-application-key-secret",
    "B2_REGION": "us-east-005"
    }

    Restart Claude Desktop and the B2 tools appear. To persist local stdio logs from clients that do not expose child-process stderr, add "B2_LOG_FILE" to the same env block, set to an OS-appropriate absolute path (for example /var/log/b2-mcp.log on macOS/Linux or C:\\logs\\b2-mcp.log on Windows).

    One non-master application key covers normal storage work: B2 native, S3, and key management. SDK-backed Partner/Groups tools require B2_MASTER_KEY_ID / B2_MASTER_KEY on an account authorized for the Partner API. B2's S3 endpoint rejects master keys, which is why the application key remains the primary credential. See Configuration for the full list.

    Why your client may show fewer than 40 tools: registration is capability-aware, so a client only sees the tools its key can actually use. With a non-master key and no master key configured, the three Partner/Groups tools that require a master key (b2_list_groups, b2_list_group_members, b2_eject_group_member) are not surfaced, so tools/list reports 37. Add B2_MASTER_KEY_ID / B2_MASTER_KEY on a Partner-entitled account to get the full 40. A read-only key trims the surface further, and durable-secret tools appear as non-secret "unavailable" stubs unless a secret sink is configured. This is expected, not a missing-install problem.

    Other clients: docs/CLIENTS.md has copy-paste setup for Cursor, VS Code, Cline, Windsurf, Zed, Continue, Goose, Claude.ai, and hosted (Streamable HTTP), plus a compatibility matrix.

    Run from a source checkout instead
    git clone https://github.com/backblaze-labs/b2-mcp.git b2-mcp
    cd b2-mcp
    corepack enable pnpm
    corepack prepare 'pnpm@11.20.0+sha256.34e198cb1e43237517ecedfd31f9ae26a6c0a3e5366ce58a2d05f4b21fb5f19a' --activate
    pnpm install --frozen-lockfile
    pnpm run build # produces dist/, required before first run

    Then set "command": "node" and "args": ["/ABSOLUTE/PATH/TO/b2-mcp/dist/index.js"] (or use the installed b2-mcp binary) in the config above.

    Then just ask:

    "List the buckets this key can access." · "Upload ./data.csv to reports/may-2026.csv." · "Give me a 1-hour download link for backups/latest.tar.gz." · "List files under logs/2026/."

    Local stdio runs can create application keys through the sink-backed tools; the new key secret is written to ~/.b2-mcp/secrets.jsonl by default and is not shown in the MCP response on POSIX platforms. Windows currently rejects file sink paths because this implementation does not enforce owner-only ACLs there, so use B2_SECRET_SINK=off or explicit local inline mode on Windows. For hosted HTTP deployments, create and rotate keys outside the MCP flow unless you have deliberately configured a reviewed secret sink.

    This repo bundles a client-side Backblaze B2 skills pack under skills/ (manifest: skills/pack.json). The MCP server is the action layer; these Markdown playbooks are the expertise layer for common workflows: backup/restore, least-privilege keys, Object Lock, lifecycle and cost hygiene, migration, and incident response.

    The pack is optional but recommended for clients that support Markdown skills. Each skill keeps bulk object bytes off the model and MCP server, uses presigned/direct transfer paths for data movement, and pauses before destructive or irreversible steps that are also gated by B2_DESTRUCTIVE_POLICY.

    Validate the pack locally. The Node validator is a structural guard for the declared pack, tool references, byte-path rules, and per-tool destructive gates; it is not a content-safety proof, so skills/** changes require CODEOWNERS review before publish. Each skill repeats the byte-path guardrails intentionally so standalone client imports keep the no-model/no-server object-byte rule.

    pnpm run validate:skills
    

    Load the pack in supported clients:

    • Claude Code: put each skills/b2-*/ directory under ~/.claude/skills/ or the client-supported project skills directory, then restart the session.
    • Claude.ai / Claude Desktop with Skills: create ZIP archives for the desired skills/b2-*/ directories, with each SKILL.md at the ZIP root, then open Settings -> Capabilities -> Skills and upload those ZIP files.
    • Other MCP clients with Markdown skills: register each skills/b2-*/SKILL.md file or containing directory according to that client's skills documentation.

    The skills do not add server endpoints or new permissions. They only sequence the existing B2 MCP tools and reinforce the same byte-path and destructive-action guardrails enforced by the server.

    The published image defaults to the HTTP transport, reads configuration only from environment variables, and does not publish a mutable latest tag. Choose the version tag that matches the package release. Cosign signatures are published to a sibling GHCR repository so the package page's default pull command stays on a runnable image tag:

    B2_MCP_VERSION=VERSION # replace with the release version you want
    B2_MCP_IMAGE="ghcr.io/backblaze-labs/b2-mcp:${B2_MCP_VERSION}"
    docker run --rm --name b2-mcp \
    --stop-timeout 20 \
    -p 127.0.0.1:3000:3000 \
    -e B2_HTTP_CREDENTIAL_MODE=server \
    -e B2_APPLICATION_KEY_ID=your-application-key-id \
    -e B2_APPLICATION_KEY=your-application-key-secret \
    -e B2_ALLOWED_HOSTS=localhost,127.0.0.1 \
    -e B2_DESTRUCTIVE_POLICY=block \
    -e B2_REGISTER_ALL_TOOLS=false \
    -e B2_SECRET_SINK=off \
    -e B2_ALLOW_INLINE_SECRETS=false \
    -e B2_ALLOW_LOCAL_FILES=false \
    "$B2_MCP_IMAGE"

    For stdio clients inside a container, pass the transport explicitly and keep stdin open:

    B2_MCP_VERSION=VERSION # replace with the release version you want
    B2_MCP_IMAGE="ghcr.io/backblaze-labs/b2-mcp:${B2_MCP_VERSION}"
    docker run --rm -i \
    --no-healthcheck \
    -e B2_APPLICATION_KEY_ID=your-application-key-id \
    -e B2_APPLICATION_KEY=your-application-key-secret \
    "$B2_MCP_IMAGE" stdio

    See deploy/customer-hosted/README.md for hardened HTTP examples with signature verification, B2_ALLOWED_ORIGINS, rate limits, and in-flight request caps. The deployment index is docs/DEPLOY.md, and the OAuth-secured Vercel adapter runbook is deploy/vercel. Direct deployment guides are available for Vercel, Cloudflare Workers, Cloudflare Containers, Docker/OCI, Google Cloud Run, AWS ECS Fargate, Azure Container Apps, Render, Railway, and Fly.io. All hosted paths share the security and credential contract.

    The image healthcheck applies to HTTP mode. For stdio containers, pass --no-healthcheck. For HTTP containers, set the listen port through PORT so the healthcheck probes the same port the server binds.


    Variable Required Default Description
    B2_APPLICATION_KEY_ID stdio / HTTP server Application key ID (non-master) — the workhorse for native B2 and S3-compatible tools
    B2_APPLICATION_KEY stdio / HTTP server Application key secret
    B2_MASTER_KEY_ID / B2_MASTER_KEY falls back to app key Master credential for SDK-backed Partner/Groups tools; required with Partner API entitlement for those operations
    B2_REGION us-west-004 Fallback/default S3-compatible endpoint region; authorized B2 responses override this for S3/report tools
    B2_MCP_UA_SUFFIX Optional operator token appended after the built-in b2-mcp/<version> product token on the outbound User-Agent (tag a deployment)
    B2_MCP_OUTPUT_FORMAT json LLM-facing TextContent.text format for structured successes: compact json or opt-in toon
    B2_MCP_TRANSPORT stdio CLI default transport when no stdio / http argument or --transport flag is passed; Docker images set this to http
    B2_HTTP_HOST HTTP only Node listen default Standalone Node HTTP listen host; set to 127.0.0.1 when binding behind a same-host reverse proxy
    B2_LOG_FILE stderr Optional path for redacted structured JSON logs. When set, the file replaces stderr; stdout is never used for logs
    B2_SECRET_SINK stdio: file; HTTP: off Durable-secret output mode: file, inline, or off. File mode supports b2_create_key and b2_create_group_member; b2_reserve_trial_create_account requires explicit inline mode because it has no file-mode recovery path
    B2_SECRET_SINK_FILE file override ~/.b2-mcp/secrets.jsonl on stdio Append-only plaintext JSONL credential ledger for file sink mode. HTTP/serverless file mode requires this explicit absolute path and B2_ALLOW_LOCAL_FILES=true
    B2_ALLOW_INLINE_SECRETS HTTP inline only false Dedicated HTTP/serverless opt-in required before B2_SECRET_SINK=inline can return durable secrets in MCP responses
    B2_APP_KEY_ID / B2_APP_KEY deprecated Legacy alias retained for compatibility; S3 tools use the authorized B2_APPLICATION_KEY_* credential scope
    B2_HTTP_CREDENTIAL_MODE HTTP only headers headers, server, or principal; unset preserves existing header-based clients. Set explicitly for hosted deployments
    B2_PRINCIPAL_CREDENTIAL_MAP HTTP principal JSON map from verified MCP principal to a customer-managed credential reference
    B2_CREDENTIAL_<REF>_APPLICATION_KEY_ID / _APPLICATION_KEY HTTP principal Env-backed secret-broker material for the mapped reference

    Every outbound B2 API call (native B2 SDK and the S3-compatible data plane) carries a b2-mcp product token on its User-Agent so the traffic is attributable to this server. A published release emits b2-mcp/<version> (for example b2-mcp/0.1.2); a source checkout, CI, or a dev/prerelease build emits b2-mcp/dev. B2_MCP_UA_SUFFIX appends an optional operator token after that built-in product token and does not replace it.

    S3-compatible and report tools use the s3ApiUrl returned by b2_authorize_account when a tool call authorizes; setting B2_REGION does not override that authorized region. On a cold authorization cache, the first S3/report call attempts B2 authorization to learn the authoritative region. That wait is bounded, and if authorization is temporarily unavailable, S3 tools fall back to the B2_REGION endpoint for that operation so the S3 data plane can still be attempted with the configured default. Once authorization succeeds, the derived S3 endpoint is cached for the server process lifetime; restart the process to pick up a later account-region migration. Authorized S3 endpoints remain restricted to HTTPS s3.<region>.backblazeb2.com hosts with no credentials, custom port, path, query, or fragment.

    Security / policy (safe defaults; override as needed):

    Variable Default Description
    B2_DESTRUCTIVE_POLICY stdio: confirm; HTTP: block Gate on destructive tools: confirm requires MCP form elicitation approval on compatible 2026 clients, or confirm: true when elicitation is unavailable/disabled; elicit requires human elicitation approval and refuses when no human can be prompted (a model confirm: true does not satisfy it); block refuses before elicitation; allow skips both gates
    B2_DESTRUCTIVE_ELICITATION on Set to off, false, or 0 to disable MCP form elicitation and rely only on B2_DESTRUCTIVE_POLICY
    B2_MAX_KEY_DURATION_SECONDS Optional maximum for b2_create_key; when set, non-expiring keys and longer durations are refused before any B2 create call
    B2_ALLOW_KEY_MGMT_GRANTS false Explicitly allow b2_create_key to mint keys with listKeys, writeKeys, or deleteKeys
    B2_ALLOW_UNSCOPED_KEYS false Explicitly allow b2_create_key to mint unscoped keys with write/delete capabilities
    B2_ALLOWED_HOSTS / B2_ALLOWED_ORIGINS none HTTP transport: Host/Origin allowlists (DNS-rebinding protection) — set these for any internet-facing HTTP deployment
    B2_HTTP_REQUEST_TIMEOUT_MS / B2_HTTP_HEADERS_TIMEOUT_MS 30000 / 10000 Standalone Node HTTP transport request timeout and headers timeout
    B2_TRUST_PROXY_HEADERS false HTTP transport: trust X-Forwarded-For / X-Real-IP for unauthenticated admission keys only behind a trusted proxy
    B2_MCP_RATE_LIMIT_RPS / B2_MCP_RATE_LIMIT_BURST 60 / 120 HTTP transport: per-credential request throttling
    B2_MAX_SESSIONS / B2_MAX_SESSIONS_PER_KEY 1000 / 20 HTTP transport: global and per-credential concurrent in-flight request caps
    B2_STDIO_CAPABILITY_TIMEOUT_MS 10000 Stdio bootstrap capability-discovery deadline; local expiry starts with a fail-closed tool surface
    B2_CAPABILITY_CACHE_TTL_MS / B2_CAPABILITY_CACHE_MAX_ENTRIES 300000 / 10000 Bounded capability-discovery cache TTL and size. Cache identity is secret-bound; log labels are non-secret fingerprints
    B2_S3_SAVE_TO_PATH_IDLE_TIMEOUT_MS 60000 Idle timeout while streaming s3_get_object results to saveToPath

    A ready-to-copy .env.example lists the local environment variables, and deploy/customer-hosted/b2-mcp.env.example lists the hosted container baseline. HTTP-only file-access vars (B2_ALLOW_LOCAL_FILES, B2_FILE_ROOT) are covered in docs/DEPLOY.md.


    b2-mcp emits one structured JSON log object per line. Logs default to stderr so the stdio transport's stdout channel stays reserved for MCP protocol frames.

    Set B2_LOG_FILE=/absolute/path/to/b2-mcp.log to append those same redacted JSON lines to a file instead of stderr. The path must be absolute. The file is created with owner-only permissions when it does not exist; its parent directory must already exist and be writable. Existing log files must be regular files, must not be symlinks or hard links, and must be owned by the current user. Owned pre-existing files are tightened to owner-only permissions at startup. A bad path fails at startup with a clear B2_LOG_FILE error. Runtime write failures are reported to stderr, and subsequent structured log lines fall back to stderr. B2_LOG_FILE is currently supported only on POSIX platforms; Windows startup fails clearly because this implementation does not enforce owner-only ACLs.

    File logging does not mirror to stderr by default. Because B2_LOG_FILE is an append-only file sink with no built-in rotation or retention, use operator-managed rotation before enabling it for a long-running process. Do not enable it on an internet-facing HTTP transport unless the host has a size and retention policy and a log shipper tails the file directly. For external logrotate, use rename/create rotation and send SIGHUP to the b2-mcp process after rotation so the file destination is reopened. Copytruncate is not recommended.


    The npm package intentionally supports only the root CommonJS entry (require("@backblaze-labs/b2-mcp")), which exposes startStdio(): Promise<void>, plus ./package.json for metadata. TypeScript consumers may compile against that same root CommonJS surface:

    import b2Mcp = require("@backblaze-labs/b2-mcp");

    const start: () => Promise<void> = b2Mcp.startStdio;

    Programmatic TypeScript imports beyond that root entry are not a supported public API. The supported form is the CommonJS import = require interop shown above; ESM named imports such as import { startStdio } from "@backblaze-labs/b2-mcp" are not part of the contract. Deep imports such as @backblaze-labs/b2-mcp/dist/server.js are private implementation details and are closed by the package exports map. Use the CLI/bin entry or the root startStdio export instead.


    The source entry point and installed package binary share the same CLI:

    Usage: b2-mcp [stdio|http] [options]
    
    Options:
      --transport <stdio|http>  Transport to serve (default: B2_MCP_TRANSPORT or stdio)
      --port <port>             HTTP listen port (default: PORT or 3000)
      --host <host>             HTTP listen host (default: Node listen default)
      --version                 Print the package version
      --help                    Show this help
    

    Examples:

    b2-mcp --transport stdio             # or: npx -y @backblaze-labs/b2-mcp --transport stdio
    b2-mcp http --host 127.0.0.1 --port 3000
    node dist/index.js http --host 127.0.0.1 --port 3000 # equivalent from a source checkout

    MCP transport messages always remain JSON-RPC JSON. Structured successful tool results carry the lossless sanitized value in structuredContent, and the single LLM-facing text block in content[0].text is selected by B2_MCP_OUTPUT_FORMAT.

    • json (default): compact JSON text for clients that parse text content.
    • toon: opt-in TOON text using the repo-owned encoder for TOON spec 4.1.

    Errors, validation failures, and concise one-line status messages stay plain text. TextContent has no media-type field, so the server advertises the selected text format in instructions instead of per-result prefixes or protocol extensions.

    Example b2_list_buckets text in default compact JSON mode:

    {"accountId":"account-123","buckets":[{"bucketId":"bucket-a","bucketName":"logs-2026","bucketType":"allPrivate"},{"bucketId":"bucket-b","bucketName":"public-assets","bucketType":"allPublic"}],"bucket_count":2,"total_bucket_count":2}
    

    The same structured result with B2_MCP_OUTPUT_FORMAT=toon:

    accountId: account-123
    buckets[2]{bucketId,bucketName,bucketType}:
      bucket-a,logs-2026,allPrivate
      bucket-b,public-assets,allPublic
    bucket_count: 2
    total_bucket_count: 2
    

    The canonical structuredContent value is identical in both modes.

    Rollout note: TextContent has no media-type field. Keep the default json for rolling deployments and text-parsing clients. Opt into TOON only after clients prefer structuredContent or explicitly support TOON; otherwise a fleet with mixed B2_MCP_OUTPUT_FORMAT values can return either text shape.


    The server exposes 40 tools (registration is capability-aware, so a given key sees only the subset it can use).

    Native B2 SDK (17):

    • b2_authorize_account — Verify credentials and return account info
    • b2_list_buckets — List buckets (optional filters)
    • b2_create_bucket — Create a bucket
    • b2_delete_bucket — Delete an empty bucket
    • b2_update_bucket — Update type, CORS, lifecycle, encryption, replication, Object Lock
    • b2_get_bucket_notification_rules — Get webhook notification rules
    • b2_set_bucket_notification_rules — Set webhook notification rules
    • b2_list_keys — List application keys
    • b2_delete_key — Delete an application key
    • b2_create_key — Create an application key (one-time secret written to the configured sink)
    • b2_update_file_legal_hold — Set/clear legal hold on an object
    • b2_update_file_retention — Set/clear retention on an object
    • b2_list_groups — List partner groups (Partner API credential)
    • b2_eject_group_member — Remove a member from a partner group (Partner API credential)
    • b2_list_group_members — List group members (Partner API credential)
    • b2_create_group_member — Create a Partner group member (Partner API credential)
    • b2_reserve_trial_create_account — Reserve a trial account (Partner API credential)

    AWS S3 SDK — data plane (19):

    • s3_put_object — Inline upload of a small (≤1 MiB) control-plane object
    • s3_get_object — Inline download of a small (≤1 MiB) control-plane object
    • s3_delete_object — Delete an object
    • s3_delete_objects — Bulk-delete objects
    • s3_head_object — Object metadata
    • s3_copy_object — Server-side copy
    • s3_list_objects_v2 — List objects
    • s3_list_object_versions — List object versions
    • s3_create_multipart_upload — Begin a multipart upload
    • s3_presign_upload_part — Mint a presigned PUT URL for a part
    • s3_complete_multipart_upload — Finish a multipart upload
    • s3_abort_multipart_upload — Abort a multipart upload
    • s3_list_parts — List uploaded parts
    • s3_list_multipart_uploads — List in-progress multipart uploads
    • s3_upload_part_copy — Server-side copy of a part
    • s3_get_presigned_url — Short-lived presigned PUT/GET bearer URL
    • s3_head_bucket — Check a bucket is reachable on the S3 endpoint
    • s3_get_bucket_location — Bucket region / location constraint
    • s3_put_bucket_lifecycle — Set S3 lifecycle rules

    Custom MCP analytics (4):

    • b2_usage_growth — Rank accounts by stored-data growth between two dates
    • b2_egress_leaders — Top egress by account or bucket over a period
    • b2_largest_files — A bucket's largest objects via bounded live listing
    • b2_unfinished_uploads — Abandoned multipart uploads consuming storage

    For availability nuances, the destructive-gate list, and durable-secret handling, see the detailed reference below.

    40 total — 17 Native B2 SDK + 19 AWS S3 SDK + 4 Neither SDK/custom MCP tools. Prefix counts remain 21 native b2_* names + 19 data-plane s3_* names. Availability is orthogonal to backing: b2_create_key and b2_create_group_member are available when B2_SECRET_SINK=file or inline; b2_reserve_trial_create_account is available only with explicit inline mode because Reserve Trial has no provider-side recovery path after a file sink write failure. These names are non-secret compatibility stubs when unavailable. The inherited s3_* aliases use the AWS S3 SDK against B2's S3-compatible endpoint, with configuration derived from the official B2 SDK /s3 helper. Under stdio's default confirm policy, fifteen destructive, durable-secret-producing, or protection-weakening tool names require confirm: true or MCP form elicitation before execution: the explicit deletes (s3_delete_object, s3_delete_objects, s3_abort_multipart_upload, b2_delete_bucket, b2_delete_key), durable key creation (b2_create_key), PutObject presigning (s3_get_presigned_url with operation: "PutObject"), Partner group membership changes (b2_eject_group_member, b2_create_group_member), trial-account reservation (b2_reserve_trial_create_account), persistent outbound webhook replacement (b2_set_bucket_notification_rules), and the protection-removal or copy/delete policy paths (b2_update_file_retention when clearing/bypassing, b2_update_file_legal_hold when set off, b2_update_bucket when it makes a bucket public or weakens Object Lock/lifecycle/replication, and s3_put_bucket_lifecycle when a rule schedules deletion). HTTP defaults to block, so the same calls are refused unless the operator explicitly selects confirm or allow.

    Category 1 — Native B2 SDK (17)
    Tool Availability Description
    b2_authorize_account Available Verify credentials and return account info
    b2_list_buckets Available List buckets (optional filters)
    b2_create_bucket Available Create a bucket
    b2_delete_bucket Available Delete an empty bucket
    b2_update_bucket Available Update type, CORS, lifecycle, encryption, replication, Object Lock
    b2_get_bucket_notification_rules Available Get webhook notification rules
    b2_set_bucket_notification_rules Available Set webhook notification rules
    b2_list_keys Available List application keys
    b2_delete_key Available Delete an application key
    b2_create_key Sink-backed; HTTP default stub Create an application key; file mode writes the one-time secret out of band
    b2_update_file_legal_hold Available Set/clear legal hold on an object
    b2_update_file_retention Available Set/clear retention on an object
    b2_list_groups Available with Partner API credential List partner groups through the official B2 SDK
    b2_eject_group_member Available with Partner API credential Remove a member from a partner group through the official B2 SDK
    b2_list_group_members Available with Partner API credential List group members through the official B2 SDK
    b2_create_group_member Sink-backed with Partner credential Create a Partner group member; file mode writes the one-time secret out of band
    b2_reserve_trial_create_account Inline only with Partner credential Reserve a trial account; file mode is unavailable because no provider-side recovery exists

    Durable-secret-producing operations split their result: the one-time applicationKey is written to the configured sink, while MCP output returns redacted metadata plus a secretSink pointer. Each request must include an idempotencyKey; retrying the same key with identical input returns the original sink pointer without creating a second credential or account. On POSIX platforms, stdio defaults to file at ~/.b2-mcp/secrets.jsonl. Windows rejects file sink paths because owner-only ACLs are not enforced by this implementation; configure B2_SECRET_SINK=off or explicit local inline mode there. HTTP/serverless defaults to off; enabling file there requires both B2_ALLOW_LOCAL_FILES=true and an explicit B2_SECRET_SINK_FILE. B2_SECRET_SINK=inline is an unsafe explicit opt-in that returns the secret into MCP output with a warning; HTTP/serverless also requires B2_ALLOW_INLINE_SECRETS=true. File sink records use stable JSONL metadata fields (ts, tool, recordId) plus idempotency metadata and a result payload. File mode also writes non-secret sidecar idempotency markers, plus <B2_SECRET_SINK_FILE>.idempotency.jsonl as an audit trail, so retry history survives when the plaintext ledger is rotated or vaulted. The ledger has no built-in rotation or pruning, so operators must rotate, prune, vault, or delete it under the same credential-retention policy used for live B2 keys while retaining the sidecars for the deployment's retry window. The SDK-backed Partner/Groups tools remain available only when a distinct master key is configured and the account is authorized for the Partner API.

    Category 2 — AWS S3 SDK (19)
    Tool Availability Description
    s3_put_object / s3_get_object Available Inline upload / download of small (<=1 MiB) control-plane objects; bulk data uses a presigned URL
    s3_delete_object / s3_delete_objects Available Delete one / bulk-delete objects
    s3_head_object Available Object metadata
    s3_copy_object Available Server-side copy; acl is a no-op compatibility hint because B2 access follows bucket policy
    s3_list_objects_v2 / s3_list_object_versions Available List objects / versions
    s3_create_multipart_upload / s3_presign_upload_part / s3_complete_multipart_upload Available Multipart upload flow (large files); parts use short-lived presigned bearer URLs
    s3_abort_multipart_upload / s3_list_parts / s3_list_multipart_uploads Available Manage multipart uploads
    s3_upload_part_copy Available Server-side copy of a part
    s3_get_presigned_url Available Short-lived presigned PUT/GET bearer URL (browser/CORS handoff)
    s3_head_bucket Available Check bucket exists/reachable on the S3 endpoint
    s3_get_bucket_location Available Bucket region / location constraint
    s3_put_bucket_lifecycle Available Lifecycle rules incl. AbortIncompleteMultipartUpload
    Category 3 — Neither SDK, custom MCP analytics (4)
    Tool Availability Description
    b2_usage_growth Available Rank accounts by stored-data growth between two dates (daily usage reports; requires Usage Reports)
    b2_egress_leaders Available Top egress by account or bucket over a period (daily usage reports; requires Usage Reports)
    b2_largest_files Available A bucket's largest objects via live listing (bounded scan)
    b2_unfinished_uploads Available Abandoned multipart uploads silently consuming storage (bounded live listing)

    Scope follows the caller's key — a partner key sees its sub-accounts; a customer key sees only itself. The usage-report tools feature-detect the b2-reports-<accountId> bucket and return a clear "not enabled" message when Usage Reports aren't enabled on the account.


    Built-in safeguards (on by default): destructive-action gating (B2_DESTRUCTIVE_POLICY), MCP form elicitation for destructive tools on clients that advertise it for the 2026 protocol, sink-backed durable-secret creation for local stdio with hosted HTTP fail-closed defaults, central recursive response sanitization, explicit credential-provider modes, capability-aware tool registration that fails closed, rate limiting, and a values-redacted audit log (non-secret credential fingerprints only — never secrets, values, or file contents). The server never phones home.

    Destructive actions have two layers. B2_DESTRUCTIVE_POLICY=block is the hard refusal and remains the required wall for internet-facing or untrusted-client HTTP deployments. Under confirm, capable 2026 MCP clients are asked for form elicitation first; clients without compatible elicitation, or servers with B2_DESTRUCTIVE_ELICITATION=off, fall back to the existing confirm: true retry. elicit is the stricter middle ground between confirm and block: it requires an accepted MCP form-elicitation response from a form-capable client and refuses (rather than falling back to a model confirm: true) whenever no such response can be obtained, for deployments that want human-in-the-loop friction on every destructive action without giving up the operation entirely. Because the response is relayed by the client, this is friction, not an independent authorization boundary. Under allow, both the confirm gate and elicitation are skipped for trusted single-user sessions. Elicitation responses are relayed by the MCP client, so they are useful human-in-the-loop friction but not an independent security boundary against a malicious or compromised internet-facing client.

    Rollout note: elicitation changes compatible 2026 confirm clients from a one-request confirm: true flow to a two-request flow carrying server-minted requestState. Deploy all HTTP replicas with the same credentials and config. During an expand/contract rollout, an elicitation follow-up routed to a pre-elicitation pod fails safe with the old confirmation refusal; it does not execute an unapproved destructive operation.

    Running it safely:

    • Use a supported deployment for hosted HTTPdeploy/customer-hosted contains the portable container, compose, and nginx/OAuth edge example. deploy/vercel contains the OAuth-secured Vercel runtime adapter. The deployment index links the current provider guides: Vercel, Cloudflare Workers, Cloudflare Containers, Docker/OCI, Google Cloud Run, AWS ECS Fargate, Azure Container Apps, Render, Railway, Fly.io, and shared security.
    • Use a least-privilege key — a non-master key is correct for normal storage operations. Local stdio can create scoped keys through the file sink; hosted HTTP deployments should create and rotate keys outside the MCP tool flow unless the file sink has been explicitly configured and reviewed. b2_create_key refuses key-management grants, unscoped write/delete grants, and over-long or non-expiring keys unless the corresponding policy override is set.
    • Presigned URLs are different from durable secretss3_get_presigned_url and s3_presign_upload_part return short-lived bearer capabilities with expiresIn / expiresAt. Treat the URL as sensitive until expiry, but it is not a long-lived B2 application key.
    • Local use → stdio (the Quick Start above). Credentials stay in your client config / environment.
    • Exposing HTTP → choose a credential mode. Unset mode remains headers for one-release compatibility with existing header clients; B2 credential headers must be present on every MCP request. Set B2_HTTP_CREDENTIAL_MODE=server to keep one B2 credential in the server process/customer secret manager, or principal to map verified MCP authInfo to customer-held credentials.
    • Caller auth stays at your edge. For principal mode, terminate TLS and validate OAuth before the SDK handler receives authInfo; strip any trusted identity headers at the edge and only re-add them inside an allowlisted proxy boundary.
    • MCP SDK v2 packages are pinned. HTTP and stdio use the official @modelcontextprotocol/server v2 package from github.com/modelcontextprotocol/typescript-sdk; opt-in TOON output uses a reviewed repo-owned encoder for spec 4.1, with @toon-format/toon@4.1.1 retained only as a dev/test decoder oracle.
    • Never commit credentials — use env vars / a secrets manager. .env* is gitignored.

    Full hosted runbook (nginx, Let's Encrypt, hardened systemd, fail2ban, monitoring, and a security baseline checklist): docs/DEPLOY.md.

    Authentication, credential custody, OAuth metadata, and B2 credential-mode details are documented in docs/AUTHENTICATION.md.


    pnpm run build              # clean + compile to dist/
    pnpm run typecheck # type-check src + tests (no emit)
    pnpm test # typecheck, then fast unit tests
    pnpm run test:contract # deterministic MCP/package/schema contracts
    pnpm run test:protocol # modern + legacy MCP protocol behavior
    pnpm run test:coverage # deterministic source-covering suites + coverage summary
    pnpm run test:diagnostics # MaxListeners/open-handle warning diagnostics
    pnpm run test:slow # deterministic high-cost tests, isolated from unit
    pnpm run test:package # packed-package installation test
    pnpm run verify # fast no-credential quality gate
    pnpm run test:live:b2-integration # live B2 tests; requires B2_APPLICATION_KEY_ID / B2_APPLICATION_KEY
    pnpm run test:live:b2-contract # live B2 request-shape checks; requires B2 credentials
    pnpm run test:live:b2 # both protected live B2 suites
    pnpm run evals # deterministic LLM eval harness; live provider cases skip by default
    pnpm run evals:provider-comparison # opt-in Claude vs OpenAI comparison; requires provider keys and current dist/
    pnpm start # stdio transport
    pnpm run start:http --port 3000 # MCP 2026-07-28 HTTP transport
    b2-mcp --help # installed package CLI help after publish/install
    b2-mcp --transport http --port 3000 # installed package HTTP command after publish/install
    pnpm run smoke:local # deterministic local MCP smoke; no endpoint or B2 credentials
    pnpm run smoke:client # advisory SDK client smoke; requires existing dist/, no B2 calls
    pnpm run smoke:inspector # advisory locked Inspector CLI smoke; requires existing dist/

    Compatible MCP Inspector release for isolated manual inspection: @modelcontextprotocol/inspector@2.4.0, which requires Node.js 22.19.0 or newer. Run it through pnpm run smoke:inspector so the command uses the committed lockfile and a sanitized temporary environment.

    MIT — © 2026 Backblaze, Inc.