Skip to content

Conversation

@marcpradas-IAG
Copy link

@marcpradas-IAG marcpradas-IAG commented Sep 19, 2025

Follow-up PR: OCI Validator Enhancements (Issue #498)

This PR builds on the GHCR compatibility branch and delivers a more robust OCI image validation flow plus developer ergonomics for testing and CI.

Highlights

  • GHCR authentication flow

    • Supports Personal Access Token (PAT) + optional MCP_REGISTRY_OCI_GHCR_USERNAME Basic exchange to obtain a repository-scoped Bearer token
    • Fallback to using GITHUB_TOKEN automatically for ghcr.io when available
    • Prefer Bearer tokens for registry API calls
  • Header standardization

    • Unify Accept headers for manifests (Docker v2 manifest + list, OCI manifest + index)
    • Unify Accept headers for image configs (OCI image config, Docker container config, binary fallback)
  • Multi-arch image handling

    • Automatically resolve manifest lists/indexes to the correct platform-specific manifest
    • Resolve config digest correctly and fetch the image config to inspect labels
  • Label validation with test toggle

    • Enforce MCP label presence by default
    • Allow skipping label validation during tests via MCP_REGISTRY_OCI_SKIP_LABEL_VALIDATION=1
  • Auth discovery and environment variables

    • Per-host token envs: MCP_REGISTRY_OCI_TOKEN_GHCR_IO, MCP_REGISTRY_OCI_TOKEN_DOCKER_IO
    • Mapping env: MCP_REGISTRY_OCI_REGISTRY_AUTH="host=token,..." (e.g. ghcr.io=<token>,docker.io=<token>)
    • Docker Hub mapping key uses docker.io (API host is registry-1.docker.io)
  • Test-only base URL override

    • MCP_REGISTRY_OCI_TEST_BASE_URL for mocking registry endpoints in unit tests
  • Developer diagnostics

    • MCP_REGISTRY_OCI_DEBUG=1 prints non-sensitive debug traces: auth source selection, GHCR exchange path, header decisions

Tests

  • Mocked HTTP tests
    • Cover auth resolution, media type negotiation, multi-arch handling, and label validation
  • GHCR integration tests (env-gated)
    • Use real GHCR when credentials are present; support skipping label validation
  • End-to-end test
    • Pulls image, runs container, executes commands inside (e.g. print /etc/os-release and uname), validates runtime

Docs & Lint

  • Added Container Registry Auth Matrix (docs/guides/publishing/github-actions.md)
  • Fixed markdown lint warnings in docs

Notes

  • Docker Hub public images require no configuration; anonymous token flow is performed automatically
  • For GHCR, MCP_REGISTRY_OCI_GHCR_USERNAME enables exchange of PAT to Bearer; otherwise, token is used as Bearer directly
  • Debug traces avoid printing secrets while making CI issues much easier to diagnose

Add GHCR (ghcr.io) compatibility to OCI validator
Implement robust auth resolution:
Per-host token envs (e.g., MCP_REGISTRY_OCI_TOKEN_GHCR_IO)
Mapping var MCP_REGISTRY_OCI_REGISTRY_AUTH
GITHUB_TOKEN fallback for ghcr.io
Optional MCP_REGISTRY_OCI_GHCR_USERNAME + PAT; exchange PAT→Bearer via ghcr.io/token (service=ghcr.io, scope=repository:<ns>/<repo>:pull), prefer Bearer over Basic
Broaden Accept headers for manifests/config; propagate auth to follow-up requests
Support multi-segment repository paths (e.g., owner/sub/repo)
Allow skipping label check via MCP_REGISTRY_OCI_SKIP_LABEL_VALIDATION (test-only)
Tests:
Mocked HTTP: single-arch, multi-arch, missing label, auth header
GHCR integration test gated by GHCR_TEST_IMAGE/TAG (+ server name or skip)
Optional E2E docker test (OCI_E2E_RUN) that login/pull/run, execs into container (os-release, uname), and cleans up; controllable via OCI_E2E_RUN_ARGS and OCI_E2E_CMD
Docs: README markdown lint fixes and GHCR/private auth env guidance
Closes modelcontextprotocol#498
@tadasant
Copy link
Member

GHCR was added here: #439

Does that solve your need here? If not, could you please explain more about the intent behind this PR?

@marcpradas-IAG
Copy link
Author

marcpradas-IAG commented Sep 25, 2025

GHCR was only added there for public GHCR registries, my PR apart of working for private registries, solves the mocked tests, cause it actually test e2e pulling the image from a private GHCR, run it and exec a command inside the running container to get the OS info @tadasant

@marcpradas-IAG
Copy link
Author

marcpradas-IAG commented Sep 25, 2025

@tadasant
image

image

ENV Pre-requisites execute the e2e test

GHCR (private repository) Scenarios

A. PAT + Username (recommended for private org images)
Set:

MCP_REGISTRY_OCI_TOKEN_GHCR_IO = <your GitHub PAT with at least packages:read (and repo if needed)>
MCP_REGISTRY_OCI_GHCR_USERNAME =
The code will exchange the PAT+username for a repository-scoped Bearer token automatically.

B. Direct Bearer / No Username
If you already have a repo-scoped Bearer token:

MCP_REGISTRY_OCI_TOKEN_GHCR_IO = (Do NOT set MCP_REGISTRY_OCI_GHCR_USERNAME; it will just use it directly.)

C. GitHub Actions Ephemeral
(No extra work if your workflow already has permissions.)

GITHUB_TOKEN is provided by Actions; ensure permissions.packages=read (Optional to override with MCP_REGISTRY_OCI_TOKEN_GHCR_IO if you want a PAT instead.)

Optional Test Label Vars
GHCR_TEST_SERVER_NAME =
Needed if you’re not skipping label validation and the image should contain that label.
MCP_REGISTRY_OCI_SKIP_LABEL_VALIDATION=1 to bypass ownership label checks (useful for arbitrary images).

Private Docker Hub Repository

The validator only supports supplying a Bearer-style token (it does NOT do Basic username/password exchange). So you must provide a token that grants pull access:

Use either:

MCP_REGISTRY_OCI_TOKEN_DOCKER_IO = OR
MCP_REGISTRY_OCI_REGISTRY_AUTH = docker.io=
(If both GHCR and Docker tokens are needed you can combine in the mapping, e.g. MCP_REGISTRY_OCI_REGISTRY_AUTH="ghcr.io=AAA,docker.io=BBB".)

Note: The code will try an anonymous token if you don’t supply one; that only works for public images. For private repos you must inject a token as above.

@marcpradas-IAG
Copy link
Author

@claude Can you review this?

@marcpradas-IAG
Copy link
Author

@copilot review this too please

@marcpradas-IAG
Copy link
Author

@tadasant @toby can someone review it or introduce this feature at your own way?
image

@marcpradas-IAG
Copy link
Author

@domdomegg sorry but I saw the number of contribution lines and I also needed to add you

Copy link
Member

@rdimitrov rdimitrov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey, thanks a lot for identifying this gap 👍 I just had a quick look, so apologies if my feedback is a bit incomplete:

  • To get started I’d recommend keeping things simple and generic so we can streamline the implementation to support bearer token authentication and have better chances this gets merged
  • Right now the changes feel a bit all over the place and more like a rewrite whereas it might be better to align more closely with the existing design.
  • The tests could use some improvements, i.e switching from if and fatal to proper assertions.
  • I also noticed a few unrelated lines being modified which might be worth revisiting
  • Commit descriptions could use some love too

The overall goal looks great 👍 I’d just suggest spending a bit more time polishing the details and refining the design so it’s more solid 👍

@tadasant
Copy link
Member

Can we talk about the premise here a bit first please --

GHCR was only added there for public GHCR registries, my PR apart of working for private registries

Do we need to support private GHCR registries?

We've already decided we won't support private GitHub repos, so it's not clear to me what the use case is for private containers.

@rdimitrov
Copy link
Member

After reviewing this more closely it became clear that the docs might not have fully explained what’s considered open vs. closed source and how that relates to public vs. private MCP servers (likely causing some confusion here on me too).

We’ve clarified the reasoning and expanded the explanation in the FAQ: https://github.com/modelcontextprotocol/registry/blob/main/docs/reference/faq.md#can-i-publish-a-private-server

That said we'll close the PR since private registries are out of scope for this project. Thank you! 🙏

@rdimitrov rdimitrov closed this Sep 29, 2025
@marcpradas-IAG
Copy link
Author

Wooow amazing feedback @rdimitrov!!!

Many thanks for the positive vibes, and sorry for my informal way, and there was a test that I know I've messed and moved into another file, and for sure will solve all 'fatal' to the correct assertions.

Today in the afternoon I'll take some time to solve the issues so we can have a fresh iteration!!

GoGo! DEVS

@rdimitrov
Copy link
Member

@marcpradas-IAG - hey 👋 I think you might have missed my last comment but it won't be necessary to iterate on this since we clarified that supporting private registries is not in the scope of the registry project.

@marcpradas-IAG
Copy link
Author

Oh I haven't seen the next messages, sorry to hear that @tadasant and @rdimitrov don't want to disturb anymore but just to give a bit of context why we needed that:

From IAG we are willing to be able to use MCP from a long time ago, but we assessed the security of the connectivity layer between some agentic tools and MCP servers and we found many possibilities of infection threat or data leakage.

Example:
I use MCP_blabla and its source code lives in a public repo from a 3rd party company, some mantainer from this company that does not have the right security/quality gates merges the vulnerable code into main, that package gets released I fetch it using the latest tag and from that point it can start sending the agent daya anywhere or responding to agent tool calls with malicious orders.

Then we analyzed the different possibilities of installing MCP servers (uv, npm, docker, locally...), seeing the scenario and within our context and we thought that any server could be wrapped into a docker image (one that we control and where we can add observability and so) and we also knew how to store this images in GHCR, this brought us to the next point which is a private GHCR also will use the same authentication credentials than Github, so that will solve all our problems.

@rdimitrov
Copy link
Member

@marcpradas-IAG - thanks for the context 🙏 Totally understand why you’d want to wrap MCP servers into Docker images you control and host them in GHCR 😃 It gives you the control, observability and security guarantees you need.

This registry though is meant as a community-driven public good instance so for your case a private MCP registry you manage directly would be the better fit 👍

@marcpradas-IAG
Copy link
Author

amazing and thanks again!!
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants