From e2e1ef7b20b1918e58c0bd054e07e41b6c8e7c4e Mon Sep 17 00:00:00 2001 From: stationeros Date: Sat, 25 Apr 2026 14:02:16 +0530 Subject: [PATCH 01/10] fix: ignore deprecated servers in remote URL conflict checks --- internal/service/registry_service.go | 14 ++- internal/service/registry_service_test.go | 136 ++++++++++++++++++++++ 2 files changed, 144 insertions(+), 6 deletions(-) diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index 05c4f168b..6a54b6950 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -176,8 +176,11 @@ func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, return fmt.Errorf("failed to check remote URL conflict: %w", err) } - // Check if any conflicting server has a different name + // Only active servers reserve remote URLs. for _, conflictingServer := range conflictingServers { + if conflictingServer.Meta.Official != nil && conflictingServer.Meta.Official.Status != model.StatusActive { + continue + } if conflictingServer.Server.Name != serverDetail.Name { return fmt.Errorf("remote URL %s is already used by server %s", remote.URL, conflictingServer.Server.Name) } @@ -269,10 +272,10 @@ func (s *registryServiceImpl) updateServerStatusInTransaction(ctx context.Contex return nil, err } - // When transitioning to active from deleted, validate remote URLs don't conflict + // When transitioning to active from a non-active status, validate remote URLs don't conflict. if statusChange.NewStatus == model.StatusActive && currentServer.Meta.Official != nil && - currentServer.Meta.Official.Status == model.StatusDeleted { + currentServer.Meta.Official.Status != model.StatusActive { if err := s.validateNoDuplicateRemoteURLs(ctx, tx, currentServer.Server); err != nil { return nil, err } @@ -297,11 +300,10 @@ func (s *registryServiceImpl) updateAllVersionsStatusInTransaction(ctx context.C return nil, err } - // When transitioning to active, validate remote URLs for any versions currently deleted + // When transitioning to active, validate remote URLs for any versions that are currently non-active. if statusChange.NewStatus == model.StatusActive { includeDeleted := true - // When transitioning to active, it means the current status is either deprecated or deleted, so it should include deleted server also filter := &database.ServerFilter{Name: &serverName, IncludeDeleted: &includeDeleted} versions, _, err := s.db.ListServers(ctx, tx, filter, "", 1000) if err != nil { @@ -310,7 +312,7 @@ func (s *registryServiceImpl) updateAllVersionsStatusInTransaction(ctx context.C for _, version := range versions { if version.Meta.Official != nil && - version.Meta.Official.Status == model.StatusDeleted { + version.Meta.Official.Status != model.StatusActive { if err := s.validateNoDuplicateRemoteURLs(ctx, tx, version.Server); err != nil { return nil, err } diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index 63b652127..66fc0aaf4 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -52,6 +52,22 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { require.NoError(t, err, "failed to create server: %v", err) } + deprecatedServer := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/deprecated-server", + Description: "A deprecated server", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, + }, + } + _, err := service.CreateServer(ctx, deprecatedServer) + require.NoError(t, err) + _, err = service.UpdateServerStatus(ctx, deprecatedServer.Name, deprecatedServer.Version, &StatusChangeRequest{ + NewStatus: model.StatusDeprecated, + }) + require.NoError(t, err) + tests := []struct { name string serverDetail apiv0.ServerJSON @@ -97,6 +113,19 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { expectError: true, errorMsg: "remote URL https://api.example.com/mcp is already used by server com.example/existing-server", }, + { + name: "duplicate remote URL used only by deprecated server - should pass", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/new-server-with-deprecated-conflict", + Description: "A new server reusing a deprecated remote URL", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, + }, + }, + expectError: false, + }, { name: "updating same server with same URLs - should pass", serverDetail: apiv0.ServerJSON{ @@ -889,6 +918,53 @@ func TestUpdateServerStatus_ValidateRemoteURLsOnRestoreFromDeleted(t *testing.T) assert.Contains(t, err.Error(), "already used by server") } +func TestUpdateServerStatus_ValidateRemoteURLsOnRestoreFromDeprecated(t *testing.T) { + ctx := context.Background() + testDB := database.NewTestDB(t) + service := NewRegistryService(testDB, &config.Config{EnableRegistryValidation: false}) + + remoteURL := "https://api.deprecated.com/mcp" + + // Create Server A with a remote URL and deprecate it. + serverA := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/deprecated-server", + Description: "Server to be deprecated", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: remoteURL}, + }, + } + _, err := service.CreateServer(ctx, serverA) + require.NoError(t, err) + + _, err = service.UpdateServerStatus(ctx, "com.example/deprecated-server", "1.0.0", &StatusChangeRequest{ + NewStatus: model.StatusDeprecated, + }) + require.NoError(t, err) + + // Create Server B with the same remote URL (should succeed since A is deprecated). + serverB := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/replacement-server", + Description: "Replacement server with same remote URL", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: remoteURL}, + }, + } + _, err = service.CreateServer(ctx, serverB) + require.NoError(t, err) + + // Try to restore deprecated server to active - should fail due to URL conflict. + _, err = service.UpdateServerStatus(ctx, "com.example/deprecated-server", "1.0.0", &StatusChangeRequest{ + NewStatus: model.StatusActive, + }) + assert.Error(t, err) + assert.Contains(t, err.Error(), "remote URL") + assert.Contains(t, err.Error(), "already used by server") +} + func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing.T) { ctx := context.Background() testDB := database.NewTestDB(t) @@ -949,6 +1025,66 @@ func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing. assert.Contains(t, err.Error(), "already used by server") } +func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreFromDeprecatedToActive(t *testing.T) { + ctx := context.Background() + testDB := database.NewTestDB(t) + service := NewRegistryService(testDB, &config.Config{EnableRegistryValidation: false}) + + remoteURL := "https://api.allversions-deprecated.com/mcp" + + // Create Server A with multiple versions. + serverAv1 := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/deprecated-multi-version-server", + Description: "Server A version 1", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: remoteURL}, + }, + } + _, err := service.CreateServer(ctx, serverAv1) + require.NoError(t, err) + + serverAv2 := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/deprecated-multi-version-server", + Description: "Server A version 2", + Version: "2.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: remoteURL}, + }, + } + _, err = service.CreateServer(ctx, serverAv2) + require.NoError(t, err) + + // Deprecate all versions of Server A. + _, err = service.UpdateAllVersionsStatus(ctx, "com.example/deprecated-multi-version-server", &StatusChangeRequest{ + NewStatus: model.StatusDeprecated, + }) + require.NoError(t, err) + + // Create Server B with the same remote URL (should succeed since A is deprecated). + serverB := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/active-conflicting-server", + Description: "Server B with same remote URL", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: remoteURL}, + }, + } + _, err = service.CreateServer(ctx, serverB) + require.NoError(t, err) + + // Try to restore all versions of Server A to active - should fail. + _, err = service.UpdateAllVersionsStatus(ctx, "com.example/deprecated-multi-version-server", &StatusChangeRequest{ + NewStatus: model.StatusActive, + }) + assert.Error(t, err) + assert.Contains(t, err.Error(), "remote URL") + assert.Contains(t, err.Error(), "already used by server") +} + func TestUpdateServerStatus_NoConflictWhenRestoringWithUniqueURLs(t *testing.T) { ctx := context.Background() testDB := database.NewTestDB(t) From 35f327c5899b6d3572aa6ff68bfc9004c8dec4e4 Mon Sep 17 00:00:00 2001 From: stationeros Date: Sat, 25 Apr 2026 16:41:40 +0530 Subject: [PATCH 02/10] fix: exclude deleted servers from remote URL conflict checks --- internal/service/registry_service.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index 6a54b6950..b2a08922a 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -164,12 +164,13 @@ func (s *registryServiceImpl) createServerInTransaction(ctx context.Context, tx return s.db.CreateServer(ctx, tx, &serverJSON, officialMeta) } -// validateNoDuplicateRemoteURLs checks that no other server is using the same remote URLs +// validateNoDuplicateRemoteURLs checks that no non-deleted server is using the same remote URLs func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, tx pgx.Tx, serverDetail apiv0.ServerJSON) error { // Check each remote URL in the new server for conflicts for _, remote := range serverDetail.Remotes { - // Use filter to find servers with this remote URL - filter := &database.ServerFilter{RemoteURL: &remote.URL} + // Use a filter that only returns non-deleted servers with this remote URL + includeDeleted := false + filter := &database.ServerFilter{RemoteURL: &remote.URL, IncludeDeleted: &includeDeleted} conflictingServers, _, err := s.db.ListServers(ctx, tx, filter, "", 1000) if err != nil { From 26efeaf7cc73019774dfebe573f2867f38f3452d Mon Sep 17 00:00:00 2001 From: stationeros Date: Sat, 25 Apr 2026 17:04:15 +0530 Subject: [PATCH 03/10] fix: treat only deleted servers as reusable for remote URL validation --- internal/service/registry_service.go | 14 +-- internal/service/registry_service_test.go | 141 +++++----------------- 2 files changed, 39 insertions(+), 116 deletions(-) diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index b2a08922a..de71527c1 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -177,11 +177,8 @@ func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, return fmt.Errorf("failed to check remote URL conflict: %w", err) } - // Only active servers reserve remote URLs. + // Check if any conflicting server has a different name for _, conflictingServer := range conflictingServers { - if conflictingServer.Meta.Official != nil && conflictingServer.Meta.Official.Status != model.StatusActive { - continue - } if conflictingServer.Server.Name != serverDetail.Name { return fmt.Errorf("remote URL %s is already used by server %s", remote.URL, conflictingServer.Server.Name) } @@ -273,10 +270,10 @@ func (s *registryServiceImpl) updateServerStatusInTransaction(ctx context.Contex return nil, err } - // When transitioning to active from a non-active status, validate remote URLs don't conflict. + // When transitioning to active from deleted, validate remote URLs don't conflict if statusChange.NewStatus == model.StatusActive && currentServer.Meta.Official != nil && - currentServer.Meta.Official.Status != model.StatusActive { + currentServer.Meta.Official.Status == model.StatusDeleted { if err := s.validateNoDuplicateRemoteURLs(ctx, tx, currentServer.Server); err != nil { return nil, err } @@ -301,10 +298,11 @@ func (s *registryServiceImpl) updateAllVersionsStatusInTransaction(ctx context.C return nil, err } - // When transitioning to active, validate remote URLs for any versions that are currently non-active. + // When transitioning to active, validate remote URLs for any versions currently deleted if statusChange.NewStatus == model.StatusActive { includeDeleted := true + // When transitioning to active, it means the current status is either deprecated or deleted, so it should include deleted server also filter := &database.ServerFilter{Name: &serverName, IncludeDeleted: &includeDeleted} versions, _, err := s.db.ListServers(ctx, tx, filter, "", 1000) if err != nil { @@ -313,7 +311,7 @@ func (s *registryServiceImpl) updateAllVersionsStatusInTransaction(ctx context.C for _, version := range versions { if version.Meta.Official != nil && - version.Meta.Official.Status != model.StatusActive { + version.Meta.Official.Status == model.StatusDeleted { if err := s.validateNoDuplicateRemoteURLs(ctx, tx, version.Server); err != nil { return nil, err } diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index 66fc0aaf4..c34e6a850 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -52,6 +52,22 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { require.NoError(t, err, "failed to create server: %v", err) } + deletedServer := &apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/deleted-server", + Description: "A deleted server", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deleted.example.com/mcp"}, + }, + } + _, err := service.CreateServer(ctx, deletedServer) + require.NoError(t, err) + _, err = service.UpdateServerStatus(ctx, deletedServer.Name, deletedServer.Version, &StatusChangeRequest{ + NewStatus: model.StatusDeleted, + }) + require.NoError(t, err) + deprecatedServer := &apiv0.ServerJSON{ Schema: model.CurrentSchemaURL, Name: "com.example/deprecated-server", @@ -61,7 +77,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, }, } - _, err := service.CreateServer(ctx, deprecatedServer) + _, err = service.CreateServer(ctx, deprecatedServer) require.NoError(t, err) _, err = service.UpdateServerStatus(ctx, deprecatedServer.Name, deprecatedServer.Version, &StatusChangeRequest{ NewStatus: model.StatusDeprecated, @@ -114,7 +130,20 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { errorMsg: "remote URL https://api.example.com/mcp is already used by server com.example/existing-server", }, { - name: "duplicate remote URL used only by deprecated server - should pass", + name: "duplicate remote URL used only by deleted server - should pass", + serverDetail: apiv0.ServerJSON{ + Schema: model.CurrentSchemaURL, + Name: "com.example/new-server-with-deleted-conflict", + Description: "A new server reusing a deleted remote URL", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deleted.example.com/mcp"}, + }, + }, + expectError: false, + }, + { + name: "duplicate remote URL used by deprecated server - should fail", serverDetail: apiv0.ServerJSON{ Schema: model.CurrentSchemaURL, Name: "com.example/new-server-with-deprecated-conflict", @@ -124,7 +153,8 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, }, }, - expectError: false, + expectError: true, + errorMsg: "remote URL https://deprecated.example.com/mcp is already used by server com.example/deprecated-server", }, { name: "updating same server with same URLs - should pass", @@ -918,52 +948,6 @@ func TestUpdateServerStatus_ValidateRemoteURLsOnRestoreFromDeleted(t *testing.T) assert.Contains(t, err.Error(), "already used by server") } -func TestUpdateServerStatus_ValidateRemoteURLsOnRestoreFromDeprecated(t *testing.T) { - ctx := context.Background() - testDB := database.NewTestDB(t) - service := NewRegistryService(testDB, &config.Config{EnableRegistryValidation: false}) - - remoteURL := "https://api.deprecated.com/mcp" - - // Create Server A with a remote URL and deprecate it. - serverA := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/deprecated-server", - Description: "Server to be deprecated", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: remoteURL}, - }, - } - _, err := service.CreateServer(ctx, serverA) - require.NoError(t, err) - - _, err = service.UpdateServerStatus(ctx, "com.example/deprecated-server", "1.0.0", &StatusChangeRequest{ - NewStatus: model.StatusDeprecated, - }) - require.NoError(t, err) - - // Create Server B with the same remote URL (should succeed since A is deprecated). - serverB := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/replacement-server", - Description: "Replacement server with same remote URL", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: remoteURL}, - }, - } - _, err = service.CreateServer(ctx, serverB) - require.NoError(t, err) - - // Try to restore deprecated server to active - should fail due to URL conflict. - _, err = service.UpdateServerStatus(ctx, "com.example/deprecated-server", "1.0.0", &StatusChangeRequest{ - NewStatus: model.StatusActive, - }) - assert.Error(t, err) - assert.Contains(t, err.Error(), "remote URL") - assert.Contains(t, err.Error(), "already used by server") -} func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing.T) { ctx := context.Background() @@ -1025,65 +1009,6 @@ func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing. assert.Contains(t, err.Error(), "already used by server") } -func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreFromDeprecatedToActive(t *testing.T) { - ctx := context.Background() - testDB := database.NewTestDB(t) - service := NewRegistryService(testDB, &config.Config{EnableRegistryValidation: false}) - - remoteURL := "https://api.allversions-deprecated.com/mcp" - - // Create Server A with multiple versions. - serverAv1 := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/deprecated-multi-version-server", - Description: "Server A version 1", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: remoteURL}, - }, - } - _, err := service.CreateServer(ctx, serverAv1) - require.NoError(t, err) - - serverAv2 := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/deprecated-multi-version-server", - Description: "Server A version 2", - Version: "2.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: remoteURL}, - }, - } - _, err = service.CreateServer(ctx, serverAv2) - require.NoError(t, err) - - // Deprecate all versions of Server A. - _, err = service.UpdateAllVersionsStatus(ctx, "com.example/deprecated-multi-version-server", &StatusChangeRequest{ - NewStatus: model.StatusDeprecated, - }) - require.NoError(t, err) - - // Create Server B with the same remote URL (should succeed since A is deprecated). - serverB := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/active-conflicting-server", - Description: "Server B with same remote URL", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: remoteURL}, - }, - } - _, err = service.CreateServer(ctx, serverB) - require.NoError(t, err) - - // Try to restore all versions of Server A to active - should fail. - _, err = service.UpdateAllVersionsStatus(ctx, "com.example/deprecated-multi-version-server", &StatusChangeRequest{ - NewStatus: model.StatusActive, - }) - assert.Error(t, err) - assert.Contains(t, err.Error(), "remote URL") - assert.Contains(t, err.Error(), "already used by server") -} func TestUpdateServerStatus_NoConflictWhenRestoringWithUniqueURLs(t *testing.T) { ctx := context.Background() From 16772a6623b98e36d37889c7684c3844464da35e Mon Sep 17 00:00:00 2001 From: Rohit Kumar <112308320+stationeros@users.noreply.github.com> Date: Sat, 25 Apr 2026 17:10:21 +0530 Subject: [PATCH 04/10] remove extra lines for lint fixes --- internal/service/registry_service_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index c34e6a850..2cfac1ed9 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -948,7 +948,6 @@ func TestUpdateServerStatus_ValidateRemoteURLsOnRestoreFromDeleted(t *testing.T) assert.Contains(t, err.Error(), "already used by server") } - func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing.T) { ctx := context.Background() testDB := database.NewTestDB(t) @@ -1009,7 +1008,6 @@ func TestUpdateAllVersionsStatus_ValidateRemoteURLsOnRestoreToActive(t *testing. assert.Contains(t, err.Error(), "already used by server") } - func TestUpdateServerStatus_NoConflictWhenRestoringWithUniqueURLs(t *testing.T) { ctx := context.Background() testDB := database.NewTestDB(t) From 982589247d7b6d0b45c2008779049a383bec97b8 Mon Sep 17 00:00:00 2001 From: stationeros Date: Mon, 27 Apr 2026 21:32:12 +0530 Subject: [PATCH 05/10] test: fold deleted server into shared fixture setup --- internal/service/registry_service_test.go | 30 +++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index c34e6a850..144c5200d 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -41,6 +41,15 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { {Type: "streamable-http", URL: "https://api.microsoft.com/mcp"}, }, }, + "deleted": { + Schema: model.CurrentSchemaURL, + Name: "com.example/deleted-server", + Description: "A deleted server", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deleted.example.com/mcp"}, + }, + }, } testDB := database.NewTestDB(t) @@ -50,23 +59,14 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { for _, server := range existingServers { _, err := service.CreateServer(ctx, server) require.NoError(t, err, "failed to create server: %v", err) - } - deletedServer := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/deleted-server", - Description: "A deleted server", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: "https://deleted.example.com/mcp"}, - }, + if server.Name == "com.example/deleted-server" { + _, err = service.UpdateServerStatus(ctx, server.Name, server.Version, &StatusChangeRequest{ + NewStatus: model.StatusDeleted, + }) + require.NoError(t, err) + } } - _, err := service.CreateServer(ctx, deletedServer) - require.NoError(t, err) - _, err = service.UpdateServerStatus(ctx, deletedServer.Name, deletedServer.Version, &StatusChangeRequest{ - NewStatus: model.StatusDeleted, - }) - require.NoError(t, err) deprecatedServer := &apiv0.ServerJSON{ Schema: model.CurrentSchemaURL, From 97d3e01f791a61be099bb3b17351e7d582086cfc Mon Sep 17 00:00:00 2001 From: stationeros Date: Mon, 27 Apr 2026 21:56:08 +0530 Subject: [PATCH 06/10] lint: fold deleted server into shared fixture setup --- internal/service/registry_service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index e6e2d758f..70dffed7f 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -77,7 +77,7 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, }, } - _, err = service.CreateServer(ctx, deprecatedServer) + _, err := service.CreateServer(ctx, deprecatedServer) require.NoError(t, err) _, err = service.UpdateServerStatus(ctx, deprecatedServer.Name, deprecatedServer.Version, &StatusChangeRequest{ NewStatus: model.StatusDeprecated, From 3eb18668bfd48b318e3dec49633aa2292414e4a6 Mon Sep 17 00:00:00 2001 From: stationeros Date: Mon, 27 Apr 2026 22:18:06 +0530 Subject: [PATCH 07/10] lint: fold deleted server into shared fixture setup --- internal/service/registry_service_test.go | 32 +++++++++++------------ 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/internal/service/registry_service_test.go b/internal/service/registry_service_test.go index 70dffed7f..97d3a9a1f 100644 --- a/internal/service/registry_service_test.go +++ b/internal/service/registry_service_test.go @@ -50,6 +50,15 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { {Type: "streamable-http", URL: "https://deleted.example.com/mcp"}, }, }, + "deprecated": { + Schema: model.CurrentSchemaURL, + Name: "com.example/deprecated-server", + Description: "A deprecated server", + Version: "1.0.0", + Remotes: []model.Transport{ + {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, + }, + }, } testDB := database.NewTestDB(t) @@ -59,26 +68,15 @@ func TestValidateNoDuplicateRemoteURLs(t *testing.T) { for _, server := range existingServers { _, err := service.CreateServer(ctx, server) require.NoError(t, err, "failed to create server: %v", err) - - if server.Name == "com.example/deleted-server" { - _, err = service.UpdateServerStatus(ctx, server.Name, server.Version, &StatusChangeRequest{ - NewStatus: model.StatusDeleted, - }) - require.NoError(t, err) - } } - deprecatedServer := &apiv0.ServerJSON{ - Schema: model.CurrentSchemaURL, - Name: "com.example/deprecated-server", - Description: "A deprecated server", - Version: "1.0.0", - Remotes: []model.Transport{ - {Type: "streamable-http", URL: "https://deprecated.example.com/mcp"}, - }, - } - _, err := service.CreateServer(ctx, deprecatedServer) + deletedServer := existingServers["deleted"] + _, err := service.UpdateServerStatus(ctx, deletedServer.Name, deletedServer.Version, &StatusChangeRequest{ + NewStatus: model.StatusDeleted, + }) require.NoError(t, err) + + deprecatedServer := existingServers["deprecated"] _, err = service.UpdateServerStatus(ctx, deprecatedServer.Name, deprecatedServer.Version, &StatusChangeRequest{ NewStatus: model.StatusDeprecated, }) From c31055301c27ffcf8351e80b6b327601434e4d80 Mon Sep 17 00:00:00 2001 From: Rohit Kumar <112308320+stationeros@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:24:55 +0530 Subject: [PATCH 08/10] Putting back original From 7b2c3b61e32b0ef95e4f5e78f5a577e5812ecf4f Mon Sep 17 00:00:00 2001 From: Rohit Kumar <112308320+stationeros@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:27:27 +0530 Subject: [PATCH 09/10] Update registry_service.go --- internal/service/registry_service.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index d7afd8178..cc2612eb4 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -298,13 +298,13 @@ func pickLatestVersion(versions []*apiv0.ServerResponse, allowDeleted bool) *api return winner } -// validateNoDuplicateRemoteURLs checks that no non-deleted server is using the same remote URLs +// validateNoDuplicateRemoteURLs checks that no other server is using the same remote URLs func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, tx pgx.Tx, serverDetail apiv0.ServerJSON) error { // Check each remote URL in the new server for conflicts for _, remote := range serverDetail.Remotes { - // Use a filter that only returns non-deleted servers with this remote URL - includeDeleted := false - filter := &database.ServerFilter{RemoteURL: &remote.URL, IncludeDeleted: &includeDeleted} + // Use filter to find servers with this remote URL + + filter := &database.ServerFilter{RemoteURL: &remote.URL} conflictingServers, _, err := s.db.ListServers(ctx, tx, filter, "", 1000) if err != nil { @@ -446,7 +446,7 @@ func (s *registryServiceImpl) updateAllVersionsStatusInTransaction(ctx context.C if statusChange.NewStatus == model.StatusActive { includeDeleted := true - // Include deleted versions so we can revalidate any currently deleted versions before restoring them to active. + // When transitioning to active, it means the current status is either deprecated or deleted, so it should include deleted server also filter := &database.ServerFilter{Name: &serverName, IncludeDeleted: &includeDeleted} versions, _, err := s.db.ListServers(ctx, tx, filter, "", 1000) if err != nil { From 0a4cd0d5be44781a8da0155494fd991b8af35814 Mon Sep 17 00:00:00 2001 From: Rohit Kumar <112308320+stationeros@users.noreply.github.com> Date: Tue, 28 Apr 2026 18:27:57 +0530 Subject: [PATCH 10/10] Update registry_service.go --- internal/service/registry_service.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index cc2612eb4..16a910002 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -303,7 +303,6 @@ func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, // Check each remote URL in the new server for conflicts for _, remote := range serverDetail.Remotes { // Use filter to find servers with this remote URL - filter := &database.ServerFilter{RemoteURL: &remote.URL} conflictingServers, _, err := s.db.ListServers(ctx, tx, filter, "", 1000)