Skip to content

Decide & document server versioning approach for server.json #158

Description

@tadasant

server.json has a version_detail.version field that is currently just defined as a string, with a rough expectation that it is some flavor of SemVer.

@jonathanhefner raised:

Is there any place that we specify the version number format? For example, would we support "1.0.0-alpha" => "1.0.0-beta"?

@joelverhagen:

I had assumed SemVer, but this is a nuanced problem. I imagine folks will want to use the same version string as the underlying package for simplicity. And there is no guarantee of a unified version model for N package ecosystems. For example NuGet is SemVer-ish with case insensitive and a 4th version digit supported.

Perhaps complaint SemVer 2.0.0 for MCP Registry, and build metadata rejected? (1.0.0-alpha but not 1.0.0-alpha+foo which SemVer 2.0.0 supports but adds complexity).

Me:

I think it is actually unlikely that folks will want to bind the MCP server version with their package version. There may be cases where the MCP server version gets incremented even though the code doesn't change (for example, in the case of me deciding to update the description. It would be limiting myself to require that I make a code change to make that MCP server-level metadata change.

@jonathanhefner here:

Actually, from the end user's perspective, I think it would be preferable to allow any format. I think the core issue is how the registry tracks version history.

The FAQ says version numbers should be "bumped" or "incremented", which, obviously, requires version numbers to have an ordering scheme. However, since the registry only tracks which version is "latest" (i.e. doesn't support branching), we could just base "latest" off of the submission date, and change the version number requirement to "unique" instead of "incremented". But perhaps the intention was to leave the door open to support branching in the future?

I had said this would be a fast-follow to #153 but I think it merits its own discussion as an Issue first

Activity

  1. domdomegg commented on Aug 20, 2025

    @domdomegg
    Member

    I think I probably support @.jonathanhefner's view, that we should allow any format (perhaps setting some reasonable cap on string length e.g. no more than 255 chars, which matches npm and ruby gems limits)

    I think it is actually unlikely that folks will want to bind the MCP server version with their package version. There may be cases where the MCP server version gets incremented even though the code doesn't change (for example, in the case of me deciding to update the description. It would be limiting myself to require that I make a code change to make that MCP server-level metadata change.

    I actually think as a package maintainer I'd really want to keep the version in lockstep with the underlying package version, to avoid making things confusing with many different version specifiers. E.g. so people raise bugs with a version number, I have much less overhead of figuring out what that means.

    What I'd probably do if I also want releases separate to the package, I'd add an extra version specifier. E.g. if the NPM package is 1.2.3, I'd set the registry version to 1.2.3-1 (I think unlikely in reality - tbh if I was updating the description in the MCP registry I'd probably be updating the description on NPM which would require a version bump). This is what most cloud vendors do for their Kubernetes versions, which seems to work well. (examples: GKE does <k8s version>-gke.<gke version> e.g. 1.33.2-gke.1240000, VKE does v<k8s version>+<VKE version>, e.g. v1.33.0+1)

    I think having a registry version and package version being different will be confusing and I think causes a lot of confusion in the Helm chart land where this is the norm. (But of course if we leave it a string people can do what works for them!).

  2. joelverhagen commented on Aug 20, 2025

    @joelverhagen
    Contributor

    I agree that matching the version will be the most likely pattern for authors. I am imagining many folks will set up a GitHub Actions pipeline that publishes both the npm/Python/NuGet/Docker package and then later publishes to the community MCP registry, all with a build version generated in the pipeline.

    Note that the v1.33.0+1 example look like a SemVer stable version with build metadata (the stuff after the +) which per spec must not be used for determining precedence, i.e. it's not part of the version identity:
    https://semver.org/#spec-item-10
    This is in the weeds a bit, but at least NuGet interprets this like in the SemVer spec to mean that it's not used for comparison at all (meaning 1.33.0 == 1.33.0+1 == 1.33.0+foo. So the suffixing idea should perhaps use the prerelease label like your 1.33.2-gke.1240000 example` (hyphen separator instead of plus). I think this only matters if we are providing guidance -- IMO we should align with SemVer for guidance ("MAY") but still use the full string for uniqueness.

    BTW if we are only using submission date for the is_latest determining and not version string ordering, this means that UX around version listing will similarly need to use submission data to order the list. This is probably fine but it should probably be called out in the docs so new integrators know about it as soon as possible when they're understanding the data/endpoints.

    Things that a version schema provides a package manager:

    • Proper sorting on numeric components, e.g. 10.0.0 is a higher version than 2.0.0 but the lex order is different. The same extends to numeric components of the prerelease label (1.0.0-beta.2 < 1.0.0-beta.10`) per SemVer.
    • Clarity on "servicing" trains. When 2.1.0 is the latest but 1.3.1 is pushed (maybe a critical bug fix on 1.3.1), is 1.3.1 really the latest? I think most people would answer no because new users should adopt 2.1.0 and only existing users on the 1.x train should care about 1.3.1. But it will appear at the top of our chrono sorted list.
    • SemVer semantics of prerelease. Some organizations have policies or recommendations around consumption of prerelease software, meaning they stick to 2.1.0 until 2.2.0-beta iterates to 2.2.0.
    • Equivalence or rules around non-normalized versions, e.g. is 1.02.0 valid and/or equivalent to 1.2.0?

    Said another way, we are losing these things by not having a versioning schema on the MCP registry.

  3. domdomegg commented on Aug 20, 2025

    @domdomegg
    Member

    Maybe something like this could work:

    1. version MUST be a string up to 255 characters
    2. Server authors SHOULD use semantic versions
    3. Server authors SHOULD use versions aligned with the underlying packages
    4. If server authors expect to have multiple registry versions for the same package registry, they SHOULD follow the semantic version spec using the prerelease label (note that as per the semver spec 1.0.0-2 is actually lower than 1.0.0, so if you expect to need a 1.0.0-2 you should publish 1.0.0-1)
    5. The official registry will try to parse versions as a semantic version. if this succeeds, it will use the semantic versioning spec to determine if it is is_latest. if this fails, we will always mark it as latest.
    6. Registry clients SHOULD attempt to interpret versions as semantic versions. When ordering versions: if both are valid semver, use semver comparison; if neither are valid semver, use publish timestamp; if one is semver and one is not, the semver version is always considered higher.

    Possibly 3 and 4 could be softened to MAY, but I don't think this makes much difference.

    Note that 'version being an arbitrary string, with best efforts approach to semver' is I think what many registries do, e.g. this is what NPM, Maven, RubyGems, Docker do. Although there are some registries which do enforce some versioning schema strictly e.g. NuGet, Rust crates.io, PyPI.

  4. tadasant commented on Aug 21, 2025

    @tadasant
    MemberAuthor

    I think I'm ok with the SHOULD-driven approach that falls back to allowing anything.

    Of note: whatever decision we make here should align closely with a proposed change to Implementation.version in the spec. i.e. if we introduce SHOULD language, I think we'll eventually want to propose a SEP to bring the spec into alignment as well. And for backwards compatibility reasons, I think there will be a preference to not make that a MUST.

  5. rdimitrov commented on Aug 21, 2025

    @rdimitrov
    Member

    Another thing to consider is by design server.json allows for a list of packages and remotes all related to the same server. In the context of versioning, this means that having the same version is possible when you have 1 server <-> 1 package/remote, but it gets less likely to happen if you have 1 server <-> Many packages/remotes.

  6. domdomegg commented on Aug 21, 2025

    @domdomegg
    Member

    Great, seems like it sounds like we are aligned? Going to move this to implementation ready.

    @claude are you able to take a stab at this?

  7. claude commented on Aug 21, 2025

    @claude
    Contributor

    Claude finished @domdomegg's task —— View job • claude/issue-158-20250821-2216 • Create PR ➔


    I have successfully implemented the server versioning approach based on the discussion consensus.

    Task List

    • Analyze current codebase structure and versioning implementation
    • Locate relevant schema and documentation files
    • Implement the agreed-upon versioning approach from the discussion
    • Update documentation with the new versioning guidelines
    • Test the implementation
    • Create pull request

    Summary of Implementation

    🎯 Implemented the flexible versioning approach from @domdomegg's proposal:

    1. New Versioning Guide (docs/versioning.md)

    Comprehensive documentation covering:

    • Overview of the flexible versioning approach
    • Best practices and recommendations
    • Version ordering and "latest" determination
    • Client implementation guidance
    • Examples and migration path

    2. Enhanced JSON Schema (docs/server-json/schema.json)

    • Added 255-character limit constraint
    • Enhanced description with SHOULD guidance for semantic versioning
    • Clear documentation about non-semantic version limitations

    3. Updated FAQ (docs/faq.md)

    • Replaced "incremented version" language with "unique version string"
    • Added specific version format recommendations
    • Referenced the comprehensive versioning guide

    4. Robust Version Comparison Logic (internal/database/memory.go)

    • isSemanticVersion(): Proper semantic version detection with prerelease support
    • compareSemanticVersions(): Enhanced with prerelease handling per semver spec
    • compareVersions(): Implements the agreed strategy:
      • Both semver → use semantic comparison
      • Neither semver → use timestamp comparison
      • Mixed → semver always wins
    • Updated publish logic: Uses new comparison strategy for is_latest determination
    • Validation: Added 255-character limit enforcement

    ✅ Key Features Delivered

    • Flexible: Accepts any string up to 255 characters
    • Best Practice Encouraged: Semantic versioning with proper parsing/comparison
    • Fallback Strategy: Timestamp-based ordering for non-semantic versions
    • Mixed Version Support: Semantic versions take precedence over non-semantic
    • Backward Compatible: Existing non-semantic versions continue working
    • Future-Proof: Aligns with potential MCP specification changes

    🧪 Testing Results

    • ✅ All unit tests pass (97.7% coverage maintained)
    • ✅ Schema validation passes for all examples
    • ✅ Code formatting clean
  8. self-assigned this
    on Aug 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions