# Discoverability runbook

How the official Backblaze B2 MCP server is listed across MCP registries and
directories, and how to keep those listings current on each release. Tracks the
work in [#297](https://github.com/backblaze-labs/b2-mcp/issues/297) /
[#300](https://github.com/backblaze-labs/b2-mcp/issues/300) /
[#301](https://github.com/backblaze-labs/b2-mcp/issues/301).

## Canonical identity (use everywhere)

| Field | Value |
| --- | --- |
| Repo | `https://github.com/backblaze-labs/b2-mcp` |
| Registry name | `io.github.backblaze-labs/b2-mcp` |
| npm | `@backblaze-labs/b2-mcp` |
| Container | `ghcr.io/backblaze-labs/b2-mcp` |
| Display name | **Backblaze B2 MCP Server** (never bare "B2 MCP") |
| Description | *Official Backblaze B2 MCP server for buckets, files, keys, Object Lock, and S3 storage.* |
| Privacy policy | `https://backblaze-labs.github.io/b2-mcp/privacy/` |
| Anchor text for backlinks | `Backblaze B2 MCP server` |

Every submission must use the display name above and link the canonical repo, so
directories de-duplicate community forks under the official entry.

## Repo manifests (the source of truth for directories)

| File | Directory | Notes |
| --- | --- | --- |
| `server.json` | Official MCP Registry | Version synced by `scripts/update-server-json-version.mjs` at release cut. Schema `2025-12-11` has no privacy-policy field, so the registry entry relies on `websiteUrl`, README, and the hosted privacy page. |
| `smithery.yaml` | Smithery (deferred) | stdio one-click config; credential fields masked as `password`. Retained but not on the roadmap — see [Smithery (deferred)](#smithery-deferred). |
| `glama.json` | Glama | `maintainers` list gates the org claim. Read from the default branch. |
| `lhm.plugin.json` | LobeHub | Owner declaration used by `lhm plugin update`; regenerate on release. |
| `mcpb/manifest.json` | Claude Connectors Directory / GitHub Release | MCPB 0.3 manifest with `privacy_policies`; packed to a reproducible `.mcpb` bundle (`pnpm run build:mcpb`), attached to every GitHub Release (checksummed in `SHA256SUMS`). Consumed by the Claude Connectors Directory submission ([#385](https://github.com/backblaze-labs/b2-mcp/issues/385)). |

The canonical registry description lives in
`scripts/lib/mcp-registry-manifest.mjs` (`mcpRegistryDescription`) and is
contract-checked against `server.json`; keep it ≤100 characters.

## Credential-less tool scans

Directories that enumerate tools by launching stdio or HTTP transports (mcp.so,
Glama build tests, LobeHub `plugin init`, MCP Inspector) need `initialize` and
`tools/list` to work before a user supplies real B2 credentials. This is the
default when credentials are absent. Placeholder credentials rejected by B2 also
enter discovery for stdio and HTTP header-mode scanner requests, but rejected
server-owned or principal-mode credentials stay as HTTP credential errors so
operator misconfiguration remains visible.

Discovery mode advertises the full 40-tool surface for schema scanners. It
registers the durable-secret input schemas for `b2_create_key`,
`b2_create_group_member`, and `b2_reserve_trial_create_account` so registries
can see the real arguments, but every `tools/call` returns a structured
`missing_credentials` error until the caller supplies valid B2 credentials.
Credentialed deployments without an enabled secret sink still advertise the
durable-secret tools as non-secret unavailable stubs, as documented in the
README.

Do not force `B2_REGISTER_ALL_TOOLS` for scanner compatibility. It remains an
operator/test escape hatch that bypasses capability-aware registration for real
credentialed deployments.

During a rolling deploy, old replicas may still return the previous HTTP
credential error for credential-free scanner requests until every replica has
the discovery-mode behavior.

## Glama

1. **Claim:** `glama.json` (this repo) lists the maintainer; on the server's
   "Score" tab, click **Login with GitHub to claim** and authorize with the
   maintainer account. Then merge community forks into the official entry.
2. **Release** (containerized build → security scan → one-click deploy → A
   grade): on `https://glama.ai/mcp/servers/backblaze-labs/b2-mcp/admin/dockerfile`,
   point Glama at the repo `Dockerfile`, use the plain image command
   `node dist/index.js` (the image sets `B2_MCP_TRANSPORT=http` and
   `PORT=3000`), and set the health check to `/health`. If Glama requires an
   explicit listen host, add `B2_HTTP_HOST=0.0.0.0`. Keep the build-time scanner
   config separate from the real deployment env:

Scanner configuration for Glama build tests:

| Setting | Value |
| --- | --- |
| Command | `node dist/index.js` |
| Health check | `/health` |
| `placeholderArguments` | `{}` |
| `B2_HTTP_CREDENTIAL_MODE` | `headers` |
| B2 key env values | omit |

Header mode keeps `/health` green without static B2 credentials and lets the
scanner initialize and run `tools/list` without credential headers. Do not inject
`B2_APPLICATION_KEY_ID` / `B2_APPLICATION_KEY` placeholders into the scanner;
placeholder env credentials are ignored only in header mode, not server mode.

Env schema for the real Glama deploy form:

| Name | Required | Secret | Placeholder |
| --- | --- | --- | --- |
| `B2_APPLICATION_KEY_ID` | yes | yes | `your-application-key-id` |
| `B2_APPLICATION_KEY` | yes | yes | `your-application-key-secret` |
| `B2_REGION` | no | no | `us-east-005` |
| `B2_MASTER_KEY_ID` | no | yes | (Partner tools only) |
| `B2_MASTER_KEY` | no | yes | (Partner tools only) |
| `B2_HTTP_CREDENTIAL_MODE` | yes | no | `server` |

`B2_HTTP_CREDENTIAL_MODE=server` is the one-click deployment shape for real
users: tool calls use the env-supplied application key, and those env values
must be valid. Missing env credentials make `/health` fail, and rejected
server-mode credentials return HTTP credential errors instead of discovery mode.
Actual `tools/call` requests stay credential-gated in every mode.

## LobeHub

Uses the `@lobehub/market-cli` (`lhm`) CLI. `login` and `github connect` are
browser flows a human must complete; `plugin init` needs no auth.

```bash
# Read-only probes
npx -y @lobehub/market-cli auth status --output json
npx -y @lobehub/market-cli github status

# Human-in-the-loop (browser)
npx -y @lobehub/market-cli login
npx -y @lobehub/market-cli github connect

# Regenerate the manifest (no auth; discovery mode handles missing credentials)
npx -y @lobehub/market-cli plugin init \
  --stdio "node dist/index.js" \
  --dir "$(pwd)" --force
# then restore the official name/description/identifier in lhm.plugin.json

# Claim the auto-crawled listing, then push the manifest
npx -y @lobehub/market-cli plugin claim backblaze-labs-b2-mcp
npx -y @lobehub/market-cli plugin update --dir "$(pwd)"
npx -y @lobehub/market-cli plugin list --output json
```

Never read or print `~/.lobehub-market/` credential files.

## Directory checklist

Aggregators that ingest the Official MCP Registry pick the server up
automatically; the rest need a submission or claim. Full status lives in
[#300](https://github.com/backblaze-labs/b2-mcp/issues/300).

- Privacy URL — use `https://backblaze-labs.github.io/b2-mcp/privacy/` for
  Claude Connectors ([#358](https://github.com/backblaze-labs/b2-mcp/issues/358))
  and the OpenAI directory
  ([#359](https://github.com/backblaze-labs/b2-mcp/issues/359)); both require a
  publicly reachable privacy-policy URL.
- Official MCP Registry — published (`server.json` + `publish.yml`).
- mcp.so — submitted (`mcp.so/servers/backblaze-b2-mcp-server`).
- MCP Market — live, auto-crawled from the registry (`mcpmarket.com/server/backblaze-b2`).
- Glama — claim + release (above).
- Smithery — deferred, not on the roadmap. See [Smithery (deferred)](#smithery-deferred).
- LobeHub — claim + `lhm plugin update` (above).
- PulseMCP — crawls the registry; verify, submit if absent.
- Cline MCP Marketplace, Docker MCP Catalog, OpenTools, Fleur — submit.
  (`mcp-get` is retired — its repository is archived and unmaintained.)
- Awesome-list PRs — only `punkpeye/awesome-mcp-servers` is a viable target
  (PR [#13422](https://github.com/punkpeye/awesome-mcp-servers/pull/13422)). The
  others were dropped: `wong2/awesome-mcp-servers` disabled pull requests and is
  auto-generated from the mcp.so database (so mcp.so coverage flows through),
  `appcypher/awesome-mcp-servers` is archived (read-only) with PRs disabled, and
  `modelcontextprotocol/servers` no longer keeps a third-party server list.
- VS Code / Cursor / Windsurf — auto-ingest the registry; verify only.

## Authority backlinks (highest ranking lever, #301)

- A `backblaze.com` page linking the repo with anchor text
  `Backblaze B2 MCP server`.
- A featured card on backblazelabs.com with the display name and description.

## MCPB desktop-extension bundle

The `.mcpb` desktop-extension bundle is the local-stdio artifact directories
consume — primarily the Claude Connectors Directory submission
([#385](https://github.com/backblaze-labs/b2-mcp/issues/385)). It is built and
attached to every GitHub Release automatically.

`Publish Package` builds `dist-mcpb/b2-mcp.mcpb` (`pnpm run build:mcpb`), records
its SHA-256 in the release `SHA256SUMS`, and attaches it to the release assets on
every release, so no manual build is needed — download `b2-mcp.mcpb` from the
release. (To rebuild locally for inspection, run `pnpm run build:mcpb`.) The
bundle packs `mcpb/manifest.json`, which runs `npx -y @backblaze-labs/b2-mcp@<version>`
and prompts for the B2 credentials. Both the manifest version and the pinned npx
launcher version are kept in lockstep with `package.json` by
`scripts/update-server-json-version.mjs`, and `scripts/build-mcpb.mjs` normalizes
the archive timestamps, so the advertised bundle is byte-for-byte reproducible.

> **Scope of the `.mcpb` checksum.** The bundle contains `mcpb/manifest.json` —
> a launcher that runs `npx -y @backblaze-labs/b2-mcp@<version>` — plus the
> bundled `icon.png` used by Claude Desktop. The reproducible SHA-256 therefore
> attests to the *launcher manifest and icon*, not to the server code, which npx
> resolves from npm at runtime by version tag (no integrity/provenance pin). It
> is not an end-to-end supply-chain guarantee over the executed code; assurance
> for the npm package itself comes from the npm publish pipeline (`publish.yml`),
> not from this digest.

## Smithery (deferred)

Smithery is **not on the current roadmap.** Its publish flow at
[smithery.ai/new](https://smithery.ai/new) has two tabs, and neither is a good
fit today:

- The **URL** tab expects a remote server hosted at a public HTTPS endpoint
  (Streamable HTTP + OAuth). b2-mcp intentionally has no hosted, multi-tenant
  endpoint — it runs locally per user with the user's own B2 keys — so this tab
  does not apply (same reason [#359](https://github.com/backblaze-labs/b2-mcp/issues/359)
  was closed).
- The **Local (MCPB Bundle)** tab could accept `dist-mcpb/b2-mcp.mcpb`, but that
  overlaps the Claude Connectors Directory path we already prioritize, so it is
  not maintained as a parallel channel.

Revisit if Backblaze ever operates a self-hosted, OAuth-authenticated MCP
endpoint — at that point the Smithery **URL** listing becomes the natural, richer
integration. `smithery.yaml` is retained in the repo (and kept in sync by the
release-scripts contract) so a future submission needs no rebuild.

## On every release

1. Bump + `scripts/update-server-json-version.mjs` (syncs `server.json`,
   `lhm.plugin.json`, and `mcpb/manifest.json` versions).
2. `Publish Package` builds `b2-mcp.mcpb`, checksums it into `SHA256SUMS`, and
   attaches it to the GitHub Release automatically (no local `pnpm run build:mcpb`
   required). That release asset is what the Claude Connectors Directory
   submission ([#385](https://github.com/backblaze-labs/b2-mcp/issues/385)) consumes.
3. Regenerate `lhm.plugin.json` and `lhm plugin update`.
4. Cut a new Glama release (rerun the Dockerfile deploy → Make Release).
5. Confirm the registry badge shows the new version.
