Commit graph registry/pkg/model
Author SHA1 Message Date
Radoslav Dimitrov
7a6d1bc30a
fix(cargo): harden README fetch, clarify status handling, strengthen tests (#1330)
Follow-up to #1207, addressing items from the cargo validator review.
**Scoped to cargo + shared helpers — no behavior change for existing
npm/pypi/nuget/oci/mcpb publishers.** Safe to merge and promote.

### Changes
**SSRF hardening of the two-call README retrieval**
- Pin the step-2 README URL to an allowed host (`static.crates.io` in
prod; the base host under test) *before* fetching, so a metadata
response can't steer the validator at an internal/attacker host.
- `CheckRedirect` policy pins every redirect hop to the same allowlist
(the initial URL being pinned isn't enough if an upstream 3xx is
followed).
- Cap the README body with `io.LimitReader` (5 MiB).

> Not publisher-exploitable today (the URL comes from crates.io), so
this is defense-in-depth — but it makes the "host is pinned" guarantee
hold in code rather than rely on crates.io's behavior.

**Clearer status handling** (previously any non-5xx/non-200 collapsed to
"not found")
- **429** → reported as transient/retryable, at both the metadata and
README steps.
- **403** → disambiguated via the crate-version endpoint:
genuinely-missing stays "not found"; *exists-but-no-README* gets an
actionable "add a README with `mcp-name` and republish" message (mirrors
the NuGet validator). This continues the 5xx-vs-403 diagnostic split
@P4ST4S started in the #1207 review — thanks!

**Shared `containsMCPNameToken` helper**
Boundary-anchored ownership-token match (prevents prefix confusion, e.g.
a README declaring `io.github.acme/widget-pro` satisfying a claim for
`io.github.acme/widget`), used here **by the cargo validator only**.
Adopting it in PyPI/NuGet is a separate follow-up because it's a
behavior change for those already-live registries.

**Tests & docs**
Hermetic positive `ServerNameFormats`; combined fixture gains a
version-existence endpoint + cases for 403-missing vs 403-no-README,
429, and prefix-confusion rejection; new foreign-README-host (SSRF)
test; internal test for the helper. Docs: list `crates.io` in the
registry-requirements list + the `Package` model doc.

### Testing
`go build`, `go vet`, full `./internal/validators/...` suite (incl. live
cargo positive), `make check-schema`, `validate-examples` all pass. No
new `golangci-lint` findings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 17:34:54 -04:00
Wolfe-James
685e354b2f
feat: add cargo (crates.io) as a package registry type (#1207)
> **Update — 2026-06-01 (commit 1f3be53)**
>
> - **All @P4ST4S review feedback addressed** — positive-path hermetic
mock + live anchor against `rust-faf-mcp v0.3.1`; 5xx routed as
transient; doc comment qualified. See the [close-out
comment](https://github.com/modelcontextprotocol/registry/pull/1207#issuecomment-4589711057)
for the per-item breakdown.
> - **Runtime-model question RESOLVED** — `package-types.mdx` documents
cargo and MCPB as both first-class Rust MCP distribution paths (cargo
for source-distributed, MCPB for prebuilt-binary). The "Open question"
section below was the original draft framing; the doc now ships the
resolution.
> - **Cargo-specific gotcha discovered and documented** — crates.io
strips HTML comments during README rendering, unlike PyPI/NuGet.
`package-types.mdx` now spells this out so cargo authors don't ship
invisible mcp-name tokens (which is exactly what happened to
`rust-faf-mcp v0.3.0`; fixed in v0.3.1).
> - **Stale reference removed in this update** — the "Out of scope" line
mentioning `docs/guides/publishing/publish-cargo.md` pointed at a path
that doesn't exist. The canonical per-type doc is
`docs/modelcontextprotocol-io/package-types.mdx`; the Cargo section has
been added there directly.
> - **Two real-world Rust MCP servers queued for day-one register**:
`rust-faf-mcp v0.3.1` (live, end-to-end validated by the new live test)
and `perfetto-mcp-rs` ([@0xZOne](https://github.com/0xZOne) in #1055).
> - **Tests:** 19/19 cargo tests pass (16 existing + 2 hermetic + 1 live
anchor). `make validate` clean. `golangci-lint` 0 issues.

---

Adds support for `registryType: cargo` so Rust MCP servers published to
crates.io can be registered through the
documented validation flow rather than the MCPB binary-packaging
workaround. Closes #1055.

  ## Motivation and Context

#1055 noted that crates.io has ~1,800 MCP-related packages with no
direct path into the registry — only the MCPB
binary-packaging workaround. This PR adds first-class support for cargo
as a package registry type: schema +
API surface, validator, integration tests, and a documented example. The
publishing guide
(`docs/guides/publishing/publish-cargo.md`) follows on this branch once
the runtime-model direction in
  **Additional context** is settled.

  ## How Has This Been Tested?

- **`make validate`** — clean. Schema-vs-openapi sync verified; 17/17
examples in `generic-server-json.md`
validate against the schema; `expectedServerJSONCount` bumped 16 → 17 to
match the new Cargo example.
- **`go test ./internal/validators/...`** — passes. 16 cargo validator
sub-cases across 4 test functions, run
  against real crates.io (~2.5s wall):
    - Input validation rejection paths
- Registry-baseURL rejection (4 variants: different host, trailing
slash, http-not-https, subdomain typo)
- Ownership validation against real crates (`serde`, `tokio`, `rand`) —
all correctly rejected for missing
  `mcp-name` token
- Server-name format variations (canonical `io.github.OWNER/REPO`,
multi-hyphen, underscore, numeric suffix)
- **Positive-path test** — gated on `rust-faf-mcp` v0.2.3+ being
published with `mcp-name:
io.github.Wolfe-Jam/rust-faf-mcp` in its README. Reserved as a TODO in
`cargo_test.go`; uncomments to become the
   live anchor once that publish lands.
- **Local `make test-unit`** — not run due to a Go toolchain version
quirk on my workstation (project
auto-downloads 1.26.0; my local `go` is 1.25.6, causing compile
mismatch). CI will exercise the full
  PostgreSQL-backed suite.

  ## Breaking Changes

None. This is an additive change — `cargo` joins the supported
`registryType` enum alongside
`npm`/`pypi`/`nuget`/`oci`/`mcpb`. Existing publishes continue to work
unchanged.

  ## Types of changes

  - [x] New feature (non-breaking change which adds functionality)
- [x] Documentation update (new Cargo example in
`generic-server-json.md`)

  ## Checklist

- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
  - [x] My code follows the repository's style guidelines
  - [x] New and existing tests pass locally
  - [x] I have added appropriate error handling
  - [x] I have added or updated documentation as needed

  ## Additional context

  ### Validator design — two-call retrieval on the documented API

`internal/validators/registries/cargo.go` mirrors the PyPI validator's
README-token approach (substring-match
`mcp-name: <serverName>`), with a two-call retrieval pattern to stay on
the documented public crates.io API:

1. `GET /api/v1/crates/{name}/{version}/readme` returns 200 OK with a
JSON pointer (`{"url":
"https://static.crates.io/readmes/.../...html"}`) — crates.io hands us
the URL rather than emitting a 302.
2. Follow the pointer to the rendered HTML; substring-match for the
token.

The two-call pattern stays on the documented public surface. The CDN URL
layout is observed-stable, but treating
it as the entry point would mean depending on an undocumented path. With
two calls, crates.io controls where
the README lives — if they move it, the metadata endpoint hands us the
new URL.

Missing crates and missing versions surface as **403** from the CDN
(S3's default for missing keys), not 404.
The validator treats any non-200 as "not found" and surfaces the actual
status code in the error message.

  ### Open question — runtime model

Cargo's runtime model is genuinely different from npm/PyPI/NuGet. `cargo
install` is one-time (binary lands on
PATH at `~/.cargo/bin`), not per-invocation like `npx`, `uvx`, or `dnx`
(the new one in .NET 10 SDK Preview 6+).
The new Cargo example in `generic-server-json.md` annotates this
honestly and omits `runtimeHint`.

If a different framing is preferred — e.g. recommending **MCPB**
(prebuilt binary distribution via GitHub
Releases) as the primary path for Rust MCP servers instead of cargo —
happy to adjust the documentation
accordingly. The schema + validator code in this PR is **additive** and
doesn't force a recommendation either
way; a Rust author who chooses cargo can use it, and one who prefers
MCPB still can.

  ### Out of scope (deferred)

- **`docs/guides/publishing/publish-cargo.md`** — follows on this branch
once the runtime-model direction above
  is settled.
- **Publisher CLI `Cargo.toml` autodetect** in
`cmd/publisher/commands/init.go` — separate concern, separate PR.
- **Positive-path validator test** — gated on `rust-faf-mcp` v0.2.3+
publishing as noted in *How Has This Been
  Tested?*.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
2026-06-03 10:56:43 -04:00
Radoslav Dimitrov
1201cbd82b
security: fix open redirect and add small hardening (#1227)
## What this does

Fixes an open redirect plus a handful of small, mostly-invisible
hardening changes around it.

## What's in it

- **The fix**: trailing-slash redirects no longer let `//evil.com/`
redirect off-host.
- **SSRF block** on the DNS/HTTP namespace verification — refuses to
dial loopback, RFC1918, link-local, multicast, CGNAT, or
IP-literal/single-label \"domains\".
- **Slow-client guard**: `ReadTimeout` and `IdleTimeout` on the HTTP
server (no `WriteTimeout` — would risk cutting off legitimate
multi-package publishes).
- **Defence-in-depth headers** on the UI (`/`) and 404 responses.
- **5xx responses** stop leaking raw DB error text to clients (logged
server-side instead).
- **Search filter** stops treating `%` and `_` as wildcards.
- **Validators**: PyPI/NuGet identifiers URL-escaped before fetching;
MCPB no longer follows redirects.
- **Misc**: `Version` field bounded to 255 chars; logs quote user input;
`BlockedNamespaces` denylist now catches subdomain claimants.

Each change is its own commit so they can be reviewed (or reverted)
independently.

## Test plan

- [ ] CI green
- [ ] Synthetic publish in staging for each package type (npm, pypi,
nuget, oci, mcpb) — confirms validator changes don't regress
- [ ] Quick browser check of `/` after deploy to confirm UI still loads
with the new CSP
- [ ] `curl https://<host>//evil.com/` — confirm the open redirect is
closed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 19:14:00 -04:00
Mikel Olasagasti Uranga
7c446e75ad
feat(oci): add support for Quay.io registry (#1150)
Adds support for the Quay.io container registry to the OCI validator.
This allows MCP servers hosted on Quay.io to be registered and validated
by the official registry.

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->

Quay.io is a major, trusted public OCI registry widely used by the
cloud-native and open-source communities. Currently, attempting to
publish a server using a Quay image results in an unsupported OCI
registry error. This change enables developers to use Quay.io as a
first-class hosting option for their MCP server images.

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
- **Unit Tests:** Updated `internal/validators/registries/oci_test.go`
to transition Quay.io from a rejected test case to an allowed one.
- **Pattern Matching:** Verified that the allowlist correctly handles
both specific image identifiers and general pattern matching for the
`quay.io` host.
- **Local Validation:** Ran `make check` to ensure no regressions in the
existing OCI validation logic.

## Breaking Changes
<!-- Will users need to update their code or configurations? -->
No. This is an additive change that expands the allowlist of supported
registries. Existing configurations are unaffected.

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
The implementation follows the existing pattern for OCI registries:
1. Added a `RegistryURLQuay` constant to `pkg/model` for consistency.
2. Hardcoded `quay.io` into the `allowedOCIRegistries` map in the
validator to minimize architectural complexity.
3. Updated all relevant documentation files (`package-types.mdx`,
`generic-server-json.md`, and `official-registry-requirements.md`) to
ensure the source of truth is updated across the project.
4. Validation remains scoped to public images; no private registry
authentication was added for this host.

Signed-off-by: Mikel Olasagasti Uranga <mikel@olasagasti.info>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
2026-04-24 06:11:46 -04:00
dependabot[bot]
52178183f3
build(deps): bump github.com/danielgtaylor/huma/v2 from 2.35.0 to 2.37.2 (#989)
Bumps
[github.com/danielgtaylor/huma/v2](https://github.com/danielgtaylor/huma)
from 2.35.0 to 2.37.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/danielgtaylor/huma/releases">github.com/danielgtaylor/huma/v2's
releases</a>.</em></p>
<blockquote>
<h2>v2.37.2</h2>
<h2>Overview</h2>
<p>This bugfix release fixes an issue with how form data was being
documented in OpenAPI.</p>
<p>This also fixes embedded objects with valid JSON tags being
incorrectly embedded in the OpenAPI docs.</p>
<h2>What's Changed</h2>
<ul>
<li>Don't embed embedded objects with valid JSON tags by <a
href="https://github.com/wolveix"><code>@​wolveix</code></a> in <a
href="https://redirect.github.com/danielgtaylor/huma/pull/978">danielgtaylor/huma#978</a></li>
<li>Fix OpenAPI path prefix regression from $schema fix PR by <a
href="https://github.com/wolveix"><code>@​wolveix</code></a> in <a
href="https://redirect.github.com/danielgtaylor/huma/pull/979">danielgtaylor/huma#979</a></li>
<li>Fix form param doc regression by <a
href="https://github.com/wolveix"><code>@​wolveix</code></a> in <a
href="https://redirect.github.com/danielgtaylor/huma/pull/981">danielgtaylor/huma#981</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/danielgtaylor/huma/compare/v2.37.1...v2.37.2">https://github.com/danielgtaylor/huma/compare/v2.37.1...v2.37.2</a></p>
<h2>v2.37.1</h2>
<h2>Overview</h2>
<p>This bugfix release fixes an issue regarding the Swagger UI docs
renderer, as well as fixes an issue preventing Groups from using the
configurable options released in v2.37.1.</p>
<p>This also brings interface constructors to <code>humamux</code>.</p>
<h2>What's Changed</h2>
<ul>
<li>Export Gorilla Mux interface constructors by <a
href="https://github.com/RangelReale"><code>@​RangelReale</code></a> in
<a
href="https://redirect.github.com/danielgtaylor/huma/pull/965">danielgtaylor/huma#965</a></li>
<li>fix(api): use proper CSP hash for inline script in Swagger doc
renderer by <a
href="https://github.com/leonklingele"><code>@​leonklingele</code></a>
in <a
href="https://redirect.github.com/danielgtaylor/huma/pull/977">danielgtaylor/huma#977</a></li>
<li>fix(group): ensure &quot;Group&quot; satisfies the configProvider
interface by <a
href="https://github.com/leonklingele"><code>@​leonklingele</code></a>
in <a
href="https://redirect.github.com/danielgtaylor/huma/pull/976">danielgtaylor/huma#976</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/danielgtaylor/huma/compare/v2.37.0...v2.37.1">https://github.com/danielgtaylor/huma/compare/v2.37.0...v2.37.1</a></p>
<h2>v2.37.0</h2>
<h2>Overview</h2>
<h3>Dropped Explicit IDN-Hostname Validation</h3>
<p>This validation unintentionally imported an external library to the
base Huma library. Since this was not a requested feature, it has been
removed for now. The <code>idn-hostname</code> format value has become
an alias for <code>hostname</code> in the meantime.</p>
<h3>Operation ID Normalization</h3>
<p>Spaces in operation IDs get automatically converted to hyphens
now.</p>
<h3>Optimizations &amp; Fixed Memory Leak</h3>
<p>Various internal operations have been optimized (~7% overall
improvement): <a
href="https://redirect.github.com/danielgtaylor/huma/pull/973#issue-3960297052">danielgtaylor/huma#973</a></p>
<p>A memory leak when using <code>MultipartFormFiles</code> has been
resolved.</p>
<h3>New Configurable Options</h3>
<h4>Allow Additional Properties By Default</h4>
<p>A new config option has been added to allow additional properties by
default. This can be set in the API config.</p>
<pre lang="go"><code>config.AllowAdditionalPropertiesByDefault = true
</code></pre>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="887f7d4322"><code>887f7d4</code></a>
Fix form param doc regression (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/981">#981</a>)</li>
<li><a
href="f02efeb11d"><code>f02efeb</code></a>
Fix OpenAPI path prefix regression from $schema fix PR (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/979">#979</a>)</li>
<li><a
href="cbf60b60af"><code>cbf60b6</code></a>
Don't embed embedded objects with valid JSON tags (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/978">#978</a>)</li>
<li><a
href="6d0295c4e1"><code>6d0295c</code></a>
fix(group): ensure &quot;Group&quot; satisfies the configProvider
interface (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/976">#976</a>)</li>
<li><a
href="07ca6c5d17"><code>07ca6c5</code></a>
fix(api): use proper CSP hash for inline script in Swagger doc renderer
(<a
href="https://redirect.github.com/danielgtaylor/huma/issues/977">#977</a>)</li>
<li><a
href="58edcf2bf5"><code>58edcf2</code></a>
Export humamux constructors (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/965">#965</a>)</li>
<li><a
href="6c29f67c9d"><code>6c29f67</code></a>
chore(api,docs): update unpkg libraries, specify SRI hash, add strict
CSP (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/916">#916</a>)</li>
<li><a
href="3aee9bd172"><code>3aee9bd</code></a>
Additional docs + normalize operation IDs (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/974">#974</a>)</li>
<li><a
href="e31a8198ad"><code>e31a819</code></a>
Resource optimizations, Go 1.25, remove IDNA library, add benchmark CI
(<a
href="https://redirect.github.com/danielgtaylor/huma/issues/973">#973</a>)</li>
<li><a
href="ddbb810fd5"><code>ddbb810</code></a>
Implement Registry and Query Validation Options (<a
href="https://redirect.github.com/danielgtaylor/huma/issues/925">#925</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/danielgtaylor/huma/compare/v2.35.0...v2.37.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/danielgtaylor/huma/v2&package-manager=go_modules&previous-version=2.35.0&new-version=2.37.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
2026-03-16 17:06:31 +02:00
Tadas Antanavicius
453956d975
chore: Release server.json schema version 2025-12-11 (#841)
Prepared by Claude Code, iterated and reviewed by me.

## Summary

This PR releases the server.json schema version `2025-12-11`,
incorporating URL template variables for remote servers from #570.

### What's New

- **URL Template Variables for Remote Servers** - Remote servers can now
define configurable variables in URLs using `{curly_braces}` notation,
enabling multi-tenant deployments.

### Schema Version
- `2025-10-17` → `2025-12-11`

## Release Sequence

1. ~~**First: Merge static repo PR** -
https://github.com/modelcontextprotocol/static/pull/11 (publishes schema
to versioned URL)~~
2. **Then: Merge this PR** - Updates registry code to reference the new
schema version

## Changes in This PR

- [x] Update CHANGELOG.md with release notes
- [x] Update `CurrentSchemaVersion` in `pkg/model/constants.go`
- [x] Update schema example URL in `docs/reference/api/openapi.yaml`
- [x] Update schema URL in `pkg/api/v0/types.go`
- [x] Update all documentation examples to use new schema version
- [x] Regenerate `server.schema.json`

## Test Plan
- [x] `make check` passes (lint, schema validation, example validation)
- [x] Unit tests pass for validators and publisher commands

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-12 09:33:57 -08:00
Tadas Antanavicius
b58836c48e
feat: Add LocalTransport/RemoteTransport with URL template variables (#570)
Co-authored with Claude Code, but I've closely reviewed/modified/vetted
all changes; ready for final review.

## Summary

This PR adds LocalTransport and RemoteTransport separation with URL
template variable support for remote servers, enabling e.g. multi-tenant
deployments with configurable endpoints.

**Key additions:**
- LocalTransport (for Packages) and RemoteTransport (for Remotes)
- URL template variables for remote transports (e.g., `{tenant_id}` in
URLs)
- Pattern validation ensuring URLs are URL-like while allowing templates
- Full test coverage via Go validator tests and documentation examples

## ⚠️ server.json Update

This PR updates the `server.json` schema. A new schema version will be
cut after this lands.

## Problem

The current schema describes URL templating with `{curly_braces}` for
transports but provides no mechanism for Remote contexts to define what
those variables should resolve to, making the feature unusable for
remote servers.

Referenced issue: #394
- Users need multi-tenant remote servers with different endpoints per
deployment
- Each tenant/region has its own URL (e.g., `us-cell1.example.com`,
`emea-cell1.example.com`)
- Current schema doesn't support parameterized remote URLs

## Solution

### Schema Architecture

**LocalTransport** (for Package context):
```typescript
LocalTransport = StdioTransport | StreamableHttpTransport | SseTransport
```
- Used in Package context (non-breaking rename of existing behavior)
- Variables in `{curly_braces}` reference parent Package
arguments/environment variables
- Supports all three transport types including stdio

**RemoteTransport** (for Remote context):
```typescript
RemoteTransport = (StreamableHttpTransport | SseTransport) + { variables: object }
```
- Extends StreamableHttp/Sse via `allOf` composition - no duplication!
- Adds `variables` object for URL templating
- Only supports streamable-http and sse (stdio not valid for remotes)

### Key Changes

**1. Schema Updates** (`openapi.yaml`, `server.schema.json`):
- Added `LocalTransport` union type for Package context
- Added `RemoteTransport` with `allOf` composition extending base
transports
- Updated Package to reference `LocalTransport`
- Updated remotes to reference `RemoteTransport`
- Added URL pattern validation: `^https?://[^\\s]+$` to both
StreamableHttp and SSE
- Removed `format: uri` from SSE (was blocking template variables)

**2. Go Types** (`pkg/model/types.go`):
- Base `Transport` struct unchanged for Package context
- `RemoteTransport` struct for remotes with `Variables` field
- Both work with existing validation infrastructure

**3. Validators** (`internal/validators/`):
- `validateRemoteTransport()` validates Remote-specific constraints
- `collectRemoteTransportVariables()` extracts available variables
- `IsValidTemplatedURL()` validates template variables reference defined
variables
- `IsValidRemoteURL()` handles template variable substitution before
localhost check
- 6 new test cases for remote transport variable validation

**4. Documentation Examples** (`generic-server-json.md`):
- Remote Server with URL Templating (StreamableHttp with `{tenant_id}`)
- SSE Remote with URL Templating (SSE with `{tenant_id}`)
- Local Server with URL Templating (Package with `{port}`)
- All examples validate via existing `validate-examples` tool

## Example: Remote Transport with Variables

```json
{
  "remotes": [
    {
      "type": "streamable-http",
      "url": "https://api.example.com/mcp/{tenant_id}/{region}",
      "variables": {
        "tenant_id": {
          "description": "Tenant identifier",
          "isRequired": true,
          "choices": ["us-cell1", "emea-cell1", "apac-cell1"]
        },
        "region": {
          "description": "Deployment region",
          "isRequired": true
        }
      }
    }
  ]
}
```

Clients configure the variables, and `{tenant_id}` and `{region}` get
replaced to connect to tenant-specific endpoints like
`https://api.example.com/mcp/us-cell1/east`.

## Architecture Details

**Context-based variable resolution:**
- **Package + LocalTransport**: `{port}` references `--port` argument or
`PORT` env var from parent Package
- **Remote + RemoteTransport**: `{tenant_id}` references
`variables.tenant_id` defined in the transport itself
- **Code reuse**: StreamableHttp/Sse definitions shared via `allOf`, not
duplicated
- **Validation**: Template variables validated against available
variables for each context

---

## Follow-on Work

Follow-on work will be done to adopt the feedback in
https://github.com/modelcontextprotocol/registry/pull/570#issuecomment-3367417636
regarding variable naming/prioritzation/scoping conventions, but should
not have any impact on the shape being introduced here (just
validations).

---------

Co-authored-by: yuna0x0 <yuna@yuna0x0.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Connor Peet <connor@peet.io>
2025-12-11 09:17:32 -08:00
Joel Verhagen
80cb03ff7a
Fix NuGet.org base URL default, improve API integration (#813)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->

This resolves
https://github.com/modelcontextprotocol/registry/issues/738. There are
two issues with the NuGet.org integration today:

1. Change the `registryBaseUrl` for NuGet to
`https://api.nuget.org/v3/index.json`. `https://api.nuget.org` is not
the entry point for our service and is not specific enough.
`https://api.nuget.org/v3/index.json` is the value that users put into
their tooling to connect to our public registry (it is installed by
default in .NET client tooling).
2. Use the service index API to get the URL pattern for package READMEs.
- This URL is not guaranteed to be stable. The service index URL
(`registryBaseUrl`) is, however.

Additionally, I polished up the error messages so various error modes
are clearer. When packages are published to NuGet.org, they take 2-5
minutes to become available due to validations we run.

Some possible states that are now handled and described more helpfully
are:
- Version exists, but the package has no README
- The ID exists, but the version does not
- The ID does not exist at all

There are only 3 authors (me, another MSFT person, and a community
member) explicitly setting the old value. The DB migration will fix the
issue. A future publish will fail with the validation error but the
error message is clear.

`registry type and base URL do not match: 'https://api.nuget.org' is not
valid for registry type 'nuget'. Expected:
https://api.nuget.org/v3/index.json`

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

- Unit tests, new and existing
- Manual test locally
- Set old data in the DB, `docker compose up`, confirm the migration
updates the specific package

## Breaking Changes

Yes, but minimal impact expected, unless there is a dependency on the
specific `https://api.nuget.org` value downstream. I am not aware of any
such dependency, and the new value is more proper and specific.

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

For more information about the NuGet API see:
https://learn.microsoft.com/en-us/nuget/api/overview#service-index (I
wrote most of the docs).
2025-12-09 07:19:38 -08:00
Radoslav Dimitrov
ef4a60505e
Make Repository field properly optional in server.json (#717)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The Repository field in ServerJSON was not properly omitting empty
values
when marshaling to JSON. Even when a server had no repository
configured,
the JSON would include `"repository": {"url": "", "source": ""}` due to:

1. Repository struct fields (URL, Source) lacking omitempty tags
2. Repository being a value type instead of pointer in ServerJSON

This caused validation warnings for servers without repository URLs.

Changes:
- Add omitempty tags to Repository.URL and Repository.Source fields
- Change ServerJSON.Repository from model.Repository to
*model.Repository
- Update validateRepository to handle nil pointers
- Update all code creating Repository instances to use pointers

Now, servers without repository information correctly omit the field
entirely from JSON output, eliminating spurious validation warnings.
## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-10-29 13:23:47 +00:00
Radoslav Dimitrov
913147be3a
Add support for Google Artifact Registry (GAR) (#692)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR:
* Deprecates the existing OCI reference parser
* Deprecates the existing OCI way of authenticating and accessing the
image manifest
* Replaces the above by leveraging go-containerregistry
* Introduces support for Google Artifact Registry
* Enables us to easily add support for other OCI-compliant registries in
the future
* Introduces better error handling
* Introduces custom context timeouts for validation 

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
Related to #427

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-10-28 15:00:06 +02:00
Radoslav Dimitrov
0828bc483c
Make mcpb package version optional and fix schema validation (#686)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR:
* Makes mcpb package version property optional
* Bumps the schema and reflects that in the code
* Makes sure the publisher tests are being covered by doing `make check`

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-10-17 01:35:29 +03:00
adam jones
f870a4c000
Improve golang type documentation and examples (#631)
Enhanced Go struct tags throughout `pkg/api/v0/types.go` and
`pkg/model/types.go` to better align with the OpenAPI specification.

## Changes

- Added comprehensive `doc` tags with detailed field descriptions
matching OpenAPI
- Added `example` tags showing valid values for fields (e.g.,
`"io.github.user/weather"`, `"npx"`)
- Added `format` tags (`uri`, `date-time`) for better type specification
- Added `pattern` and `enum` tags for validation constraints
- Added `placeholder` field to `Input` struct matching OpenAPI spec
- Removed redundant comments in favor of inline struct tags

These changes improve code clarity and make the types more
self-documenting, while maintaining compatibility with the OpenAPI
schema definitions in `docs/reference/api/openapi.yaml`.

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-10-16 21:55:52 +01:00
Radoslav Dimitrov
632cbce815
Refactor package types to use dedicated schema types per package type (NPM, PyPI, NuGet, OCI, MCPB) (#634) 2025-10-11 10:53:45 +03:00
adam jones
a09ae89b4c
Align golang types with openapi.yaml schema (#628)
Change Format constant from `file_path` to `filepath` to match the
OpenAPI schema definition.

This is not used by any servers yet, nor is it enforced by the database,
so it's safe to change.
2025-10-07 16:38:04 +01:00
adam jones
66993e9121
Add icon support to server.json schema (#620)
Implements icon support based on the Model Context Protocol
specification, allowing servers to specify display icons with optional
size, MIME type, and theme variants.

## Changes

- Add `Icon` type to `pkg/model/types.go` with struct tags for automatic
API validation
- Add `icons` field to `ServerJSON` in `pkg/api/v0/types.go`
- Add icon validation in `internal/validators/validators.go`:
  - Only HTTPS URLs allowed (no HTTP or data URIs)
  - Maximum URL length of 255 characters
  - Validates absolute URLs with proper scheme
- Update JSON schema and OpenAPI documentation with Icon definitions
- Add comprehensive test cases for icon validation
- Add example icon to seed.json (Airtable server)
- Change `websiteUrl` validation to HTTPS-only for consistency

## Implementation Details

The implementation uses a two-layer validation architecture:

1. **Huma framework** validates struct tags (`required`, `maxLength`,
`enum`, `pattern`) and returns 422 for violations
2. **Custom validators** handle business logic (HTTPS scheme
requirement, absolute URL requirement) and return 400 for violations

This approach leverages Huma's automatic validation while keeping
business-specific rules in the validator layer.

## Icon Field Specification

- `src` (required): HTTPS URL to icon resource, max 255 characters
- `mimeType` (optional): One of `image/png`, `image/jpeg`, `image/jpg`,
`image/svg+xml`, `image/webp`
- `sizes` (optional): Array of size strings in "WxH" format or "any" for
scalable formats
- `theme` (optional): Either "light" or "dark" to indicate intended
background

Multiple icons can be provided (e.g., for different themes or sizes).
2025-10-07 13:30:32 +01:00
Radoslav Dimitrov
44950c23bb
Enforce schema validation on the publish and edit API level (#598)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR:
* Enforces schema validation on the API level (requests without schema
or older schema will fail)
* Updates the unit tests and examples to match that

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->
**Note this can be considered breaking if clients have not included it
before.**

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-10-05 13:57:10 +01:00
Tadas Antanavicius
8bd13d5ed7
Apply gofmt formatting to all Go files (#588)
## Summary
- Applied `gofmt -s -w` across the entire codebase to ensure consistent
Go formatting
- This will trigger a deployment with minimal code changes

## Test plan
- [x] Pre-commit hooks pass
- [x] No functional changes, formatting only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude <noreply@anthropic.com>
2025-09-30 17:32:22 +03:00
tadasant
a0bc09dbe1 Revert "docs: clarify release deployment process and enable manual deploy trigger"
This reverts commit c40374c280.
2025-09-29 18:57:40 -07:00
tadasant
c40374c280 docs: clarify release deployment process and enable manual deploy trigger
- Add workflow_dispatch to deploy.yml for manual deployment triggers
- Document that releases don't auto-deploy to production
- Add instructions for deploying releases to production
- Add verification steps for deployment

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-29 18:54:56 -07:00
Tadas Antanavicius
56e8b4879b
Introduce serverId, rename id to versionId (#465)
Wielded Claude Code to do this; across many iterations and have reviewed
all the code + largely rewritten the PR commentary here.

This PR implements the server ID consistency changes from
[#396](https://github.com/modelcontextprotocol/registry/issues/396). Our
goal is to:
- Rename `id` to `versionId` to make it clear that it is the ID for a
specific version, not a server
- Introduce `serverId` as a net new concept. This will be 1:1 with
`name`. While not strictly necessary (we could just use name as a PK),
the convention of having a UUID as an ID on our objects is just a
helpful subjective architecture decision. Plus also leaves open the door
to reconsidering the "should we allow renames" question.

## Key Changes

### 🗄️ Database Schema Changes
- **Renamed**: `id` column → `version_id` (unique identifier for each
server version)

### 📋 Metadata Structure Updates
- **JSON Schema**: Updated
`_meta.io.modelcontextprotocol.registry/official` to include:
  - `serverId`: Consistent ID across all versions of a server
  - `versionId`: Unique ID for this specific version (renamed from `id`)

### 🔧 API Endpoint Updates
- **New endpoint structure**: Changed from version-ID-based to
server-ID-based URLs:
  - `GET /v0/servers/{server_id}` - Get latest version of server
  - `GET /v0/servers/{server_id}?version=X.X.X` - Get specific version  
- `GET /v0/servers/{server_id}/versions` - List all versions of a server
  - `PUT /v0/servers/{server_id}?version=X.X.X` - Edit specific version
- **Consistent URL patterns**: All server endpoints now use `server_id`
as the primary identifier
 
### Database Migration Strategy
The migration (`005_add_server_id_rename_version_id.sql`):
1. Adds new `version_id` column  
2. Generates deterministic UUIDs for servers with the same name
3. Updates JSON metadata to add `serverId` and rename `id` to
`versionId`
4. Copies existing `id` values to `version_id` column
5. Drops old `id` column and makes `version_id` the new primary key

## Testing

Besides of course automated tests passing, I:
1. Set up my local db with the pre-005-migration state, imported all the
production data
2. Ran the migration
3. Spot checked some diffs of the data that resulted --

```json
// before
{
  "name": "io.github.ruvnet/ruv-swarm",
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "id": "0a9cda7f-2b73-4839-844b-6582f335de42",
      "is_latest": false,
      "updated_at": "2025-09-10T17:21:34.92137012Z",
      "published_at": "2025-09-10T17:15:32.69690433Z"
    }
  },
  "version": "1.0.18",
  "repository": {
    "url": "",
    "source": ""
  },
  "description": "Neural network swarm orchestration with WebAssembly acceleration and MCP integration"
}

// after
{
  "name": "io.github.ruvnet/ruv-swarm",
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "serverId": "e8538952-96af-4a33-9e31-7fbed012521e",
      "is_latest": false,
      "versionId": "0a9cda7f-2b73-4839-844b-6582f335de42",
      "updated_at": "2025-09-10T17:21:34.92137012Z",
      "published_at": "2025-09-10T17:15:32.69690433Z"
    }
  },
  "version": "1.0.18",
  "repository": {
    "url": "",
    "source": ""
  },
  "description": "Neural network swarm orchestration with WebAssembly acceleration and MCP integration"
}

```

Servers that have multiple versions stayed consistent in their
`serverId`:

```json
// First version
{
  "name": "app.getdialer/dialer",
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "serverId": "80f08bdb-f3e4-4f19-b072-1676ae49b663",
      "is_latest": false,
      "versionId": "04f25b17-331d-48d7-b08b-37baece208a7",
      "updated_at": "2025-09-09T00:16:49.162620072Z",
      "published_at": "2025-09-08T23:47:09.452137971Z"
    }
  },
  "status": "active",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
  "remotes": [
    {
      "url": "https://getdialer.app/mcp",
      "type": "streamable-http"
    },
    {
      "url": "https://getdialer.app/sse",
      "type": "sse"
    }
  ],
  "version": "1.0.0",
  "repository": {
    "url": "",
    "source": ""
  },
  "description": "An MCP server that provides your you make outbound phone calls using your own phone number"
}

// Second version
{
  "name": "app.getdialer/dialer",
  "_meta": {
    "io.modelcontextprotocol.registry/official": {
      "serverId": "80f08bdb-f3e4-4f19-b072-1676ae49b663",
      "is_latest": true,
      "versionId": "faa26cb9-3aad-415e-aece-f715fff5fe5e",
      "updated_at": "2025-09-09T00:16:49.107842808Z",
      "published_at": "2025-09-09T00:16:49.107842808Z"
    }
  },
  "status": "active",
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
  "remotes": [
    {
      "url": "https://getdialer.app/mcp",
      "type": "streamable-http"
    },
    {
      "url": "https://getdialer.app/sse",
      "type": "sse"
    }
  ],
  "version": "1.0.1",
  "repository": {
    "url": "",
    "source": ""
  },
  "description": "An MCP server that provides lets you make outbound phone calls using your own phone number"
}
```

And I also tried publishing a test server anew; looked good:

```bash
⏺ Bash(curl -s "http://localhost:8080/v0/servers/102dc4e4-6ca8-40e6-aa11-cd45763d3352" | jq '.')
  ⎿  {                                                                                             
       "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
       "name": "io.modelcontextprotocol.anonymous/test-claude-migration-server",
       "description": "A test server to verify the new migration and API endpoints work correctly",
       "status": "active",
       "repository": {
         "url": "https://github.com/example/test-claude-migration-server",
         "source": "github",
         "id": "example/test-claude-migration-server"
       },
       "version": "1.0.0",
       "_meta": {
         "io.modelcontextprotocol.registry/official": {
           "serverId": "102dc4e4-6ca8-40e6-aa11-cd45763d3352",
           "versionId": "48c9cd55-7bc4-4ac2-896e-59e81eb653e4",
           "published_at": "2025-09-12T18:33:23.264203-07:00",
           "updated_at": "2025-09-12T18:33:23.264203-07:00",
           "is_latest": true
         }
       }
     }

⏺ Bash(curl -s "http://localhost:8080/v0/servers/102dc4e4-6ca8-40e6-aa11-cd45763d3352/versions" | jq '.')
  ⎿  {                                                                                                 
       "servers": [
         {
           "$schema": "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json",
           "name": "io.modelcontextprotocol.anonymous/test-claude-migration-server",
           "description": "A test server to verify the new migration and API endpoints work correctly",
           "status": "active",
           "repository": {
             "url": "https://github.com/example/test-claude-migration-server",
             "source": "github",
             "id": "example/test-claude-migration-server"
           },
           "version": "1.0.0",
           "_meta": {
             "io.modelcontextprotocol.registry/official": {
               "serverId": "102dc4e4-6ca8-40e6-aa11-cd45763d3352",
               "versionId": "48c9cd55-7bc4-4ac2-896e-59e81eb653e4",
               "published_at": "2025-09-12T18:33:23.264203-07:00",
               "updated_at": "2025-09-12T18:33:23.264203-07:00",
               "is_latest": true
             }
           }
         }
       ],
       "metadata": {
         "count": 1
       }
     }
```

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Preeti Dewani <preetidewani1990@gmail.com>
Co-authored-by: adam jones <adamj+git@anthropic.com>
Co-authored-by: Adam Jones <adamj@anthropic.com>
2025-09-21 15:00:09 +03:00
Gaurav Gosain
2280e4da38
Add GitHub Container Registry (GHCR) support for MCP servers (#439)
This commit implements support for publishing MCP servers to GitHub
Container
Registry (ghcr.io) in addition to the existing Docker Hub support,
addressing
Docker Hub rate limiting concerns as requested in #393.

Key changes:
- Add RegistryURLGHCR constant for https://ghcr.io
- Refactor OCI validation to support multiple container registries with
extensible RegistryConfig system
- Implement registry-agnostic authentication system that handles:
  - Docker Hub token-based authentication via auth.docker.io
  - GHCR token-based authentication via ghcr.io/token service
- Update Accept headers to support OCI image indexes for multi-arch
images
- Extract helper functions to reduce cyclomatic complexity and improve
code maintainability
- Add comprehensive test coverage for both Docker Hub and GHCR scenarios
- Include real image testing with github/github-mcp-server and
nkapila6/mcp-local-rag
- Update publishing documentation with GHCR examples and authentication
details

The implementation maintains backward compatibility with existing Docker
Hub
usage while providing a future-proof architecture for adding additional
container registries. All authentication is now handled through proper
token
services for both registries.

Fixes #393

## Motivation and Context
Docker Hub rate limiting has been causing issues for the MCP registry
when validating OCI images. Adding GHCR support provides an alternative
container registry that many MCP server authors are already using,
reducing the load on Docker Hub and providing more options for the
community.

## How Has This Been Tested?
- All existing unit tests continue to pass
- Added comprehensive test coverage for GHCR scenarios including:
  - Non-existent images (proper error handling)
  - Real images without MCP annotations (github/github-mcp-server)  
  - Real images with proper MCP annotations (nkapila6/mcp-local-rag)
  - Registry URL validation for both supported registries
- Tested authentication flow manually using curl commands
- Verified multi-arch image support with OCI index manifests

## Breaking Changes
None. This is a purely additive change that maintains full backward
compatibility with existing Docker Hub configurations.

## Types of changes
- [x] New feature (non-breaking change which adds functionality)
- [x] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed

## Additional context
The implementation uses a RegistryConfig struct to abstract
registry-specific details like API endpoints, authentication URLs, and
token services. This design makes it straightforward to add support for
additional container registries in the future (such as AWS ECR, Azure
Container Registry, etc.) by simply adding new cases to the
getRegistryConfig function.

The authentication system properly handles the different token services
used by each registry:
- Docker Hub: auth.docker.io with service=registry.docker.io
- GHCR: ghcr.io/token with service=ghcr.io

Both registries now support the full OCI specification including
multi-arch images via OCI image indexes.
2025-09-17 11:56:52 -07:00
adam jones
f975e68cf2
Clean up schema by simplifying version structure (#379)
## Summary

Simplified the schema structure by:
- Replacing `version_detail.version` with direct `version` field  
- Removing unused `release_date` field from seed data
- Updating all API types, models, and tests to match new structure
- Maintaining backwards compatibility in API responses

This change makes the schema more intuitive and reduces nesting depth.
2025-09-08 14:32:59 -07:00
Kalle Bylin
0ffcd36047
Add optional subfolder field to Repository schema (#363)
Adds an optional `subfolder` field to the Repository object in
server.json schema to support MCP servers located within subdirectories
of monorepo structures.

## Motivation and Context

Addresses issue #360 .

The current MCP registry schema doesn't explicitly define how to
reference servers that are located within a subdirectory of a Git
repository (a "monorepo" structure). This is a common pattern (e.g.,
[microsoft/mcp](https://github.com/microsoft/mcp) &
[awslabs/mcp](https://github.com/awslabs/mcp).

## How Has This Been Tested?

- **Validator tests**: Added 6 new test cases covering valid subfolders
and security validation (path traversal, absolute paths, invalid
characters, etc.)
- **Schema validation**: All 11 examples in `examples.md` validate
successfully against both `server.schema.json` and
`registry-schema.json`
- **End-to-end validation**: Publisher tool (`mcp-publisher init`) works
correctly and generates valid templates without subfolder
- **Backward compatibility**: Existing server.json files without
subfolder continue to work unchanged

## Breaking Changes

**None.** This is a fully backward-compatible change:
- The `subfolder` field is optional (uses `omitempty` JSON tag)
- Existing server.json files work unchanged
- Publisher tools generate valid templates without subfolder by default
- All existing validation and schemas remain compatible

## Types of changes
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update

## Checklist
- [x] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [x] My code follows the repository's style guidelines
- [x] New and existing tests pass locally
- [x] I have added appropriate error handling
- [x] I have added or updated documentation as needed


### Implementation Details

**Schema Changes:**
- Added `subfolder` property to Repository definition in
`server.schema.json` and `openapi.yaml`
- Field is optional with description and example (`"src/everything"`)

**Go Model:**
- Added `Subfolder string` field to Repository struct with
`json:"subfolder,omitempty"` tag
- Maintains backward compatibility through omitempty behavior

**Security-Focused Validation:**
- Validates subfolder is a clean relative path (no leading `/`)
- Prevents path traversal attacks (no `..` sequences)
- Blocks malformed paths (no trailing `/`, empty segments, invalid
characters)
- Uses regex validation for allowed characters: `^[a-zA-Z0-9\-_./]+$`

**Documentation:**
- Added monorepo example to `examples.md` demonstrating subfolder usage
- Updated `repository_references.md` with concise subfolder
documentation
- Maintained consistency across all documentation with same example path

**Testing:**
- 6 new integration tests in validator covering security and format
validation
- Updated example count validation tool for new example
- All existing tests continue to pass

### Design Decisions

1. **Optional by design**: Most servers don't need subfolder
(single-repo pattern is common)
2. **Clean separation**: Repository URL stays clean, subfolder is
separate metadata
3. **Security first**: Comprehensive validation prevents common
path-based attacks
4. **Publisher tool unchanged**: Default templates don't include
subfolder to avoid confusion for typical use cases

This enables publishers with monorepo structures to clearly specify
server locations while maintaining simplicity for the common
single-repository case.
2025-09-05 21:29:09 +01:00
Radoslav Dimitrov
e0e51eae37
Reflect the latest registry changes in openapi.yaml (#345)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR:
* Adds a new `transport` type used in Package and Remotes
* Added `docker` to the `runtime_hint` examples
* Added support for templated URLs. It is available for streamable-http
and sse transports for Packages. I didn't thought of reasons to have
this for Remotes, but we can enable it if needed.
* Added validation for templated URLs so we can ensure all referenced
placeholder variables are available.
* For streamable-http and SSE transport types the URL is now a required
property
* Updated the publisher init command to reflect these changes
* Updated the seed.json file
* Added unit tests for the transport type related changes
* Updated the server.json schema and the external pkg structs to reflect
the new transport type
* Updated the examples

Thanks to @kkkarthik for spotting it! 🙏 

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
Ran the tests locally

## Breaking Changes
<!-- Will users need to update their code or configurations? -->
Yes

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-09-05 21:07:08 +01:00
adam jones
694a4d8879
Add registry validators (#350)
Fixes #96

## Motivation and Context

See #96

## How Has This Been Tested?

Has some unit and integration tests, still needs proper testing of the
different registry types

## Breaking Changes

Yes, new package uploads will need extra verification

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [x] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
2025-09-04 22:45:59 +01:00
Radoslav Dimitrov
0c4a9035bc
Add transport type property to Packages (#340)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR:
* Adds the Transport Type property to Packages. _Even though most
packaged MCP servers are stdio this is not always the case so it's nice
to have the option to specify this for clients._
* Adds a constant for the "stdio" type
* Renames the "streamable" one to "streamable-http" (matching better how
the spec refers to it)
* Updates the seed.file to reflect these changes

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
Locally
## Breaking Changes
<!-- Will users need to update their code or configurations? -->
No
## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

This was discussed in
https://github.com/modelcontextprotocol/registry/discussions/200

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-09-02 14:58:19 +01:00
adam jones
9d9a02c57f
Database implementation cleanup (#335)
## Motivation and Context

The database logic was getting a bit unwieldy and fragile - especially
because business logic that should really have lived at the registry
service level was being pushed into the persistence level.

This PR tightens the interface, simplifies the code there, as well as
rips out a bunch of mocks etc. we don't need.

## How Has This Been Tested?

Locally everything works

## Breaking Changes

The list endpoint was surprisingly always filtering for isLatest only,
which seems like a bug? I have removed this filter.
2025-09-02 13:37:28 +01:00
adam jones
218b0b422d
Implement flattened _meta format for server extensions (#331)
## Summary

This PR implements the flattened `_meta` format for server extensions as
discussed in #284, replacing the confusing wrapper format with a clean
single-file approach.

**Before (wrapper format):**
```json
{
  "server": { "name": "my-server", "description": "..." },
  "x-publisher": { "build_info": "..." },
  "x-io.modelcontextprotocol.registry": { "id": "...", "published_at": "..." }
}
```

**After (flattened format):**
```json
{
  "name": "my-server",
  "description": "...",
  "_meta": {
    "publisher": { "build_info": "..." },
    "io.modelcontextprotocol.registry": { "id": "...", "published_at": "..." }
  }
}
```

## Key Changes

- **Flattened Format**: Single `ServerJSON` file with structured `_meta`
field
- **Better DX**: Publishers maintain one file instead of separate
server.json + extensions.json
- **MCP Compliance**: Uses standard `_meta` mechanism instead of `x-*`
prefixes
- **Simplified Database**: PostgreSQL now uses simple `id, value` table
structure
- **Type Safety**: Structured `ServerMeta` with known extension fields

## Database Migration

Added migration `003_simplify_to_key_value.sql` that drops the complex
relational structure and creates a simple key-value table. This
significantly simplifies database management.

## Testing

- All core tests passing (validators, service layer)
- Schema validation working for all 10 examples
- Seed data successfully migrated (396 entries)
- Publishing functionality verified

Fixes #284
2025-09-01 19:27:23 +01:00
Radoslav Dimitrov
2a2bbfed84
Use constants instead of hardcoded strings (#330)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR updates some of the hardcoded references to public
constants.


## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
Locally
## Breaking Changes
<!-- Will users need to update their code or configurations? -->
No

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-09-01 16:51:14 +01:00
adam jones
e0aecadc24
refactor: update registry type from 'docker-hub' to 'oci' across seed data (#325)
Updates the registry type for all Docker Hub packages in the seed data
from `docker-hub` to `oci` to align with the standardized OCI registry
format. This change affects the `registry_type` field and simplifies the
`identifier` field by removing the full Docker Hub URL prefix.

Changes:
- Updated `registry_type` from `docker-hub` to `oci` for all Docker
packages
- Simplified `identifier` field to use just the repository name/path
instead of full URLs
- Maintained `registry_base_url` as `https://docker.io` for all entries

This refactoring improves consistency and aligns with OCI standards
while maintaining backward compatibility through the registry base URL.
2025-08-30 00:12:10 +01:00
Radoslav Dimitrov
12dc4c3b99
Remove leftover bson tags from the Go structs (#327)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->
The following PR removes the now obsolete bson tags (we moved away from
MongoDB).

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->
Locally

## Breaking Changes
<!-- Will users need to update their code or configurations? -->
No

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-08-30 00:09:39 +01:00
Radoslav Dimitrov
099a2d702e
Deduplicate server JSON structs between publisher and registry (#318)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
<!-- Why is this change needed? What problem does it solve? -->

The following PR eliminates duplicate struct definitions by migrating
the publisher tool to use canonical types from pkg/model, creating a
single source of truth across the codebase. The publisher tool
previously had its own copies of structs that were duplicated, ie.
ServerJSON, Package, Repository, VersionDetail, EnvironmentVariable,
RuntimeArgument and a few others which was not optimal


**Changes in the PR:**
- Refactored the structs to single canonical types located at pkg/model
- Refactor the implementation to use/build canonical structures directly
  - Remove all duplicate definitions (5 structs eliminated)
- Publisher now uses model.ServerJSON, model.Package, model.Repository,
etc.
- Renamed some of the structs to better reflect their use case, i.e.
ServerJSON instead of ServerDetail
- Fixes an issue where the Remote property was missing from the previous
publisher copy of the Server

**Benefits:**
  - Single source of truth - Schema changes in one place
  - Type safety - Compiler catches mismatches
  - Enhanced validation - Field constraints and bson tags
  - Zero breaking changes - Same CLI interface and JSON output
  - Future-proof - New canonical fields automatically available

Supersedes: #217 and #240

## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

Locally

## Breaking Changes
<!-- Will users need to update their code or configurations? -->
No

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->

---------

Signed-off-by: Radoslav Dimitrov <radoslav@stacklok.com>
2025-08-28 14:58:15 +01:00