diff --git a/internal/api/handlers/v0/edit.go b/internal/api/handlers/v0/edit.go index 306338f..e11dd8e 100644 --- a/internal/api/handlers/v0/edit.go +++ b/internal/api/handlers/v0/edit.go @@ -13,7 +13,7 @@ import ( "github.com/modelcontextprotocol/registry/internal/database" "github.com/modelcontextprotocol/registry/internal/service" "github.com/modelcontextprotocol/registry/internal/validators" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -39,7 +39,7 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg * Security: []map[string][]string{ {"bearer": {}}, }, - }, func(ctx context.Context, input *EditServerInput) (*Response[apiv1.ServerRecord], error) { + }, func(ctx context.Context, input *EditServerInput) (*Response[apiv0.ServerRecord], error) { // Extract bearer token const bearerPrefix = "Bearer " authHeader := input.Authorization @@ -74,7 +74,7 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg * } // Parse the validated request body - var editRequest apiv1.PublishRequest + var editRequest apiv0.PublishRequest if err := json.Unmarshal(input.RawBody, &editRequest); err != nil { return nil, huma.Error400BadRequest("Invalid JSON format", err) } @@ -104,7 +104,7 @@ func RegisterEditEndpoints(api huma.API, registry service.RegistryService, cfg * return nil, huma.Error400BadRequest("Failed to edit server", err) } - return &Response[apiv1.ServerRecord]{ + return &Response[apiv0.ServerRecord]{ Body: *updatedServer, }, nil }) diff --git a/internal/api/handlers/v0/edit_test.go b/internal/api/handlers/v0/edit_test.go index 403946a..a9be004 100644 --- a/internal/api/handlers/v0/edit_test.go +++ b/internal/api/handlers/v0/edit_test.go @@ -17,7 +17,7 @@ import ( "github.com/modelcontextprotocol/registry/internal/auth" "github.com/modelcontextprotocol/registry/internal/config" "github.com/modelcontextprotocol/registry/internal/database" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -45,7 +45,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Updated test server", @@ -62,7 +62,7 @@ func TestEditServerEndpoint(t *testing.T) { }, setupMocks: func(registry *MockRegistryService) { // Current server (not deleted) - currentServer := &apiv1.ServerRecord{ + currentServer := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Original server", @@ -71,14 +71,14 @@ func TestEditServerEndpoint(t *testing.T) { } registry.On("GetByID", "550e8400-e29b-41d4-a716-446655440001").Return(currentServer, nil) - expectedResponse := &apiv1.ServerRecord{ + expectedResponse := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Updated test server", Status: model.StatusDeprecated, }, } - registry.On("EditServer", "550e8400-e29b-41d4-a716-446655440001", mock.AnythingOfType("v1.PublishRequest")).Return(expectedResponse, nil) + registry.On("EditServer", "550e8400-e29b-41d4-a716-446655440001", mock.AnythingOfType("v0.PublishRequest")).Return(expectedResponse, nil) }, expectedStatus: http.StatusOK, }, @@ -86,7 +86,7 @@ func TestEditServerEndpoint(t *testing.T) { name: "missing authorization header", serverID: "550e8400-e29b-41d4-a716-446655440001", authHeader: "", - requestBody: apiv1.PublishRequest{}, + requestBody: apiv0.PublishRequest{}, setupMocks: func(_ *MockRegistryService) {}, expectedStatus: 422, expectedError: "required header parameter is missing", @@ -95,7 +95,7 @@ func TestEditServerEndpoint(t *testing.T) { name: "invalid authorization header format", serverID: "550e8400-e29b-41d4-a716-446655440001", authHeader: "InvalidFormat token123", - requestBody: apiv1.PublishRequest{}, + requestBody: apiv0.PublishRequest{}, setupMocks: func(_ *MockRegistryService) {}, expectedStatus: http.StatusUnauthorized, expectedError: "Unauthorized", @@ -104,7 +104,7 @@ func TestEditServerEndpoint(t *testing.T) { name: "invalid token", serverID: "550e8400-e29b-41d4-a716-446655440001", authHeader: "Bearer invalid-token", - requestBody: apiv1.PublishRequest{}, + requestBody: apiv0.PublishRequest{}, setupMocks: func(_ *MockRegistryService) {}, expectedStatus: http.StatusUnauthorized, expectedError: "Unauthorized", @@ -123,7 +123,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Updated test server", @@ -131,7 +131,7 @@ func TestEditServerEndpoint(t *testing.T) { }, setupMocks: func(registry *MockRegistryService) { // Need to mock GetByID since we check permissions against existing server name - currentServer := &apiv1.ServerRecord{ + currentServer := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Original server", @@ -157,7 +157,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.other/test-server", Description: "Updated test server", @@ -166,7 +166,7 @@ func TestEditServerEndpoint(t *testing.T) { setupMocks: func(registry *MockRegistryService) { // Need to mock GetByID since we check permissions against existing server name // This test case shows a different scenario: existing server is "other" but user only has perms for "domdomegg" - currentServer := &apiv1.ServerRecord{ + currentServer := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.other/test-server", Description: "Original server", @@ -192,7 +192,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Updated test server", @@ -218,7 +218,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Updated test server", @@ -226,7 +226,7 @@ func TestEditServerEndpoint(t *testing.T) { }, setupMocks: func(registry *MockRegistryService) { // Current server (not deleted) - currentServer := &apiv1.ServerRecord{ + currentServer := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Original server", @@ -234,7 +234,7 @@ func TestEditServerEndpoint(t *testing.T) { }, } registry.On("GetByID", "550e8400-e29b-41d4-a716-446655440001").Return(currentServer, nil) - registry.On("EditServer", "550e8400-e29b-41d4-a716-446655440001", mock.AnythingOfType("v1.PublishRequest")).Return(nil, errors.New("database error")) + registry.On("EditServer", "550e8400-e29b-41d4-a716-446655440001", mock.AnythingOfType("v0.PublishRequest")).Return(nil, errors.New("database error")) }, expectedStatus: http.StatusBadRequest, expectedError: "Bad Request", @@ -272,7 +272,7 @@ func TestEditServerEndpoint(t *testing.T) { }) return "Bearer " + token }(), - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Trying to undelete server", @@ -281,7 +281,7 @@ func TestEditServerEndpoint(t *testing.T) { }, setupMocks: func(registry *MockRegistryService) { // Current server is deleted - currentServer := &apiv1.ServerRecord{ + currentServer := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "io.github.domdomegg/test-server", Description: "Original server", diff --git a/internal/api/handlers/v0/publish.go b/internal/api/handlers/v0/publish.go index d6dc785..a732254 100644 --- a/internal/api/handlers/v0/publish.go +++ b/internal/api/handlers/v0/publish.go @@ -11,7 +11,7 @@ import ( "github.com/modelcontextprotocol/registry/internal/config" "github.com/modelcontextprotocol/registry/internal/service" "github.com/modelcontextprotocol/registry/internal/validators" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" ) // PublishServerInput represents the input for publishing a server @@ -35,7 +35,7 @@ func RegisterPublishEndpoint(api huma.API, registry service.RegistryService, cfg Security: []map[string][]string{ {"bearer": {}}, }, - }, func(ctx context.Context, input *PublishServerInput) (*Response[apiv1.ServerRecord], error) { + }, func(ctx context.Context, input *PublishServerInput) (*Response[apiv0.ServerRecord], error) { // Extract bearer token const bearerPrefix = "Bearer " authHeader := input.Authorization @@ -56,7 +56,7 @@ func RegisterPublishEndpoint(api huma.API, registry service.RegistryService, cfg } // Parse the validated request body - var publishRequest apiv1.PublishRequest + var publishRequest apiv0.PublishRequest if err := json.Unmarshal(input.RawBody, &publishRequest); err != nil { return nil, huma.Error400BadRequest("Invalid JSON format", err) } @@ -82,7 +82,7 @@ func RegisterPublishEndpoint(api huma.API, registry service.RegistryService, cfg } // Return the published server in extension wrapper format - return &Response[apiv1.ServerRecord]{ + return &Response[apiv0.ServerRecord]{ Body: *publishedServer, }, nil }) diff --git a/internal/api/handlers/v0/publish_integration_test.go b/internal/api/handlers/v0/publish_integration_test.go index 7126bab..253b510 100644 --- a/internal/api/handlers/v0/publish_integration_test.go +++ b/internal/api/handlers/v0/publish_integration_test.go @@ -17,7 +17,7 @@ import ( "github.com/modelcontextprotocol/registry/internal/auth" "github.com/modelcontextprotocol/registry/internal/config" "github.com/modelcontextprotocol/registry/internal/service" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -54,7 +54,7 @@ func TestPublishIntegration(t *testing.T) { v0.RegisterPublishEndpoint(api, registryService, testConfig) t.Run("successful publish with GitHub auth", func(t *testing.T) { - publishReq := apiv1.PublishRequest{ + publishReq := apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.testuser/test-mcp-server", Description: "A test MCP server for integration testing", @@ -92,7 +92,7 @@ func TestPublishIntegration(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code) - var response apiv1.ServerRecord + var response apiv0.ServerRecord err = json.Unmarshal(rr.Body.Bytes(), &response) require.NoError(t, err) @@ -101,7 +101,7 @@ func TestPublishIntegration(t *testing.T) { }) t.Run("successful publish with none auth (no prefix)", func(t *testing.T) { - publishReq := apiv1.PublishRequest{ + publishReq := apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "com.example/test-mcp-server-no-auth", Description: "A test MCP server without authentication", @@ -138,7 +138,7 @@ func TestPublishIntegration(t *testing.T) { assert.Equal(t, http.StatusOK, rr.Code) - var response apiv1.ServerRecord + var response apiv0.ServerRecord err = json.Unmarshal(rr.Body.Bytes(), &response) require.NoError(t, err) @@ -146,7 +146,7 @@ func TestPublishIntegration(t *testing.T) { }) t.Run("publish fails with missing authorization header", func(t *testing.T) { - publishReq := apiv1.PublishRequest{ + publishReq := apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "test-server", }, @@ -167,7 +167,7 @@ func TestPublishIntegration(t *testing.T) { }) t.Run("publish fails with invalid token", func(t *testing.T) { - publishReq := apiv1.PublishRequest{ + publishReq := apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "test-server", }, @@ -188,7 +188,7 @@ func TestPublishIntegration(t *testing.T) { }) t.Run("publish fails when permission denied", func(t *testing.T) { - publishReq := apiv1.PublishRequest{ + publishReq := apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.other/test-server", Description: "A test server", diff --git a/internal/api/handlers/v0/publish_test.go b/internal/api/handlers/v0/publish_test.go index ffb4954..87947c0 100644 --- a/internal/api/handlers/v0/publish_test.go +++ b/internal/api/handlers/v0/publish_test.go @@ -17,7 +17,7 @@ import ( v0 "github.com/modelcontextprotocol/registry/internal/api/handlers/v0" "github.com/modelcontextprotocol/registry/internal/auth" "github.com/modelcontextprotocol/registry/internal/config" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -29,33 +29,33 @@ type MockRegistryService struct { mock.Mock } -func (m *MockRegistryService) List(cursor string, limit int) ([]apiv1.ServerRecord, string, error) { +func (m *MockRegistryService) List(cursor string, limit int) ([]apiv0.ServerRecord, string, error) { args := m.Called(cursor, limit) - return args.Get(0).([]apiv1.ServerRecord), args.String(1), args.Error(2) + return args.Get(0).([]apiv0.ServerRecord), args.String(1), args.Error(2) } -func (m *MockRegistryService) GetByID(id string) (*apiv1.ServerRecord, error) { +func (m *MockRegistryService) GetByID(id string) (*apiv0.ServerRecord, error) { args := m.Called(id) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*apiv1.ServerRecord), args.Error(1) + return args.Get(0).(*apiv0.ServerRecord), args.Error(1) } -func (m *MockRegistryService) Publish(request apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (m *MockRegistryService) Publish(request apiv0.PublishRequest) (*apiv0.ServerRecord, error) { args := m.Called(request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*apiv1.ServerRecord), args.Error(1) + return args.Get(0).(*apiv0.ServerRecord), args.Error(1) } -func (m *MockRegistryService) EditServer(id string, request apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (m *MockRegistryService) EditServer(id string, request apiv0.PublishRequest) (*apiv0.ServerRecord, error) { args := m.Called(id, request) if args.Get(0) == nil { return nil, args.Error(1) } - return args.Get(0).(*apiv1.ServerRecord), args.Error(1) + return args.Get(0).(*apiv0.ServerRecord), args.Error(1) } // Helper function to generate a valid JWT token for testing @@ -88,7 +88,7 @@ func TestPublishEndpoint(t *testing.T) { }{ { name: "successful publish with GitHub auth", - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.example/test-server", Description: "A test server", @@ -110,13 +110,13 @@ func TestPublishEndpoint(t *testing.T) { }, }, setupMocks: func(registry *MockRegistryService) { - registry.On("Publish", mock.AnythingOfType("v1.PublishRequest")).Return(&apiv1.ServerRecord{}, nil) + registry.On("Publish", mock.AnythingOfType("v0.PublishRequest")).Return(&apiv0.ServerRecord{}, nil) }, expectedStatus: http.StatusOK, }, { name: "successful publish with no auth (AuthMethodNone)", - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "example/test-server", Description: "A test server without auth", @@ -137,13 +137,13 @@ func TestPublishEndpoint(t *testing.T) { }, }, setupMocks: func(registry *MockRegistryService) { - registry.On("Publish", mock.AnythingOfType("v1.PublishRequest")).Return(&apiv1.ServerRecord{}, nil) + registry.On("Publish", mock.AnythingOfType("v0.PublishRequest")).Return(&apiv0.ServerRecord{}, nil) }, expectedStatus: http.StatusOK, }, { name: "missing authorization header", - requestBody: apiv1.PublishRequest{}, + requestBody: apiv0.PublishRequest{}, authHeader: "", // Empty auth header setupMocks: func(_ *MockRegistryService) {}, expectedStatus: http.StatusUnprocessableEntity, @@ -151,7 +151,7 @@ func TestPublishEndpoint(t *testing.T) { }, { name: "invalid authorization header format", - requestBody: apiv1.PublishRequest{}, + requestBody: apiv0.PublishRequest{}, authHeader: "InvalidFormat", setupMocks: func(_ *MockRegistryService) {}, expectedStatus: http.StatusUnauthorized, @@ -159,7 +159,7 @@ func TestPublishEndpoint(t *testing.T) { }, { name: "invalid token", - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "test-server", Description: "A test server", @@ -175,7 +175,7 @@ func TestPublishEndpoint(t *testing.T) { }, { name: "permission denied", - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "io.github.other/test-server", Description: "A test server", @@ -201,7 +201,7 @@ func TestPublishEndpoint(t *testing.T) { }, { name: "registry service error", - requestBody: apiv1.PublishRequest{ + requestBody: apiv0.PublishRequest{ Server: model.ServerJSON{ Name: "example/test-server", Description: "A test server", @@ -222,7 +222,7 @@ func TestPublishEndpoint(t *testing.T) { }, }, setupMocks: func(registry *MockRegistryService) { - registry.On("Publish", mock.AnythingOfType("v1.PublishRequest")).Return(nil, errors.New("cannot publish duplicate version")) + registry.On("Publish", mock.AnythingOfType("v0.PublishRequest")).Return(nil, errors.New("cannot publish duplicate version")) }, expectedStatus: http.StatusBadRequest, expectedError: "Failed to publish server", diff --git a/internal/api/handlers/v0/servers.go b/internal/api/handlers/v0/servers.go index d15b31d..3921d99 100644 --- a/internal/api/handlers/v0/servers.go +++ b/internal/api/handlers/v0/servers.go @@ -7,7 +7,7 @@ import ( "github.com/danielgtaylor/huma/v2" "github.com/google/uuid" "github.com/modelcontextprotocol/registry/internal/service" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" ) // Metadata contains pagination metadata @@ -25,7 +25,7 @@ type ListServersInput struct { // ListServersBody represents the paginated server list response body type ListServersBody struct { - Servers []apiv1.ServerRecord `json:"servers" doc:"List of MCP servers with extensions"` + Servers []apiv0.ServerRecord `json:"servers" doc:"List of MCP servers with extensions"` Metadata *Metadata `json:"metadata,omitempty" doc:"Pagination metadata"` } @@ -85,7 +85,7 @@ func RegisterServersEndpoints(api huma.API, registry service.RegistryService) { Summary: "Get MCP server details", Description: "Get detailed information about a specific MCP server", Tags: []string{"servers"}, - }, func(_ context.Context, input *ServerDetailInput) (*Response[apiv1.ServerRecord], error) { + }, func(_ context.Context, input *ServerDetailInput) (*Response[apiv0.ServerRecord], error) { // Get the server details from the registry service serverDetail, err := registry.GetByID(input.ID) if err != nil { @@ -95,7 +95,7 @@ func RegisterServersEndpoints(api huma.API, registry service.RegistryService) { return nil, huma.Error500InternalServerError("Failed to get server details", err) } - return &Response[apiv1.ServerRecord]{ + return &Response[apiv0.ServerRecord]{ Body: *serverDetail, }, nil }) diff --git a/internal/api/handlers/v0/servers_test.go b/internal/api/handlers/v0/servers_test.go index 37c2c08..c8c5836 100644 --- a/internal/api/handlers/v0/servers_test.go +++ b/internal/api/handlers/v0/servers_test.go @@ -12,7 +12,7 @@ import ( "github.com/danielgtaylor/huma/v2/adapters/humago" "github.com/google/uuid" v0 "github.com/modelcontextprotocol/registry/internal/api/handlers/v0" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" @@ -24,14 +24,14 @@ func TestServersListEndpoint(t *testing.T) { queryParams string setupMocks func(*MockRegistryService) expectedStatus int - expectedServers []apiv1.ServerRecord + expectedServers []apiv0.ServerRecord expectedMeta *v0.Metadata expectedError string }{ { name: "successful list with default parameters", setupMocks: func(registry *MockRegistryService) { - servers := []apiv1.ServerRecord{ + servers := []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-1", @@ -45,7 +45,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "1.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440001", }, }, @@ -62,7 +62,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "2.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440002", }, }, @@ -70,7 +70,7 @@ func TestServersListEndpoint(t *testing.T) { registry.Mock.On("List", "", 30).Return(servers, "", nil) }, expectedStatus: http.StatusOK, - expectedServers: []apiv1.ServerRecord{ + expectedServers: []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-1", @@ -84,7 +84,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "1.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440001", }, }, @@ -101,7 +101,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "2.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440002", }, }, @@ -111,7 +111,7 @@ func TestServersListEndpoint(t *testing.T) { name: "successful list with cursor and limit", queryParams: "?cursor=550e8400-e29b-41d4-a716-446655440000&limit=10", setupMocks: func(registry *MockRegistryService) { - servers := []apiv1.ServerRecord{ + servers := []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-3", @@ -125,7 +125,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "1.5.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440003", }, }, @@ -134,7 +134,7 @@ func TestServersListEndpoint(t *testing.T) { registry.Mock.On("List", mock.AnythingOfType("string"), 10).Return(servers, nextCursor, nil) }, expectedStatus: http.StatusOK, - expectedServers: []apiv1.ServerRecord{ + expectedServers: []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-3", @@ -148,7 +148,7 @@ func TestServersListEndpoint(t *testing.T) { Version: "1.5.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "550e8400-e29b-41d4-a716-446655440003", }, }, @@ -196,7 +196,7 @@ func TestServersListEndpoint(t *testing.T) { { name: "registry service error", setupMocks: func(registry *MockRegistryService) { - registry.Mock.On("List", "", 30).Return([]apiv1.ServerRecord{}, "", errors.New("database connection error")) + registry.Mock.On("List", "", 30).Return([]apiv0.ServerRecord{}, "", errors.New("database connection error")) }, expectedStatus: http.StatusInternalServerError, expectedError: "Failed to get registry list", @@ -233,7 +233,7 @@ func TestServersListEndpoint(t *testing.T) { // Parse response body var resp struct { - Servers []apiv1.ServerRecord `json:"servers"` + Servers []apiv0.ServerRecord `json:"servers"` Metadata *v0.Metadata `json:"metadata,omitempty"` } err := json.NewDecoder(w.Body).Decode(&resp) @@ -268,14 +268,14 @@ func TestServersDetailEndpoint(t *testing.T) { serverID string setupMocks func(*MockRegistryService, string) expectedStatus int - expectedServer *apiv1.ServerRecord + expectedServer *apiv0.ServerRecord expectedError string }{ { name: "successful get server detail", serverID: uuid.New().String(), setupMocks: func(registry *MockRegistryService, serverID string) { - serverDetail := &apiv1.ServerRecord{ + serverDetail := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "test-server-detail", Description: "Test server detail", @@ -288,7 +288,7 @@ func TestServersDetailEndpoint(t *testing.T) { Version: "2.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: serverID, }, } @@ -352,7 +352,7 @@ func TestServersDetailEndpoint(t *testing.T) { assert.Equal(t, "application/json", w.Header().Get("Content-Type")) // Parse response body - var serverDetailResp apiv1.ServerRecord + var serverDetailResp apiv0.ServerRecord err := json.NewDecoder(w.Body).Decode(&serverDetailResp) assert.NoError(t, err) @@ -376,7 +376,7 @@ func TestServersEndpointsIntegration(t *testing.T) { // Test data serverID := uuid.New().String() - servers := []apiv1.ServerRecord{ + servers := []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "integration-test-server", @@ -390,13 +390,13 @@ func TestServersEndpointsIntegration(t *testing.T) { Version: "1.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: serverID, }, }, } - serverDetail := &apiv1.ServerRecord{ + serverDetail := &apiv0.ServerRecord{ Server: servers[0].Server, XIOModelContextProtocolRegistry: servers[0].XIOModelContextProtocolRegistry, } @@ -439,7 +439,7 @@ func TestServersEndpointsIntegration(t *testing.T) { // Parse response body var listResp struct { - Servers []apiv1.ServerRecord `json:"servers"` + Servers []apiv0.ServerRecord `json:"servers"` } err = json.NewDecoder(resp.Body).Decode(&listResp) assert.NoError(t, err) @@ -470,7 +470,7 @@ func TestServersEndpointsIntegration(t *testing.T) { assert.Equal(t, "application/json", resp.Header.Get("Content-Type")) // Parse response body - var serverDetailResp apiv1.ServerRecord + var serverDetailResp apiv0.ServerRecord err = json.NewDecoder(resp.Body).Decode(&serverDetailResp) assert.NoError(t, err) diff --git a/internal/api/handlers/v0/telemetry_test.go b/internal/api/handlers/v0/telemetry_test.go index 1ef8762..838c2e4 100644 --- a/internal/api/handlers/v0/telemetry_test.go +++ b/internal/api/handlers/v0/telemetry_test.go @@ -15,12 +15,12 @@ import ( "github.com/modelcontextprotocol/registry/internal/api/router" "github.com/modelcontextprotocol/registry/internal/config" "github.com/modelcontextprotocol/registry/internal/telemetry" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) func mockServerEndpoint(registry *MockRegistryService, serverID string) { - serverDetail := &apiv1.ServerRecord{ + serverDetail := &apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "test-server-detail", Description: "Test server detail", @@ -33,7 +33,7 @@ func mockServerEndpoint(registry *MockRegistryService, serverID string) { Version: "2.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: serverID, }, } diff --git a/internal/database/database.go b/internal/database/database.go index f7a575c..9adcf23 100644 --- a/internal/database/database.go +++ b/internal/database/database.go @@ -4,7 +4,7 @@ import ( "context" "errors" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -21,16 +21,16 @@ var ( // Database defines the interface for database operations with extension wrapper architecture type Database interface { // List retrieves all ServerRecord entries with optional filtering - List(ctx context.Context, filter map[string]any, cursor string, limit int) ([]*apiv1.ServerRecord, string, error) + List(ctx context.Context, filter map[string]any, cursor string, limit int) ([]*apiv0.ServerRecord, string, error) // GetByID retrieves a single ServerRecord by its ID - GetByID(ctx context.Context, id string) (*apiv1.ServerRecord, error) + GetByID(ctx context.Context, id string) (*apiv0.ServerRecord, error) // Publish adds a new server to the database with separated server.json and extensions // The registryMetadata contains metadata determined by the service layer (e.g., is_latest, timestamps) - Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv1.RegistryExtensions) (*apiv1.ServerRecord, error) + Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv0.RegistryExtensions) (*apiv0.ServerRecord, error) // UpdateLatestFlag updates the is_latest flag for a specific server record UpdateLatestFlag(ctx context.Context, id string, isLatest bool) error // UpdateServer updates an existing server record with new server details - UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv1.ServerRecord, error) + UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv0.ServerRecord, error) // ImportSeed imports initial data from a seed file ImportSeed(ctx context.Context, seedFilePath string) error // Close closes the database connection diff --git a/internal/database/import.go b/internal/database/import.go index 35cdf29..bcd378f 100644 --- a/internal/database/import.go +++ b/internal/database/import.go @@ -9,7 +9,7 @@ import ( "os" "strings" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" ) // ReadSeedFile reads seed data from various sources: @@ -17,7 +17,7 @@ import ( // 2. Direct HTTP URLs to seed.json files - expects extension wrapper format // 3. Registry root URLs (automatically appends /v0/servers and paginates) // Only the extension wrapper format is supported (array of ServerResponse objects) -func ReadSeedFile(ctx context.Context, path string) ([]*apiv1.ServerRecord, error) { +func ReadSeedFile(ctx context.Context, path string) ([]*apiv0.ServerRecord, error) { var data []byte var err error @@ -39,17 +39,17 @@ func ReadSeedFile(ctx context.Context, path string) ([]*apiv1.ServerRecord, erro } // Parse extension wrapper format (only supported format) - var serverResponses []apiv1.ServerRecord + var serverResponses []apiv0.ServerRecord if err := json.Unmarshal(data, &serverResponses); err != nil { return nil, fmt.Errorf("failed to parse seed data as extension wrapper format: %w", err) } if len(serverResponses) == 0 { - return []*apiv1.ServerRecord{}, nil + return []*apiv0.ServerRecord{}, nil } // Convert ServerResponse to ServerRecord - var records []*apiv1.ServerRecord + var records []*apiv0.ServerRecord for _, response := range serverResponses { record := convertServerResponseToRecord(response) records = append(records, record) @@ -77,8 +77,8 @@ func fetchFromHTTP(ctx context.Context, url string) ([]byte, error) { return io.ReadAll(resp.Body) } -func fetchFromRegistryAPI(ctx context.Context, baseURL string) ([]*apiv1.ServerRecord, error) { - var allRecords []*apiv1.ServerRecord +func fetchFromRegistryAPI(ctx context.Context, baseURL string) ([]*apiv0.ServerRecord, error) { + var allRecords []*apiv0.ServerRecord cursor := "" for { @@ -97,7 +97,7 @@ func fetchFromRegistryAPI(ctx context.Context, baseURL string) ([]*apiv1.ServerR } var response struct { - Servers []apiv1.ServerRecord `json:"servers"` + Servers []apiv0.ServerRecord `json:"servers"` Metadata *struct { NextCursor string `json:"next_cursor,omitempty"` } `json:"metadata,omitempty"` @@ -123,7 +123,7 @@ func fetchFromRegistryAPI(ctx context.Context, baseURL string) ([]*apiv1.ServerR return allRecords, nil } -func convertServerResponseToRecord(response apiv1.ServerRecord) *apiv1.ServerRecord { +func convertServerResponseToRecord(response apiv0.ServerRecord) *apiv0.ServerRecord { // The registry extensions are already properly typed, so we can use them directly registryMetadata := response.XIOModelContextProtocolRegistry @@ -133,10 +133,9 @@ func convertServerResponseToRecord(response apiv1.ServerRecord) *apiv1.ServerRec publisherExtensions = make(map[string]interface{}) } - return &apiv1.ServerRecord{ + return &apiv0.ServerRecord{ Server: response.Server, XIOModelContextProtocolRegistry: registryMetadata, XPublisher: publisherExtensions, } } - diff --git a/internal/database/import_test.go b/internal/database/import_test.go index 645327f..8023d9e 100644 --- a/internal/database/import_test.go +++ b/internal/database/import_test.go @@ -10,7 +10,7 @@ import ( "time" "github.com/modelcontextprotocol/registry/internal/database" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stretchr/testify/assert" ) @@ -18,7 +18,7 @@ import ( func TestReadSeedFile_LocalFile(t *testing.T) { // Create a temporary seed file in extension wrapper format tempFile := "/tmp/test_seed.json" - seedData := []apiv1.ServerRecord{ + seedData := []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-1", @@ -32,7 +32,7 @@ func TestReadSeedFile_LocalFile(t *testing.T) { Version: "1.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "test-id-1", PublishedAt: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC), IsLatest: true, @@ -66,13 +66,13 @@ func TestReadSeedFile_LocalFile(t *testing.T) { func TestReadSeedFile_DirectHTTPURL(t *testing.T) { // Create a test HTTP server that serves seed JSON directly in extension wrapper format - seedData := []apiv1.ServerRecord{ + seedData := []apiv0.ServerRecord{ { Server: model.ServerJSON{ Name: "test-server-1", Description: "Test server 1", }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "test-id-1", PublishedAt: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC), IsLatest: true, @@ -98,7 +98,7 @@ func TestReadSeedFile_DirectHTTPURL(t *testing.T) { func TestReadSeedFile_RegistryURL(t *testing.T) { // Create mock registry responses - server1 := apiv1.ServerRecord{ + server1 := apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "Test Server 1", Description: "First test server", @@ -111,14 +111,14 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { }, }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "server-1", PublishedAt: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC), IsLatest: true, ReleaseDate: "2023-01-01T00:00:00Z", }, } - server2 := apiv1.ServerRecord{ + server2 := apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "Test Server 2", Description: "Second test server", @@ -131,7 +131,7 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { }, }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "server-2", PublishedAt: time.Date(2023, 1, 1, 0, 0, 0, 0, time.UTC), IsLatest: true, @@ -177,7 +177,7 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { } type PaginatedResponse struct { - Servers []apiv1.ServerRecord `json:"servers"` + Servers []apiv0.ServerRecord `json:"servers"` Metadata *Metadata `json:"metadata,omitempty"` } @@ -186,7 +186,7 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { case "": // First page response = PaginatedResponse{ - Servers: []apiv1.ServerRecord{server1}, + Servers: []apiv0.ServerRecord{server1}, Metadata: &Metadata{ NextCursor: "next-cursor-1", Count: 1, @@ -195,7 +195,7 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { case "next-cursor-1": // Second page response = PaginatedResponse{ - Servers: []apiv1.ServerRecord{server2}, + Servers: []apiv0.ServerRecord{server2}, Metadata: &Metadata{ Count: 1, // No NextCursor means end of pagination @@ -204,7 +204,7 @@ func TestReadSeedFile_RegistryURL(t *testing.T) { default: // No more pages response = PaginatedResponse{ - Servers: []apiv1.ServerRecord{}, + Servers: []apiv0.ServerRecord{}, Metadata: &Metadata{}, } } diff --git a/internal/database/memory.go b/internal/database/memory.go index bdb7221..be329ee 100644 --- a/internal/database/memory.go +++ b/internal/database/memory.go @@ -7,26 +7,26 @@ import ( "sync" "time" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) // MemoryDB is an in-memory implementation of the Database interface type MemoryDB struct { - entries map[string]*apiv1.ServerRecord // maps registry metadata ID to ServerRecord + entries map[string]*apiv0.ServerRecord // maps registry metadata ID to ServerRecord mu sync.RWMutex } // NewMemoryDB creates a new instance of the in-memory database func NewMemoryDB(e map[string]*model.ServerJSON) *MemoryDB { // Convert ServerJSON entries to ServerRecord entries - serverRecords := make(map[string]*apiv1.ServerRecord) + serverRecords := make(map[string]*apiv0.ServerRecord) for registryID, serverDetail := range e { // Create registry metadata now := time.Now() - record := &apiv1.ServerRecord{ + record := &apiv0.ServerRecord{ Server: *serverDetail, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: registryID, PublishedAt: now, UpdatedAt: now, @@ -48,7 +48,7 @@ func (db *MemoryDB) List( filter map[string]any, cursor string, limit int, -) ([]*apiv1.ServerRecord, string, error) { +) ([]*apiv0.ServerRecord, string, error) { if ctx.Err() != nil { return nil, "", ctx.Err() } @@ -61,7 +61,7 @@ func (db *MemoryDB) List( defer db.mu.RUnlock() // Convert all entries to a slice for pagination, filter by is_latest - var allEntries []*apiv1.ServerRecord + var allEntries []*apiv0.ServerRecord for _, entry := range db.entries { if entry.XIOModelContextProtocolRegistry.IsLatest { allEntries = append(allEntries, entry) @@ -69,7 +69,7 @@ func (db *MemoryDB) List( } // Simple filtering implementation - var filteredEntries []*apiv1.ServerRecord + var filteredEntries []*apiv0.ServerRecord for _, entry := range allEntries { include := true @@ -127,11 +127,11 @@ func (db *MemoryDB) List( // Apply pagination endIdx := min(startIdx+limit, len(filteredEntries)) - var result []*apiv1.ServerRecord + var result []*apiv0.ServerRecord if startIdx < len(filteredEntries) { result = filteredEntries[startIdx:endIdx] } else { - result = []*apiv1.ServerRecord{} + result = []*apiv0.ServerRecord{} } // Determine next cursor using registry metadata ID @@ -144,7 +144,7 @@ func (db *MemoryDB) List( } // GetByID retrieves a single ServerRecord by its registry metadata ID -func (db *MemoryDB) GetByID(ctx context.Context, id string) (*apiv1.ServerRecord, error) { +func (db *MemoryDB) GetByID(ctx context.Context, id string) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } @@ -163,7 +163,7 @@ func (db *MemoryDB) GetByID(ctx context.Context, id string) (*apiv1.ServerRecord } // Publish adds a new server to the database with separated server.json and extensions -func (db *MemoryDB) Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv1.RegistryExtensions) (*apiv1.ServerRecord, error) { +func (db *MemoryDB) Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv0.RegistryExtensions) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } @@ -188,7 +188,7 @@ func (db *MemoryDB) Publish(ctx context.Context, serverDetail model.ServerJSON, } // Create server record - record := &apiv1.ServerRecord{ + record := &apiv0.ServerRecord{ Server: serverDetail, XIOModelContextProtocolRegistry: registryMetadata, XPublisher: publisherExtensions, @@ -245,7 +245,7 @@ func (db *MemoryDB) UpdateLatestFlag(ctx context.Context, id string, isLatest bo } // UpdateServer updates an existing server record with new server details -func (db *MemoryDB) UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv1.ServerRecord, error) { +func (db *MemoryDB) UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } diff --git a/internal/database/postgres.go b/internal/database/postgres.go index e8ca584..96bd277 100644 --- a/internal/database/postgres.go +++ b/internal/database/postgres.go @@ -10,7 +10,7 @@ import ( "github.com/google/uuid" "github.com/jackc/pgx/v5" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -48,7 +48,7 @@ func (db *PostgreSQL) List( filter map[string]any, cursor string, limit int, -) ([]*apiv1.ServerRecord, string, error) { +) ([]*apiv0.ServerRecord, string, error) { if limit <= 0 { limit = 10 } @@ -113,9 +113,9 @@ func (db *PostgreSQL) List( } defer rows.Close() - var results []*apiv1.ServerRecord + var results []*apiv0.ServerRecord for rows.Next() { - var record apiv1.ServerRecord + var record apiv0.ServerRecord var repositoryJSON, packagesJSON, remotesJSON, publisherExtensionsJSON []byte var publishedAt, updatedAt, releaseDate time.Time @@ -167,7 +167,7 @@ func (db *PostgreSQL) List( } // parseJSONFields parses JSON fields for a server record -func parseJSONFields(record *apiv1.ServerRecord, repositoryJSON, packagesJSON, remotesJSON, publisherExtensionsJSON []byte) error { +func parseJSONFields(record *apiv0.ServerRecord, repositoryJSON, packagesJSON, remotesJSON, publisherExtensionsJSON []byte) error { if len(repositoryJSON) > 0 { if err := json.Unmarshal(repositoryJSON, &record.Server.Repository); err != nil { return fmt.Errorf("failed to unmarshal repository: %w", err) @@ -198,7 +198,7 @@ func parseJSONFields(record *apiv1.ServerRecord, repositoryJSON, packagesJSON, r } // GetByID retrieves a single ServerRecord by its registry metadata ID -func (db *PostgreSQL) GetByID(ctx context.Context, id string) (*apiv1.ServerRecord, error) { +func (db *PostgreSQL) GetByID(ctx context.Context, id string) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } @@ -212,7 +212,7 @@ func (db *PostgreSQL) GetByID(ctx context.Context, id string) (*apiv1.ServerReco WHERE se.id = $1 ` - var record apiv1.ServerRecord + var record apiv0.ServerRecord var repositoryJSON, packagesJSON, remotesJSON, publisherExtensionsJSON []byte var publishedAt, updatedAt, releaseDate time.Time @@ -278,7 +278,7 @@ func (db *PostgreSQL) GetByID(ctx context.Context, id string) (*apiv1.ServerReco } // Publish adds a new server to the database with separated server.json and extensions -func (db *PostgreSQL) Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv1.RegistryExtensions) (*apiv1.ServerRecord, error) { +func (db *PostgreSQL) Publish(ctx context.Context, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, registryMetadata apiv0.RegistryExtensions) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } @@ -360,10 +360,10 @@ func (db *PostgreSQL) Publish(ctx context.Context, serverDetail model.ServerJSON } // Create and return the ServerRecord - record := &apiv1.ServerRecord{ - Server: serverDetail, - XIOModelContextProtocolRegistry: registryMetadata, - XPublisher: publisherExtensions, + record := &apiv0.ServerRecord{ + Server: serverDetail, + XIOModelContextProtocolRegistry: registryMetadata, + XPublisher: publisherExtensions, } return record, nil @@ -409,7 +409,7 @@ func (db *PostgreSQL) ImportSeed(ctx context.Context, seedFilePath string) error } // publishWithTransaction handles publishing within an existing transaction, optionally with predefined metadata -func (db *PostgreSQL) publishWithTransaction(ctx context.Context, tx pgx.Tx, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, existingMetadata *apiv1.RegistryExtensions) error { +func (db *PostgreSQL) publishWithTransaction(ctx context.Context, tx pgx.Tx, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}, existingMetadata *apiv0.RegistryExtensions) error { // Use the same ID for both server and server_extensions (1:1 relationship) var id string if existingMetadata != nil && existingMetadata.ID != "" { @@ -531,7 +531,7 @@ func (db *PostgreSQL) UpdateLatestFlag(ctx context.Context, id string, isLatest } // UpdateServer updates an existing server record with new server details -func (db *PostgreSQL) UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv1.ServerRecord, error) { +func (db *PostgreSQL) UpdateServer(ctx context.Context, id string, serverDetail model.ServerJSON, publisherExtensions map[string]interface{}) (*apiv0.ServerRecord, error) { if ctx.Err() != nil { return nil, ctx.Err() } diff --git a/internal/service/fake_service.go b/internal/service/fake_service.go index 4430bab..4f1a206 100644 --- a/internal/service/fake_service.go +++ b/internal/service/fake_service.go @@ -7,7 +7,7 @@ import ( "github.com/google/uuid" "github.com/modelcontextprotocol/registry/internal/database" "github.com/modelcontextprotocol/registry/internal/validators" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -71,7 +71,7 @@ func NewFakeRegistryService() RegistryService { } // List retrieves servers with extension wrapper format -func (s *fakeRegistryService) List(cursor string, limit int) ([]apiv1.ServerRecord, string, error) { +func (s *fakeRegistryService) List(cursor string, limit int) ([]apiv0.ServerRecord, string, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -83,7 +83,7 @@ func (s *fakeRegistryService) List(cursor string, limit int) ([]apiv1.ServerReco } // Return ServerRecords directly (they're now the same as ServerResponse) - result := make([]apiv1.ServerRecord, len(serverRecords)) + result := make([]apiv0.ServerRecord, len(serverRecords)) for i, record := range serverRecords { result[i] = *record } @@ -92,7 +92,7 @@ func (s *fakeRegistryService) List(cursor string, limit int) ([]apiv1.ServerReco } // GetByID retrieves a specific server by its registry metadata ID in extension wrapper format -func (s *fakeRegistryService) GetByID(id string) (*apiv1.ServerRecord, error) { +func (s *fakeRegistryService) GetByID(id string) (*apiv0.ServerRecord, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -108,7 +108,7 @@ func (s *fakeRegistryService) GetByID(id string) (*apiv1.ServerRecord, error) { } // Publish publishes a server with separated extensions -func (s *fakeRegistryService) Publish(req apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (s *fakeRegistryService) Publish(req apiv0.PublishRequest) (*apiv0.ServerRecord, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -128,7 +128,7 @@ func (s *fakeRegistryService) Publish(req apiv1.PublishRequest) (*apiv1.ServerRe // Create registry metadata for fake service (always marks as latest) now := time.Now() - registryMetadata := apiv1.RegistryExtensions{ + registryMetadata := apiv0.RegistryExtensions{ ID: uuid.New().String(), PublishedAt: now, UpdatedAt: now, @@ -147,7 +147,7 @@ func (s *fakeRegistryService) Publish(req apiv1.PublishRequest) (*apiv1.ServerRe } // EditServer updates an existing server with new details (admin operation) -func (s *fakeRegistryService) EditServer(id string, req apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (s *fakeRegistryService) EditServer(id string, req apiv0.PublishRequest) (*apiv0.ServerRecord, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() diff --git a/internal/service/registry_service.go b/internal/service/registry_service.go index 9689ac3..04897d6 100644 --- a/internal/service/registry_service.go +++ b/internal/service/registry_service.go @@ -11,7 +11,7 @@ import ( "github.com/google/uuid" "github.com/modelcontextprotocol/registry/internal/database" "github.com/modelcontextprotocol/registry/internal/validators" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -30,7 +30,7 @@ func NewRegistryServiceWithDB(db database.Database) RegistryService { } // List returns registry entries with cursor-based pagination in extension wrapper format -func (s *registryServiceImpl) List(cursor string, limit int) ([]apiv1.ServerRecord, string, error) { +func (s *registryServiceImpl) List(cursor string, limit int) ([]apiv0.ServerRecord, string, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -47,7 +47,7 @@ func (s *registryServiceImpl) List(cursor string, limit int) ([]apiv1.ServerReco } // Return ServerRecords directly (they're now the same as ServerResponse) - result := make([]apiv1.ServerRecord, len(serverRecords)) + result := make([]apiv0.ServerRecord, len(serverRecords)) for i, record := range serverRecords { result[i] = *record } @@ -56,7 +56,7 @@ func (s *registryServiceImpl) List(cursor string, limit int) ([]apiv1.ServerReco } // GetByID retrieves a specific server by its registry metadata ID in extension wrapper format -func (s *registryServiceImpl) GetByID(id string) (*apiv1.ServerRecord, error) { +func (s *registryServiceImpl) GetByID(id string) (*apiv0.ServerRecord, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -127,7 +127,7 @@ func validatePackage(pkg *model.Package) error { } // Publish publishes a server with separated extensions -func (s *registryServiceImpl) Publish(req apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (s *registryServiceImpl) Publish(req apiv0.PublishRequest) (*apiv0.ServerRecord, error) { // Create a timeout context for the database operation ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() @@ -204,7 +204,7 @@ func (s *registryServiceImpl) Publish(req apiv1.PublishRequest) (*apiv1.ServerRe publisherExtensions := validators.ExtractPublisherExtensions(req) // Create registry metadata with service-determined values - registryMetadata := apiv1.RegistryExtensions{ + registryMetadata := apiv0.RegistryExtensions{ ID: uuid.New().String(), PublishedAt: currentTime, UpdatedAt: currentTime, @@ -256,7 +256,7 @@ func (s *registryServiceImpl) validateNoDuplicateRemoteURLs(ctx context.Context, } // EditServer updates an existing server with new details (admin operation) -func (s *registryServiceImpl) EditServer(id string, req apiv1.PublishRequest) (*apiv1.ServerRecord, error) { +func (s *registryServiceImpl) EditServer(id string, req apiv0.PublishRequest) (*apiv0.ServerRecord, error) { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() diff --git a/internal/service/service.go b/internal/service/service.go index 70ad619..528add9 100644 --- a/internal/service/service.go +++ b/internal/service/service.go @@ -1,15 +1,15 @@ package service -import apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" +import apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" // RegistryService defines the interface for registry operations type RegistryService interface { // List retrieves servers with unified format - List(cursor string, limit int) ([]apiv1.ServerRecord, string, error) + List(cursor string, limit int) ([]apiv0.ServerRecord, string, error) // GetByID retrieves a single server by registry metadata ID with unified format - GetByID(id string) (*apiv1.ServerRecord, error) + GetByID(id string) (*apiv0.ServerRecord, error) // Publish publishes a server with separated extensions - Publish(req apiv1.PublishRequest) (*apiv1.ServerRecord, error) + Publish(req apiv0.PublishRequest) (*apiv0.ServerRecord, error) // EditServer updates an existing server with new details - EditServer(id string, req apiv1.PublishRequest) (*apiv1.ServerRecord, error) + EditServer(id string, req apiv0.PublishRequest) (*apiv0.ServerRecord, error) } diff --git a/internal/validators/validators.go b/internal/validators/validators.go index 3ffc47d..84f96fb 100644 --- a/internal/validators/validators.go +++ b/internal/validators/validators.go @@ -7,7 +7,7 @@ import ( "slices" "strings" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" ) @@ -129,7 +129,7 @@ func (ov *ObjectValidator) Validate(obj *model.ServerJSON) error { } // ValidatePublisherExtensions validates that publisher extensions are within size limits -func ValidatePublisherExtensions(req apiv1.PublishRequest) error { +func ValidatePublisherExtensions(req apiv0.PublishRequest) error { const maxExtensionSize = 4 * 1024 // 4KB limit // Check size limit for x-publisher extension @@ -175,8 +175,8 @@ func ValidatePublishRequestExtensions(requestData []byte) error { return nil } -// ExtractPublisherExtensions extracts publisher extensions from a apiv1.PublishRequest -func ExtractPublisherExtensions(req apiv1.PublishRequest) map[string]interface{} { +// ExtractPublisherExtensions extracts publisher extensions from a apiv0.PublishRequest +func ExtractPublisherExtensions(req apiv0.PublishRequest) map[string]interface{} { publisherExtensions := make(map[string]interface{}) if req.XPublisher != nil { // Copy fields directly, avoiding double nesting diff --git a/internal/validators/validators_test.go b/internal/validators/validators_test.go index fa389cc..eb9c9a4 100644 --- a/internal/validators/validators_test.go +++ b/internal/validators/validators_test.go @@ -6,7 +6,7 @@ import ( "time" "github.com/modelcontextprotocol/registry/internal/validators" - apiv1 "github.com/modelcontextprotocol/registry/pkg/api/v1" + apiv0 "github.com/modelcontextprotocol/registry/pkg/api/v0" "github.com/modelcontextprotocol/registry/pkg/model" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -258,19 +258,19 @@ func TestObjectValidator_Validate(t *testing.T) { func TestExtractPublisherExtensions(t *testing.T) { tests := []struct { name string - request apiv1.PublishRequest + request apiv0.PublishRequest expected map[string]interface{} }{ { name: "nil publisher extensions", - request: apiv1.PublishRequest{ + request: apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, }, expected: map[string]interface{}{}, }, { name: "empty publisher extensions", - request: apiv1.PublishRequest{ + request: apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, XPublisher: map[string]interface{}{}, }, @@ -278,7 +278,7 @@ func TestExtractPublisherExtensions(t *testing.T) { }, { name: "simple publisher extensions", - request: apiv1.PublishRequest{ + request: apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, XPublisher: map[string]interface{}{ "build_info": map[string]interface{}{ @@ -298,7 +298,7 @@ func TestExtractPublisherExtensions(t *testing.T) { }, { name: "nested publisher extensions", - request: apiv1.PublishRequest{ + request: apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, XPublisher: map[string]interface{}{ "ci": map[string]interface{}{ @@ -322,7 +322,7 @@ func TestExtractPublisherExtensions(t *testing.T) { }, { name: "nil publisher extensions (should be ignored)", - request: apiv1.PublishRequest{ + request: apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, XPublisher: nil, }, @@ -340,7 +340,7 @@ func TestExtractPublisherExtensions(t *testing.T) { func TestExtractPublisherExtensions_DoesNotDoubleNest(t *testing.T) { // This test specifically verifies the bug we fixed - no double nesting - request := apiv1.PublishRequest{ + request := apiv0.PublishRequest{ Server: model.ServerJSON{Name: "test"}, XPublisher: map[string]interface{}{ "tool": "publisher-cli", @@ -362,7 +362,7 @@ func TestServerResponse_JSONSerialization(t *testing.T) { // Test that ServerResponse properly serializes to extension wrapper format publishedTime := time.Date(2023, 12, 1, 10, 30, 0, 0, time.UTC) - response := apiv1.ServerRecord{ + response := apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "test-server", Description: "A test server", @@ -375,7 +375,7 @@ func TestServerResponse_JSONSerialization(t *testing.T) { Version: "1.0.0", }, }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "registry-id-123", PublishedAt: publishedTime, IsLatest: true, @@ -434,7 +434,7 @@ func TestPublishRequest_WithPublisherExtensions(t *testing.T) { } }` - var request apiv1.PublishRequest + var request apiv0.PublishRequest err := json.Unmarshal([]byte(jsonData), &request) require.NoError(t, err) @@ -453,12 +453,12 @@ func TestPublishRequest_WithPublisherExtensions(t *testing.T) { func TestServerResponse_EmptyExtensions(t *testing.T) { // Test behavior with empty/nil extensions - response := apiv1.ServerRecord{ + response := apiv0.ServerRecord{ Server: model.ServerJSON{ Name: "minimal-server", Description: "Minimal test", }, - XIOModelContextProtocolRegistry: apiv1.RegistryExtensions{ + XIOModelContextProtocolRegistry: apiv0.RegistryExtensions{ ID: "min-id", }, XPublisher: nil, diff --git a/pkg/api/v1/types.go b/pkg/api/v0/types.go similarity index 99% rename from pkg/api/v1/types.go rename to pkg/api/v0/types.go index 7b00205..8af8833 100644 --- a/pkg/api/v1/types.go +++ b/pkg/api/v0/types.go @@ -1,4 +1,4 @@ -package v1 +package v0 import ( "time"