cg-versions: the upstream version history MCP server
Connect an MCP client to cg-versions to look up upstream release history, version streams, and end-of-life dates for the …
For the complete documentation index, see llms.txt.
cg-oci gives an AI tool read-only access to the Chainguard container registry at cgr.dev. Through it, a client can list the repositories and tags your account can reach, fetch a manifest or image config by tag or digest, and read the signed attestations attached to an image — its SPDX SBOM, its apko build configuration, and its SLSA build provenance. Every response comes from the registry as it exists at the moment of the call, so an AI tool can answer what a specific image actually contains rather than what its documentation says it contains.
The server uses the Streamable HTTP transport, at this endpoint:
https://cgr.dev/mcpAdd the server with claude mcp add, using the HTTP transport:
claude mcp add --transport http cg-oci https://cgr.dev/mcpPick the scope that fits how you want to use it: local (the default — only you, in the current directory), project (writes a shared .mcp.json at the repository root, checked in for teammates), or user (only you, across every project). A registry lookup is useful almost everywhere, so --scope user is usually the right choice:
claude mcp add --transport http --scope user cg-oci https://cgr.dev/mcpThe server is added unauthenticated. To complete OAuth, start a session and run the /mcp command:
/mcpSelect cg-oci, choose Authenticate, and approve the connection in the browser window that opens. Check the status any time with:
claude mcp listcg-oci: https://cgr.dev/mcp (HTTP) - ✓ ConnectedCursor supports HTTP transport natively. Add the server to your MCP configuration:
{
"mcpServers": {
"cg-oci": {
"url": "https://cgr.dev/mcp"
}
}
}Restart Cursor, then connect the server from Tools & MCPs in settings and complete the browser sign-in.
Claude Desktop reads MCP servers from a JSON file but does not yet support HTTP transport directly. Use mcp-remote to bridge to the hosted server:
{
"mcpServers": {
"cg-oci": {
"command": "npx",
"args": [
"mcp-remote",
"https://cgr.dev/mcp"
]
}
}
}The configuration file lives at:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonnpx downloads and runs mcp-remote on demand, so you need Node.js installed on the host. Restart Claude Desktop after saving the file.
Any client that supports a remote Streamable HTTP MCP server with OAuth can connect to the same endpoint. Point it at https://cgr.dev/mcp and complete the browser sign-in when prompted. Consult your client’s documentation for where its MCP configuration lives.
Authentication is OAuth 2.0 against the Chainguard issuer. You can read an image through cg-oci only if your account can pull it from the registry.
cg-oci does not authenticate you to cg-apk, cg-versions, or cg-api. Connecting all four means completing the browser sign-in four times. As of this writing, there is no unified sign-in across the four servers.On a remote or headless workstation, you can supply a token from chainctl instead of completing the browser flow. Refer to Authenticate with chainctl instead of a browser for the full recipe; cg-oci’s audience is https://cgr.dev/mcp.
Results are scoped to your account, which has two effects:
list_repos does not list the public Chainguard catalog. It lists every repository your token can reach, across every organization you belong to, in _catalog order. If your organization mirrors images into its own namespace, those repositories appear alongside the public ones.chainguard/* repositories expose only latest and latest-dev. Version tags such as 3.12 live in your organization’s own namespace and require an entitlement. chainguard/python:3.12 is not a valid reference for an unentitled caller, even though 3.12 builds of the Python image exist.To browse the public catalog and its documented tags, use the Chainguard Containers directory instead.
The tools fall into two groups. The list_* tools return one bounded page at a time — 50 items by default, 200 at most — and you continue by passing a cursor back. The get_* tools return a single object exactly as the registry stores it.
Every tool identifies an image with two separate parameters rather than one fully qualified reference:
repo — the repository name without the registry host, for example chainguard/pythonreference — a tag such as latest, or a digest such as sha256:5a673f...Passing cgr.dev/chainguard/python:3.12 as a single string does not work.
| Tool | Parameters | Returns | Example prompt |
|---|---|---|---|
list_repos | page_size, cursor | {repos, count, has_more} | “What Chainguard repositories can I access?” |
list_tags | repo, page_size, cursor, include_digest_tags | {tags, count, has_more, next_cursor} | “What tags exist for chainguard/python?” |
get_manifest | repo, reference | {digest, manifest, media_type, size} | “Get the manifest for chainguard/python:latest” |
get_config | repo, reference, architecture | {digest, config} | “What’s the entrypoint of the chainguard/python image?” |
get_sbom | repo, reference, architecture | {subject_digest, size_bytes, attestations} | “Show me the SBOM for chainguard/python:latest” |
list_sbom_packages | repo, reference, architecture, page_size, cursor | {subject_digest, documents, packages, count, total_packages, has_more, next_cursor} | “What packages are in the amd64 chainguard/python image?” |
get_apko_config | repo, reference, architecture | {subject_digest, attestations} | “What apko config built chainguard/python:latest?” |
get_provenance | repo, reference, architecture | {subject_digest, attestations} | “Show me the build provenance for chainguard/python:latest” |
Depending on your organization’s entitlements, the server may advertise additional tools — a vulnerability listing, for instance, where that feature is enabled. Run /mcp in Claude Code to see the tool list your own token receives.
Lists the repositories your token can reach, through the registry’s /v2/_catalog endpoint. The registry offers no server-side name filtering, so to find a specific repository, an MCP client must page through the whole list and filter the results itself.
| Parameter | Type | Required | Description |
|---|---|---|---|
page_size | integer | no | Repositories per page (default 50, max 200) |
cursor | string | no | The last repository name from the previous page; omit to start at the first page |
The cursor here is a repository name rather than an opaque token, unlike the other list_* tools on this server.
Lists the tags in one repository. Each call requests a single page from the registry, so a repository with thousands of tags responds as quickly as a small one.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host, for example chainguard/python |
page_size | integer | no | Tags per page (default 50, max 200) |
cursor | string | no | The next_cursor from the previous page |
include_digest_tags | boolean | no | Include the sha256- prefixed tags that Cosign uses for signatures, attestations, and SBOMs (default false) |
Digest tags are omitted by default because they outnumber an image’s real tags by a wide margin. Set include_digest_tags=true only when you are looking for the attachment tags themselves.
Fetches an OCI manifest by tag or digest. The server returns the manifest body as a raw JSON string, which preserves the exact bytes the registry computed the digest over.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | A tag such as latest, or a digest such as sha256:.... Prefer digests for content-addressable lookups. |
For a multi-architecture tag this returns the image index, whose manifests array names the per-architecture children. The index’s annotations carry useful metadata, including org.opencontainers.image.created — which is how you find out when an image was built.
Fetches the OCI image config: the build-time description of the image’s entrypoint, environment, working directory, and user.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | Tag or manifest digest |
architecture | string | no | Which child manifest to descend into when the reference resolves to a multi-arch index (default amd64) |
Fetches the signed SPDX SBOM attestation (predicateType https://spdx.dev/Document). Each predicate in the response is the raw SPDX document exactly as it was signed.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | Tag or manifest digest |
architecture | string | no | Descend into this architecture’s child manifest. Omit to read the attestation attached to the reference itself — the index, for a multi-arch tag. |
The server refuses a document larger than 512 KB outright rather than truncating it; the error names the size and the cosign command that fetches the file directly. Use list_sbom_packages when you only need the package list. An image with no SBOM attestation returns an empty attestations list rather than an error.
Pages through the packages in an image’s SPDX SBOM, returning package names, versions, PURLs, licenses, and SPDX purposes without pulling the whole document into context.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | Tag or manifest digest |
architecture | string | no | Descend into this architecture’s child manifest |
page_size | integer | no | Packages per page (default 50, max 200) |
cursor | string | no | The next_cursor from the previous page |
architecture to get real packages. Omitting it on a multi-architecture tag reads the index-level SBOM, which describes the index and its child manifests rather than the software inside the image — for chainguard/python:latest that is three entries. Passing architecture=amd64 reads the per-architecture SBOM instead, which for the same image holds 134.The package list mixes several kinds of entry, distinguishable by their purpose and purl:
CONTAINER — the image and its layer descriptors, with pkg:oci/... PURLsOPERATING_SYSTEM and APPLICATION — the Wolfi base and its APK packages, with pkg:apk/wolfi/... PURLsINSTALL — the melange build definitions that produced those packagesSOURCE — the upstream source a package was built from, such as a CPython commitFILE — individual files the SBOM recordsThe OPERATING_SYSTEM and APPLICATION entries are the OS packages most readers are looking for. The OCI descriptors sort first, so the APK packages start after about a dozen CONTAINER rows on the first page.
Fetches the apko image-configuration attestation (predicateType https://apko.dev/image-configuration) — the declarative build-time description of the image’s contents, accounts, entrypoint, and environment.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | Tag or manifest digest |
architecture | string | no | Descend into this architecture’s child manifest |
Fetches the SLSA build provenance attestation (predicateType https://slsa.dev/provenance/v1), describing the build that produced the image.
| Parameter | Type | Required | Description |
|---|---|---|---|
repo | string | yes | Repository name without the registry host |
reference | string | yes | Tag or manifest digest |
architecture | string | no | Descend into this architecture’s child manifest |
The predicate’s buildDefinition.internalParameters pins every package version that went into the image, and runDetails.builder names the builder and its version. This makes get_provenance a fast way to read exact package versions without paging through an SBOM.
Sample exchanges from a Claude Code session with cg-oci connected. You don’t call the tools yourself — you describe what you want, and the AI tool decides which calls to make. Images are rebuilt often, so your answers will differ.
What tags are available for chainguard/python? Called cg-oci (ctrl+o to expand)
● The chainguard/python repository exposes two tags: latest and
latest-dev. Version-specific tags such as 3.12 live in an entitled
namespace rather than the public chainguard/ one.When was chainguard/python:latest built, and what Python version is in it? Called cg-oci (ctrl+o to expand)
● chainguard/python:latest was built on 2026-09-20. Its build provenance
pins the python-3.14 package, so latest is currently Python 3.14.What OS packages are in the amd64 build of chainguard/python:latest? Called cg-oci (ctrl+o to expand)
● The amd64 image's SBOM lists 134 entries. The APK packages include
wolfi-baselayout, glibc, openssl's libcrypto3 and libssl3, sqlite-libs,
and python-3.14 itself.| Symptom | What it means | What to do |
|---|---|---|
MANIFEST_UNKNOWN: Unknown manifest | The repository is readable but that tag or digest is not. Most often the tag genuinely doesn’t exist in the namespace you’re reading — for example chainguard/python:3.12, where public chainguard/* repositories carry only latest and latest-dev. | Call list_tags on the repository to see the tags your token can actually read, then use one of those. |
FORBIDDEN: Forbidden | Your token cannot read the repository at all. The registry returns this for a repository that doesn’t exist and for one you aren’t entitled to, without distinguishing them. | Confirm the repository name with list_repos, and check your organization’s entitlement for it. |
Server shows as not connected in claude mcp list | OAuth was never completed, or the token expired. Claude Code’s tokens against the Chainguard issuer last about an hour and carry no refresh token. | Run /mcp, select cg-oci, and authenticate again. To stop re-authenticating, switch to the chainctl helper. |
401 invalid token when using the chainctl helper | The audience was registered as a bare hostname. MCP audiences must include the /mcp path. | Run chainctl auth login --audience=https://cgr.dev/mcp and try again. |
no chainctl token for audience ... | The helper script ran but that audience was never logged in. | Run the chainctl auth login command the error prints. |
| An SBOM request is refused for size | The SPDX document exceeds the server’s 512 KB ceiling. Documents are never truncated. | Use list_sbom_packages instead, or fetch the file with the cosign command named in the error. |
list_sbom_packages returns only two or three entries | The call read the index-level SBOM rather than a per-architecture one. | Pass architecture=amd64 (or arm64). |
| The AI tool can’t find an image you know exists | It may be searching list_repos, which reflects your token rather than the public catalog, and offers no server-side name filter. | Name the repository explicitly, as chainguard/<name>, or look it up in the Containers directory. |
cg-apk — search the Wolfi package index and read package SBOMs and build recipescg-versions — check upstream releases and end-of-life datescg-api — query organizations, IAM, and registry metadata through the platform APIchainctl authentication recipeLast updated: 2026-09-28 00:00