{"record":{"id":"bc1e8cbc43d1469c","repo":"Tencent/WeKnora","slug":"oauth-repository-is-required-for-oauth-mcp-service","errorCode":null,"errorMessage":"OAuth repository is required for OAuth MCP services","messagePattern":"OAuth repository is required for OAuth MCP services","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/mcp/client.go","lineNumber":259,"sourceCode":"\t\t\t*config.Service.URL,\n\t\t\toauthConfig,\n\t\t)\n\t}\n\tmcpClient.OnConnectionLost(instance.onConnectionLost)\n\treturn instance, nil\n}\n\n// buildOAuthConfig returns the OAuth configuration for an OAuth-enabled MCP\n// service, or (_, false, nil) when the service does not use OAuth. It loads\n// the dynamically-registered client_id and wires a per-user token store so\n// the transport injects the invoking user's bearer token and refreshes it.\nfunc buildOAuthConfig(config *ClientConfig, httpClient *http.Client) (transport.OAuthConfig, bool, error) {\n\tsvc := config.Service\n\tif !svc.AuthConfig.IsOAuth() {\n\t\treturn transport.OAuthConfig{}, false, nil\n\t}\n\tif config.OAuthRepo == nil {\n\t\treturn transport.OAuthConfig{}, false, fmt.Errorf(\"OAuth repository is required for OAuth MCP services\")\n\t}\n\tprincipal := config.Principal.Normalize()\n\tif !principal.Valid() && config.UserID != \"\" {\n\t\tprincipal = types.Principal{Type: types.PrincipalWebUser, ID: config.UserID}.Normalize()\n\t}\n\tif !principal.Valid() {\n\t\treturn transport.OAuthConfig{}, false, fmt.Errorf(\"principal context is required to connect to an OAuth MCP service\")\n\t}\n\tconfig.Principal = principal\n\n\toauthCfg := transport.OAuthConfig{\n\t\tScopes:                svc.AuthConfig.Scopes,\n\t\tTokenStore:            newManagedTokenStore(config.OAuthRepo, config.TenantID, principal, svc.ID),\n\t\tPKCEEnabled:           true,\n\t\tAuthServerMetadataURL: svc.AuthConfig.AuthServerMetadataURL,\n\t\tHTTPClient:            httpClient,\n\t}\n\tif regClient, err := config.OAuthRepo.GetClient(context.Background(), config.TenantID, svc.ID); err == nil && regClient != nil {","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/mcp/client.go#L241-L277","documentation":"buildOAuthConfig requires an OAuth repository to hold dynamically-registered OAuth clients and per-user tokens. When the service's AuthConfig is OAuth but ClientConfig.OAuthRepo is nil, the client cannot persist tokens, so it refuses to construct rather than failing later mid-flow.","triggerScenarios":"NewMCPClient called for a service whose AuthConfig.IsOAuth() is true while config.OAuthRepo was left nil.","commonSituations":"Caller wired up the ClientConfig without the OAuth repository dependency (DI not initialized in tests/CLI tools); OAuth enabled on the service after the calling code was written; test harness constructing ClientConfig by hand without the repo.","solutions":["Pass a non-nil OAuthRepo in ClientConfig when the service uses OAuth auth","Initialize the OAuth repository before building the client (DI container / store bootstrap)","Or remove the OAuth auth strategy from the service if token-based OAuth is not intended"],"exampleFix":"// before\ncfg := &ClientConfig{Service: svc, TenantID: tid, Principal: p} // OAuthRepo missing\n// after\ncfg := &ClientConfig{Service: svc, TenantID: tid, Principal: p, OAuthRepo: oauthRepo}\nif svc.AuthConfig.IsOAuth() && cfg.OAuthRepo == nil {\n    return nil, fmt.Errorf(\"OAuthRepo must be set for OAuth services\")\n}","handlingStrategy":"validation","validationCode":"func requireOAuthRepo(cfg *ClientConfig) error {\n    if cfg.Service != nil && cfg.Service.AuthConfig.IsOAuth() && cfg.OAuthRepo == nil {\n        return errors.New(\"OAuthRepo is required for OAuth MCP services\")\n    }\n    return nil\n}","typeGuard":"func needsOAuthRepo(cfg *ClientConfig) bool {\n    return cfg != nil && cfg.Service != nil && cfg.Service.AuthConfig.IsOAuth()\n}","tryCatchPattern":"_, err := NewMCPClient(cfg)\nif err != nil && strings.Contains(err.Error(), \"OAuth repository is required\") {\n    return fmt.Errorf(\"dependency wiring bug: OAuthRepo not provided for OAuth service %s\", cfg.Service.ID)\n}","preventionTips":["Make OAuthRepo a mandatory constructor dependency when OAuth is enabled","Add unit tests asserting ClientConfig completeness for OAuth services","Fail fast at DI bootstrap if the OAuth repo store is unconfigured"],"tags":["go","mcp","oauth","configuration"],"backgroundTag":"missing-dependency","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}