Skip to content

Tracking: package and release a .mcpb bundle #250

Description

@millsmillsymills

Goal

Ship gandi-mcp as an MCPB bundle: a gandi-mcp.mcpb file attached to a GitHub
Release, installable into MCPB-capable hosts (Claude Desktop and others) in one
click.

Spec: https://github.com/modelcontextprotocol/mcpb
MANIFEST.md,
CLI.md.

Facts from the spec that shape the plan:

  • A .mcpb is a zip containing the server plus a manifest.json; the host
    reads the manifest and launches the server over stdio.
  • The uv server type (manifest v0.4+) declares dependencies via
    pyproject.toml; the host installs them with uv at install time. This is the
    right choice here because the dependency tree includes pydantic-core
    (platform-specific compiled wheels), which cannot be portably vendored into a
    plain python-type bundle.
  • manifest.user_config fields render in the host's install UI and substitute
    into server.mcp_config.env via ${user_config.key}; sensitive: true
    strings are stored in the OS keychain.
  • The @anthropic-ai/mcpb CLI validates the manifest (mcpb validate) and
    packs the bundle (mcpb pack). Signing (mcpb sign, PKCS#7) is optional.

One consideration worth recording: gandi-mcp only talks to the Gandi v5 cloud
API, and the MCPB docs recommend remote HTTP servers for that shape. MCPB is
still worth shipping here — it keeps the token on the user's machine and needs
no hosted infrastructure — but if a remote deployment ever happens, it
supersedes this as the primary install path.

shortcut-mcp already implements this exact pipeline (uv-type manifest,
scripts/build_mcpb.py, mcpb.yml release-attach workflow:
https://github.com/millsymills-com/shortcut-mcp) and is the pattern to copy.

Current state

  • Stage S3, version 0.1.0. stdio FastMCP server, console script gandi-mcp,
    Python >=3.13, uv.lock committed.
  • Config is env-only: GANDI_TOKEN (required PAT), GANDI_SHARING_ID
    (optional org scoping), GANDI_MODE (readonly default / readwrite),
    GANDI_ALLOW_PURCHASES (default false; independent gate for tools that
    spend money), plus GANDI_API_BASE_URL, GANDI_REQUEST_TIMEOUT,
    GANDI_MAX_RETRIES.
  • No MCPB artifacts exist: no manifest, no icon, no build script, no
    .mcpbignore.
  • No release has ever been cut: the CHANGELOG has only [Unreleased],
    there are no git tags, no GitHub Releases, no release workflow, and no
    RELEASING.md. The release process itself has to be stood up, not just the
    bundle step.

Work items

1. Bundle assets

  • mcpb/manifest.jsonmanifest_version 0.4, server.type: "uv",
    mcp_config launching uv run --directory ${__dirname} gandi-mcp;
    repository/homepage/support/license metadata; compatibility declaring
    python >=3.13,<4 and darwin/win32/linux.
  • user_config mapping:
    - gandi_token (string, sensitive: true, required: true) →
    GANDI_TOKEN
    - mode (string, default readonly) → GANDI_MODE — note this is a
    string enum (readonly/readwrite), not a boolean
    - allow_purchases (boolean, default false) → GANDI_ALLOW_PURCHASES
    - sharing_id (string, optional) → GANDI_SHARING_ID — without it,
    multi-org/reseller accounts operate against the token owner's default
    scope
    Base URL / timeout / retries stay env-tunable outside the install UI.
  • mcpb/icon.png.

2. Build script

  • scripts/build_mcpb.py (port from shortcut-mcp): stage
    pyproject.toml, uv.lock, README.md, LICENSE, src/ into a clean
    dir, sync the manifest version from pyproject.toml (single-source
    rule), zip to dist/gandi-mcp.mcpb.
  • Validate the staged manifest against the v0.4 schema in the script or
    via npx @anthropic-ai/mcpb validate.

3. Release process (currently nonexistent)

  • RELEASING.md: semver policy, version bump in pyproject.toml, CHANGELOG
    roll ([Unreleased] → dated version heading), tag vX.Y.Z, create the
    GitHub Release from the tag (port from shortcut-mcp's RELEASING.md).
  • Cut the first tagged release so the mechanics are proven before the
    bundle lands on one.

4. CI

  • .github/workflows/mcpb.yml: build the bundle on push/PR to main (catch
    packaging rot), and on release: published build + attach
    dist/gandi-mcp.mcpb to the release via gh release upload. Actions
    SHA-pinned with version comments, persist-credentials: false,
    least-privilege permissions: (only the attach job gets
    contents: write).

5. Docs

  • README: add an MCPB install section (download the .mcpb from the
    latest release, open with Claude Desktop, fill in the token) ahead of
    the existing uv tool install path.
  • README ## Status: note the packaged distribution once the first
    bundle ships.

6. Verification

  • npx @anthropic-ai/mcpb validate passes on the built manifest.
  • Install the built .mcpb into Claude Desktop: config UI shows the
    fields above, tools list, a read tool works, write tools are hidden in
    readonly mode, and purchase tools stay unavailable until both
    mode=readwrite and allow_purchases=true.
  • Confirm the release workflow attached the asset on a real release.

Acceptance criteria

  • A GitHub Release has gandi-mcp.mcpb attached, built by CI.
  • A fresh Claude Desktop install from that file reaches a working readonly
    server with no terminal steps.
  • Write and purchase tools stay opt-in (default off) through the install UI.

Out of scope / follow-ups

  • Bundle signing (mcpb sign) — optional in the spec.
  • MCP registry submission (server.json) — follow-up once bundle releases
    are routine.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions