From a100367461eeca87537cfb26a8c1f7e0ce3bcfab Mon Sep 17 00:00:00 2001 From: adam jones Date: Thu, 11 Sep 2025 09:34:57 -0700 Subject: [PATCH] Fix NPM package validation for scoped packages (#429) ## Summary - Add URL encoding for package identifiers and versions in NPM registry requests - Fixes issue where scoped packages like @hellocoop/admin-mcp failed validation due to unencoded @ and / symbols - Add unit tests for scoped NPM packages to prevent regression Fixes #409 Co-authored-by: Radoslav Dimitrov --- internal/validators/registries/npm.go | 5 +++-- internal/validators/registries/npm_test.go | 23 ++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/internal/validators/registries/npm.go b/internal/validators/registries/npm.go index db372db..0cff56d 100644 --- a/internal/validators/registries/npm.go +++ b/internal/validators/registries/npm.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "net/http" + "net/url" "time" "github.com/modelcontextprotocol/registry/pkg/model" @@ -42,8 +43,8 @@ func ValidateNPM(ctx context.Context, pkg model.Package, serverName string) erro client := &http.Client{Timeout: 10 * time.Second} - url := pkg.RegistryBaseURL + "/" + pkg.Identifier + "/" + pkg.Version - req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + requestURL := pkg.RegistryBaseURL + "/" + url.PathEscape(pkg.Identifier) + "/" + url.PathEscape(pkg.Version) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil) if err != nil { return fmt.Errorf("failed to create request: %w", err) } diff --git a/internal/validators/registries/npm_test.go b/internal/validators/registries/npm_test.go index 6b32a84..f9bf7da 100644 --- a/internal/validators/registries/npm_test.go +++ b/internal/validators/registries/npm_test.go @@ -91,6 +91,29 @@ func TestValidateNPM_RealPackages(t *testing.T) { serverName: "io.github.domdomegg/airtable-mcp-server", expectError: false, }, + { + name: "scoped package that doesn't exist should fail", + packageName: "@nonexistent-scope/nonexistent-package", + version: "1.0.0", + serverName: "com.example/test", + expectError: true, + errorMessage: "not found", + }, + { + name: "scoped package without mcpName should fail", + packageName: "@types/node", + version: "20.0.0", + serverName: "com.example/test", + expectError: true, + errorMessage: "missing required 'mcpName' field", + }, + { + name: "scoped package with mcpName should pass", + packageName: "@hellocoop/admin-mcp", + version: "1.5.7", + serverName: "io.github.hellocoop/admin-mcp", + expectError: false, + }, } for _, tt := range tests {