Self-hosted marketplace: desktop app rejects non-allowlisted git hosts, and authenticated marketplaces appear to require managed settings

Status Open
Reported on v2.1.247
Maintainer reply None cached
Activity 1 comment · opened Aug 27, 2026

Use case

I work on a self-hosted developer-tools product. We want each customer's own product instance to serve the Claude skills that match it, so that:

  • the skills are always version-matched to the instance that serves them,
  • air-gapped and network-restricted installs work with no external dependency,
  • no customer-facing skill content has to be published to a public host.

Serving them as a git-source marketplace from the instance works in the Claude Code CLI today.

What fails

Adding the same marketplace in the desktop app is refused:

This host isn't supported. Use github.com, gitlab.com, bitbucket.org, or a GitHub Enterprise instance configured by your organization.

The CLI accepts a git marketplace on an arbitrary host; the desktop app does not. That difference is not documented as far as I can find, and it means a self-hosted vendor cannot use in-app hosting as its distribution channel for desktop users.

The two documented alternatives don't fit:

  • Mirroring to a public host defeats air-gapped customers and means publishing customer-facing content publicly.
  • "a GitHub Enterprise instance configured by your organization" is the customer's GHE, so every customer would have to mirror a vendor's skills into their own GHE.

What I verified while looking for a way round

A marketplace.json served at a plain HTTPS URL is a separate source type from a git repo, and it looks like it sidesteps the host check. In the CLI I confirmed:

  • adding a marketplace by direct marketplace.json URL works end to end — downloads, validates, caches, registers;
  • the manifest schema accepts archive plugin sources with sha256 and headersHelper;
  • the archive host restrictions (HTTPS only, no loopback) apply to the zip fetch but not to the marketplace.json fetch — plain http://127.0.0.1 was accepted for the manifest.

So the url + archive route may already be the answer for desktop. I could not confirm that, because I don't yet have the manifest served from a reachable host — if a maintainer can confirm that the desktop app accepts a url-source marketplace on an arbitrary host, that alone may resolve this.

The authentication gap

Skills served from a customer instance need the same authentication as everything else on that instance, and here the story is harder:

  • A bare plugin marketplace add against an auth-gated URL fails with HTTP 401. No prompt, and no credential helper is consulted, so an authenticated marketplace cannot be added interactively at all.
  • Authenticating one appears to require extraKnownMarketplaces with headers / headersHelper. extraKnownMarketplaces in user settings was ignored in my testing (No marketplaces configured, no request reaching the server), which suggests it is managed-settings-only.

If that's right, every customer needs an admin-deployed managed-settings policy purely to authenticate to their own instance — a significant adoption cost for something that is not really an org policy decision.

Requests

Either of these would unblock the use case:

  1. Confirm or document that a url-source marketplace.json on an arbitrary HTTPS host is accepted by the desktop app, and that archive sources may be hosted anywhere subject to the existing transport rules.
  2. Allow authenticated marketplaces outside managed settings — support headers / headersHelper (or a credential helper) for a marketplace a user adds themselves, so authenticating to a self-hosted instance doesn't require an admin-deployed policy.

A vendor/operator host escape for git-source marketplaces would also solve the original problem, though the url + archive route seems the cleaner fit if it already works.

Environment

Claude Code 2.1.247, macOS. headersHelper requires 2.1.238+, so version isn't the constraint here.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗