Repository navigation
Decide & document server versioning approach for server.json #158
Description
Activity
- addedgo-live blockerThis issue is one we need to address prior to initial go-liveThis issue is one we need to address prior to initial go-liveproduct requirements workUpstream of development workUpstream of development work
on Jun 30, 2025 - added a commit that references this issue
on Jul 9, 2025 - added a commit that references this issue
on Aug 7, 2025 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 to1.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 doesv<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!).
Reacted by Joel Verhagen and Jonathan HefnerI 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+1example 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 (meaning1.33.0 == 1.33.0+1 == 1.33.0+foo. So the suffixing idea should perhaps use the prerelease label like your1.33.2-gke.1240000example` (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_latestdetermining 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.0is a higher version than2.0.0but 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.0is the latest but1.3.1is pushed (maybe a critical bug fix on1.3.1), is1.3.1really the latest? I think most people would answer no because new users should adopt2.1.0and only existing users on the1.xtrain should care about1.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.0until2.2.0-betaiterates to2.2.0. - Equivalence or rules around non-normalized versions, e.g. is
1.02.0valid and/or equivalent to1.2.0?
Said another way, we are losing these things by not having a versioning schema on the MCP registry.
- Proper sorting on numeric components, e.g.
Maybe something like this could work:
versionMUST be a string up to 255 characters- Server authors SHOULD use semantic versions
- Server authors SHOULD use versions aligned with the underlying packages
- 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-2is actually lower than1.0.0, so if you expect to need a1.0.0-2you should publish1.0.0-1) - 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. - 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.
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.versionin 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.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.
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?
- addedimplementation workShovel-ready to write codeShovel-ready to write codeand removedproduct requirements workUpstream of development workUpstream of development work
on Aug 21, 2025 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 supportcompareSemanticVersions(): Enhanced with prerelease handling per semver speccompareVersions(): 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_latestdetermination - 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
- added a commit that references this issue
on Aug 21, 2025 - added a commit that references this issue
on Aug 26, 2025 - added a commit that references this issue
on Sep 12, 2025
server.jsonhas aversion_detail.versionfield that is currently just defined as a string, with a rough expectation that it is some flavor of SemVer.@jonathanhefner raised:
@joelverhagen:
Me:
@jonathanhefner here:
I had said this would be a fast-follow to #153 but I think it merits its own discussion as an Issue first