## Motivation and Context - Add MCPB as a new registry_name option - Add file_hashes field to package model for integrity verification - Implement URL validation restricting MCPB packages to GitHub/GitLab hosts - Require SHA-256 hash for all MCPB packages - Add example MCPB package in documentation - Update schemas and OpenAPI specification See issue #260 ## How Has This Been Tested? <!-- Have you tested this in a real application? Which scenarios were tested? --> ## Breaking Changes N/A, registry has not yet been launched ## 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. --> - [x] 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 - [x] I have added or updated documentation as needed --------- Co-authored-by: Adam Jones <adamj+git@anthropic.com>
124 lines
3.2 KiB
Go
124 lines
3.2 KiB
Go
package validators
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/modelcontextprotocol/registry/internal/model"
|
|
)
|
|
|
|
// ServerValidator validates server details
|
|
type ServerValidator struct {
|
|
*RepositoryValidator // Embedded RepositoryValidator for repository validation
|
|
}
|
|
|
|
// Validate checks if the server details are valid
|
|
func (v *ServerValidator) Validate(obj *model.ServerDetail) error {
|
|
if err := v.RepositoryValidator.Validate(&obj.Repository); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewServerValidator creates a new ServerValidator instance
|
|
func NewServerValidator() *ServerValidator {
|
|
return &ServerValidator{
|
|
RepositoryValidator: NewRepositoryValidator(),
|
|
}
|
|
}
|
|
|
|
// RepositoryValidator validates repository details
|
|
type RepositoryValidator struct {
|
|
validSources map[RepositorySource]bool
|
|
}
|
|
|
|
// Validate checks if the repository details are valid
|
|
func (rv *RepositoryValidator) Validate(obj *model.Repository) error {
|
|
// Skip validation for empty repository (optional field)
|
|
if obj.URL == "" && obj.Source == "" {
|
|
return nil
|
|
}
|
|
|
|
// validate the repository source
|
|
repoSource := RepositorySource(obj.Source)
|
|
if !IsValidRepositoryURL(repoSource, obj.URL) {
|
|
return fmt.Errorf("%w: %s", ErrInvalidRepositoryURL, obj.URL)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NewRepositoryValidator creates a new RepositoryValidator instance
|
|
func NewRepositoryValidator() *RepositoryValidator {
|
|
return &RepositoryValidator{
|
|
validSources: map[RepositorySource]bool{SourceGitHub: true, SourceGitLab: true},
|
|
}
|
|
}
|
|
|
|
// PackageValidator validates package details
|
|
type PackageValidator struct{}
|
|
|
|
// Validate checks if the package details are valid
|
|
func (pv *PackageValidator) Validate(obj *model.Package) error {
|
|
if !HasNoSpaces(obj.Identifier) {
|
|
return ErrPackageNameHasSpaces
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// NewPackageValidator creates a new PackageValidator instance
|
|
func NewPackageValidator() *PackageValidator {
|
|
return &PackageValidator{}
|
|
}
|
|
|
|
// RemoteValidator validates remote connection details
|
|
type RemoteValidator struct{}
|
|
|
|
// Validate checks if the remote connection details are valid
|
|
func (rv *RemoteValidator) Validate(obj *model.Remote) error {
|
|
if !IsValidURL(obj.URL) {
|
|
return fmt.Errorf("%w: %s", ErrInvalidRemoteURL, obj.URL)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// NewRemoteValidator creates a new RemoteValidator instance
|
|
func NewRemoteValidator() *RemoteValidator {
|
|
return &RemoteValidator{}
|
|
}
|
|
|
|
// ObjectValidator aggregates multiple validators for different object types
|
|
// This allows for a single entry point to validate complex objects that may contain multiple fields
|
|
// that need validation.
|
|
type ObjectValidator struct {
|
|
ServerValidator *ServerValidator
|
|
PackageValidator *PackageValidator
|
|
RemoteValidator *RemoteValidator
|
|
}
|
|
|
|
func NewObjectValidator() *ObjectValidator {
|
|
return &ObjectValidator{
|
|
ServerValidator: NewServerValidator(),
|
|
PackageValidator: NewPackageValidator(),
|
|
RemoteValidator: NewRemoteValidator(),
|
|
}
|
|
}
|
|
|
|
func (ov *ObjectValidator) Validate(obj *model.ServerDetail) error {
|
|
if err := ov.ServerValidator.Validate(obj); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, pkg := range obj.Packages {
|
|
if err := ov.PackageValidator.Validate(&pkg); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for _, remote := range obj.Remotes {
|
|
if err := ov.RemoteValidator.Validate(&remote); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|