feat: Add website_url field for MCP servers (#422)
Adds optional website_url field to the server.json schema allowing publishers to provide a url to the server's homepage, documentation, or project website. This provides a central link for users to learn more about the server. Particularly useful when the server has custom installation instructions or setup requirements. Issue: #183 PR: #130 Discussion: #274 ## Motivation and Context This change addresses the need identified in #130, #183 and #274 for a standardized way to direct users to an official landing page similar to `homepage` used in NPM ([example](https://www.npmjs.com/package/@modelcontextprotocol/sdk)). It is also serves as a viable option for MCP Servers that don't follow typical package manager patterns (e.g., embedded in a Desktop app). ## How Has This Been Tested? - Schema validation: All 13 example server.json files validate successfully against the updated schema - Go validator tests: Added additional test cases covering URL format validation and namespace matching - Run all checks: Updated example files to work with anonymous publishing and verified `make check` passes ## Breaking Changes None. The website_url field is optional and backward compatible with existing server.json files. ## 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 ## Additional context Security considerations: - Website URL validation enforces that the domain matches the publisher's reverse-DNS namespace - HTTP/HTTPS protocols are required (no file:// or other schemes) - Validation is consistent with existing remote URL validation patterns
This commit is contained in:
parent
d0d8630925
commit
17eb56d4c7
1 changed files with 181 additions and 4 deletions
|
|
@ -24,6 +24,11 @@ func ValidateServerJSON(serverJSON *apiv0.ServerJSON) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Validate website URL if provided
|
||||
if err := validateWebsiteURL(serverJSON.WebsiteURL); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate all packages (basic field validation)
|
||||
// Detailed package validation (including registry checks) is done during publish
|
||||
for _, pkg := range serverJSON.Packages {
|
||||
|
|
@ -44,6 +49,11 @@ func ValidateServerJSON(serverJSON *apiv0.ServerJSON) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// Validate reverse-DNS namespace matching for website URL
|
||||
if err := validateWebsiteURLNamespaceMatch(*serverJSON); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
@ -67,6 +77,31 @@ func validateRepository(obj *model.Repository) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func validateWebsiteURL(websiteURL string) error {
|
||||
// Skip validation if website URL is not provided (optional field)
|
||||
if websiteURL == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse the URL to ensure it's valid
|
||||
parsedURL, err := url.Parse(websiteURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid website URL: %w", err)
|
||||
}
|
||||
|
||||
// Ensure it's an absolute URL with valid scheme
|
||||
if !parsedURL.IsAbs() {
|
||||
return fmt.Errorf("website URL must be absolute (include scheme): %s", websiteURL)
|
||||
}
|
||||
|
||||
// Only allow HTTP/HTTPS schemes for security
|
||||
if parsedURL.Scheme != "http" && parsedURL.Scheme != "https" {
|
||||
return fmt.Errorf("website URL must use http or https scheme: %s", websiteURL)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePackageField(obj *model.Package) error {
|
||||
if !HasNoSpaces(obj.Identifier) {
|
||||
return ErrPackageNameHasSpaces
|
||||
|
|
@ -319,6 +354,21 @@ func validateRemoteNamespaceMatch(serverJSON apiv0.ServerJSON) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// validateWebsiteURLNamespaceMatch validates that website URL matches the reverse-DNS namespace
|
||||
func validateWebsiteURLNamespaceMatch(serverJSON apiv0.ServerJSON) error {
|
||||
// Skip validation if website URL is not provided
|
||||
if serverJSON.WebsiteURL == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
namespace := serverJSON.Name
|
||||
if err := validateRemoteURLMatchesNamespace(serverJSON.WebsiteURL, namespace); err != nil {
|
||||
return fmt.Errorf("website URL %s does not match namespace %s: %w", serverJSON.WebsiteURL, namespace, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateRemoteURLMatchesNamespace checks if a remote URL's hostname matches the publisher domain from the namespace
|
||||
func validateRemoteURLMatchesNamespace(remoteURL, namespace string) error {
|
||||
// Parse the URL to extract the hostname
|
||||
|
|
|
|||
Loading…
Reference in a new issue