Skip to content

Conversation

ossamalafhel
Copy link
Contributor

@ossamalafhel ossamalafhel commented Sep 15, 2025

Summary

Following @domdomegg's suggestion in #476, this PR started as adding regex validation to the server name field but evolved based on extensive reviewer feedback into a comprehensive validation improvement.

Changes

Initial Implementation

  • Added pattern validation to the Name field in pkg/api/v0/types.go
  • Updated tests to expect HTTP 422 for validation errors

Based on Review Feedback

  • Removed regex from API annotations - Moved validation to handler code to maintain HTTP 400 status (more familiar than 422) as suggested by @joelverhagen
  • Updated regex pattern - Changed from ^[^/]+/[^/]+$ to the more specific ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$ to match the schema definition
  • Moved regex patterns to utils.go - Centralized all validation regexes in one place as suggested by @Avish34
  • Added error constants to constants.go - Created ErrInvalidNamespaceCharacters and ErrInvalidNameCharacters for consistent error messages
  • Improved error messages - Now provides clearer messages like "server name must match pattern..." instead of generic validation errors
  • Removed redundant validation - Eliminated unnecessary strings.Contains(name, "//") check that was already covered by slash count validation

Key Decisions

  • Chose handler validation over schema validation to maintain HTTP 400 status and provide better error messages
  • Kept case-sensitive validation allowing uppercase letters (discussion with @joelverhagen about potentially enforcing lowercase for future consideration)
  • Centralized validation logic following the existing codebase patterns

Context

This PR demonstrates the value of code review - what started as a simple regex addition evolved into a better implementation that:

  • Maintains backward compatibility with HTTP 400 status codes
  • Provides clearer, more actionable error messages
  • Follows the codebase's existing patterns for validation
  • Makes the code more maintainable by centralizing regex patterns and error messages

Related to #471
Builds on #476

Testing

  • All existing tests updated and passing
  • Added comprehensive test cases for the new validation pattern
  • Verified error messages are clear and helpful
  • Tested various edge cases discovered during review

Note: Special thanks to @joelverhagen, @Avish34, and @domdomegg for their thorough reviews that significantly improved this implementation.

ossamalafhel and others added 2 commits September 13, 2025 22:22
…otocol#471)

Added validation to reject server names with multiple slashes, ensuring
consistency between JSON schema pattern and API validation.

- Count slashes in parseServerName() and reject if > 1
- Add ErrMultipleSlashesInServerName error constant
- Add unit tests in validators_test.go
- Add integration test in publish_test.go
…e-validation-inconsistency

fix: validate server names to allow only single slash (modelcontextprotocol#471)
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch 16 times, most recently from c43df8e to aad4d4b Compare September 15, 2025 13:30
@ossamalafhel ossamalafhel changed the title feat: add regex validation to server name in API types feat: add regex validation to server name in API types (#398) Sep 15, 2025
@ossamalafhel ossamalafhel changed the title feat: add regex validation to server name in API types (#398) feat: add regex validation to server name in API types Sep 15, 2025
@ossamalafhel ossamalafhel changed the title feat: add regex validation to server name in API types feat: add regex validation to server name in API types (#471) Sep 15, 2025
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch from aad4d4b to 6a6e710 Compare September 15, 2025 14:25
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch 2 times, most recently from 8352aca to 6d19849 Compare September 15, 2025 14:57
// Validate namespace and name format according to schema
// Pattern: ^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$
namespacePattern := regexp.MustCompile(`^[a-zA-Z0-9.-]+$`)
namePattern := regexp.MustCompile(`^[a-zA-Z0-9._-]+$`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@domdomegg - are server names case sensitive? NuGet and PyPI treat package names as case insensitive at the API level but npm and Docker do not (last I checked). Personally, I recommend enforcing lowercase everywhere and being case sensitive. It is has caused headaches in NuGet and the roughly "domain name + path" pattern of server names is not unlike URLs which have a lowercase domain name (ubiquitous) and kebab case path portion (not ubiquitous but common in say GH repo names).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joelverhagen Good point! Currently the regex allows uppercase letters in both namespace and name parts.

I agree that enforcing lowercase would be beneficial for consistency, especially since:

  • The namespace part follows reverse DNS convention where domains are lowercase
  • It avoids confusion between Com.Example/server vs com.example/server
  • It aligns with web conventions

Should we update the regex to enforce lowercase in this PR or create a separate issue for it? If we do it here, we'd need to:

  1. Update the regex patterns to ^[a-z0-9.-]+/[a-z0-9._-]+$
  2. Update the error messages and documentation
  3. Add tests for uppercase rejection

What do you think @domdomegg?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Can we move the regex to utils.go? We have kept regex for the URLs there. It kind of make sense to have all regex used in validation at one place.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Avish34 Thanks for the review! Good suggestions:

  1. Moved regex patterns to utils.go alongside other validation regexes
  2. Added constant error messages in constants.go:
    • ErrInvalidNamespaceCharacters
    • ErrInvalidNameCharacters

This keeps all validation patterns centralized and error messages consistent. Changes implemented in the latest commit!

Add descriptive documentation to the Name field in ServerJSON struct
explaining the expected format 'reverse-dns-namespace/name' and
allowed characters for namespace and name parts.
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch 3 times, most recently from 67a0979 to 251c65a Compare September 15, 2025 15:27
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch from 251c65a to a6d5cb8 Compare September 15, 2025 16:35
…sages

- Add regex validation in parseServerName with specific error messages
- Validate namespace allows only alphanumeric, dots and hyphens
- Validate name allows only alphanumeric, dots, underscores and hyphens
- Update tests to expect descriptive error messages
- Add tests for invalid character validation
- Fix test server names to use valid format
- Move regex patterns to utils.go for centralization
- Add error constants to constants.go for consistency
- Remove redundant validation checks

Based on feedback from PR reviewers, this implementation:
- Maintains HTTP 400 status instead of 422 for better developer experience
- Provides clear, actionable error messages
- Follows existing codebase patterns for validation
- Centralizes validation logic for maintainability

Co-authored-by: Joel Verhagen <[email protected]>
Co-authored-by: Avish <[email protected]>
Co-authored-by: Adam Jones <[email protected]>
@ossamalafhel ossamalafhel force-pushed the fix/add-regex-validation-server-name branch from a6d5cb8 to bb64ce1 Compare September 15, 2025 20:44

// Prevent renaming servers
if currentServer.Name != input.Body.Name {
// Validate the new name format before rejecting the rename
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems unnecessary, if we're going to reject the request anyway?

}

// Check for multiple slashes - reject if found
slashCount := strings.Count(name, "/")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would already be caught by the parts split and patterns below? Ideally I want to keep this simple as it's hard to follow when there are quite so many rules - eliminating overlapping/duplicate ones is valuable. Possibly can all be merged into one fairly simple regex.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants