Problem
MCPPackage.RegistryBaseURL is exposed as a user-settable field in the v1alpha1 API, but the validators for NPM, NuGet, and PyPI all follow the same pattern:
- If the user leaves it empty, default it to the canonical registry URL
- If the user sets it to anything other than the canonical URL, reject the request
Example — pkg/api/v1alpha1/registries/npm.go:
```go
// Set default registry base URL if empty
if pkg.RegistryBaseURL == "" {
pkg.RegistryBaseURL = v1alpha1.RegistryURLNPM
}
// ...
// Validate that the registry base URL matches NPM exactly
if pkg.RegistryBaseURL != v1alpha1.RegistryURLNPM {
return fmt.Errorf("registry type and base URL do not match: '%s' is not valid for registry type '%s'. Expected: %s",
pkg.RegistryBaseURL, v1alpha1.RegistryTypeNPM, v1alpha1.RegistryURLNPM)
}
```
Same pattern in nuget.go:23,37 and pypi.go:30,48. Meanwhile oci.go and mcpb.go reject the field entirely.
So RegistryBaseURL is either:
- Empty (default applied internally)
- Set to exactly the canonical URL (pointless echo of the default)
Any other value is rejected. There is no override behavior.
Why it's a smell
A field on a user-facing API implies the user has a meaningful choice. RegistryBaseURL does not:
- If you want it to be an override (alternate NPM mirror, enterprise PyPI proxy, etc.) — then validation should accept alternate URLs, not reject them
- If you want it to be a discriminator — it's redundant with
RegistryType, which already tells us we're dealing with NPM/NuGet/PyPI
- If you want it internal-only — remove it from the user-facing spec and set it in the validator
Either way, the current shape is wrong. It looks configurable, documents itself as configurable (json:\"registryBaseUrl,omitempty\"), but the validator forces it to a single value.
Proposed fix
Pick one of:
- Remove from user API — the validator already knows the canonical URL per
RegistryType. Move RegistryBaseURL out of the public spec and set it internally.
- Make it a real override — remove the exact-match check and allow alternate URLs per registry type (with appropriate scheme/host validation). Useful for private registries and enterprise mirrors.
Option 1 is simpler. Option 2 enables enterprise use cases (pull-through proxies, private mirrors) but requires thinking through how to validate "this is a reasonable alternate URL for this registry type."
Surfaced while reviewing PR #449.
Problem
MCPPackage.RegistryBaseURLis exposed as a user-settable field in the v1alpha1 API, but the validators for NPM, NuGet, and PyPI all follow the same pattern:Example —
pkg/api/v1alpha1/registries/npm.go:```go
// Set default registry base URL if empty
if pkg.RegistryBaseURL == "" {
pkg.RegistryBaseURL = v1alpha1.RegistryURLNPM
}
// ...
// Validate that the registry base URL matches NPM exactly
if pkg.RegistryBaseURL != v1alpha1.RegistryURLNPM {
return fmt.Errorf("registry type and base URL do not match: '%s' is not valid for registry type '%s'. Expected: %s",
pkg.RegistryBaseURL, v1alpha1.RegistryTypeNPM, v1alpha1.RegistryURLNPM)
}
```
Same pattern in
nuget.go:23,37andpypi.go:30,48. Meanwhileoci.goandmcpb.goreject the field entirely.So
RegistryBaseURLis either:Any other value is rejected. There is no override behavior.
Why it's a smell
A field on a user-facing API implies the user has a meaningful choice.
RegistryBaseURLdoes not:RegistryType, which already tells us we're dealing with NPM/NuGet/PyPIEither way, the current shape is wrong. It looks configurable, documents itself as configurable (
json:\"registryBaseUrl,omitempty\"), but the validator forces it to a single value.Proposed fix
Pick one of:
RegistryType. MoveRegistryBaseURLout of the public spec and set it internally.Option 1 is simpler. Option 2 enables enterprise use cases (pull-through proxies, private mirrors) but requires thinking through how to validate "this is a reasonable alternate URL for this registry type."
Surfaced while reviewing PR #449.