diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 65f0c3f0..a7cacebb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: - name: Install golangci-lint run: | - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.3.1 - name: Run golangci-lint run: golangci-lint run --timeout=5m diff --git a/.gitignore b/.gitignore index 3e114486..b586d0b4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ build/* .mcpregistry* **/bin cmd/registry/registry +.DS_Store validate-examples validate-schemas .idea/ diff --git a/.golangci.yml b/.golangci.yml index 051bb5fa..e86a4f39 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,19 +1,11 @@ # GolangCI-Lint configuration # See: https://golangci-lint.run/usage/configuration/ +version: "2" run: - timeout: 5m modules-download-mode: readonly - linters: enable: - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - typecheck - - unused - asasalint - asciicheck - bidichk @@ -28,14 +20,11 @@ linters: - exhaustive - forbidigo - funlen - - gci - gocognit - goconst - gocritic - gocyclo - godox - - gofmt - - goimports - gomoddirectives - gomodguard - goprintffuncname @@ -59,8 +48,7 @@ linters: - revive - rowserrcheck - sqlclosecheck - - stylecheck - - tenv + - staticcheck - testpackage - thelper - tparallel @@ -69,55 +57,69 @@ linters: - usestdlibvars - wastedassign - whitespace - -linters-settings: - revive: + settings: + cyclop: + max-complexity: 50 + funlen: + lines: 150 + statements: 150 + gocognit: + min-complexity: 50 + goconst: + min-len: 3 + min-occurrences: 3 + gocyclo: + min-complexity: 25 + lll: + line-length: 150 + misspell: + locale: US + mnd: + checks: + - argument + - case + - condition + - operation + - return + nestif: + min-complexity: 8 + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling rules: - - name: use-any - disabled: false - severity: error - cyclop: - max-complexity: 50 - funlen: - lines: 150 - statements: 150 - gocognit: - min-complexity: 50 - gocyclo: - min-complexity: 25 - goconst: - min-len: 3 - min-occurrences: 3 - mnd: - checks: - - argument - - case - - condition - - operation - - return - lll: - line-length: 150 - misspell: - locale: US - nestif: - min-complexity: 8 - -issues: - exclude-rules: - # Exclude some linters from running on tests files. - - path: _test\.go - linters: - - mnd - - funlen - - gocyclo - - errcheck - - dupl - - gosec - # Ignore long lines in generated code - - path: docs/ - linters: - - lll - # Allow local replacement directives in go.mod - - path: go\.mod - linters: - - gomoddirectives + - linters: + - dupl + - errcheck + - funlen + - gocyclo + - gosec + - mnd + path: _test\.go + - linters: + - lll + path: docs/ + - linters: + - mnd + path: integrationtests/ + - linters: + - gomoddirectives + path: go\.mod + paths: + - third_party$ + - builtin$ + - examples$ +formatters: + enable: + - gci + - gofmt + - goimports + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 21541693..6e2143fd 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,9 +10,9 @@ MCP Registry is a community-driven registry service for Model Context Protocol ( ### Prerequisites - **Go 1.23.x** - The project requires this specific version (check with `go version`) - Consider using a Go version manager like `g` or `gvm` if you work on multiple projects -- **golangci-lint v1.61.0** - Install with: +- **golangci-lint v2.3.1** - Install with: ```bash - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.3.1 ``` ### Git Hooks (Optional) @@ -72,7 +72,7 @@ gofmt -s -l . gofmt -s -w . ``` -**Note**: The project uses golangci-lint v1.61.0 with 62 enabled linters. Always run linting locally before pushing to avoid CI failures. +**Note**: The project uses golangci-lint v2.3.1 with 62 enabled linters. Always run linting locally before pushing to avoid CI failures. ## Architecture Overview diff --git a/README.md b/README.md index 82b26aa6..6210cc63 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,9 @@ The MCP Registry service provides a centralized repository for MCP server entrie - Docker (optional, but recommended for development) For development: -- golangci-lint v1.61.0 - Install with: +- golangci-lint v2.3.1 - Install with: ```bash - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.61.0 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.3.1 ``` ## Running diff --git a/internal/api/handlers/v0/publish_test.go b/internal/api/handlers/v0/publish_test.go index 414c6be1..deedf8d7 100644 --- a/internal/api/handlers/v0/publish_test.go +++ b/internal/api/handlers/v0/publish_test.go @@ -23,17 +23,17 @@ type MockRegistryService struct { } func (m *MockRegistryService) List(cursor string, limit int) ([]model.Server, string, error) { - args := m.Mock.Called(cursor, limit) + args := m.Called(cursor, limit) return args.Get(0).([]model.Server), args.String(1), args.Error(2) } func (m *MockRegistryService) GetByID(id string) (*model.ServerDetail, error) { - args := m.Mock.Called(id) + args := m.Called(id) return args.Get(0).(*model.ServerDetail), args.Error(1) } func (m *MockRegistryService) Publish(serverDetail *model.ServerDetail) error { - args := m.Mock.Called(serverDetail) + args := m.Called(serverDetail) return args.Error(0) } @@ -45,17 +45,17 @@ type MockAuthService struct { func (m *MockAuthService) StartAuthFlow( ctx context.Context, method model.AuthMethod, repoRef string, ) (map[string]string, string, error) { - args := m.Mock.Called(ctx, method, repoRef) + args := m.Called(ctx, method, repoRef) return args.Get(0).(map[string]string), args.String(1), args.Error(2) } func (m *MockAuthService) CheckAuthStatus(ctx context.Context, statusToken string) (string, error) { - args := m.Mock.Called(ctx, statusToken) + args := m.Called(ctx, statusToken) return args.String(0), args.Error(1) } func (m *MockAuthService) ValidateAuth(ctx context.Context, authentication model.Authentication) (bool, error) { - args := m.Mock.Called(ctx, authentication) + args := m.Called(ctx, authentication) return args.Bool(0), args.Error(1) } @@ -416,8 +416,8 @@ func TestPublishHandler(t *testing.T) { } // Assert that all expectations were met - mockRegistry.Mock.AssertExpectations(t) - mockAuthService.Mock.AssertExpectations(t) + mockRegistry.AssertExpectations(t) + mockAuthService.AssertExpectations(t) }) } } @@ -487,7 +487,7 @@ func TestPublishHandlerBearerTokenParsing(t *testing.T) { handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusCreated, rr.Code) - mockAuthService.Mock.AssertExpectations(t) + mockAuthService.AssertExpectations(t) }) } } @@ -552,7 +552,7 @@ func TestPublishHandlerAuthMethodSelection(t *testing.T) { handler.ServeHTTP(rr, req) assert.Equal(t, http.StatusCreated, rr.Code) - mockAuthService.Mock.AssertExpectations(t) + mockAuthService.AssertExpectations(t) }) } } @@ -639,9 +639,9 @@ func TestPublishIntegration(t *testing.T) { // Verify the server was actually published by retrieving it publishedServer, err := registryService.GetByID(response["id"]) require.NoError(t, err) - assert.Equal(t, publishReq.ServerDetail.Name, publishedServer.Name) - assert.Equal(t, publishReq.ServerDetail.Description, publishedServer.Description) - assert.Equal(t, publishReq.ServerDetail.VersionDetail.Version, publishedServer.VersionDetail.Version) + assert.Equal(t, publishReq.Name, publishedServer.Name) + assert.Equal(t, publishReq.Description, publishedServer.Description) + assert.Equal(t, publishReq.VersionDetail.Version, publishedServer.VersionDetail.Version) assert.Len(t, publishedServer.Packages, 1) assert.Len(t, publishedServer.Remotes, 1) }) diff --git a/internal/api/handlers/v0/servers.go b/internal/api/handlers/v0/servers.go index b2fc21f6..e3329417 100644 --- a/internal/api/handlers/v0/servers.go +++ b/internal/api/handlers/v0/servers.go @@ -60,12 +60,8 @@ func ServersHandler(registry service.RegistryService) http.HandlerFunc { return } - if parsedLimit > 100 { - // Cap maximum limit to prevent excessive queries - limit = 100 - } else { - limit = parsedLimit - } + // Cap maximum limit to prevent excessive queries + limit = min(parsedLimit, 100) } // Use the GetAll method to get paginated results diff --git a/internal/api/handlers/v0/servers_test.go b/internal/api/handlers/v0/servers_test.go index 380a3a6f..c0dd7f61 100644 --- a/internal/api/handlers/v0/servers_test.go +++ b/internal/api/handlers/v0/servers_test.go @@ -257,7 +257,7 @@ func TestServersHandler(t *testing.T) { } // Verify mock expectations - mockRegistry.Mock.AssertExpectations(t) + mockRegistry.AssertExpectations(t) }) } } @@ -321,7 +321,7 @@ func TestServersHandlerIntegration(t *testing.T) { assert.Empty(t, paginatedResp.Metadata.NextCursor) // Verify mock expectations - mockRegistry.Mock.AssertExpectations(t) + mockRegistry.AssertExpectations(t) } // TestServersDetailHandlerIntegration tests the servers detail handler with actual HTTP requests @@ -387,5 +387,5 @@ func TestServersDetailHandlerIntegration(t *testing.T) { assert.Equal(t, *serverDetail, serverDetailResp) // Verify mock expectations - mockRegistry.Mock.AssertExpectations(t) + mockRegistry.AssertExpectations(t) } diff --git a/internal/database/memory.go b/internal/database/memory.go index 6cd6cb01..bb077cb4 100644 --- a/internal/database/memory.go +++ b/internal/database/memory.go @@ -48,10 +48,7 @@ func compareSemanticVersions(version1, version2 string) int { parts2 := strings.Split(version2, ".") // Pad with zeros if needed - maxLen := len(parts1) - if len(parts2) > maxLen { - maxLen = len(parts2) - } + maxLen := max(len(parts2), len(parts1)) for len(parts1) < maxLen { parts1 = append(parts1, "0") @@ -162,10 +159,7 @@ func (db *MemoryDB) List( }) // Apply pagination - endIdx := startIdx + limit - if endIdx > len(filteredEntries) { - endIdx = len(filteredEntries) - } + endIdx := min(startIdx+limit, len(filteredEntries)) var result []*model.Server if startIdx < len(filteredEntries) {