feat: support Go modules as a package type#1321
Conversation
Adds "registryType": "go" so MCP servers distributed as go-install-able modules can be published. Ownership reuses the publisher's GitHub namespace: a server under io.github.<owner> must use a module path rooted at github.com/<owner>/... (compared case-insensitively, since GitHub owners are case-insensitive). Existence is verified against the Go module proxy (proxy.golang.org). Non-GitHub module paths are left for a follow-up. Closes modelcontextprotocol#1307
ea04153 to
f6fa124
Compare
|
This looks excellent, thanks for moving so fast on this. A few notes from a careful read, none of them blocking: Things I especially liked:
Small things worth considering, not blocking:
Thanks again, this is high-quality work and the design choice to anchor ownership in GitHub namespace authentication is exactly the right shape for v1. |
Closes #1307.
Adds
"registryType": "go"so MCP servers distributed asgo install-able modules can be published to the registry. Design discussed in #1307.Ownership reuses the publisher's GitHub namespace rather than inventing an
mcpName-style marker (which wouldn't be idiomatic in ago.mod). A Go module path is its source location, so a server published underio.github.<owner>must use a module path rooted atgithub.com/<owner>/.... The owner is compared case-insensitively (GitHub owners are case-insensitive). Since the publisher already authenticates for theio.github.<owner>namespace, matching the module owner proves ownership. Non-GitHub module paths are intentionally left for a follow-up (a sentinel-file/go.mod-directive check can be added later without changing this).Existence is verified against the Go module proxy (
https://proxy.golang.org) — the canonical source of truth, with no auth/rate-limit concerns. The module path and version are case-encoded per the goproxy protocol (uppercase →!+lowercase), and./..path elements are rejected so a crafted identifier can't escape the proxy path.Changes
pkg/model/constants.go:RegistryTypeGo+RegistryURLGoProxy.internal/validators/package.go: dispatchgotoValidateGo.internal/validators/registries/go.go:ValidateGo+ValidateGoModuleOwnership+ module-proxy existence check +EscapeGoModulePath.internal/validators/registries/go_test.go: ownership matrix (incl. case-insensitivity and mismatch), path-escaping/traversal, andValidateGoguard errors — all deterministic, no network.docs/.../package-types.mdx: Go section.Example
{ "registryType": "go", "identifier": "github.com/username/audit-mcp", "version": "v1.0.0" }go test ./internal/validators/...passes;gofmt/go vetclean. The existence path is exercised against the live proxy on a real publish; the unit tests cover the ownership and escaping logic without network. Happy to adjust theidentifiersemantics (module path vs.go installsub-path) if you'd prefer a different convention.