-
Notifications
You must be signed in to change notification settings - Fork 566
Deprecated, yanked and partial renaming support #893
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Deprecated, yanked and partial renaming support #893
Conversation
…check for publish permission for new server
|
Fixes #637 |
tadasant
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you @pree-dew for taking this on!
Added inline comments, and also: let's update docs/reference/cli/commands.md with notes on how to use the new CLI commands/options.
Some additional feedback by way of Claude (that I've picked out and agree with):
1. newName pointing to itself
There's no check preventing:
mcp-publisher status io.github.user/my-server --all-versions --status deprecated \
--new-name io.github.user/my-serverThe validateNewName function checks that the new server exists and user has permissions, but doesn't check if newName == currentServerName. This would create a self-referential deprecation.
2. --all-versions isn't atomic
Looking at updateAllVersionsStatus (lines 123-157):
for _, v := range versions {
if err := updateServerStatus(...); err != nil {
failureCount++
} else {
successCount++
}
}Each version is updated in a separate HTTP request. If one fails mid-way:
- Some versions are deprecated, others aren't
- No rollback mechanism
- The
newNamecould be set on some versions but not others
Can we make this happen in a transaction?
3. newName without --all-versions at API level
The CLI enforces --new-name requires --all-versions, but the API doesn't:
// In validateNewName - only checks status, not all-versions
if input.Status != string(model.StatusDeprecated) && input.Status != string(model.StatusYanked) {
return huma.Error400BadRequest("new_name can only be used with deprecated or yanked status")
}Someone hitting the API directly could set newName on a single version, leaving other versions without it. This creates inconsistent state.
| StatusActive Status = "active" | ||
| StatusDeprecated Status = "deprecated" | ||
| StatusDeleted Status = "deleted" | ||
| StatusYanked Status = "yanked" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I agree with the semantic reason for this change, I worry a bit about this being a breaking change. I think we don't currently have any data in the official registry using deleted, but I suspect a lot of downstream consumers do.
So by default, I'd be inclined to keep it deleted (knowing we really mean yanked), and maybe leave an issue as something we consider addressing for a bigger, breaking GA launch of the registry.
| Status model.Status `json:"status" enum:"active,deprecated,yanked" doc:"Server lifecycle status"` | ||
| StatusChangedAt time.Time `json:"statusChangedAt" format:"date-time" doc:"Timestamp when the server status was last changed"` | ||
| StatusMessage *string `json:"statusMessage,omitempty" doc:"Optional message explaining status change (e.g., deprecation reason, migration guidance)"` | ||
| AlternativeURL *string `json:"alternativeUrl,omitempty" format:"uri" doc:"Optional URL to alternative/replacement server for deprecated or yanked servers"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need AlternativeURL in addition to StatusMessage and NewName? It feels redundant to me, and if someone really wants a non-registry reference (which would be NewName), they could put the URL in the StatusMessage. Or is there compelling reason to have the structured AlternativeURL?
| // For now, only allow status changes for admins | ||
| // Future: Implement logic to allow server authors to change active <-> deprecated | ||
| // but only admins can set to deleted | ||
| // but only admins can set to yanked |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is now outdated; should delete
| Authorization string `header:"Authorization" doc:"Registry JWT token with edit permissions" required:"true"` | ||
| ServerName string `path:"serverName" doc:"URL-encoded server name" example:"com.example%2Fmy-server"` | ||
| Version string `path:"version" doc:"URL-encoded version to edit" example:"1.0.0"` | ||
| Status string `query:"status" doc:"New status for the server (active, deprecated, yanked)" required:"false" enum:"active,deprecated,yanked"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This endpoint design feels awkward to me. I know we had precedent here with status already, but I think overloading this shape with being responsible for both Body (core ServerJSON) changes as well as status & associated fields (statusmessage, newname)
Should we move status wrangling over to a dedicated PATCH endpoint?
To-date, status has only been an admin tool anyway, so I'm not worried about a breaking change in the API here.
| apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" | ||
| ) | ||
|
|
||
| func StatusCommand(args []string) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about calling this command status. It's also used for setting e.g. newName, which isn't necessarily associated with a status change. Can we make it more generic, like mcp-publisher update, mcp-publisher patch or something similar?
|
@tadasant Thank you for the review, I will address the points. Also wanted your feedback on these questions: Do we need bulk endpoint for status transitions, renaming for all servers? |
If I understand the question correctly, we'd want the ability to e.g. "deprecate all versions of server with name
Yes.
Ideally: it should show up on /servers?updated_since calls, but not by default on server details / server version history calls unless we provide some explicit query param that "unhides" them. |
Yes, for all versions of a server. Noted. I will accommodate recommended changes. |
Motivation and Context
Deprecation and yanking are standard requirements when it comes to manages servers(packages), many use cases like rebranding, security vulnerabilities in packages etc demand these kind of features.
How Has This Been Tested?
This has been tested via test cases and local setup
Breaking Changes
Types of changes
Checklist
Additional context