diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index f9c4940..d6d211a 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -48,29 +48,122 @@ {"id":"mcp-51r.8","title":"Migrate handleRefreshTokenGrant to use OAuth.Types newtypes","description":"Migrate handleRefreshTokenGrant handler in src/MCP/Server/HTTP.hs:1107 to use OAuth.Types newtypes.\n\nCURRENT SIGNATURE:\nhandleRefreshTokenGrant :: JWTSettings -\u003e HTTPServerConfig -\u003e IOTracer HTTPTrace -\u003e TVar OAuthState -\u003e Map Text Text -\u003e Handler TokenResponse\n\nTYPE CHANGES (form params -\u003e newtypes):\n- grant_type: Text -\u003e GrantType (should be GrantRefreshToken)\n- refresh_token: Text -\u003e RefreshTokenId\n- client_id: Text -\u003e ClientId (if present)\n\nINTERNAL PROCESSING:\n- Lookup in refreshTokens map should use RefreshTokenId key\n- New refresh token generation should produce RefreshTokenId\n\nCOMPLEXITY: Low (few field changes, similar pattern to handleAuthCodeGrant)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-11T22:13:44.790088951+01:00","updated_at":"2025-12-11T23:05:53.512703408+01:00","closed_at":"2025-12-11T23:05:53.512703408+01:00","labels":["handler:refresh","phase:migration"],"dependencies":[{"issue_id":"mcp-51r.8","depends_on_id":"mcp-51r","type":"parent-child","created_at":"2025-12-11T22:13:44.79129163+01:00","created_by":"daemon"},{"issue_id":"mcp-51r.8","depends_on_id":"mcp-51r.1","type":"blocks","created_at":"2025-12-11T22:14:28.352863834+01:00","created_by":"daemon"}]} {"id":"mcp-51r.9","title":"Migrate handleMetadata and handleProtectedResourceMetadata to use OAuth.Types","description":"Migrate metadata handlers in src/MCP/Server/HTTP.hs:676,684 to ensure consistent type usage.\n\nHANDLERS:\n- handleProtectedResourceMetadata :: HTTPServerConfig -\u003e Handler ProtectedResourceMetadata\n- handleMetadata :: HTTPServerConfig -\u003e Handler OAuthMetadata\n\nThese handlers primarily return configuration data. Check if any internal types need migration:\n- Scopes in metadata responses\n- Grant types in metadata responses\n- Response types in metadata responses\n\nEXISTING PROOF-OF-CONCEPT:\nhandleMetadataAppM (line 745) already uses typeclass constraints pattern.\nMay serve as reference for migration pattern.\n\nCOMPLEXITY: Low (mostly response type fields, not input parsing)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-11T22:13:55.363764843+01:00","updated_at":"2025-12-11T23:20:29.540097127+01:00","closed_at":"2025-12-11T23:20:29.540097127+01:00","labels":["handler:metadata","phase:migration"],"dependencies":[{"issue_id":"mcp-51r.9","depends_on_id":"mcp-51r","type":"parent-child","created_at":"2025-12-11T22:13:55.365620245+01:00","created_by":"daemon"},{"issue_id":"mcp-51r.9","depends_on_id":"mcp-51r.1","type":"blocks","created_at":"2025-12-11T22:14:28.362939968+01:00","created_by":"daemon"}]} {"id":"mcp-55k","title":"T006: Create ServerTrace skeleton in src/MCP/Trace/Server.hs","description":"[P] Create MCP.Trace.Server module with ServerTrace type (composite placeholder only) and renderServerTrace stub. Ref: data-model.md ServerTrace section.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T11:33:35.697634413+01:00","updated_at":"2025-12-10T12:17:35.551473295+01:00","closed_at":"2025-12-10T12:17:35.551473295+01:00"} -{"id":"mcp-5wk","title":"Epic: Remove MCP Imports from Servant.OAuth2.IDP","description":"Prepare Servant.OAuth2.IDP.* modules for extraction to separate package by removing all MCP.* dependencies. Pure refactoring: move types to new Servant modules, use explicit record parameters, clean break with no backwards-compatibility re-exports. See /home/claude/workspace/specs/005-servant-oauth-extraction for full specification.","status":"open","priority":1,"issue_type":"epic","created_at":"2025-12-18T20:08:49.968197161+01:00","updated_at":"2025-12-18T20:08:49.968197161+01:00","labels":["feature:005-servant-oauth-extraction"]} -{"id":"mcp-5wk.1","title":"Create Servant.OAuth2.IDP.Trace module with OAuthTrace ADT","description":"WHERE: src/Servant/OAuth2/IDP/Trace.hs (NEW FILE)\nWHAT: Create OAuthTrace ADT for OAuth-specific trace events. Constructors: TraceClientRegistration, TraceAuthorizationRequest, TraceLoginPageServed, TraceLoginAttempt, TracePKCEValidation, TraceAuthorizationGranted, TraceAuthorizationDenied, TraceTokenExchange, TraceTokenRefresh, TraceSessionExpired, TraceValidationError.\nWHY: Enables Servant OAuth handlers to emit traces without depending on MCP.Trace.* modules.\nHOW: Define ADT with Show, Eq deriving. Import types from Servant.OAuth2.IDP.Types (ClientId, SessionId, etc.). Add renderOAuthTrace :: OAuthTrace -\u003e Text function.","status":"open","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:06.617950127+01:00","updated_at":"2025-12-18T20:09:06.617950127+01:00","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.1","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:06.61901111+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.10","title":"Update Handlers/Helpers.hs - use OAuthEnv for config access","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Helpers.hs\nWHAT: Replace MCP imports with Servant imports. Use OAuthEnv for authCodePrefix, refreshTokenPrefix.\nWHY: Helper functions access config for token generation prefixes. Must use OAuthEnv instead.\nHOW: 1) Replace MCP.Server.Auth import with Servant.OAuth2.IDP.Config. 2) Replace MCP.Server.HTTP.AppEnv import removal. 3) Update functions using config: change httpOAuthConfig access pattern to direct OAuthEnv field access (oauthAuthCodePrefix, oauthRefreshTokenPrefix).","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:21.083199513+01:00","updated_at":"2025-12-18T20:10:21.083199513+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.10","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:21.085386043+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.10","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.754720779+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.11","title":"Update Handlers/Registration.hs - use OAuthEnv and OAuthTrace","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Registration.hs\nWHAT: Replace MCP imports. Use OAuthEnv for clientIdPrefix. Use OAuthTrace for trace emission.\nWHY: Registration handler emits TraceClientRegistration trace and accesses clientIdPrefix config.\nHOW: 1) Replace MCP.Server.Auth import with Servant.OAuth2.IDP.Config for OAuthEnv. 2) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 3) Update handler signature: HasType OAuthEnv env, HasType (IOTracer OAuthTrace) env. 4) Update config access: oauthClientIdPrefix. 5) Update trace: TraceClientRegistration.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:31.973620747+01:00","updated_at":"2025-12-18T20:10:31.973620747+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:31.97593652+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.772457534+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.789525983+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.12","title":"Update Handlers/Authorization.hs - use OAuthEnv, OAuthTrace, and Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Authorization.hs\nWHAT: Replace all MCP imports. Use OAuthEnv, OAuthTrace, and direct MonadTime import.\nWHY: Authorization handler is central to OAuth flow. Emits multiple traces, accesses config, uses MonadTime.\nHOW: 1) Replace MCP.Server.Time with Control.Monad.Time. 2) Replace MCP.Server.Auth/HTTP.AppEnv with Servant.OAuth2.IDP.Config. 3) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 4) Update handler signature constraints. 5) Update config access patterns. 6) Update trace emissions: TraceAuthorizationRequest, TraceAuthorizationGranted, TraceAuthorizationDenied.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:39.266519488+01:00","updated_at":"2025-12-18T20:10:39.266519488+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:39.269269354+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.807054721+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.826439007+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.13","title":"Update Handlers/Login.hs - use OAuthEnv, OAuthTrace, and Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Login.hs\nWHAT: Replace all MCP imports. Use OAuthEnv, OAuthTrace, and direct MonadTime import.\nWHY: Login handler emits TraceLoginPageServed, TraceLoginAttempt traces and accesses session expiry config.\nHOW: 1) Replace MCP.Server.Time with Control.Monad.Time. 2) Replace MCP.Server.Auth/HTTP.AppEnv with Servant.OAuth2.IDP.Config. 3) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 4) Update handler signature constraints. 5) Update config access: oauthLoginSessionExpiry. 6) Update trace emissions: TraceLoginPageServed, TraceLoginAttempt.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:48.406904308+01:00","updated_at":"2025-12-18T20:10:48.406904308+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:48.408977515+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.842116284+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.858199875+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.14","title":"Update Server.hs - use OAuthEnv and OAuthTrace type constraints","description":"WHERE: src/Servant/OAuth2/IDP/Server.hs\nWHAT: Replace MCP imports. Update server composition to use OAuthEnv and OAuthTrace constraints.\nWHY: Server.hs composes handlers and exports the server. Type constraints must match handler signatures.\nHOW: 1) Replace MCP.Server.HTTP.AppEnv import with Servant.OAuth2.IDP.Config. 2) Replace MCP.Trace.HTTP import with Servant.OAuth2.IDP.Trace. 3) Update oauthServer type signature: HasType OAuthEnv env, HasType (IOTracer OAuthTrace) env.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:55.943727027+01:00","updated_at":"2025-12-18T20:10:55.943727027+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:55.944951898+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.875240833+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.891783627+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.15","title":"Update Test/Internal.hs - fix doc comment typo and MonadTime import","description":"WHERE: src/Servant/OAuth2/IDP/Test/Internal.hs\nWHAT: 1) Fix doc comment at line 7 from 'Module : MCP.Server.OAuth.Test.Internal' to 'Module : Servant.OAuth2.IDP.Test.Internal'. 2) Fix usage example at line 22 to use correct module name. 3) Replace MCP.Server.Time import with Control.Monad.Time.\nWHY: Doc comments have stale module name causing confusion. MonadTime import should be direct.\nHOW: 1) Line 7: change 'MCP.Server.OAuth.Test.Internal' to 'Servant.OAuth2.IDP.Test.Internal'. 2) Line 22: same change in example. 3) Replace import MCP.Server.Time with import Control.Monad.Time.","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-18T20:11:04.923136551+01:00","updated_at":"2025-12-18T20:11:04.923136551+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.15","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:04.925017881+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.16","title":"Add OAuthEnv field to AppEnv and create mkOAuthEnv adapter","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: 1) Add envOAuthEnv :: OAuthEnv field to AppEnv record. 2) Create mkOAuthEnv :: HTTPServerConfig -\u003e OAuthEnv function to build OAuthEnv from existing config.\nWHY: MCP handlers use OAuthEnv-constrained Servant handlers. AppEnv must provide OAuthEnv via HasType.\nHOW: 1) Import Servant.OAuth2.IDP.Config (OAuthEnv (..)). 2) Add field to AppEnv record. 3) Implement mkOAuthEnv: extract httpBaseUrl, unwrap httpOAuthConfig with defaults, map fields (authCodeExpirySeconds -\u003e fromIntegral -\u003e oauthAuthCodeExpiry, etc.). 4) Generic instance auto-generates HasType OAuthEnv AppEnv.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:15.689690037+01:00","updated_at":"2025-12-18T20:11:15.689690037+01:00","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.16","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:15.691412599+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.16","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:47.80398682+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.17","title":"Create mkOAuthTracer adapter function for trace type conversion","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: Create mkOAuthTracer :: IOTracer HTTPTrace -\u003e IOTracer OAuthTrace using contramap.\nWHY: Servant handlers emit OAuthTrace events but MCP uses HTTPTrace. Need adapter to convert at boundary.\nHOW: 1) Import Servant.OAuth2.IDP.Trace (OAuthTrace). 2) Import Data.Functor.Contravariant (contramap). 3) Define mkOAuthTracer = contramap HTTPOAuth - wraps each OAuthTrace in HTTPOAuth constructor before emission.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:24.964321457+01:00","updated_at":"2025-12-18T20:11:24.964321457+01:00","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.17","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:24.965812438+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.17","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:47.824087887+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.18","title":"Update MCP HTTP server to construct AppEnv with OAuthEnv","description":"WHERE: src/MCP/Server/HTTP.hs (or wherever AppEnv is constructed)\nWHAT: Update AppEnv construction to include envOAuthEnv field using mkOAuthEnv.\nWHY: AppEnv must be complete with all fields for HTTP server to start.\nHOW: Find where AppEnv is constructed (likely in HTTP.hs or main). Add envOAuthEnv = mkOAuthEnv config to the record construction. Ensure mkOAuthEnv is imported from AppEnv module.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:32.723421047+01:00","updated_at":"2025-12-18T20:11:32.723421047+01:00","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.18","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:32.724887672+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.19","title":"Remove moved types from MCP.Server.Auth exports","description":"WHERE: src/MCP/Server/Auth.hs\nWHAT: Remove exports and implementations of types/functions that moved to Servant: OAuthMetadata, ProtectedResourceMetadata, validateCodeVerifier, generateCodeChallenge.\nWHY: Clean break - no backwards-compatibility re-exports. MCP.Server.Auth should only contain MCP-specific types.\nHOW: 1) Remove from export list: OAuthMetadata (..), ProtectedResourceMetadata (..), validateCodeVerifier, generateCodeChallenge. 2) Remove type definitions (data OAuthMetadata, data ProtectedResourceMetadata). 3) Remove JSON instances for those types. 4) Remove function implementations (validateCodeVerifier, generateCodeChallenge). 5) Remove now-unused imports (cryptonite, base64-bytestring if only used by removed functions).","status":"open","priority":2,"issue_type":"task","created_at":"2025-12-18T20:11:42.987274484+01:00","updated_at":"2025-12-18T20:11:42.987274484+01:00","labels":["phase:d-clean-break"],"dependencies":[{"issue_id":"mcp-5wk.19","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:42.988403041+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.2","title":"Create Servant.OAuth2.IDP.Config module with OAuthEnv record","description":"WHERE: src/Servant/OAuth2/IDP/Config.hs (NEW FILE)\nWHAT: Define OAuthEnv record with protocol-agnostic OAuth configuration. Fields: oauthBaseUrl :: Text, oauthAuthCodeExpiry :: NominalDiffTime, oauthAccessTokenExpiry :: NominalDiffTime, oauthLoginSessionExpiry :: NominalDiffTime, oauthAuthCodePrefix :: Text, oauthRefreshTokenPrefix :: Text, oauthClientIdPrefix :: Text, oauthSupportedScopes :: [Scope], oauthSupportedResponseTypes :: [ResponseType], oauthSupportedGrantTypes :: [GrantType], oauthSupportedAuthMethods :: [ClientAuthMethod], oauthSupportedCodeChallengeMethods :: [CodeChallengeMethod].\nWHY: Replaces HasType HTTPServerConfig constraint in handlers with HasType OAuthEnv - no MCP dependency.\nHOW: Import types from Servant.OAuth2.IDP.Types. Add Generic deriving for generic-lens compatibility. Optionally add mkOAuthEnv smart constructor with sensible defaults.","status":"open","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:15.224752162+01:00","updated_at":"2025-12-18T20:09:15.224752162+01:00","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.2","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:15.225941125+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.20","title":"Verify no MCP imports in Servant modules","description":"WHERE: src/Servant/**/*.hs\nWHAT: Run verification command to ensure no MCP imports remain in Servant namespace.\nWHY: Primary acceptance criterion - Servant modules must be MCP-independent.\nHOW: Run: rg '^import MCP\\.' src/Servant/ - should return empty. If any matches found, fix the remaining imports in those files.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:51.04522668+01:00","updated_at":"2025-12-18T20:11:51.04522668+01:00","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.20","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:51.046965163+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.20","depends_on_id":"mcp-5wk.19","type":"blocks","created_at":"2025-12-18T20:12:47.841317393+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.21","title":"Verify cabal build succeeds","description":"WHERE: Project root\nWHAT: Run cabal build and ensure it succeeds without errors.\nWHY: Build must pass after refactoring - no missing modules, no type errors.\nHOW: Run: cabal build. Fix any compilation errors. Common issues: missing imports, type mismatches in handler signatures, missing module in cabal file.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:12:01.155334066+01:00","updated_at":"2025-12-18T20:12:01.155334066+01:00","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.21","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:12:01.157258941+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.21","depends_on_id":"mcp-5wk.20","type":"blocks","created_at":"2025-12-18T20:12:47.860694392+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.22","title":"Verify cabal test passes","description":"WHERE: Project root\nWHAT: Run cabal test and ensure all existing tests pass.\nWHY: Pure refactoring should not change behavior. All existing tests must still pass.\nHOW: Run: cabal test. Fix any test failures. Failures indicate behavior changed unexpectedly.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:12:07.62322988+01:00","updated_at":"2025-12-18T20:12:07.62322988+01:00","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.22","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:12:07.625325676+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.22","depends_on_id":"mcp-5wk.21","type":"blocks","created_at":"2025-12-18T20:12:47.882234471+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.3","title":"Create Servant.OAuth2.IDP.Metadata module with OAuthMetadata and ProtectedResourceMetadata","description":"WHERE: src/Servant/OAuth2/IDP/Metadata.hs (NEW FILE)\nWHAT: Move OAuthMetadata (RFC 8414) and ProtectedResourceMetadata (RFC 9728) types from MCP.Server.Auth to this new module. Include all JSON instances.\nWHY: API.hs and Handlers/Metadata.hs need these types but should not import from MCP.\nHOW: Copy type definitions and FromJSON/ToJSON instances from MCP.Server.Auth. Use snake_case JSON keys per RFC 8414/9728. Import Scope, ResponseType, GrantType, etc. from Servant.OAuth2.IDP.Types.","status":"open","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:23.673044465+01:00","updated_at":"2025-12-18T20:09:23.673044465+01:00","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.3","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:23.674656056+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.4","title":"Create Servant.OAuth2.IDP.PKCE module with validation functions","description":"WHERE: src/Servant/OAuth2/IDP/PKCE.hs (NEW FILE)\nWHAT: Move PKCE validation functions from MCP.Server.Auth: validateCodeVerifier :: CodeVerifier -\u003e CodeChallenge -\u003e Bool, generateCodeChallenge :: Text -\u003e Text.\nWHY: Token.hs handler needs PKCE validation but should not import from MCP.Server.Auth.\nHOW: Copy functions from MCP.Server.Auth. Use cryptonite for SHA256, base64-bytestring for B64URL encoding. Import CodeVerifier, CodeChallenge from Servant.OAuth2.IDP.Types. Pure functions only - no IO.","status":"open","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:30.961000538+01:00","updated_at":"2025-12-18T20:09:30.961000538+01:00","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.4","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:30.962835327+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.5","title":"Update mcp-haskell.cabal with new Servant.OAuth2.IDP modules","description":"WHERE: mcp-haskell.cabal\nWHAT: Add new modules to exposed-modules list: Servant.OAuth2.IDP.Trace, Servant.OAuth2.IDP.Config, Servant.OAuth2.IDP.Metadata, Servant.OAuth2.IDP.PKCE.\nWHY: New modules must be registered in cabal file for build to succeed.\nHOW: Add to exposed-modules section in alphabetical order with existing Servant.OAuth2.IDP.* modules.","status":"open","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:37.877486488+01:00","updated_at":"2025-12-18T20:09:37.877486488+01:00","labels":["phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.5","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:37.879613797+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.6","title":"Update Store.hs and Store/InMemory.hs - replace MCP.Server.Time with Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Store.hs, src/Servant/OAuth2/IDP/Store/InMemory.hs\nWHAT: Replace 'import MCP.Server.Time (MonadTime (..))' with 'import Control.Monad.Time (MonadTime (..))'.\nWHY: MCP.Server.Time is just a thin re-export. Direct import from monad-time package removes MCP dependency.\nHOW: Simple find-replace in both files. monad-time is already a transitive dependency.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:09:45.709194204+01:00","updated_at":"2025-12-18T20:09:45.709194204+01:00","labels":["parallel:true","phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.6","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:45.710537517+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.7","title":"Update API.hs - import Metadata from Servant.OAuth2.IDP.Metadata","description":"WHERE: src/Servant/OAuth2/IDP/API.hs\nWHAT: Replace 'import MCP.Server.Auth (OAuthMetadata, ProtectedResourceMetadata)' with 'import Servant.OAuth2.IDP.Metadata (OAuthMetadata, ProtectedResourceMetadata)'.\nWHY: API.hs defines the Servant API type which includes metadata endpoints. Types must come from Servant namespace.\nHOW: Change import statement. Types and JSON instances are identical.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:09:52.950806611+01:00","updated_at":"2025-12-18T20:09:52.950806611+01:00","labels":["parallel:true","phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.7","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:52.952842344+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.8","title":"Update Handlers/Metadata.hs - use Servant Metadata types and OAuthEnv","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Metadata.hs\nWHAT: Replace MCP imports with Servant imports. Change HasType HTTPServerConfig env to HasType OAuthEnv env.\nWHY: Metadata handler constructs OAuthMetadata response using config values. Must use OAuthEnv instead.\nHOW: 1) Replace MCP.Server.Auth imports with Servant.OAuth2.IDP.Metadata. 2) Replace MCP.Server.HTTP.AppEnv import with Servant.OAuth2.IDP.Config. 3) Update handler signature: HasType OAuthEnv env. 4) Update field access: use oauthBaseUrl, oauthSupportedScopes, etc. from OAuthEnv.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:02.563440081+01:00","updated_at":"2025-12-18T20:10:02.563440081+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:02.565078596+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk.3","type":"blocks","created_at":"2025-12-18T20:12:21.327900887+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:21.367469395+01:00","created_by":"daemon"}]} -{"id":"mcp-5wk.9","title":"Update Handlers/Token.hs - use PKCE from Servant.OAuth2.IDP.PKCE and OAuthEnv/OAuthTrace","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Token.hs\nWHAT: Replace MCP imports. Use validateCodeVerifier from Servant.OAuth2.IDP.PKCE. Use OAuthEnv and OAuthTrace.\nWHY: Token handler validates PKCE and emits traces. Must not depend on MCP modules.\nHOW: 1) Replace MCP.Server.Auth imports with Servant.OAuth2.IDP.PKCE for validateCodeVerifier. 2) Import OAuthEnv from Servant.OAuth2.IDP.Config. 3) Import OAuthTrace from Servant.OAuth2.IDP.Trace. 4) Replace HasType HTTPServerConfig with HasType OAuthEnv. 5) Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). 6) Update trace emissions to use OAuthTrace constructors.","status":"open","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:11.105498164+01:00","updated_at":"2025-12-18T20:10:11.105498164+01:00","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:11.106689977+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.4","type":"blocks","created_at":"2025-12-18T20:12:21.348386054+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:21.385221409+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:21.406470244+01:00","created_by":"daemon"}]} +{"id":"mcp-5pf","title":"Add oauthServerName and oauthScopeDescriptions to OAuthEnv (Q17)","description":"WHERE: src/Servant/OAuth2/IDP/Config.hs (OAuthEnv type)\n\nWHAT: Add configurable branding fields to OAuthEnv per clarification Q17:\n- oauthServerName :: Text (for HTML titles like 'Sign In - {serverName}')\n- oauthScopeDescriptions :: Map Scope Text (for consent page scope descriptions)\n\nWHY: Removes hardcoded 'MCP Server' branding from Servant modules, enabling package-independent OAuth server.\n\nHOW:\n1. Add to OAuthEnv record in Config.hs:\n oauthServerName :: Text\n oauthScopeDescriptions :: Map Scope Text\n2. Update defaultOAuthEnv (if exists) with sensible defaults:\n oauthServerName = 'OAuth Server'\n oauthScopeDescriptions = mempty\n3. Import Data.Map (Map) if not already imported\n4. Update any OAuthEnv construction sites\n\nVERIFY: cabal build succeeds","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T19:48:36.191676586+01:00","updated_at":"2025-12-19T20:42:18.076758783+01:00","closed_at":"2025-12-19T20:42:18.076758783+01:00","close_reason":"Task already completed in commit 32e5214. Added oauthServerName and oauthScopeDescriptions fields to OAuthEnv with comprehensive test coverage. All tests passing (493/493), build successful.","labels":["clarification:Q17","phase:foundational"],"dependencies":[{"issue_id":"mcp-5pf","depends_on_id":"mcp-5wk","type":"discovered-from","created_at":"2025-12-19T19:48:36.199581565+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk","title":"Epic: Remove MCP Imports from Servant.OAuth2.IDP","description":"Prepare Servant.OAuth2.IDP.* modules for extraction to separate package by removing all MCP.* dependencies. Pure refactoring: move types to new Servant modules, use explicit record parameters, clean break with no backwards-compatibility re-exports. See /home/claude/workspace/specs/005-servant-oauth-extraction for full specification.","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-12-18T20:08:49.968197161+01:00","updated_at":"2025-12-22T10:26:26.832312913+01:00","labels":["feature:005-servant-oauth-extraction"]} +{"id":"mcp-5wk.1","title":"Create Servant.OAuth2.IDP.Trace module with OAuthTrace ADT","description":"WHERE: src/Servant/OAuth2/IDP/Trace.hs (NEW FILE)\nWHAT: Create OAuthTrace ADT for OAuth-specific trace events. Constructors: TraceClientRegistration, TraceAuthorizationRequest, TraceLoginPageServed, TraceLoginAttempt, TracePKCEValidation, TraceAuthorizationGranted, TraceAuthorizationDenied, TraceTokenExchange, TraceTokenRefresh, TraceSessionExpired, TraceValidationError.\nWHY: Enables Servant OAuth handlers to emit traces without depending on MCP.Trace.* modules.\nHOW: Define ADT with Show, Eq deriving. Import types from Servant.OAuth2.IDP.Types (ClientId, SessionId, etc.). Add renderOAuthTrace :: OAuthTrace -\u003e Text function.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:06.617950127+01:00","updated_at":"2025-12-19T11:38:33.811259046+01:00","closed_at":"2025-12-19T11:38:33.811259046+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.1","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:06.61901111+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.10","title":"Update Handlers/Helpers.hs - use OAuthEnv for config access","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Helpers.hs\nWHAT: Replace MCP imports with Servant imports. Use OAuthEnv for authCodePrefix, refreshTokenPrefix.\nWHY: Helper functions access config for token generation prefixes. Must use OAuthEnv instead.\nHOW: 1) Replace MCP.Server.Auth import with Servant.OAuth2.IDP.Config. 2) Replace MCP.Server.HTTP.AppEnv import removal. 3) Update functions using config: change httpOAuthConfig access pattern to direct OAuthEnv field access (oauthAuthCodePrefix, oauthRefreshTokenPrefix).","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:21.083199513+01:00","updated_at":"2025-12-19T11:38:33.973130785+01:00","closed_at":"2025-12-19T11:38:33.973130785+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.10","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:21.085386043+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.10","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.754720779+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.100","title":"Delete domainErrorToServerError from MCP.Server.HTTP.AppEnv","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: 1) Remove domainErrorToServerError function (lines ~308-400). 2) Remove from module exports. 3) Remove unused imports (AsType prism helpers, Const, First if no longer needed). 4) Remove OAuthBoundaryTrace type if unused. 5) Clean up any orphaned helper functions.\nWHY: Legacy function replaced by oauthErrorToServerError in Servant namespace + appErrorToServerError in MCP. Eliminates MCP-specific code that was blocking package extraction.\nDONE WHEN: Function deleted, module compiles, no exports reference it, hlint clean.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T14:13:04.116076224+01:00","updated_at":"2025-12-22T15:28:16.092030237+01:00","closed_at":"2025-12-22T15:28:16.092030237+01:00","close_reason":"Deleted domainErrorToServerError function (123 lines), removed from exports, cleaned unused imports (OAuthBoundaryTrace, Const, First, Status, traceWith, OAuthErrorResponse). Build passes, 524 tests pass, hlint clean. Superseded by appErrorToServerError.","dependencies":[{"issue_id":"mcp-5wk.100","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T14:13:04.11776805+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.100","depends_on_id":"mcp-5wk.101","type":"blocks","created_at":"2025-12-22T14:13:38.388111053+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.101","title":"Update tests for oauthErrorToServerError","description":"WHERE: test/Laws/ErrorBoundarySecuritySpec.hs, test/MCP/Server/OAuth/BoundarySpec.hs\nWHAT: 1) Update imports: replace domainErrorToServerError with oauthErrorToServerError from Servant.OAuth2.IDP.Errors. 2) Update test cases to construct OAuthError m values directly instead of using AsType prisms. 3) For AuthBackendError tests: test appErrorToServerError from MCP.Server.HTTP.AppEnv instead. 4) Verify all security properties still hold (generic 500 for store errors, etc.).\nWHY: Tests must verify new error boundary functions maintain security properties.\nDONE WHEN: All tests pass, no references to domainErrorToServerError remain in test/, hlint clean.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T14:13:21.303036859+01:00","updated_at":"2025-12-22T15:22:29.464200863+01:00","closed_at":"2025-12-22T15:22:29.464200863+01:00","close_reason":"Tests migrated to appErrorToServerError. Removed domainErrorToServerError from tests, simplified assertions, removed tracer mocking. 524 tests pass, hlint clean, security properties preserved.","dependencies":[{"issue_id":"mcp-5wk.101","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T14:13:21.304589652+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.101","depends_on_id":"mcp-5wk.99","type":"blocks","created_at":"2025-12-22T14:13:38.325794005+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.102","title":"Bug: baseUrl CLI argument not threaded to defaultDemoOAuthBundle","description":"WHERE: src/MCP/Server/HTTP.hs:695-709 (defaultDemoOAuthBundle)\n\nWHAT: defaultDemoOAuthBundle is a pure function that hardcodes 'http://localhost:8080' for both baseUri (line 697) and baseUrlText (line 700). When user passes --base-url https://example.com via CLI, this value is NOT threaded to the bundle - resourceMetadata still uses hardcoded localhost URL.\n\nWHY: Causes 'Invalid hardcoded resource metadata in defaultDemoOAuthBundle' error because mkProtectedResourceMetadata fails when the actual server baseUrl doesn't match the hardcoded localhost URL in the metadata.\n\nREPRODUCTION:\n cabal run mcp-http -- --oauth --base-url https://mad.v.toscat.net\n → Error: Invalid hardcoded resource metadata in defaultDemoOAuthBundle\n\nROOT CAUSE: defaultDemoOAuthBundle :: DemoOAuthBundle takes no parameters. Need to either:\n 1. Make it defaultDemoOAuthBundle :: URI -\u003e DemoOAuthBundle (parameterize by baseUrl)\n 2. Or thread the httpBaseUrl from HTTPServerConfig through to bundle creation\n\nDONE WHEN:\n - defaultDemoOAuthBundle (or replacement) accepts baseUrl parameter\n - cabal run mcp-http -- --oauth --base-url https://example.com starts without error\n - resourceServerMetadata uses the provided baseUrl, not hardcoded localhost","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-12-22T17:29:00.16165512+01:00","updated_at":"2025-12-22T17:49:31.540106968+01:00","closed_at":"2025-12-22T17:49:31.540106968+01:00","close_reason":"Fixed baseUrl CLI argument threading to defaultDemoOAuthBundle. Implementation: (1) Created mkDemoOAuthBundle :: URI -\u003e DemoOAuthBundle parameterized function; (2) Created mkDemoOAuthBundleFromText :: Text -\u003e Maybe DemoOAuthBundle convenience wrapper; (3) Added mkProtectedResourceMetadataForDemo for HTTP URLs in demo mode; (4) Fixed login button action value regression. 3 commits: cc79868, fe6e977, 0664327. All 524 tests pass, hlint clean.","dependencies":[{"issue_id":"mcp-5wk.102","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T17:29:00.163190759+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.103","title":"Add type precision to ProtectedResourceMetadata","description":"WHERE: src/Servant/OAuth2/IDP/Metadata.hs (lines 267-322, 364-394)\n\nWHAT: Replace Text/[Text] with proper domain types per FR-004c:\n1. prResource :: Text → prResource :: URI (from Network.URI)\n2. prAuthorizationServers :: [Text] → prAuthorizationServers :: NonEmpty URI\n3. prBearerMethodsSupported :: Maybe [Text] → prBearerMethodsSupported :: Maybe (NonEmpty BearerMethod)\n4. Create data BearerMethod = BearerHeader | BearerBody | BearerUri per RFC 6750\n5. Update smart constructors (mkProtectedResourceMetadata, mkProtectedResourceMetadataForDemo) to accept typed params\n6. Update ToJSON/FromJSON instances for new types\n7. Update all call sites (likely in MCP.Server.HTTP, handlers)\n\nWHY: FR-004c mandates domain types flow throughout without Text conversions mid-flow. Session 2025-12-19 decided NonEmpty for RFC-mandated ≥1 fields.\n\nDONE WHEN:\n- rg 'FIXME' src/Servant/OAuth2/IDP/Metadata.hs returns empty\n- cabal build succeeds\n- hlint . returns zero hints\n- All existing tests pass","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-22T17:50:48.192514908+01:00","updated_at":"2025-12-22T18:23:23.787233118+01:00","closed_at":"2025-12-22T18:23:23.787233118+01:00","close_reason":"Implemented type precision for ProtectedResourceMetadata per FR-004c. Added BearerMethod ADT for RFC 6750, changed prResource to URI, prAuthorizationServers to NonEmpty URI. All 524 tests pass, hlint clean, no FIXME comments remain.","labels":["phase:polish","story:fr-004c"],"dependencies":[{"issue_id":"mcp-5wk.103","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T17:50:48.193944595+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.11","title":"Update Handlers/Registration.hs - use OAuthEnv and OAuthTrace","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Registration.hs\nWHAT: Replace MCP imports. Use OAuthEnv for clientIdPrefix. Use OAuthTrace for trace emission.\nWHY: Registration handler emits TraceClientRegistration trace and accesses clientIdPrefix config.\nHOW: 1) Replace MCP.Server.Auth import with Servant.OAuth2.IDP.Config for OAuthEnv. 2) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 3) Update handler signature: HasType OAuthEnv env, HasType (IOTracer OAuthTrace) env. 4) Update config access: oauthClientIdPrefix. 5) Update trace: TraceClientRegistration.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:31.973620747+01:00","updated_at":"2025-12-19T11:38:33.98920847+01:00","closed_at":"2025-12-19T11:38:33.98920847+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:31.97593652+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.772457534+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.11","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.789525983+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.12","title":"Update Handlers/Authorization.hs - use OAuthEnv, OAuthTrace, and Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Authorization.hs\nWHAT: Replace all MCP imports. Use OAuthEnv, OAuthTrace, and direct MonadTime import.\nWHY: Authorization handler is central to OAuth flow. Emits multiple traces, accesses config, uses MonadTime.\nHOW: 1) Replace MCP.Server.Time with Control.Monad.Time. 2) Replace MCP.Server.Auth/HTTP.AppEnv with Servant.OAuth2.IDP.Config. 3) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 4) Update handler signature constraints. 5) Update config access patterns. 6) Update trace emissions: TraceAuthorizationRequest, TraceAuthorizationGranted, TraceAuthorizationDenied.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:39.266519488+01:00","updated_at":"2025-12-19T11:38:34.00876219+01:00","closed_at":"2025-12-19T11:38:34.00876219+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:39.269269354+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.807054721+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.12","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.826439007+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.13","title":"Update Handlers/Login.hs - use OAuthEnv, OAuthTrace, and Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Login.hs\nWHAT: Replace all MCP imports. Use OAuthEnv, OAuthTrace, and direct MonadTime import.\nWHY: Login handler emits TraceLoginPageServed, TraceLoginAttempt traces and accesses session expiry config.\nHOW: 1) Replace MCP.Server.Time with Control.Monad.Time. 2) Replace MCP.Server.Auth/HTTP.AppEnv with Servant.OAuth2.IDP.Config. 3) Replace MCP.Trace imports with Servant.OAuth2.IDP.Trace. 4) Update handler signature constraints. 5) Update config access: oauthLoginSessionExpiry. 6) Update trace emissions: TraceLoginPageServed, TraceLoginAttempt.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:48.406904308+01:00","updated_at":"2025-12-19T11:38:34.02661953+01:00","closed_at":"2025-12-19T11:38:34.02661953+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:48.408977515+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.842116284+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.13","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.858199875+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.14","title":"Update Server.hs - use OAuthEnv and OAuthTrace type constraints","description":"WHERE: src/Servant/OAuth2/IDP/Server.hs\nWHAT: Replace MCP imports. Update server composition to use OAuthEnv and OAuthTrace constraints.\nWHY: Server.hs composes handlers and exports the server. Type constraints must match handler signatures.\nHOW: 1) Replace MCP.Server.HTTP.AppEnv import with Servant.OAuth2.IDP.Config. 2) Replace MCP.Trace.HTTP import with Servant.OAuth2.IDP.Trace. 3) Update oauthServer type signature: HasType OAuthEnv env, HasType (IOTracer OAuthTrace) env.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:55.943727027+01:00","updated_at":"2025-12-19T11:38:34.044337629+01:00","closed_at":"2025-12-19T11:38:34.044337629+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:55.944951898+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:30.875240833+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.14","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:30.891783627+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.15","title":"Update Test/Internal.hs - fix doc comment typo and MonadTime import","description":"WHERE: src/Servant/OAuth2/IDP/Test/Internal.hs\nWHAT: 1) Fix doc comment at line 7 from 'Module : MCP.Server.OAuth.Test.Internal' to 'Module : Servant.OAuth2.IDP.Test.Internal'. 2) Fix usage example at line 22 to use correct module name. 3) Replace MCP.Server.Time import with Control.Monad.Time.\nWHY: Doc comments have stale module name causing confusion. MonadTime import should be direct.\nHOW: 1) Line 7: change 'MCP.Server.OAuth.Test.Internal' to 'Servant.OAuth2.IDP.Test.Internal'. 2) Line 22: same change in example. 3) Replace import MCP.Server.Time with import Control.Monad.Time.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-18T20:11:04.923136551+01:00","updated_at":"2025-12-19T11:38:34.061941719+01:00","closed_at":"2025-12-19T11:38:34.061941719+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.15","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:04.925017881+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.16","title":"Add OAuthEnv field to AppEnv and create mkOAuthEnv adapter","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: 1) Add envOAuthEnv :: OAuthEnv field to AppEnv record. 2) Create mkOAuthEnv :: HTTPServerConfig -\u003e OAuthEnv function to build OAuthEnv from existing config.\nWHY: MCP handlers use OAuthEnv-constrained Servant handlers. AppEnv must provide OAuthEnv via HasType.\nHOW: 1) Import Servant.OAuth2.IDP.Config (OAuthEnv (..)). 2) Add field to AppEnv record. 3) Implement mkOAuthEnv: extract httpBaseUrl, unwrap httpOAuthConfig with defaults, map fields (authCodeExpirySeconds -\u003e fromIntegral -\u003e oauthAuthCodeExpiry, etc.). 4) Generic instance auto-generates HasType OAuthEnv AppEnv.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:15.689690037+01:00","updated_at":"2025-12-19T11:38:34.078603951+01:00","closed_at":"2025-12-19T11:38:34.078603951+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.16","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:15.691412599+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.16","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:47.80398682+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.17","title":"Create mkOAuthTracer adapter function for trace type conversion","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: Create mkOAuthTracer :: IOTracer HTTPTrace -\u003e IOTracer OAuthTrace using contramap.\nWHY: Servant handlers emit OAuthTrace events but MCP uses HTTPTrace. Need adapter to convert at boundary.\nHOW: 1) Import Servant.OAuth2.IDP.Trace (OAuthTrace). 2) Import Data.Functor.Contravariant (contramap). 3) Define mkOAuthTracer = contramap HTTPOAuth - wraps each OAuthTrace in HTTPOAuth constructor before emission.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:24.964321457+01:00","updated_at":"2025-12-19T11:38:34.094821532+01:00","closed_at":"2025-12-19T11:38:34.094821532+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.17","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:24.965812438+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.17","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:47.824087887+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.18","title":"Update MCP HTTP server to construct AppEnv with OAuthEnv","description":"WHERE: src/MCP/Server/HTTP.hs (or wherever AppEnv is constructed)\nWHAT: Update AppEnv construction to include envOAuthEnv field using mkOAuthEnv.\nWHY: AppEnv must be complete with all fields for HTTP server to start.\nHOW: Find where AppEnv is constructed (likely in HTTP.hs or main). Add envOAuthEnv = mkOAuthEnv config to the record construction. Ensure mkOAuthEnv is imported from AppEnv module.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:32.723421047+01:00","updated_at":"2025-12-19T11:38:34.110907949+01:00","closed_at":"2025-12-19T11:38:34.110907949+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:c-update-mcp"],"dependencies":[{"issue_id":"mcp-5wk.18","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:32.724887672+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.19","title":"Remove moved types from MCP.Server.Auth exports","description":"WHERE: src/MCP/Server/Auth.hs\nWHAT: Remove exports and implementations of types/functions that moved to Servant: OAuthMetadata, ProtectedResourceMetadata, validateCodeVerifier, generateCodeChallenge.\nWHY: Clean break - no backwards-compatibility re-exports. MCP.Server.Auth should only contain MCP-specific types.\nHOW: 1) Remove from export list: OAuthMetadata (..), ProtectedResourceMetadata (..), validateCodeVerifier, generateCodeChallenge. 2) Remove type definitions (data OAuthMetadata, data ProtectedResourceMetadata). 3) Remove JSON instances for those types. 4) Remove function implementations (validateCodeVerifier, generateCodeChallenge). 5) Remove now-unused imports (cryptonite, base64-bytestring if only used by removed functions).","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-18T20:11:42.987274484+01:00","updated_at":"2025-12-19T11:38:34.127589496+01:00","closed_at":"2025-12-19T11:38:34.127589496+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:d-clean-break"],"dependencies":[{"issue_id":"mcp-5wk.19","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:42.988403041+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.2","title":"Create Servant.OAuth2.IDP.Config module with OAuthEnv record","description":"WHERE: src/Servant/OAuth2/IDP/Config.hs (NEW FILE)\nWHAT: Define OAuthEnv record with protocol-agnostic OAuth configuration. Fields: oauthBaseUrl :: Text, oauthAuthCodeExpiry :: NominalDiffTime, oauthAccessTokenExpiry :: NominalDiffTime, oauthLoginSessionExpiry :: NominalDiffTime, oauthAuthCodePrefix :: Text, oauthRefreshTokenPrefix :: Text, oauthClientIdPrefix :: Text, oauthSupportedScopes :: [Scope], oauthSupportedResponseTypes :: [ResponseType], oauthSupportedGrantTypes :: [GrantType], oauthSupportedAuthMethods :: [ClientAuthMethod], oauthSupportedCodeChallengeMethods :: [CodeChallengeMethod].\nWHY: Replaces HasType HTTPServerConfig constraint in handlers with HasType OAuthEnv - no MCP dependency.\nHOW: Import types from Servant.OAuth2.IDP.Types. Add Generic deriving for generic-lens compatibility. Optionally add mkOAuthEnv smart constructor with sensible defaults.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:15.224752162+01:00","updated_at":"2025-12-19T11:38:33.839461906+01:00","closed_at":"2025-12-19T11:38:33.839461906+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.2","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:15.225941125+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.20","title":"Verify no MCP imports in Servant modules","description":"WHERE: src/Servant/**/*.hs\nWHAT: Run verification command to ensure no MCP imports remain in Servant namespace.\nWHY: Primary acceptance criterion - Servant modules must be MCP-independent.\nHOW: Run: rg '^import MCP\\.' src/Servant/ - should return empty. If any matches found, fix the remaining imports in those files.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:11:51.04522668+01:00","updated_at":"2025-12-19T11:38:34.143743788+01:00","closed_at":"2025-12-19T11:38:34.143743788+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.20","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:11:51.046965163+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.20","depends_on_id":"mcp-5wk.19","type":"blocks","created_at":"2025-12-18T20:12:47.841317393+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.21","title":"Verify cabal build succeeds","description":"WHERE: Project root\nWHAT: Run cabal build and ensure it succeeds without errors.\nWHY: Build must pass after refactoring - no missing modules, no type errors.\nHOW: Run: cabal build. Fix any compilation errors. Common issues: missing imports, type mismatches in handler signatures, missing module in cabal file.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:12:01.155334066+01:00","updated_at":"2025-12-19T11:38:34.160974716+01:00","closed_at":"2025-12-19T11:38:34.160974716+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.21","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:12:01.157258941+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.21","depends_on_id":"mcp-5wk.20","type":"blocks","created_at":"2025-12-18T20:12:47.860694392+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.22","title":"Verify cabal test passes","description":"WHERE: Project root\nWHAT: Run cabal test and ensure all existing tests pass.\nWHY: Pure refactoring should not change behavior. All existing tests must still pass.\nHOW: Run: cabal test. Fix any test failures. Failures indicate behavior changed unexpectedly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:12:07.62322988+01:00","updated_at":"2025-12-19T11:38:34.177201756+01:00","closed_at":"2025-12-19T11:38:34.177201756+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:d-clean-break","verification"],"dependencies":[{"issue_id":"mcp-5wk.22","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:12:07.625325676+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.22","depends_on_id":"mcp-5wk.21","type":"blocks","created_at":"2025-12-18T20:12:47.882234471+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.23","title":"Create Servant.OAuth2.IDP.Errors module with consolidated error types","description":"FR-004b (P0 Critical): Create src/Servant/OAuth2/IDP/Errors.hs consolidating all error types. Move from Types: ValidationError, AuthorizationError. Move from LoginFlowError.hs: LoginFlowError. Add new types: TokenParameter (TokenParamCode|TokenParamCodeVerifier|TokenParamRefreshToken), OAuthErrorCode ADT with RFC 6749 error codes (ErrInvalidRequest|ErrInvalidClient|ErrInvalidGrant|...) with ToJSON to snake_case. Add new ValidationError constructors: UnsupportedCodeChallengeMethod, MissingTokenParameter, InvalidTokenParameterFormat, EmptyRedirectUris. Update OAuthErrorResponse.oauthErrorCode to use OAuthErrorCode ADT.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:33:25.964687196+01:00","updated_at":"2025-12-19T12:07:35.191434577+01:00","closed_at":"2025-12-19T12:07:35.191434577+01:00","close_reason":"Implemented: Created Servant.OAuth2.IDP.Errors consolidating all OAuth error types (ValidationError, AuthorizationError, LoginFlowError) with new types (TokenParameter, OAuthErrorCode). All 5 review violations fixed: OAuthErrorCode ADT used throughout, FromJSON added, RecordWildCards extension added, all validationErrorToResponse tests added. Verified: cabal build succeeds, cabal test passes (438 examples, 0 failures). Commits: f784f01, 627d7ad.","labels":["fr:004b","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.23","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:33:25.966857657+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.24","title":"Create Servant.OAuth2.IDP.Trace module with OAuthTrace ADT","description":"FR-005 (P1 High): Create src/Servant/OAuth2/IDP/Trace.hs with OAuthTrace ADT using domain newtypes. Add supporting types: OperationResult (Success|Failure), DenialReason (UserDenied|InvalidRequest|UnauthorizedClient|ServerError Text). Constructors use domain types from Types: TraceClientRegistration ClientId RedirectUri, TraceAuthorizationRequest ClientId [Scope] OperationResult, TraceLoginPageServed SessionId, TraceLoginAttempt Username OperationResult, TracePKCEValidation OperationResult, TraceAuthorizationGranted ClientId Username, TraceAuthorizationDenied ClientId DenialReason, TraceTokenExchange OAuthGrantType OperationResult, TraceTokenRefresh OperationResult, TraceSessionExpired SessionId, TraceValidationError ValidationError.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:33:37.271559034+01:00","updated_at":"2025-12-19T17:09:52.365045636+01:00","closed_at":"2025-12-19T17:09:52.365045636+01:00","close_reason":"Duplicate of mcp-5wk.1 (Trace module)","labels":["fr:005","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.24","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:33:37.273083078+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.24","depends_on_id":"mcp-5wk.23","type":"blocks","created_at":"2025-12-19T11:37:23.40768616+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.24","depends_on_id":"mcp-5wk.28","type":"blocks","created_at":"2025-12-19T11:37:23.424327176+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.25","title":"Create Servant.OAuth2.IDP.Config module with OAuthEnv record","description":"FR-004 (P1 High): Create src/Servant/OAuth2/IDP/Config.hs with OAuthEnv record for protocol-agnostic OAuth configuration. Fields: oauthBaseUrl :: URI, oauthAuthCodeExpiry :: NominalDiffTime, oauthAccessTokenExpiry :: NominalDiffTime, oauthLoginSessionExpiry :: NominalDiffTime, oauthAuthCodePrefix :: Text, oauthRefreshTokenPrefix :: Text, oauthClientIdPrefix :: Text, oauthSupportedScopes :: [Scope], oauthSupportedResponseTypes :: NonEmpty ResponseType, oauthSupportedGrantTypes :: NonEmpty OAuthGrantType, oauthSupportedAuthMethods :: NonEmpty TokenAuthMethod, oauthSupportedCodeChallengeMethods :: NonEmpty CodeChallengeMethod. Uses Network.URI and Data.List.NonEmpty.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:33:48.221479369+01:00","updated_at":"2025-12-19T17:09:52.381289233+01:00","closed_at":"2025-12-19T17:09:52.381289233+01:00","close_reason":"Duplicate of mcp-5wk.2 (Config module)","labels":["fr:004","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.25","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:33:48.222635855+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.25","depends_on_id":"mcp-5wk.28","type":"blocks","created_at":"2025-12-19T11:37:23.440577023+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.26","title":"Create Servant.OAuth2.IDP.Metadata module with OAuth discovery types","description":"FR-002 (P0 Critical): Create src/Servant/OAuth2/IDP/Metadata.hs with OAuth metadata types moved from MCP.Server.Auth. Types: OAuthMetadata (RFC 8414 discovery response), ProtectedResourceMetadata (RFC 9728). Include all associated ToJSON/FromJSON instances. Export smart constructors if applicable.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:33:58.032852335+01:00","updated_at":"2025-12-19T17:09:52.396854275+01:00","closed_at":"2025-12-19T17:09:52.396854275+01:00","close_reason":"Duplicate of mcp-5wk.3 (Metadata module)","labels":["fr:002","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.26","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:33:58.034112012+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.27","title":"Create Servant.OAuth2.IDP.PKCE module with PKCE functions","description":"FR-003 (P0 Critical): Create src/Servant/OAuth2/IDP/PKCE.hs with PKCE functions moved from MCP.Server.Auth. Functions: generateCodeVerifier :: IO CodeVerifier (using cryptonite random, returns domain newtype), validateCodeVerifier :: CodeVerifier -\u003e CodeChallenge -\u003e Bool, generateCodeChallenge :: CodeVerifier -\u003e CodeChallenge. All functions use domain newtypes from Types module. Domain-based module boundaries (IO and pure together).","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:34:07.520540743+01:00","updated_at":"2025-12-19T17:09:52.412525559+01:00","closed_at":"2025-12-19T17:09:52.412525559+01:00","close_reason":"Duplicate of mcp-5wk.4 (PKCE module)","labels":["fr:003","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.27","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:07.52154028+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.28","title":"Move OAuthGrantType to Servant.OAuth2.IDP.Types","description":"Move OAuthGrantType to Servant.OAuth2.IDP.Types with prefixed constructor names (OAuthAuthorizationCode, OAuthClientCredentials) to avoid collision with existing AuthorizationCode entity type. JSON serialization uses standard OAuth strings ('authorization_code', 'client_credentials'). Implementation complete per Q's clarification.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:34:15.899761516+01:00","updated_at":"2025-12-19T13:55:34.133019777+01:00","closed_at":"2025-12-19T13:55:34.133019777+01:00","close_reason":"OAuthGrantType moved to Types.hs with OAuthAuthorizationCode/OAuthClientCredentials constructors. JSON uses standard OAuth strings. Tests pass.","labels":["fr:002b","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.28","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:15.900850867+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.29","title":"Add new domain types for type precision (LoginAction, TokenValidity)","description":"FR-004c: Add new domain types for type precision improvements. Types to add: (1) LoginAction ADT (ActionApprove | ActionDeny) with FromHttpApiData/ToHttpApiData, (2) TokenValidity newtype over NominalDiffTime with ToJSON outputting integer seconds. Update LoginForm.formAction to use LoginAction. Update TokenResponse.expires_in to use Maybe TokenValidity. File: src/Servant/OAuth2/IDP/Types.hs. UNBLOCKED: mcp-5wk.49 resolved (OAuthGrantType uses OAuthAuthorizationCode prefix).","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:34:27.019706897+01:00","updated_at":"2025-12-19T14:47:14.626470559+01:00","closed_at":"2025-12-19T14:47:14.626470559+01:00","close_reason":"Implemented: LoginAction ADT and TokenValidity newtype with smart constructor hygiene. All 489 tests pass, review PASS for spec conformance.","labels":["fr:004c","phase:a"],"dependencies":[{"issue_id":"mcp-5wk.29","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:27.020779754+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.3","title":"Create Servant.OAuth2.IDP.Metadata module with OAuthMetadata and ProtectedResourceMetadata","description":"WHERE: src/Servant/OAuth2/IDP/Metadata.hs (NEW FILE)\nWHAT: Move OAuthMetadata (RFC 8414) and ProtectedResourceMetadata (RFC 9728) types from MCP.Server.Auth to this new module. Include all JSON instances.\nWHY: API.hs and Handlers/Metadata.hs need these types but should not import from MCP.\nHOW: Copy type definitions and FromJSON/ToJSON instances from MCP.Server.Auth. Use snake_case JSON keys per RFC 8414/9728. Import Scope, ResponseType, GrantType, etc. from Servant.OAuth2.IDP.Types.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:23.673044465+01:00","updated_at":"2025-12-19T11:38:33.856330319+01:00","closed_at":"2025-12-19T11:38:33.856330319+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.3","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:23.674656056+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.30","title":"Update mcp-haskell.cabal with new modules","description":"Update mcp-haskell.cabal: Add new exposed-modules: Servant.OAuth2.IDP.Trace, Servant.OAuth2.IDP.Config, Servant.OAuth2.IDP.Metadata, Servant.OAuth2.IDP.PKCE, Servant.OAuth2.IDP.Errors. Remove: Servant.OAuth2.IDP.LoginFlowError (consolidated into Errors). Verify build-depends includes monad-time and network-uri.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:34:35.383950277+01:00","updated_at":"2025-12-19T17:09:52.428721951+01:00","closed_at":"2025-12-19T17:09:52.428721951+01:00","close_reason":"Duplicate of mcp-5wk.5 (cabal update)","labels":["phase:a"],"dependencies":[{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:35.385922156+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.23","type":"blocks","created_at":"2025-12-19T11:37:41.17185769+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.24","type":"blocks","created_at":"2025-12-19T11:37:41.199412159+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.25","type":"blocks","created_at":"2025-12-19T11:37:41.22496231+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.26","type":"blocks","created_at":"2025-12-19T11:37:41.248850073+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.27","type":"blocks","created_at":"2025-12-19T11:37:41.27595482+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.28","type":"blocks","created_at":"2025-12-19T11:37:41.302101874+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.30","depends_on_id":"mcp-5wk.29","type":"blocks","created_at":"2025-12-19T11:37:41.327137792+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.31","title":"Update Store.hs and Store/InMemory.hs with MonadTime import","description":"FR-001 (P0 Critical): Update src/Servant/OAuth2/IDP/Store.hs and src/Servant/OAuth2/IDP/Store/InMemory.hs. Replace 'import MCP.Server.Time (MonadTime)' with 'import Control.Monad.Time (MonadTime)'. Also update OAuthState record to use domain type keys (Map AuthCodeId instead of Map Text) per FR-004c.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:34:45.216657604+01:00","updated_at":"2025-12-19T17:09:52.444107509+01:00","closed_at":"2025-12-19T17:09:52.444107509+01:00","close_reason":"Duplicate of mcp-5wk.6 (Store MonadTime)","labels":["fr:001","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.31","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:45.218541173+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.31","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.542828618+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.32","title":"Update API.hs with Metadata import from Servant module","description":"Update src/Servant/OAuth2/IDP/API.hs: Replace any MCP.Server.Auth imports for OAuthMetadata/ProtectedResourceMetadata with imports from Servant.OAuth2.IDP.Metadata.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:34:53.966647185+01:00","updated_at":"2025-12-19T17:09:52.460796439+01:00","closed_at":"2025-12-19T17:09:52.460796439+01:00","close_reason":"Duplicate of mcp-5wk.7 (API.hs)","labels":["fr:002","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.32","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:34:53.9684344+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.32","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.567511659+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.33","title":"Update Handlers/Metadata.hs with Servant imports","description":"Update src/Servant/OAuth2/IDP/Handlers/Metadata.hs: Import OAuthMetadata/ProtectedResourceMetadata from Servant.OAuth2.IDP.Metadata. Replace HasType HTTPServerConfig env with HasType OAuthEnv env per FR-006.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:35:03.01484359+01:00","updated_at":"2025-12-19T17:09:52.478158115+01:00","closed_at":"2025-12-19T17:09:52.478158115+01:00","close_reason":"Duplicate of mcp-5wk.8 (Handlers/Metadata)","labels":["fr:002","fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.33","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:03.016412103+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.33","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.592123832+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.34","title":"Update Handlers/Token.hs with PKCE and Errors imports","description":"Update src/Servant/OAuth2/IDP/Handlers/Token.hs:\n\nPHASE B (import updates):\n- Import PKCE functions from Servant.OAuth2.IDP.PKCE\n- Import error types from Servant.OAuth2.IDP.Errors\n- Replace HasType HTTPServerConfig env with HasType OAuthEnv env\n- Replace HasType (IOTracer HTTPTrace) env with HasType (IOTracer OAuthTrace) env per FR-006\n\nNOTE: Handler signature changes (Map Text Text → typed params) are tracked separately in mcp-5wk.66 (Phase F)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:35:10.05096651+01:00","updated_at":"2025-12-19T17:09:52.495365768+01:00","closed_at":"2025-12-19T17:09:52.495365768+01:00","close_reason":"Duplicate of mcp-5wk.9 (Handlers/Token)","labels":["fr:003","fr:004b","fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.34","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:10.053030279+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.34","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.615548944+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.35","title":"Update Handlers/Helpers.hs with OAuthEnv and trace","description":"Update src/Servant/OAuth2/IDP/Handlers/Helpers.hs: Import from Servant.OAuth2.IDP.Config and Servant.OAuth2.IDP.Trace. Update generator signatures per FR-004c: generateAuthCode :: OAuthEnv -\u003e IO AuthCodeId, generateJWTAccessToken returns AccessTokenId, generateRefreshTokenWithConfig :: OAuthEnv -\u003e IO RefreshTokenId. Replace HasType HTTPServerConfig with HasType OAuthEnv. Import errors from Servant.OAuth2.IDP.Errors.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:35:20.104987881+01:00","updated_at":"2025-12-19T17:09:52.511560461+01:00","closed_at":"2025-12-19T17:09:52.511560461+01:00","close_reason":"Duplicate of mcp-5wk.10 (Handlers/Helpers)","labels":["fr:004c","fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.35","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:20.107212258+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.35","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.641328834+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.36","title":"Update Handlers/Registration.hs with OAuthEnv and trace","description":"Update src/Servant/OAuth2/IDP/Handlers/Registration.hs: Import from Servant.OAuth2.IDP.Config and Servant.OAuth2.IDP.Trace. Replace HasType HTTPServerConfig with HasType OAuthEnv. Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). Import errors from Servant.OAuth2.IDP.Errors.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:35:29.772771346+01:00","updated_at":"2025-12-19T17:09:52.529596343+01:00","closed_at":"2025-12-19T17:09:52.529596343+01:00","close_reason":"Duplicate of mcp-5wk.11 (Handlers/Registration)","labels":["fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.36","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:29.775217393+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.36","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.665788116+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.37","title":"Update Handlers/Authorization.hs with OAuthEnv, trace, MonadTime","description":"Update src/Servant/OAuth2/IDP/Handlers/Authorization.hs: Replace 'import MCP.Server.Time (MonadTime)' with 'import Control.Monad.Time (MonadTime)'. Import from Servant.OAuth2.IDP.Config and Servant.OAuth2.IDP.Trace. Replace HasType HTTPServerConfig with HasType OAuthEnv. Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). Import errors from Servant.OAuth2.IDP.Errors.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:35:37.757172312+01:00","updated_at":"2025-12-19T16:12:15.657808354+01:00","closed_at":"2025-12-19T16:12:15.657808354+01:00","close_reason":"Implemented: Replaced MCP imports with Servant.OAuth2.IDP imports in Authorization.hs. Added OAuthEnv/OAuthTracer to AppEnv. Fixed error response status codes. All 496 tests pass. Discovered work: mcp-5wk.69 for re-enabling ErrorBoundarySecuritySpec tests.","labels":["fr:001","fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.37","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:37.758290557+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.37","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.689885379+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.38","title":"Update Handlers/Login.hs with OAuthEnv, trace, MonadTime, LoginAction","description":"Update src/Servant/OAuth2/IDP/Handlers/Login.hs: Replace 'import MCP.Server.Time (MonadTime)' with 'import Control.Monad.Time (MonadTime)'. Import from Servant.OAuth2.IDP.Config and Servant.OAuth2.IDP.Trace. Replace HasType HTTPServerConfig with HasType OAuthEnv. Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). Import errors from Servant.OAuth2.IDP.Errors. Update to pattern match on LoginAction ADT instead of string comparison per FR-004c.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:35:46.576219204+01:00","updated_at":"2025-12-19T17:51:29.736516333+01:00","closed_at":"2025-12-19T17:51:29.736516333+01:00","close_reason":"Completed: Updated Login.hs, Helpers.hs, Token.hs to use OAuthEnv/OAuthTrace types. All 496 tests pass. Commit fc9df1e.","labels":["fr:001","fr:004c","fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.38","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:46.578313123+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.38","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.714939374+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.38","depends_on_id":"mcp-5wk.29","type":"blocks","created_at":"2025-12-19T17:10:36.246196538+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.39","title":"Update Server.hs with OAuthEnv and OAuthTrace","description":"Update src/Servant/OAuth2/IDP/Server.hs: Import from Servant.OAuth2.IDP.Config and Servant.OAuth2.IDP.Trace. Replace HasType HTTPServerConfig with HasType OAuthEnv. Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). Import errors from Servant.OAuth2.IDP.Errors.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:35:53.588452178+01:00","updated_at":"2025-12-19T17:09:52.546836766+01:00","closed_at":"2025-12-19T17:09:52.546836766+01:00","close_reason":"Duplicate of mcp-5wk.14 (Server.hs)","labels":["fr:006","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.39","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:35:53.589606613+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.39","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.745659943+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.4","title":"Create Servant.OAuth2.IDP.PKCE module with validation functions","description":"WHERE: src/Servant/OAuth2/IDP/PKCE.hs (NEW FILE)\nWHAT: Move PKCE validation functions from MCP.Server.Auth: validateCodeVerifier :: CodeVerifier -\u003e CodeChallenge -\u003e Bool, generateCodeChallenge :: Text -\u003e Text.\nWHY: Token.hs handler needs PKCE validation but should not import from MCP.Server.Auth.\nHOW: Copy functions from MCP.Server.Auth. Use cryptonite for SHA256, base64-bytestring for B64URL encoding. Import CodeVerifier, CodeChallenge from Servant.OAuth2.IDP.Types. Pure functions only - no IO.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:30.961000538+01:00","updated_at":"2025-12-19T11:38:33.873939929+01:00","closed_at":"2025-12-19T11:38:33.873939929+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.4","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:30.962835327+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.40","title":"Update Test/Internal.hs with MonadTime import and fix doc typo","description":"Update src/Servant/OAuth2/IDP/Test/Internal.hs: Replace 'import MCP.Server.Time (MonadTime)' with 'import Control.Monad.Time (MonadTime)'. Fix documentation typo: change 'Module : MCP.Server.OAuth.Test.Internal' to 'Module : Servant.OAuth2.IDP.Test.Internal' in doc comments.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:36:01.954451031+01:00","updated_at":"2025-12-19T17:09:52.56419896+01:00","closed_at":"2025-12-19T17:09:52.56419896+01:00","close_reason":"Duplicate of mcp-5wk.15 (Test/Internal)","labels":["fr:001","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.40","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:01.956076459+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.40","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.772268791+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.41","title":"Audit Types.hs exports for smart constructor hygiene","description":"FR-004c (P0 Critical): Fix smart constructor hygiene in src/Servant/OAuth2/IDP/Types.hs. Change exports from 'Type(..)' to 'Type' for 8 types that have smart constructors with validation:\n\nCRITICAL (security bypass):\n- RedirectUri (..) → RedirectUri (bypasses SSRF protection in mkRedirectUri)\n- SessionId (..) → SessionId (bypasses UUID format validation)\n- Scope (..) → Scope (bypasses RFC 6749 whitespace/empty validation)\n\nSTANDARD (data integrity):\n- AuthCodeId (..) → AuthCodeId (bypasses non-empty validation)\n- ClientId (..) → ClientId (bypasses non-empty validation)\n- RefreshTokenId (..) → RefreshTokenId (bypasses non-empty validation)\n- UserId (..) → UserId (bypasses non-empty validation)\n- ClientName (..) → ClientName (bypasses non-empty validation)\n\nNOTE: Types/Internal.hs intentionally keeps (..) exports for boundary translation (by design).\nAlso remove ValidationError and AuthorizationError from exports (moved to Errors module).","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T11:36:11.195075535+01:00","updated_at":"2025-12-19T17:37:50.032686428+01:00","closed_at":"2025-12-19T17:37:50.032686428+01:00","close_reason":"Implemented: enforced smart constructor hygiene for 9 newtypes in Types.hs. Changed exports from Type(..) to Type. Added unsafe constructors in Internal.hs. Updated all test files. Verified: 496 tests pass, build clean. Review: PASS.","labels":["fr:004c","phase:b"],"dependencies":[{"issue_id":"mcp-5wk.41","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:11.197255755+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.41","depends_on_id":"mcp-5wk.30","type":"blocks","created_at":"2025-12-19T11:37:32.797249728+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.42","title":"Add OAuthEnv field to AppEnv and create adapters","description":"FR-007 (P1 High): Update src/MCP/Server/HTTP/AppEnv.hs. Add envOAuthEnv :: OAuthEnv field to AppEnv record. Create mkOAuthEnv :: HTTPServerConfig -\u003e OAuthEnv function to construct OAuthEnv from existing config. Create mkOAuthTracer :: IOTracer HTTPTrace -\u003e IOTracer OAuthTrace via contramap to adapt trace types. Update handler call sites to use new OAuthEnv.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:36:20.156853698+01:00","updated_at":"2025-12-19T17:09:52.580886302+01:00","closed_at":"2025-12-19T17:09:52.580886302+01:00","close_reason":"Duplicate of mcp-5wk.16 (AppEnv)","labels":["fr:007","phase:c"],"dependencies":[{"issue_id":"mcp-5wk.42","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:20.15826562+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.42","depends_on_id":"mcp-5wk.39","type":"blocks","created_at":"2025-12-19T11:37:51.970027384+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.43","title":"Create MCPOAuthConfig for demo-specific fields","description":"FR-004/FR-008: Update MCPOAuthConfig in MCP.Server.Auth - UNBLOCKED. Remove mcp prefix from all fields (autoApproveAuth, demoUserIdTemplate, demoEmailDomain, authorizationSuccessTemplate). Add missing fields (oauthProviders, demoUserName, publicClientSecret). No collision since OAuthConfig is being removed entirely per spec clarification.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T11:36:29.187156801+01:00","updated_at":"2025-12-19T14:22:17.331538821+01:00","closed_at":"2025-12-19T14:22:17.331538821+01:00","close_reason":"Superseded by mcp-5wk.52 (E.1 task with full context from R-005 refinement)","labels":["fr:004","fr:008","phase:c"],"dependencies":[{"issue_id":"mcp-5wk.43","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:29.188410206+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.44","title":"Remove moved types from MCP.Server.Auth exports","description":"FR-008 (P2 Medium): Clean break - remove moved types from src/MCP/Server/Auth.hs exports. Remove: OAuthMetadata (→ Servant.OAuth2.IDP.Metadata), ProtectedResourceMetadata (→ Metadata), OAuthGrantType (→ Types), generateCodeVerifier (→ PKCE), validateCodeVerifier (→ PKCE), generateCodeChallenge (→ PKCE), ValidationError (→ Errors), AuthorizationError (→ Errors). Keep: OAuthProvider, TokenInfo, extractBearerToken, PKCEChallenge, ProtectedResourceAuth, ProtectedResourceAuthConfig.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T11:36:44.902296807+01:00","updated_at":"2025-12-19T17:09:52.601143418+01:00","closed_at":"2025-12-19T17:09:52.601143418+01:00","close_reason":"Duplicate of mcp-5wk.19 (remove Auth types)","labels":["fr:008","phase:d"],"dependencies":[{"issue_id":"mcp-5wk.44","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:44.903648943+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.44","depends_on_id":"mcp-5wk.42","type":"blocks","created_at":"2025-12-19T11:37:51.989991306+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.44","depends_on_id":"mcp-5wk.43","type":"blocks","created_at":"2025-12-19T11:37:52.007238304+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.45","title":"Delete LoginFlowError.hs (consolidated into Errors)","description":"Delete src/Servant/OAuth2/IDP/LoginFlowError.hs. Content has been moved to Servant.OAuth2.IDP.Errors module. Ensure all imports have been updated to use Errors module before deletion.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T11:36:51.574116903+01:00","updated_at":"2025-12-19T17:09:52.618977097+01:00","closed_at":"2025-12-19T17:09:52.618977097+01:00","close_reason":"Duplicate of mcp-5wk.82 (delete LoginFlowError)","labels":["phase:d"],"dependencies":[{"issue_id":"mcp-5wk.45","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:36:51.575644981+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.45","depends_on_id":"mcp-5wk.23","type":"blocks","created_at":"2025-12-19T11:37:52.023107504+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.46","title":"Verify no MCP imports in Servant modules","description":"Acceptance Criteria 1: Run 'rg \"^import MCP\\.\" src/Servant/' and verify it returns empty (no MCP imports in any Servant.OAuth2.IDP.* module). This is the primary success metric for the refactoring.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:37:03.33794574+01:00","updated_at":"2025-12-19T17:09:52.637997683+01:00","closed_at":"2025-12-19T17:09:52.637997683+01:00","close_reason":"Duplicate of mcp-5wk.20 (verify imports)","labels":["acceptance","phase:d"],"dependencies":[{"issue_id":"mcp-5wk.46","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:37:03.339167256+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.46","depends_on_id":"mcp-5wk.44","type":"blocks","created_at":"2025-12-19T11:37:52.038764876+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.46","depends_on_id":"mcp-5wk.45","type":"blocks","created_at":"2025-12-19T11:37:52.055523243+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.47","title":"Verify cabal build succeeds","description":"Acceptance Criteria 2: Run 'cabal build' and verify it completes with no errors. All modules must compile cleanly after the refactoring.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:37:09.256647205+01:00","updated_at":"2025-12-19T17:09:52.656233518+01:00","closed_at":"2025-12-19T17:09:52.656233518+01:00","close_reason":"Duplicate of mcp-5wk.21 (verify build)","labels":["acceptance","phase:d"],"dependencies":[{"issue_id":"mcp-5wk.47","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:37:09.258039623+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.47","depends_on_id":"mcp-5wk.46","type":"blocks","created_at":"2025-12-19T11:37:52.071662566+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.48","title":"Verify cabal test passes","description":"Acceptance Criteria 3: Run 'cabal test' and verify all existing tests pass. This is a pure refactoring - no functionality changes, so all tests must continue to pass.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T11:37:15.602184615+01:00","updated_at":"2025-12-19T17:09:52.675213315+01:00","closed_at":"2025-12-19T17:09:52.675213315+01:00","close_reason":"Duplicate of mcp-5wk.22 (verify test)","labels":["acceptance","phase:d"],"dependencies":[{"issue_id":"mcp-5wk.48","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T11:37:15.603280333+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.48","depends_on_id":"mcp-5wk.47","type":"blocks","created_at":"2025-12-19T11:37:52.087957008+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.49","title":"Spec clarification: OAuthGrantType constructor name collision","description":"Review found impossible constraint in FR-002b: Cannot move OAuthGrantType with original constructor names (AuthorizationCode, ClientCredentials) to Servant.OAuth2.IDP.Types because Types.hs already contains 'data AuthorizationCode userId = AuthorizationCode {...}'. Haskell prohibits duplicate constructor names in same module. Question: Should we (1) rename OAuthGrantType constructors (e.g., OAuthAuthorizationCode), (2) move OAuthGrantType to different module (e.g., Servant.OAuth2.IDP.GrantTypes), or (3) move AuthorizationCode entity elsewhere? Original implementation chose option 1 but was rejected as violating 'MOVE not REDESIGN' directive.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T13:25:36.099364971+01:00","updated_at":"2025-12-19T13:55:27.679217458+01:00","closed_at":"2025-12-19T13:55:27.679217458+01:00","close_reason":"Q clarified: Use OAuthAuthorizationCode prefix for OAuthGrantType constructors. Already implemented in Types.hs.","labels":["blocker","spec-clarification"],"dependencies":[{"issue_id":"mcp-5wk.49","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T13:25:36.100834334+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.49","depends_on_id":"mcp-5wk.28","type":"blocks","created_at":"2025-12-19T13:25:42.969627513+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.49","depends_on_id":"mcp-5wk.29","type":"blocks","created_at":"2025-12-19T13:30:43.726703418+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.5","title":"Update mcp-haskell.cabal with new Servant.OAuth2.IDP modules","description":"WHERE: mcp-haskell.cabal\nWHAT: Add new modules to exposed-modules list: Servant.OAuth2.IDP.Trace, Servant.OAuth2.IDP.Config, Servant.OAuth2.IDP.Metadata, Servant.OAuth2.IDP.PKCE.\nWHY: New modules must be registered in cabal file for build to succeed.\nHOW: Add to exposed-modules section in alphabetical order with existing Servant.OAuth2.IDP.* modules.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-18T20:09:37.877486488+01:00","updated_at":"2025-12-19T11:38:33.890279795+01:00","closed_at":"2025-12-19T11:38:33.890279795+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:a-new-modules"],"dependencies":[{"issue_id":"mcp-5wk.5","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:37.879613797+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.50","title":"Spec clarification: MCPOAuthConfig field name collision with OAuthConfig","description":"FR-004/FR-008 specifies MCPOAuthConfig field names (autoApproveAuth, demoUserIdTemplate, demoEmailDomain, authorizationSuccessTemplate) that conflict with existing OAuthConfig fields. OAuthConfig already has: demoUserIdTemplate :: Maybe Text (line 113), demoEmailDomain :: Text (line 114), authorizationSuccessTemplate :: Maybe Text (line 122). Haskell DuplicateRecordFields extension cannot disambiguate at usage sites (examples/http-server.hs:229-232). Options: (1) Use mcp prefixes (violates spec letter, compiles), (2) Remove duplicates from OAuthConfig (breaking change), (3) Rename fields in spec. Question: Which approach should be taken?","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T13:44:10.678706969+01:00","updated_at":"2025-12-19T14:14:30.379400129+01:00","closed_at":"2025-12-19T14:14:30.379400129+01:00","close_reason":"Spec clarified: Option B - Remove OAuthConfig entirely. MCPOAuthConfig uses unprefixed fields since no collision after OAuthConfig removal. See spec.md Clarifications session 2025-12-19.","labels":["blocker","spec-clarification"],"dependencies":[{"issue_id":"mcp-5wk.50","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T13:44:10.680173684+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.50","depends_on_id":"mcp-5wk.43","type":"blocks","created_at":"2025-12-19T13:44:18.004003122+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.51","title":"Update imports from LoginFlowError to Errors module","description":"BLOCKER for mcp-5wk.45: Update 6 files still importing Servant.OAuth2.IDP.LoginFlowError to use Servant.OAuth2.IDP.Errors instead. Files affected: src/Servant/OAuth2/IDP/Boundary.hs, test/Servant/OAuth2/IDP/LucidRenderingSpec.hs, src/Servant/OAuth2/IDP/Server.hs, src/Servant/OAuth2/IDP/Handlers/Login.hs, src/MCP/Server/HTTP.hs, src/MCP/Server/HTTP/AppEnv.hs. Change import from 'import Servant.OAuth2.IDP.LoginFlowError' to 'import Servant.OAuth2.IDP.Errors (LoginFlowError(..))'.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T13:49:59.300380251+01:00","updated_at":"2025-12-19T13:54:15.131545774+01:00","closed_at":"2025-12-19T13:54:15.131545774+01:00","close_reason":"Completed: Updated imports in 6 files from Servant.OAuth2.IDP.LoginFlowError to Servant.OAuth2.IDP.Errors. Library builds successfully (cabal build lib:mcp passes). Committed in 99c7f66.","dependencies":[{"issue_id":"mcp-5wk.51","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T13:49:59.301855254+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.51","depends_on_id":"mcp-5wk.45","type":"blocks","created_at":"2025-12-19T13:50:07.509987015+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.52","title":"E.1-E.4: Remove OAuthConfig, split into OAuthEnv + MCPOAuthConfig","description":"CONSOLIDATED COMMIT: Update MCPOAuthConfig fields (unprefixed), remove OAuthConfig type, update HTTPServerConfig, create DemoOAuthBundle. Absorbs: mcp-5wk.53, 54, 55","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:20:28.654952157+01:00","updated_at":"2025-12-19T19:23:26.198621182+01:00","closed_at":"2025-12-19T19:23:26.198621182+01:00","close_reason":"E.1-E.4 complete: MCPOAuthConfig fields unprefixed, OAuthConfig removed, HTTPServerConfig updated, DemoOAuthBundle created. Library (src/) compiles successfully. Test updates deferred to E.5-E.7 (mcp-5wk.56).","labels":["fr:004","fr:008","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.52","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:20:28.656776691+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.52","depends_on_id":"mcp-5wk.53","type":"blocks","created_at":"2025-12-19T14:22:04.957081727+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.52","depends_on_id":"mcp-5wk.70","type":"blocks","created_at":"2025-12-19T17:10:36.204744829+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.53","title":"E.2: Remove OAuthConfig type from MCP.Server.Auth","description":"Delete OAuthConfig data type entirely from src/MCP/Server/Auth.hs. Delete defaultDemoOAuthConfig function from src/MCP/Server/HTTP.hs. Update all imports that reference OAuthConfig across the codebase. This is the core breaking change that enables MCPOAuthConfig to use unprefixed field names. BLOCKING: Must coordinate with E.1, E.3, E.4, E.5, E.6.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T14:20:37.425974801+01:00","updated_at":"2025-12-19T17:09:52.13229491+01:00","closed_at":"2025-12-19T17:09:52.13229491+01:00","close_reason":"Consolidated into mcp-5wk.52 (single atomic commit)","labels":["fr:008","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.53","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:20:37.427070466+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.54","title":"E.3: Update HTTPServerConfig to use MCPOAuthConfig","description":"Replace httpOAuthConfig::Maybe OAuthConfig with httpMCPOAuthConfig::Maybe MCPOAuthConfig in HTTPServerConfig (src/MCP/Server/HTTP/AppEnv.hs). Presence of httpMCPOAuthConfig implies OAuth enabled (replaces oauthEnabled::Bool field). Update all call sites that access httpOAuthConfig to use httpMCPOAuthConfig.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:20:46.000186298+01:00","updated_at":"2025-12-19T17:09:52.153079321+01:00","closed_at":"2025-12-19T17:09:52.153079321+01:00","close_reason":"Consolidated into mcp-5wk.52 (single atomic commit)","labels":["fr:004","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.54","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:20:46.001557475+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.54","depends_on_id":"mcp-5wk.52","type":"blocks","created_at":"2025-12-19T14:22:04.975658567+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.54","depends_on_id":"mcp-5wk.53","type":"blocks","created_at":"2025-12-19T14:22:04.995588355+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.55","title":"E.4: Create DemoOAuthBundle convenience type","description":"Create DemoOAuthBundle type in src/MCP/Server/HTTP.hs combining OAuthEnv and MCPOAuthConfig. Create defaultDemoOAuthBundle::DemoOAuthBundle with bundleEnv=defaultOAuthEnv{oauthRequireHTTPS=False} and bundleMCPConfig=defaultDemoMCPOAuthConfig. Export from MCP.Server.HTTP for test convenience. This replaces defaultDemoOAuthConfig for migration.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:20:53.79698989+01:00","updated_at":"2025-12-19T17:09:52.171051362+01:00","closed_at":"2025-12-19T17:09:52.171051362+01:00","close_reason":"Consolidated into mcp-5wk.52 (single atomic commit)","labels":["fr:008","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.55","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:20:53.798244064+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.55","depends_on_id":"mcp-5wk.54","type":"blocks","created_at":"2025-12-19T14:22:05.015860083+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.56","title":"E.5-E.7: Update tests and docs for OAuthConfig removal","description":"CONSOLIDATED COMMIT: Update SessionCookieSpec, McpAuthSpec, OAuth Test Fixtures, AuthSpec, http-server example, CLAUDE.md, README.md, verify complete. Absorbs: mcp-5wk.57, 58, 59, 60, 61, 62, 63","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:21:02.315496916+01:00","updated_at":"2025-12-19T19:31:39.912689095+01:00","closed_at":"2025-12-19T19:31:39.912689095+01:00","close_reason":"Completed: Updated all tests (SessionCookieSpec, McpAuthSpec, OAuth Fixtures, AuthSpec), examples (http-server.hs), and docs (CLAUDE.md, README.md) to use OAuthEnv + MCPOAuthConfig instead of removed OAuthConfig. All verifications passed: no OAuthConfig references remain, defaultDemoOAuthConfig replaced with defaultDemoOAuthBundle, cabal build succeeds, 467 tests pass with 0 failures. Commit: 25dd12c","labels":["phase:e","test"],"dependencies":[{"issue_id":"mcp-5wk.56","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:02.316730559+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.56","depends_on_id":"mcp-5wk.55","type":"blocks","created_at":"2025-12-19T14:22:05.036756177+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.56","depends_on_id":"mcp-5wk.52","type":"blocks","created_at":"2025-12-19T17:10:36.223370828+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.57","title":"E.5.2: Update McpAuthSpec for OAuthConfig removal","description":"Update test/MCP/Server/HTTP/McpAuthSpec.hs: Replace 'httpOAuthConfig = Just defaultDemoOAuthConfig' with httpMCPOAuthConfig = Just (bundleMCPConfig defaultDemoOAuthBundle). Update imports accordingly.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:21:09.974614698+01:00","updated_at":"2025-12-19T17:09:52.188333784+01:00","closed_at":"2025-12-19T17:09:52.188333784+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["phase:e","test"],"dependencies":[{"issue_id":"mcp-5wk.57","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:09.975578757+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.57","depends_on_id":"mcp-5wk.55","type":"blocks","created_at":"2025-12-19T14:22:05.058096545+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.58","title":"E.5.3: Update OAuth Test Fixtures for OAuthConfig removal","description":"Update test/MCP/Server/OAuth/Test/Fixtures.hs: Replace defaultDemoOAuthConfig usage with defaultDemoOAuthBundle pattern. Update imports and fixture construction.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:21:16.65766883+01:00","updated_at":"2025-12-19T17:09:52.206817871+01:00","closed_at":"2025-12-19T17:09:52.206817871+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["phase:e","test"],"dependencies":[{"issue_id":"mcp-5wk.58","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:16.658974773+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.58","depends_on_id":"mcp-5wk.55","type":"blocks","created_at":"2025-12-19T14:22:05.075123811+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.59","title":"E.5.4: Update AuthSpec for MCPOAuthConfig unprefixed fields","description":"Update test/MCP/Server/AuthSpec.hs: Update MCPOAuthConfig tests to use unprefixed field names (autoApproveAuth instead of mcpAutoApproveAuth, etc.). Verify tests still pass with new field structure.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:21:23.818509231+01:00","updated_at":"2025-12-19T17:09:52.226109403+01:00","closed_at":"2025-12-19T17:09:52.226109403+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["phase:e","test"],"dependencies":[{"issue_id":"mcp-5wk.59","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:23.819728136+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.59","depends_on_id":"mcp-5wk.52","type":"blocks","created_at":"2025-12-19T14:22:05.091440502+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.6","title":"Update Store.hs and Store/InMemory.hs - replace MCP.Server.Time with Control.Monad.Time","description":"WHERE: src/Servant/OAuth2/IDP/Store.hs, src/Servant/OAuth2/IDP/Store/InMemory.hs\nWHAT: Replace 'import MCP.Server.Time (MonadTime (..))' with 'import Control.Monad.Time (MonadTime (..))'.\nWHY: MCP.Server.Time is just a thin re-export. Direct import from monad-time package removes MCP dependency.\nHOW: Simple find-replace in both files. monad-time is already a transitive dependency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:09:45.709194204+01:00","updated_at":"2025-12-19T11:38:33.906298235+01:00","closed_at":"2025-12-19T11:38:33.906298235+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.6","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:45.710537517+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.60","title":"E.6.1: Update http-server example for OAuthConfig removal","description":"Update examples/http-server.hs: Replace defaultDemoOAuthConfig with defaultDemoOAuthBundle pattern. Update OAuth configuration construction to use DemoOAuthBundle destructuring. Update imports.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T14:21:30.393460703+01:00","updated_at":"2025-12-19T17:09:52.243889953+01:00","closed_at":"2025-12-19T17:09:52.243889953+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["docs","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.60","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:30.394723645+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.60","depends_on_id":"mcp-5wk.55","type":"blocks","created_at":"2025-12-19T14:22:05.107259366+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.61","title":"E.6.2: Update CLAUDE.md for OAuthConfig removal","description":"Update CLAUDE.md: Replace OAuthConfig references with OAuthEnv+MCPOAuthConfig. Update defaultDemoOAuthConfig references to defaultDemoOAuthBundle pattern. Update OAuth Implementation Details section and Configuration Options section.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-19T14:21:36.466521055+01:00","updated_at":"2025-12-19T17:09:52.262208193+01:00","closed_at":"2025-12-19T17:09:52.262208193+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["docs","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.61","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:36.46776597+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.62","title":"E.6.3: Update README.md for OAuthConfig removal","description":"Update README.md: Replace httpOAuthConfig references with httpMCPOAuthConfig. Update any code examples showing OAuth configuration.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-19T14:21:44.324483061+01:00","updated_at":"2025-12-19T17:09:52.278326403+01:00","closed_at":"2025-12-19T17:09:52.278326403+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["docs","phase:e"],"dependencies":[{"issue_id":"mcp-5wk.62","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:44.325802568+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.63","title":"E.7: Verify OAuthConfig removal complete","description":"Run verification checks: (1) rg 'OAuthConfig' src/ shows only MCPOAuthConfig references, (2) rg 'defaultDemoOAuthConfig' . returns empty, (3) cabal build succeeds, (4) cabal test passes. This task blocks epic completion.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T14:21:50.621174352+01:00","updated_at":"2025-12-19T17:09:52.295023743+01:00","closed_at":"2025-12-19T17:09:52.295023743+01:00","close_reason":"Consolidated into mcp-5wk.56 (single atomic commit)","labels":["phase:e","verification"],"dependencies":[{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T14:21:50.622252626+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.56","type":"blocks","created_at":"2025-12-19T14:22:05.124562672+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.57","type":"blocks","created_at":"2025-12-19T14:22:05.141433218+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.58","type":"blocks","created_at":"2025-12-19T14:22:05.158221174+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.59","type":"blocks","created_at":"2025-12-19T14:22:05.175137102+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.60","type":"blocks","created_at":"2025-12-19T14:22:05.192338979+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.61","type":"blocks","created_at":"2025-12-19T14:22:05.209638854+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.63","depends_on_id":"mcp-5wk.62","type":"blocks","created_at":"2025-12-19T14:22:05.225574412+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.64","title":"F.2: Fix Username smart constructor hygiene in Auth/Backend.hs","description":"Fix smart constructor hygiene in src/Servant/OAuth2/IDP/Auth/Backend.hs.\n\nChange export from 'Username (..)' to 'Username' in module export list.\nThe Username newtype has mkUsername smart constructor with non-empty validation.\nExporting (..) allows bypassing the validation.\n\nFile: src/Servant/OAuth2/IDP/Auth/Backend.hs\nChange: Line ~62 in module exports","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T15:47:11.182430896+01:00","updated_at":"2025-12-19T16:24:24.580681458+01:00","closed_at":"2025-12-19T16:24:24.580681458+01:00","close_reason":"Fixed Username smart constructor hygiene: Changed export from Username(..) to Username, added usernameText accessor, updated all call sites. Verified: 496 tests pass, 0 failures. Review: PASS.","labels":["fr:004c","phase:f"],"dependencies":[{"issue_id":"mcp-5wk.64","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T15:47:11.184086182+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.65","title":"F.3-F.6: AuthorizationError ADT payloads and typed handler signatures","description":"CONSOLIDATED COMMIT: Create ADT payloads for AuthorizationError, eliminate Map Text Text from token handlers, change ClientInfo.clientName to ClientName, verify Phase F complete. Absorbs: mcp-5wk.66, 67, 68","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T15:47:44.904620591+01:00","updated_at":"2025-12-19T18:16:12.646852636+01:00","closed_at":"2025-12-19T18:16:12.646852636+01:00","close_reason":"Implemented Phase F.3-F.6: AuthorizationError ADT payloads (7 reason types), typed token handler signatures (eliminated Map Text Text), ClientInfo.clientName::ClientName. All 482 tests pass. Review: PASS. Commits: 65ab285, cf981fe, 066040a","labels":["fr:004b","phase:f"],"dependencies":[{"issue_id":"mcp-5wk.65","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T15:47:44.906438212+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.65","depends_on_id":"mcp-5wk.23","type":"blocks","created_at":"2025-12-19T15:49:08.427179099+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.65","depends_on_id":"mcp-5wk.41","type":"blocks","created_at":"2025-12-19T17:10:36.183473718+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.66","title":"F.4: Eliminate Map Text Text from token handler signatures","description":"Eliminate Map Text Text anti-pattern in src/Servant/OAuth2/IDP/Handlers/Token.hs by passing typed fields directly.\n\nCHANGE handleAuthCodeGrant signature:\n FROM: handleAuthCodeGrant :: ... -\u003e Map Text Text -\u003e m TokenResponse\n TO: handleAuthCodeGrant :: ... -\u003e AuthCodeId -\u003e CodeVerifier -\u003e Maybe ResourceIndicator -\u003e m TokenResponse\n\nCHANGE handleRefreshTokenGrant signature:\n FROM: handleRefreshTokenGrant :: ... -\u003e Map Text Text -\u003e m TokenResponse\n TO: handleRefreshTokenGrant :: ... -\u003e RefreshTokenId -\u003e Maybe ResourceIndicator -\u003e m TokenResponse\n\nUPDATE handleToken to pass typed fields directly (no Map.fromList):\n handleToken tokenRequest = case tokenRequest of\n AuthorizationCodeGrant code verifier mResource -\u003e\n handleAuthCodeGrant code verifier mResource\n RefreshTokenGrant refreshToken mResource -\u003e\n handleRefreshTokenGrant refreshToken mResource\n\nREMOVE:\n- Map.fromList and unAuthCodeId/unCodeVerifier unwrapping from handleToken\n- Map.lookup parsing logic from handleAuthCodeGrant and handleRefreshTokenGrant\n- 'import Data.Map.Strict' if no longer needed\n\nResolves FIXME at Token.hs:277","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-19T15:47:58.856361338+01:00","updated_at":"2025-12-19T17:09:52.310917877+01:00","closed_at":"2025-12-19T17:09:52.310917877+01:00","close_reason":"Consolidated into mcp-5wk.65 (single atomic commit)","labels":["fr:004c","phase:f"],"dependencies":[{"issue_id":"mcp-5wk.66","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T15:47:58.858419016+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.66","depends_on_id":"mcp-5wk.34","type":"blocks","created_at":"2025-12-19T15:49:00.732353067+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.67","title":"F.5: Change ClientInfo.clientName to use ClientName newtype","description":"Fix record field type in src/Servant/OAuth2/IDP/Types.hs to use existing newtype instead of raw Text.\n\nCHANGE in ClientInfo record (around line 826-832):\n FROM: clientName :: Text\n TO: clientName :: ClientName\n\nThe ClientName newtype already exists at Types.hs:557 with mkClientName smart constructor.\n\nUPDATE FromJSON ClientInfo:\n- Parse through ClientName smart constructor (use mkClientName or parseJSON)\n\nUPDATE ToJSON ClientInfo:\n- Use unClientName for serialization\n\nThis enforces validation (non-empty) and maintains type consistency.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T15:48:10.019558644+01:00","updated_at":"2025-12-19T17:09:52.328940068+01:00","closed_at":"2025-12-19T17:09:52.328940068+01:00","close_reason":"Consolidated into mcp-5wk.65 (single atomic commit)","labels":["fr:004c","phase:f"],"dependencies":[{"issue_id":"mcp-5wk.67","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T15:48:10.021796243+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.68","title":"F.6: Verify Phase F type precision changes complete","description":"Verify all Phase F type precision refinements are complete.\n\nVERIFICATIONS:\n1. rg 'FIXME' src/Servant/OAuth2/IDP/ returns empty (all FIXMEs resolved)\n2. rg '\\.\\.\\.\\)' src/Servant/OAuth2/IDP/Types.hs shows only legitimate enum exports (CodeChallengeMethod, GrantType, ResponseType, ClientAuthMethod, OAuthGrantType, LoginAction)\n3. rg 'Map Text Text' src/Servant/OAuth2/IDP/Handlers/Token.hs returns empty\n4. cabal build succeeds\n5. cabal test passes\n\nDEPENDS ON: mcp-5wk.41, mcp-5wk.64, mcp-5wk.65, mcp-5wk.66, mcp-5wk.67","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T15:48:20.613819611+01:00","updated_at":"2025-12-19T17:09:52.345991028+01:00","closed_at":"2025-12-19T17:09:52.345991028+01:00","close_reason":"Consolidated into mcp-5wk.65 (single atomic commit)","labels":["phase:f","verification"],"dependencies":[{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T15:48:20.614950927+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk.41","type":"blocks","created_at":"2025-12-19T15:48:33.058180083+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk.64","type":"blocks","created_at":"2025-12-19T15:48:33.076472519+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk.65","type":"blocks","created_at":"2025-12-19T15:48:33.095118151+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk.66","type":"blocks","created_at":"2025-12-19T15:48:33.114093425+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.68","depends_on_id":"mcp-5wk.67","type":"blocks","created_at":"2025-12-19T15:48:33.131529057+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.69","title":"Re-enable ErrorBoundarySecuritySpec tests","description":"22 tests in test/Laws/ErrorBoundarySecuritySpec.hs were disabled during the Authorization.hs refactoring (mcp-5wk.37). These tests verify error boundary security behavior. Need to update tests to use ValidationError from Servant.OAuth2.IDP.Errors instead of Types module and re-enable domainErrorToServerError in AppM.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T16:10:34.045974191+01:00","updated_at":"2025-12-19T19:57:38.763922991+01:00","closed_at":"2025-12-19T19:57:38.763922991+01:00","close_reason":"Re-enabled 22 ErrorBoundarySecuritySpec tests. Updated tests to use ValidationError from Servant.OAuth2.IDP.Errors. Re-enabled domainErrorToServerError in AppM. Verified: 489 tests pass, 0 pending. Review: PASS.","labels":["discovered","tech-debt"],"dependencies":[{"issue_id":"mcp-5wk.69","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:10:34.047174165+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.69","depends_on_id":"mcp-5wk.37","type":"discovered-from","created_at":"2025-12-19T16:10:40.946400347+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.7","title":"Update API.hs - import Metadata from Servant.OAuth2.IDP.Metadata","description":"WHERE: src/Servant/OAuth2/IDP/API.hs\nWHAT: Replace 'import MCP.Server.Auth (OAuthMetadata, ProtectedResourceMetadata)' with 'import Servant.OAuth2.IDP.Metadata (OAuthMetadata, ProtectedResourceMetadata)'.\nWHY: API.hs defines the Servant API type which includes metadata endpoints. Types must come from Servant namespace.\nHOW: Change import statement. Types and JSON instances are identical.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:09:52.950806611+01:00","updated_at":"2025-12-19T11:38:33.9220744+01:00","closed_at":"2025-12-19T11:38:33.9220744+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["parallel:true","phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.7","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:09:52.952842344+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.70","title":"Extract OAuthTrace to Servant.OAuth2.IDP.Trace with renderOAuthTrace","description":"CONSOLIDATED COMMIT: Add renderOAuthTrace function, update all imports (MCP.Trace.HTTP, MCP.Trace.Types, Servant handlers, test files), delete MCP.Trace.OAuth module. Absorbs: mcp-5wk.71, 72, 73, 74, 75","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:15.146396718+01:00","updated_at":"2025-12-19T18:38:58.524065787+01:00","closed_at":"2025-12-19T18:38:58.524065787+01:00","close_reason":"Implemented: renderOAuthTrace in Servant.OAuth2.IDP.Trace, updated all imports, deleted MCP.Trace.OAuth. Verified: 464 tests pass, 0 failures. Commit: 315ad08","labels":["phase:wip-completion"],"dependencies":[{"issue_id":"mcp-5wk.70","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:15.148086133+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.71","title":"Update MCP.Trace.HTTP to import OAuthTrace from Servant.OAuth2.IDP.Trace","description":"In src/MCP/Trace/HTTP.hs: Replace 'import MCP.Trace.OAuth (OAuthTrace, renderOAuthTrace)' with 'import Servant.OAuth2.IDP.Trace (OAuthTrace, renderOAuthTrace)'. This is part of the clean break - MCP imports from Servant, not vice versa.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:28.994440734+01:00","updated_at":"2025-12-19T17:09:52.030511126+01:00","closed_at":"2025-12-19T17:09:52.030511126+01:00","close_reason":"Consolidated into mcp-5wk.70 (single atomic commit)","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.71","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:28.995728917+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.71","depends_on_id":"mcp-5wk.70","type":"blocks","created_at":"2025-12-19T16:48:06.363895571+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.72","title":"Update MCP.Trace.Types to import OAuthTrace from Servant.OAuth2.IDP.Trace","description":"In src/MCP/Trace/Types.hs: Replace 'import MCP.Trace.OAuth (OAuthTrace (..), renderOAuthTrace)' with 'import Servant.OAuth2.IDP.Trace (OAuthTrace (..), renderOAuthTrace)'. Part of trace consolidation.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:30.274252511+01:00","updated_at":"2025-12-19T17:09:52.050658787+01:00","closed_at":"2025-12-19T17:09:52.050658787+01:00","close_reason":"Consolidated into mcp-5wk.70 (single atomic commit)","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.72","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:30.27551786+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.72","depends_on_id":"mcp-5wk.70","type":"blocks","created_at":"2025-12-19T16:48:06.381322624+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.73","title":"Delete MCP.Trace.OAuth module","description":"Delete src/MCP/Trace/OAuth.hs entirely. OAuthTrace has moved to Servant.OAuth2.IDP.Trace. Update mcp-haskell.cabal to remove MCP.Trace.OAuth from exposed-modules.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:32.028289212+01:00","updated_at":"2025-12-19T17:09:52.070229707+01:00","closed_at":"2025-12-19T17:09:52.070229707+01:00","close_reason":"Consolidated into mcp-5wk.70 (single atomic commit)","labels":["phase:clean-break"],"dependencies":[{"issue_id":"mcp-5wk.73","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:32.030112385+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.73","depends_on_id":"mcp-5wk.71","type":"blocks","created_at":"2025-12-19T16:48:06.400716511+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.73","depends_on_id":"mcp-5wk.72","type":"blocks","created_at":"2025-12-19T16:48:06.417588402+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.73","depends_on_id":"mcp-5wk.74","type":"blocks","created_at":"2025-12-19T16:48:06.434588005+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.73","depends_on_id":"mcp-5wk.75","type":"blocks","created_at":"2025-12-19T16:48:06.451453791+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.74","title":"Update Servant handler imports to use Servant.OAuth2.IDP.Trace","description":"Update these files to import from Servant.OAuth2.IDP.Trace instead of MCP.Trace.OAuth:\n- src/Servant/OAuth2/IDP/Handlers/Login.hs: Replace 'import MCP.Trace.OAuth qualified as OAuthTrace'\n- src/Servant/OAuth2/IDP/Handlers/Registration.hs: Replace 'import MCP.Trace.OAuth qualified as OAuthTrace' \n- src/Servant/OAuth2/IDP/Handlers/Token.hs: Replace 'import MCP.Trace.OAuth qualified as OAuthTrace'\n\nUse 'import Servant.OAuth2.IDP.Trace qualified as OAuthTrace' for each.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:45.648098151+01:00","updated_at":"2025-12-19T17:09:52.089015102+01:00","closed_at":"2025-12-19T17:09:52.089015102+01:00","close_reason":"Consolidated into mcp-5wk.70 (single atomic commit)","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.74","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:45.64961006+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.75","title":"Update test files to import OAuthTrace from Servant.OAuth2.IDP.Trace","description":"Update these test files to import from Servant.OAuth2.IDP.Trace:\n- test/Trace/FilterSpec.hs: Replace 'import MCP.Trace.OAuth (OAuthTrace (..))'\n- test/Trace/GoldenSpec.hs: Replace with 'import Servant.OAuth2.IDP.Trace (OAuthTrace (..), renderOAuthTrace)'\n- test/Trace/RenderSpec.hs: Replace 'import MCP.Trace.OAuth (OAuthTrace (..))'\n- test/Trace/OAuthSpec.hs: Replace with 'import Servant.OAuth2.IDP.Trace (OAuthTrace (..), renderOAuthTrace)'","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:46:47.262225212+01:00","updated_at":"2025-12-19T17:09:52.111501667+01:00","closed_at":"2025-12-19T17:09:52.111501667+01:00","close_reason":"Consolidated into mcp-5wk.70 (single atomic commit)","labels":["phase:test-update"],"dependencies":[{"issue_id":"mcp-5wk.75","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:46:47.263482266+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.76","title":"Update Servant.OAuth2.IDP.API to import Metadata from Servant module","description":"In src/Servant/OAuth2/IDP/API.hs: Replace 'import MCP.Server.Auth (OAuthMetadata, ProtectedResourceMetadata)' with 'import Servant.OAuth2.IDP.Metadata (OAuthMetadata, ProtectedResourceMetadata)'. The Metadata module already exists with these types.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:04.029238131+01:00","updated_at":"2025-12-19T17:09:52.692140376+01:00","closed_at":"2025-12-19T17:09:52.692140376+01:00","close_reason":"Duplicate of mcp-5wk.7 (API.hs)","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.76","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:04.030663134+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.77","title":"Update Servant handlers to import from Servant.OAuth2.IDP.PKCE","description":"In src/Servant/OAuth2/IDP/Handlers/Token.hs: Replace 'import MCP.Server.Auth (validateCodeVerifier, ...)' with 'import Servant.OAuth2.IDP.PKCE (validateCodeVerifier)'. The PKCE module already exists with domain-typed functions.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:05.102287363+01:00","updated_at":"2025-12-19T16:52:31.436045512+01:00","closed_at":"2025-12-19T16:52:31.436045512+01:00","close_reason":"Duplicate of mcp-5wk.34","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.77","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:05.10341527+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.78","title":"Update Servant handlers to replace MCP.Server.Auth OAuthConfig imports","description":"In these files, replace 'import MCP.Server.Auth (OAuthConfig (..))' with imports from Servant.OAuth2.IDP.Config (OAuthEnv):\n- src/Servant/OAuth2/IDP/Handlers/Login.hs\n- src/Servant/OAuth2/IDP/Handlers/Helpers.hs\n- src/Servant/OAuth2/IDP/Handlers/Registration.hs\n- src/Servant/OAuth2/IDP/Handlers/Metadata.hs\n\nThe handlers need to use OAuthEnv instead of OAuthConfig. Update HasType constraints and field access accordingly.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:06.571704341+01:00","updated_at":"2025-12-19T16:52:31.457199601+01:00","closed_at":"2025-12-19T16:52:31.457199601+01:00","close_reason":"Duplicate of mcp-5wk.35/36/38/39","labels":["phase:servant-update"],"dependencies":[{"issue_id":"mcp-5wk.78","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:06.573154355+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.79","title":"Update MCP.Server.HTTP.AppEnv to add OAuthEnv and tracer adapter","description":"In src/MCP/Server/HTTP/AppEnv.hs:\n1. Add 'envOAuthEnv :: OAuthEnv' field to AppEnv record\n2. Create 'mkOAuthEnv :: HTTPServerConfig -\u003e OAuthEnv' to construct OAuthEnv from config\n3. Create 'mkOAuthTracer :: IOTracer HTTPTrace -\u003e IOTracer OAuthTrace' via contramap (adapts HTTP tracer to OAuth tracer)\n4. Update AppEnv construction sites to include envOAuthEnv\n\nSee FR-007 in spec.md and Phase C in plan.md.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:22.209900768+01:00","updated_at":"2025-12-19T17:09:52.707592606+01:00","closed_at":"2025-12-19T17:09:52.707592606+01:00","close_reason":"Duplicate of mcp-5wk.16 (AppEnv)","labels":["phase:mcp-update"],"dependencies":[{"issue_id":"mcp-5wk.79","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:22.211112823+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.8","title":"Update Handlers/Metadata.hs - use Servant Metadata types and OAuthEnv","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Metadata.hs\nWHAT: Replace MCP imports with Servant imports. Change HasType HTTPServerConfig env to HasType OAuthEnv env.\nWHY: Metadata handler constructs OAuthMetadata response using config values. Must use OAuthEnv instead.\nHOW: 1) Replace MCP.Server.Auth imports with Servant.OAuth2.IDP.Metadata. 2) Replace MCP.Server.HTTP.AppEnv import with Servant.OAuth2.IDP.Config. 3) Update handler signature: HasType OAuthEnv env. 4) Update field access: use oauthBaseUrl, oauthSupportedScopes, etc. from OAuthEnv.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:02.563440081+01:00","updated_at":"2025-12-19T11:38:33.938342175+01:00","closed_at":"2025-12-19T11:38:33.938342175+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:02.565078596+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk.3","type":"blocks","created_at":"2025-12-18T20:12:21.327900887+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.8","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:21.367469395+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.80","title":"Remove moved types from MCP.Server.Auth (clean break)","description":"In src/MCP/Server/Auth.hs, remove types that moved to Servant modules:\n- Remove OAuthMetadata (moved to Servant.OAuth2.IDP.Metadata)\n- Remove ProtectedResourceMetadata (moved to Servant.OAuth2.IDP.Metadata) \n- Remove generateCodeVerifier, validateCodeVerifier, generateCodeChallenge (moved to Servant.OAuth2.IDP.PKCE)\n- Remove OAuthGrantType re-export (it's already in Servant.OAuth2.IDP.Types)\n- Keep: OAuthProvider, TokenInfo, extractBearerToken, PKCEChallenge, ProtectedResourceAuth, ProtectedResourceAuthConfig, MCPOAuthConfig\n\nSee FR-008 in spec.md.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T16:47:23.635055188+01:00","updated_at":"2025-12-19T16:52:31.492053446+01:00","closed_at":"2025-12-19T16:52:31.492053446+01:00","close_reason":"Duplicate of mcp-5wk.44","labels":["phase:clean-break"],"dependencies":[{"issue_id":"mcp-5wk.80","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:23.636161813+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.81","title":"Update mcp-haskell.cabal for module changes","description":"Update mcp-haskell.cabal:\n1. Remove 'Servant.OAuth2.IDP.LoginFlowError' from exposed-modules (moved to Errors)\n2. Remove 'MCP.Trace.OAuth' from exposed-modules (deleted, moved to Servant.OAuth2.IDP.Trace)\n3. Verify all new Servant.OAuth2.IDP.* modules are listed:\n - Servant.OAuth2.IDP.Trace\n - Servant.OAuth2.IDP.Config \n - Servant.OAuth2.IDP.Metadata\n - Servant.OAuth2.IDP.PKCE\n - Servant.OAuth2.IDP.Errors","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:37.57034026+01:00","updated_at":"2025-12-19T17:09:52.725204185+01:00","closed_at":"2025-12-19T17:09:52.725204185+01:00","close_reason":"Duplicate of mcp-5wk.5 (cabal update)","labels":["phase:clean-break"],"dependencies":[{"issue_id":"mcp-5wk.81","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:37.572294709+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.82","title":"Delete Servant.OAuth2.IDP.LoginFlowError module","description":"Delete src/Servant/OAuth2/IDP/LoginFlowError.hs - LoginFlowError type has been moved to Servant.OAuth2.IDP.Errors module. Verify no imports reference this module before deletion.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T16:47:40.618687678+01:00","updated_at":"2025-12-19T16:52:31.526569385+01:00","closed_at":"2025-12-19T16:52:31.526569385+01:00","close_reason":"Duplicate of mcp-5wk.45","labels":["phase:clean-break"],"dependencies":[{"issue_id":"mcp-5wk.82","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:40.619820802+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.83","title":"Verify no MCP imports remain in Servant modules","description":"Run verification checks per Acceptance Criteria:\n1. Run: rg '^import MCP\\.' src/Servant/ - should return empty\n2. Run: cabal build - should succeed with no errors\n3. Run: cabal test - all existing tests should pass\n\nIf any check fails, identify and fix remaining issues before marking complete.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T16:47:52.04000822+01:00","updated_at":"2025-12-19T17:09:52.742937442+01:00","closed_at":"2025-12-19T17:09:52.742937442+01:00","close_reason":"Duplicate of mcp-5wk.20 (verify imports)","labels":["phase:verification"],"dependencies":[{"issue_id":"mcp-5wk.83","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T16:47:52.041578797+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.83","depends_on_id":"mcp-5wk.73","type":"blocks","created_at":"2025-12-19T16:48:06.467808913+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.83","depends_on_id":"mcp-5wk.80","type":"blocks","created_at":"2025-12-19T16:48:06.484363149+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.83","depends_on_id":"mcp-5wk.81","type":"blocks","created_at":"2025-12-19T16:48:06.501031387+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.83","depends_on_id":"mcp-5wk.82","type":"blocks","created_at":"2025-12-19T16:48:06.517358219+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.84","title":"Make MalformedRequest constructor carry error context","description":"WHERE: src/Servant/OAuth2/IDP/Errors.hs:271, Authorization.hs:136\nWHAT: MalformedRequest constructor was a bare ADT with no payload, losing error information.\nSPEC UPDATE (2025-12-19): Added MalformedReason ADT per FR-004b:\n data MalformedReason = InvalidUriSyntax Text | DuplicateParameter Text | UnparseableBody Text\n MalformedRequest now takes MalformedReason payload.\nIMPLEMENTATION:\n1. Add MalformedReason ADT to Errors.hs\n2. Change MalformedRequest to MalformedRequest MalformedReason\n3. Update renderAuthorizationError to handle MalformedReason constructors\n4. Fix Authorization.hs:136 - should use UnsupportedCodeChallengeMethod (already exists in InvalidRequestReason), NOT MalformedRequest\nNOTE: MalformedReason is for structural issues (bad URI, duplicate params, unparseable body). PKCE method errors use the existing UnsupportedCodeChallengeMethod constructor.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-19T18:13:22.593573046+01:00","updated_at":"2025-12-20T17:34:13.246067019+01:00","closed_at":"2025-12-20T17:34:13.246067019+01:00","close_reason":"Implemented: Added MalformedReason ADT with InvalidUriSyntax, DuplicateParameter, UnparseableBody constructors. Updated MalformedRequest to carry payload. Fixed Authorization.hs to use UnsupportedCodeChallengeMethod. All 504 tests pass.","dependencies":[{"issue_id":"mcp-5wk.84","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T18:13:22.594912278+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.85","title":"Add resourceServerMetadata fields to OAuthEnv (R-006)","description":"WHERE: src/Servant/OAuth2/IDP/Config.hs (OAuthEnv type), src/Servant/OAuth2/IDP/Handlers/Metadata.hs (handleProtectedResourceMetadata), src/MCP/Server/HTTP/AppEnv.hs (mkOAuthEnv), specs/005-servant-oauth-extraction/spec.md (updated with clarification 2025-12-19).\n\nWHAT: Spec refinement R-006 discovered during clarification session - handleProtectedResourceMetadata currently depends on HTTPServerConfig (MCP namespace), violating extraction goal FR-001. Need to add resource server config directly to OAuthEnv.\n\nWHY: Eliminates MCP namespace dependency in Servant handler, enabling clean package extraction. Handler becomes trivial field accessor instead of conditional logic.\n\nHOW: \n1. Add two fields to OAuthEnv in Config.hs:\n - resourceServerBaseUrl :: URI\n - resourceServerMetadata :: ProtectedResourceMetadata (not Maybe - direct config)\n2. Simplify handleProtectedResourceMetadata to: asks (oauthResourceServerMetadata . getTyped @OAuthEnv)\n3. Move construction logic to mkOAuthEnv in MCP.Server.HTTP.AppEnv (builds ProtectedResourceMetadata from HTTPServerConfig, handles override pattern)\n4. Update data-model.md OAuthEnv definition (already done)\n5. Move defaultProtectedResourceMetadata to Servant.OAuth2.IDP.Metadata module for reuse\n\nSee plan.md R-006 section (lines 193-213) and data-model.md R-006 section (lines 526-552) for full details.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T19:34:33.137909033+01:00","updated_at":"2025-12-19T20:27:15.34248284+01:00","closed_at":"2025-12-19T20:27:15.34248284+01:00","close_reason":"Implemented R-006: Added resourceServerBaseUrl and resourceServerMetadata fields to OAuthEnv. Simplified handleProtectedResourceMetadata to trivial field accessor (return oauthResourceServerMetadata field). Moved OAuthMetadata type to Servant.OAuth2.IDP.Metadata namespace. Eliminated all MCP imports from Handlers/Metadata.hs. TDD workflow: RED (c291d96, ea953be), GREEN (dad3f29, df9e427). All 491 tests pass. Verified: rg '^import MCP\\.' src/Servant/OAuth2/IDP/Handlers/Metadata.hs returns empty.","labels":["phase:foundational"],"dependencies":[{"issue_id":"mcp-5wk.85","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-19T19:34:33.139772825+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.86","title":"Spec contradiction: UnsupportedCodeChallengeMethod placement","description":"WHERE: specs/005-servant-oauth-extraction/spec.md lines 126 vs 139\nWHAT: Spec has contradictory guidance on UnsupportedCodeChallengeMethod:\n- Line 126: Listed under ValidationError new constructors\n- Line 139: Listed under InvalidRequestReason (AuthorizationError)\nCurrent implementation uses ValidationError (per line 126).\nQUESTION: Should UnsupportedCodeChallengeMethod be ValidationError or InvalidRequestReason?\nDISCOVERED FROM: Review of mcp-5wk.84 implementation","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-20T17:32:39.57461088+01:00","updated_at":"2025-12-20T17:35:59.245777351+01:00","closed_at":"2025-12-20T17:35:59.245777351+01:00","close_reason":"Resolved: UnsupportedCodeChallengeMethod stays in ValidationError per clarification. Removed erroneous duplication from InvalidRequestReason in spec.md line 143.","labels":["discovered","spec-clarification"],"dependencies":[{"issue_id":"mcp-5wk.86","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T17:32:39.575997743+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.87","title":"Delete duplicate LoginFlowError.hs module","description":"FR-007 violation: src/Servant/OAuth2/IDP/LoginFlowError.hs still exists but should be deleted after moving LoginFlowError to Errors module. The type exists in both locations (LoginFlowError.hs:44-53 and Errors.hs:453-462). Delete the old file and verify no remaining imports: rg 'import.*Servant.OAuth2.IDP.LoginFlowError' src/","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-20T17:46:25.679880269+01:00","updated_at":"2025-12-20T17:59:07.879983004+01:00","closed_at":"2025-12-20T17:59:07.879983004+01:00","close_reason":"Deleted duplicate LoginFlowError.hs module. Type fully migrated to Errors.hs. Verified: 504 tests pass, 0 pending. Build clean.","labels":["phase:polish","review-fix"],"dependencies":[{"issue_id":"mcp-5wk.87","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T17:46:25.681283761+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.88","title":"Fix generator return types to use domain types","description":"FR-004c violation: Generator functions in src/Servant/OAuth2/IDP/Handlers/Helpers.hs still return Text instead of domain types. Constitution Principle I requires domain concepts have explicit types.\n\nChanges needed:\n1. generateAuthCode :: OAuthEnv -\u003e IO Text → IO AuthCodeId\n - Use mkAuthCodeId smart constructor after UUID generation\n - error on Nothing (impossible by construction)\n\n2. generateJWTAccessToken :: ... -\u003e m Text → m AccessTokenId\n - Create mkAccessTokenId smart constructor if missing\n - Use after TE.decodeUtf8' succeeds\n\n3. generateRefreshTokenWithConfig :: OAuthEnv -\u003e IO Text → IO RefreshTokenId\n - Use mkRefreshTokenId smart constructor after UUID generation\n - error on Nothing (impossible by construction)\n\nAfter updating signatures, update all call sites in Token.hs and other handlers to work with domain types directly (no Text conversion mid-flow).","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-20T17:46:36.510856149+01:00","updated_at":"2025-12-20T18:13:07.55419438+01:00","closed_at":"2025-12-20T18:13:07.55419438+01:00","close_reason":"Implemented: Generator functions return domain types (AuthCodeId, AccessTokenId, RefreshTokenId). Added mkAccessTokenId smart constructor. Updated call sites in Token.hs and Login.hs. Verified: 504 tests pass, 0 failures, 0 pending. Review: PASS.","labels":["phase:polish","review-fix","type-precision"],"dependencies":[{"issue_id":"mcp-5wk.88","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T17:46:36.512510898+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.89","title":"Fix PKCE timing attack vulnerability with constant-time comparison","description":"Security vulnerability: validateCodeVerifier in src/Servant/OAuth2/IDP/PKCE.hs:94 uses standard == comparison instead of constant-time comparison, creating a timing attack vulnerability.\n\nCurrent (VULNERABLE):\nvalidateCodeVerifier verifier challenge =\n let computed = generateCodeChallenge verifier\n in unCodeChallenge computed == unCodeChallenge challenge\n\nFix using cryptonite's Data.ByteArray.constEq:\nimport Data.ByteArray (constEq)\nimport Data.Text.Encoding qualified as TE\n\nvalidateCodeVerifier :: CodeVerifier -\u003e CodeChallenge -\u003e Bool\nvalidateCodeVerifier verifier challenge =\n let computed = generateCodeChallenge verifier\n computedBytes = TE.encodeUtf8 $ unCodeChallenge computed\n challengeBytes = TE.encodeUtf8 $ unCodeChallenge challenge\n in constEq computedBytes challengeBytes\n\nNote: memory package (providing Data.ByteArray) is already a dependency via cryptonite.","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-12-20T17:46:47.84442673+01:00","updated_at":"2025-12-20T17:54:32.388565975+01:00","closed_at":"2025-12-20T17:54:32.388565975+01:00","close_reason":"Fixed: validateCodeVerifier now uses constEq for constant-time comparison. Verified: 504 tests pass, 0 pending. Review: PASS.","labels":["phase:polish","review-fix","security"],"dependencies":[{"issue_id":"mcp-5wk.89","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T17:46:47.845762471+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.9","title":"Update Handlers/Token.hs - use PKCE from Servant.OAuth2.IDP.PKCE and OAuthEnv/OAuthTrace","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Token.hs\nWHAT: Replace MCP imports. Use validateCodeVerifier from Servant.OAuth2.IDP.PKCE. Use OAuthEnv and OAuthTrace.\nWHY: Token handler validates PKCE and emits traces. Must not depend on MCP modules.\nHOW: 1) Replace MCP.Server.Auth imports with Servant.OAuth2.IDP.PKCE for validateCodeVerifier. 2) Import OAuthEnv from Servant.OAuth2.IDP.Config. 3) Import OAuthTrace from Servant.OAuth2.IDP.Trace. 4) Replace HasType HTTPServerConfig with HasType OAuthEnv. 5) Replace HasType (IOTracer HTTPTrace) with HasType (IOTracer OAuthTrace). 6) Update trace emissions to use OAuthTrace constructors.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T20:10:11.105498164+01:00","updated_at":"2025-12-19T11:38:33.953914891+01:00","closed_at":"2025-12-19T11:38:33.953914891+01:00","close_reason":"Superseded by reorganized tasks mcp-5wk.23-48 with better phase organization and dependencies","labels":["phase:b-update-servant"],"dependencies":[{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-18T20:10:11.106689977+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.4","type":"blocks","created_at":"2025-12-18T20:12:21.348386054+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.1","type":"blocks","created_at":"2025-12-18T20:12:21.385221409+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.9","depends_on_id":"mcp-5wk.2","type":"blocks","created_at":"2025-12-18T20:12:21.406470244+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.90","title":"Remove unsafeCoerce - define unsafe constructors in Types.hs","description":"WHERE: src/Servant/OAuth2/IDP/Types/Internal.hs lines 63-129\nWHAT: 13 unsafeXXXX functions use unsafeCoerce to wrap raw values into validated newtypes\nWHY: unsafeCoerce is dangerous and unnecessary here - proper fix is to define these constructors in the same module as the types\nHOW: Move unsafeAuthCodeId, unsafeClientId, unsafeSessionId, unsafeAccessTokenId, unsafeRefreshTokenId, unsafeUserId, unsafeRedirectUri, unsafeScope, unsafeCodeChallenge, unsafeCodeVerifier, unsafeClientSecret, unsafeClientName to src/Servant/OAuth2/IDP/Types.hs where the newtypes are defined, then use normal constructor application instead of unsafeCoerce. Delete Types/Internal.hs module entirely. Update imports in dependent modules.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-20T18:04:54.174797002+01:00","updated_at":"2025-12-20T18:20:02.49683998+01:00","closed_at":"2025-12-20T18:20:02.49683998+01:00","close_reason":"Removed unsafeCoerce from Types/Internal.hs. Moved 13 unsafe constructors to Types.hs using direct constructor access. Deleted Internal module. Updated imports and cabal file. All 504 tests pass.","dependencies":[{"issue_id":"mcp-5wk.90","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:04:54.176669716+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.91","title":"Remove redundant constraints in Handlers/Helpers.hs","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/Helpers.hs:3,77-78\nWHAT: The file has -Wno-redundant-constraints pragma and HLint annotation to suppress warnings about unused OAuthStateStore constraint in generateJWTAccessToken.\nWHY: The OAuthStateStore m constraint is needed only to bring OAuthUser m into scope (associated type), but GHC reports it as redundant since no methods are called.\nHOW: Either (1) use standalone kind signature to express the type family dependency, (2) add a proxy/Proxy parameter, or (3) use TypeAbstractions to make the constraint necessary. Then remove line 3 OPTIONS_GHC and line 77 ANN pragma.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-20T18:14:43.355228982+01:00","updated_at":"2025-12-20T18:30:56.823959299+01:00","closed_at":"2025-12-20T18:30:56.823959299+01:00","close_reason":"Implemented: Used AllowAmbiguousTypes + TypeApplications to make OAuthStateStore constraint non-redundant. Removed OPTIONS_GHC -Wno-redundant-constraints and HLint ANN pragmas. Verified: 504 tests pass, 0 pending, no warnings.","dependencies":[{"issue_id":"mcp-5wk.91","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:14:43.356791358+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.92","title":"Remove authorization code IDs from client-facing error messages","description":"Security issue from code review: Error messages in Errors.hs expose internal authorization code IDs to clients (e.g., 'Authorization code not found: abc123'). This is an information disclosure vulnerability per RFC 6749 Section 5.2.\n\nFix: Replace specific messages with generic ones:\n- CodeNotFound _ -\u003e \"Authorization code is invalid\"\n- CodeExpired _ -\u003e \"Authorization code has expired\" \n- CodeAlreadyUsed _ -\u003e \"Authorization code has already been used\"\n\nKeep detailed errors in server logs via tracing, not in client-facing responses.\n\nFile: src/Servant/OAuth2/IDP/Errors.hs lines 388-394","status":"closed","priority":1,"issue_type":"bug","created_at":"2025-12-20T18:56:20.078936107+01:00","updated_at":"2025-12-20T19:07:04.828248043+01:00","closed_at":"2025-12-20T19:07:04.828248043+01:00","close_reason":"Fixed by removing code IDs from error messages and updating tests","labels":["phase:polish","review-finding","security"],"dependencies":[{"issue_id":"mcp-5wk.92","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:56:20.081183459+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.93","title":"Commit untracked test file HelpersSpec.hs","description":"MUST be done before merge. The test file test/Servant/OAuth2/IDP/Handlers/HelpersSpec.hs is untracked in git.\n\nCommands:\ngit add test/Servant/OAuth2/IDP/Handlers/HelpersSpec.hs\ngit commit -m \"test: add HelpersSpec for generator return types\"\n\nThis was identified by project-critic review as a required pre-merge task.","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-20T18:56:29.906763696+01:00","updated_at":"2025-12-20T19:03:52.714970106+01:00","closed_at":"2025-12-20T19:03:52.714970106+01:00","close_reason":"Committed test file test/Servant/OAuth2/IDP/Handlers/HelpersSpec.hs with commit 7f161b2","labels":["phase:polish","pre-merge","review-finding"],"dependencies":[{"issue_id":"mcp-5wk.93","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:56:29.908946158+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.94","title":"Fix HLint import consolidation warnings","description":"Code quality finding from review: 3 files have multiple import statements from the same module that should be consolidated.\n\nFiles to fix:\n1. src/Servant/OAuth2/IDP/Auth/Demo.hs - consolidate Servant.OAuth2.IDP.Types imports\n2. src/Servant/OAuth2/IDP/Handlers/Registration.hs - consolidate imports\n3. src/Servant/OAuth2/IDP/Test/Internal.hs - consolidate imports\n\nFix: Combine imports like:\n-- Before\nimport Servant.OAuth2.IDP.Types ( UserId )\nimport Servant.OAuth2.IDP.Types ( unsafeUserId )\n\n-- After \nimport Servant.OAuth2.IDP.Types ( UserId, unsafeUserId )\n\nCan also run: hlint --refactor to auto-fix","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-20T18:56:43.082306984+01:00","updated_at":"2025-12-20T19:10:51.366717615+01:00","closed_at":"2025-12-20T19:10:51.366717615+01:00","close_reason":"Fixed HLint import consolidation warnings in 3 files. All tests pass (504/504). Verified: no HLint warnings remain.","labels":["code-quality","phase:polish","review-finding"],"dependencies":[{"issue_id":"mcp-5wk.94","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:56:43.084008377+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.95","title":"Update CLAUDE.md to document new Servant.OAuth2.IDP module structure","description":"Documentation lag identified by project-critic review. CLAUDE.md needs updates to reflect the completed extraction.\n\nUpdates needed:\n1. Add section documenting the new module structure under Servant.OAuth2.IDP.*\n2. Highlight that these modules have zero MCP dependencies (the core invariant)\n3. Document the new OAuthEnv configuration approach\n4. Mention the split between OAuthEnv (protocol) and MCPOAuthConfig (demo/MCP-specific)\n5. Add list of new modules: Config.hs, Trace.hs, Errors.hs, PKCE.hs, Metadata.hs\n6. Document DemoOAuthBundle usage pattern for tests/demos\n\nFile: /home/claude/workspace/CLAUDE.md (OAuth Implementation Details section)","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-20T18:56:55.579811148+01:00","updated_at":"2025-12-20T19:29:55.828013832+01:00","closed_at":"2025-12-20T19:29:55.828013832+01:00","close_reason":"Implemented: Updated CLAUDE.md to document new Servant.OAuth2.IDP module structure, OAuthEnv vs MCPOAuthConfig split, DemoOAuthBundle pattern, and zero MCP dependencies invariant. Verified: 504 tests pass, 0 pending. Review: PASS after adding missing oauthScopeDescriptions field.","labels":["documentation","phase:polish","review-finding"],"dependencies":[{"issue_id":"mcp-5wk.95","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-20T18:56:55.581850941+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96","title":"Smart constructor hygiene cleanup: eliminate unsafe*, delete Boundary/Helpers, move Arbitrary to type modules","description":"Final cleanup for Servant.OAuth2.IDP extraction. GOLDEN RULE: Only code in type-defining module needs audit for correct construction.\n\nKey changes clarified in session 2025-12-22:\n1. Delete Boundary.hs - typeclass instances ARE the boundary\n2. Delete Helpers.hs - move ALL generators to Types.hs\n3. Delete test/Generators.hs - move Arbitrary instances to type modules\n4. Add QuickCheck to library deps (GHC DCE removes unused instances)\n5. Remove ALL unsafe* exports from Types.hs\n6. Tests use smart constructors only (no special privileges)\n\nSee spec.md Session 2025-12-22 clarifications for full details.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:51:11.210876213+01:00","updated_at":"2025-12-22T13:59:18.317701631+01:00","closed_at":"2025-12-22T13:59:18.317701631+01:00","close_reason":"All 11 child tasks completed and verified. Boundary.hs deleted, Helpers.hs deleted, test/Generators.hs deleted, all unsafe* exports removed from Types.hs, no unsafe* usage anywhere in codebase. 504 tests pass, hlint clean.","labels":["clarification:2025-12-22","phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T10:51:11.21248759+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.1","title":"Delete src/Servant/OAuth2/IDP/Boundary.hs","description":"Delete Boundary.hs module. Typeclass instances (ToJSON, FromJSON, ToHttpApiData, FromHttpApiData) ARE the system boundary and must live in type-defining modules. The unsafe* constructors in Boundary.hs are no longer needed.\n\nFile: src/Servant/OAuth2/IDP/Boundary.hs\nAction: Delete file\nUpdate: mcp-haskell.cabal (remove from exposed-modules)\nVerify: rg 'import.*Boundary' src/ returns empty","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:51:30.726053471+01:00","updated_at":"2025-12-22T11:35:44.026202836+01:00","closed_at":"2025-12-22T11:35:44.026202836+01:00","close_reason":"Boundary.hs successfully deleted. OAuthBoundaryTrace moved to MCP.Trace.HTTP, domainErrorToServerError moved to MCP.Server.HTTP.AppEnv, module removed from cabal file. Library and executables build successfully. Test failures are due to missing unsafe* constructors (tracked in mcp-5wk.96.6).","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.1","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:51:30.727862884+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.10","title":"Add crypto-random smart constructors for OAuth ID types in Types.hs","description":"Create crypto-grade random generation functions in Types.hs for ClientId, AuthCodeId, RefreshTokenId, SessionId.\n\nPROBLEM: Current UUID.nextRandom (Data.UUID.V4) uses system RNG, not crypto-secure. OAuth spec (RFC 6749 Section 10.10) mandates sufficient entropy to prevent guessing. Pattern creates awkward impossible-case errors:\n\n```haskell\ncase mkAuthCodeId codeText of\n Just cid -\u003e cid\n Nothing -\u003e error \"impossible: UUID never empty\"\n```\n\nLOCATIONS requiring update:\n- src/Servant/OAuth2/IDP/Handlers/Helpers.hs:69-75 (generateAuthCode)\n- src/Servant/OAuth2/IDP/Handlers/Helpers.hs:94-102 (generateRefreshTokenWithConfig)\n- src/Servant/OAuth2/IDP/Handlers/Registration.hs:101-106 (client ID generation)\n- src/Servant/OAuth2/IDP/Handlers/Authorization.hs:158 (session ID generation)\n- src/Servant/OAuth2/IDP/Test/Internal.hs:329-330 (test client names)\n\nSOLUTION:\n1. Add dependency: crypton or entropy package\n2. Create in Types.hs:\n - generateAuthCodeId :: Text -\u003e IO AuthCodeId (prefix param)\n - generateRefreshTokenId :: Text -\u003e IO RefreshTokenId\n - generateClientId :: Text -\u003e IO ClientId\n - generateSessionId :: IO SessionId\n3. Use System.Entropy.getEntropy or Crypto.Random for 128+ bits\n4. Return type directly (not Maybe) since crypto generation can't produce empty\n\nVERIFY: \n- rg 'UUID.nextRandom' src/ returns empty (or only test helpers)\n- cabal build succeeds\n- No impossible-case error patterns remain","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T11:22:07.562119999+01:00","updated_at":"2025-12-22T11:52:43.80004686+01:00","closed_at":"2025-12-22T11:52:43.80004686+01:00","close_reason":"Implemented crypto-random ID generators (generateAuthCodeId, generateClientId, generateSessionId, generateRefreshTokenId) using crypton. Handlers updated. UUID.nextRandom removed from production. Committed: 1c318f1","dependencies":[{"issue_id":"mcp-5wk.96.10","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T11:22:07.563507692+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.10","depends_on_id":"mcp-5wk.96.2","type":"related","created_at":"2025-12-22T11:22:14.587112372+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.11","title":"URGENT: Fix test RedirectUri - use mkRedirectUri instead of unsafeRedirectUri","description":"","status":"closed","priority":0,"issue_type":"bug","created_at":"2025-12-22T12:05:05.148467073+01:00","updated_at":"2025-12-22T12:35:00.19842935+01:00","closed_at":"2025-12-22T12:35:00.19842935+01:00","close_reason":"Fixed: Replaced all 16 unsafeRedirectUri usages in 6 test files with mkRedirectUri smart constructor. Also fixed 4 pre-existing hlint warnings (TE.decodeUtf8 → decodeUtf8'). Verified: hlint clean, 350+ tests pass, 0 unsafeRedirectUri in test/.","dependencies":[{"issue_id":"mcp-5wk.96.11","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T12:05:05.150609035+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.2","title":"Move generators from Helpers.hs to Types.hs, delete Helpers.hs","description":"Move remaining generators from Helpers.hs, then delete Helpers.hs.\n\nALREADY DONE (by mcp-5wk.96.10):\n- generateAuthCodeId, generateClientId, generateSessionId, generateRefreshTokenId moved to Types.hs\n\nREMAINING:\n- generateAuthCode (wrapper calling generateAuthCodeId) - DELETE or inline at call sites\n- generateJWTAccessToken - Move to src/Servant/OAuth2/IDP/Handlers/Token.hs (only callsite except tests)\n- generateRefreshTokenWithConfig (wrapper calling generateRefreshTokenId) - DELETE or inline at call sites\n\nSTEPS:\n1. Check if generateAuthCode/generateRefreshTokenWithConfig are just wrappers - inline at call sites\n2. Move generateJWTAccessToken to src/Servant/OAuth2/IDP/Handlers/Token.hs (its only production callsite)\n3. Update all imports from Helpers to appropriate modules\n4. Delete src/Servant/OAuth2/IDP/Handlers/Helpers.hs\n5. Update mcp-haskell.cabal (remove Helpers from exposed-modules)\n\nVERIFY: \n- rg \"import.*Helpers\" src/ returns empty\n- cabal build succeeds\n\nDONE WHEN:\n- Helpers.hs is deleted\n- generateJWTAccessToken lives in Token.hs\n- All imports updated\n- cabal build passes","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:51:31.736843144+01:00","updated_at":"2025-12-22T13:49:41.015514329+01:00","closed_at":"2025-12-22T13:49:41.015514329+01:00","close_reason":"Completed: Moved generateJWTAccessToken to Token.hs, inlined wrapper functions (generateAuthCode, generateRefreshTokenWithConfig, extractSessionFromCookie), deleted Helpers.hs, deleted HelpersSpec.hs, updated cabal file, fixed stale doc reference. Verified: 504 tests pass, 0 failures. Review: PASS.","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.2","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:51:31.738682756+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.3","title":"Move Arbitrary instances to type-defining modules, delete test/Generators.hs","description":"Move ALL Arbitrary instances from test/Generators.hs to source modules where types are defined.\n\nArbitrary instances must live with types because:\n1. Need constructor access for generation\n2. Module cohesion principle\n3. Eliminates need for unsafe* exports\n\nTarget modules:\n- src/Servant/OAuth2/IDP/Types.hs - AuthCodeId, ClientId, SessionId, UserId, RefreshTokenId, AccessTokenId, RedirectUri, Scope, etc.\n- src/Servant/OAuth2/IDP/Auth/Backend.hs - Username (if Arbitrary needed)\n- src/Servant/OAuth2/IDP/Errors.hs - Error types (if Arbitrary needed)\n\nFiles:\n- DELETE: test/Generators.hs\n- UPDATE: mcp-haskell.cabal (remove test/Generators.hs from test other-modules)\n- UPDATE: Test files importing Generators to import from Types\n\nVerify: cabal test succeeds","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:51:32.926733252+01:00","updated_at":"2025-12-22T13:32:08.954670681+01:00","closed_at":"2025-12-22T13:32:08.954670681+01:00","close_reason":"Implemented: Moved all Arbitrary instances from test/Generators.hs to type-defining source modules (Types.hs, Auth/Backend.hs, Auth/Demo.hs). Deleted test/Generators.hs. Used monomorphic arbitraryUTCTime/shrinkUTCTime helpers (no orphan instances). Verified: 504 tests pass, 0 failures. Review: PASS.","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.3","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:51:32.928449697+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.3","depends_on_id":"mcp-5wk.96.4","type":"blocks","created_at":"2025-12-22T10:52:28.958152279+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.4","title":"Add QuickCheck to library dependencies","description":"Add QuickCheck to library (not just test) dependencies in mcp-haskell.cabal.\n\nRationale: Arbitrary instances now live in type-defining modules (src/). GHC dead code elimination removes unused instances from production binaries. QuickCheck is a stable, reliable package.\n\nBLOCKER DISCOVERED 2025-12-22:\n- Added QuickCheck \u003e= 2.14 to library build-depends\n- Build FAILED with -Wunused-packages error\n- Root cause: Arbitrary instances are still in test/Generators.hs, not src/ modules\n- Chicken-and-egg: Can't add unused dep, but need dep before moving instances\n\nRESOLUTION OPTIONS:\n1. Combine with mcp-5wk.96.3 (move instances at same time as adding dep)\n2. Move at least ONE Arbitrary instance to src/ to satisfy -Wunused-packages\n3. Temporarily disable -Wunused-packages (not recommended)\n\nRecommend: Option 2 - move one instance as proof of concept\n\nFile: mcp-haskell.cabal\nChange: Add 'QuickCheck \u003e= 2.14' to library build-depends section\n\nVerify: cabal build succeeds","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-22T10:52:00.079297998+01:00","updated_at":"2025-12-22T13:08:32.545996132+01:00","closed_at":"2025-12-22T13:08:32.545996132+01:00","close_reason":"Added QuickCheck \u003e= 2.14 to library build-depends. Migrated Scope Arbitrary instance from test/Generators.hs to src/Servant/OAuth2/IDP/Types.hs as proof-of-concept. Verified: cabal build succeeds, 504 tests pass, hlint clean. Commit: f44bd97","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.4","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:52:00.080954185+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.5","title":"Remove ALL unsafe* exports from Types.hs","description":"Remove ALL unsafe* prefix functions from Types.hs exports.\n\nREGRESSION FIX NEEDED: Commit 1c318f1 re-added unsafe* exports that were removed in 3b10fdf. Must remove lines 92-106 from Types.hs module exports.\n\nBLOCKED BY:\n- mcp-5wk.96.6: Update test files to use smart constructors\n- mcp-5wk.96.11: URGENT fix for test RedirectUri type mismatch\n\nCannot remove unsafe* exports until all test files are updated to use mkRedirectUri and other smart constructors.\n\nVERIFY after completion:\n- rg 'unsafe' src/Servant/OAuth2/IDP/Types.hs returns only function definitions (not exports)\n- cabal test compiles and passes","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-22T10:52:01.712893192+01:00","updated_at":"2025-12-22T13:39:38.032314164+01:00","closed_at":"2025-12-22T13:39:38.032314164+01:00","close_reason":"Removed ALL unsafe* exports from Types.hs. Verified: rg 'unsafe' src/Servant/OAuth2/IDP/Types.hs returns empty, cabal build succeeds, 504 tests pass. Review: PASS.","labels":["phase:cleanup","security"],"dependencies":[{"issue_id":"mcp-5wk.96.5","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:52:01.714665856+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.5","depends_on_id":"mcp-5wk.96.9","type":"blocks","created_at":"2025-12-22T11:05:54.160544553+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.5","depends_on_id":"mcp-5wk.96.6","type":"blocks","created_at":"2025-12-22T12:08:01.984456485+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.5","depends_on_id":"mcp-5wk.96.11","type":"blocks","created_at":"2025-12-22T12:08:02.071055161+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.96.5","depends_on_id":"mcp-5wk.96.3","type":"blocks","created_at":"2025-12-22T12:17:01.693311601+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.6","title":"Update test files to use smart constructors instead of unsafe*","description":"Update ALL test files that use unsafe* constructors to use smart constructors instead.\n\nTests are library CONSUMERS - they must use the same public API (smart constructors) as any other code. No special test privileges.\n\nINCLUDES mcp-5wk.96.11 (urgent RedirectUri fix) as a subset.\n\nKEY PATTERN for RedirectUri:\n BEFORE: let uri = parseURIOrFail \"http://localhost/callback\"\n ... (unsafeRedirectUri uri)\n AFTER: let uri = fromJust $ mkRedirectUri \"http://localhost/callback\"\n ... uri\n\nFiles to update (from rg unsafe -t hs test/):\n- test/Generators.hs - unsafeRedirectUri (line 172)\n- test/TestMonad.hs - unsafeUserId\n- test/Trace/RenderSpec.hs - unsafeClientId, unsafeRedirectUri\n- test/Trace/FilterSpec.hs - unsafeClientId, unsafeRedirectUri\n- test/Trace/GoldenSpec.hs - unsafeClientId, unsafeRedirectUri, unsafeScope, unsafeSessionId\n- test/Laws/AuthCodeFunctorSpec.hs - multiple unsafe*\n- test/Servant/OAuth2/IDP/MetadataSpec.hs - unsafeScope\n- test/Servant/OAuth2/IDP/TraceSpec.hs - unsafeClientId, unsafeSessionId\n- test/Servant/OAuth2/IDP/TypesSpec.hs - unsafeScope, unsafeClientSecret, unsafeClientName\n- test/Servant/OAuth2/IDP/TokenRequestSpec.hs - unsafeAuthCodeId, unsafeRefreshTokenId\n- test/Servant/OAuth2/IDP/LucidRenderingSpec.hs - unsafeSessionId\n- test/Servant/OAuth2/IDP/APISpec.hs - unsafeMk helper\n- test/Servant/OAuth2/IDP/ErrorsSpec.hs - multiple unsafe*\n- test/MCP/Server/HTTP/McpAuthSpec.hs - unsafeUserId\n\nPattern: Replace unsafeFoo x with fromJust (mkFoo x) for known-good test values.\n\nVERIFY: \n- rg 'unsafe' test/ returns empty\n- cabal test compiles and passes","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:52:02.666088209+01:00","updated_at":"2025-12-22T12:59:18.720035793+01:00","closed_at":"2025-12-22T12:59:18.720035793+01:00","close_reason":"Implemented: All 14 test files updated to use smart constructors (fromJust $ mkFoo) instead of unsafe* constructors. Verified: 504 tests pass, 0 failures. rg 'unsafe' test/ returns only 1 comment (not constructor). Review: PASS.","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.6","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:52:02.66749623+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.7","title":"Update plan.md to reflect cleanup changes","description":"Update specs/005-servant-oauth-extraction/plan.md to reflect the clarifications from 2025-12-22 session.\n\nChanges needed:\n1. Line 59: Change 'Boundary.hs # UNCHANGED' to '(DELETED - typeclass instances are the boundary)'\n2. Line 63: Change 'Helpers.hs # MODIFY' to '(DELETED - generators moved to Types.hs)' \n3. Line 89: Change 'OAuth.hs # UNCHANGED' to '(DELETED - OAuthTrace moved to Servant.OAuth2.IDP.Trace)'\n4. Add section about GOLDEN RULE: Only code in type-defining module needs audit for correct construction\n5. Update Dependencies section to include QuickCheck as library dep\n6. Update Project Structure tree to show deletions\n\nFile: specs/005-servant-oauth-extraction/plan.md\n\nVerify: Plan accurately reflects current state","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-22T10:52:19.428412079+01:00","updated_at":"2025-12-22T13:55:08.977016474+01:00","closed_at":"2025-12-22T13:55:08.977016474+01:00","close_reason":"Updated plan.md: Added GOLDEN RULE section, marked Boundary.hs/Helpers.hs/OAuth.hs as DELETED, added QuickCheck to deps. Verified: 504 tests pass, hlint clean. Commit: 905bc44","labels":["phase:docs"],"dependencies":[{"issue_id":"mcp-5wk.96.7","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:52:19.430643789+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.8","title":"Delete MCP.Trace.OAuth module","description":"Delete src/MCP/Trace/OAuth.hs module.\n\nOAuthTrace ADT moved to Servant.OAuth2.IDP.Trace. MCP.Trace.HTTP imports directly from Servant. This module is no longer needed.\n\nFile: src/MCP/Trace/OAuth.hs\nAction: Delete file\nUpdate: mcp-haskell.cabal (remove from exposed-modules)\nUpdate: Any imports of MCP.Trace.OAuth -\u003e Servant.OAuth2.IDP.Trace\n\nVerify: rg 'import.*MCP.Trace.OAuth' src/ returns empty","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T10:52:20.237811445+01:00","updated_at":"2025-12-22T11:18:40.918838644+01:00","closed_at":"2025-12-22T11:18:40.918838644+01:00","close_reason":"Verified complete: MCP.Trace.OAuth already deleted in previous commit. File not found, not in cabal, no imports remain. 529 tests pass. No action needed.","labels":["phase:cleanup"],"dependencies":[{"issue_id":"mcp-5wk.96.8","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T10:52:20.239299167+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.96.9","title":"Update production source files to use smart constructors instead of unsafe*","description":"DISCOVERED: Production source files (not just tests) use unsafe* constructors.\n\nFiles to update:\n- src/MCP/Server/HTTP.hs: uses unsafeScope (lines ~696, 712, 722-724, 738)\n- src/Servant/OAuth2/IDP/Handlers/Registration.hs: uses unsafeClientId (line ~103)\n\nPattern: Replace unsafeX with smart constructor (mkX) or use trusted internal construction patterns.\n\nMUST complete BEFORE mcp-5wk.96.5 (Remove unsafe* exports) to avoid breaking the build.\n\nDiscovered from: mcp-5wk.96.5","status":"closed","priority":0,"issue_type":"task","created_at":"2025-12-22T11:05:46.830997084+01:00","updated_at":"2025-12-22T11:15:09.265536229+01:00","closed_at":"2025-12-22T11:15:09.265536229+01:00","close_reason":"Implemented: Replaced unsafe* usage in production source files (HTTP.hs, Registration.hs) with smart constructor patterns. Build passes, 504 tests pass.","labels":["discovered","phase:cleanup","security"],"dependencies":[{"issue_id":"mcp-5wk.96.9","depends_on_id":"mcp-5wk.96","type":"parent-child","created_at":"2025-12-22T11:05:46.832378322+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.97","title":"Add OAuthError m sum type to Servant.OAuth2.IDP.Errors","description":"WHERE: src/Servant/OAuth2/IDP/Errors.hs\nWHAT: Add unified error type: data OAuthError m = OAuthValidation ValidationError | OAuthAuthorization AuthorizationError | OAuthLoginFlow LoginFlowError | OAuthStore (OAuthStateError m). Import OAuthStateError from Store module.\nWHY: Enables single point of error-to-ServerError conversion with exhaustive pattern matching per spec FR-004b.\nDONE WHEN: Type compiles, exported from module, hlint clean.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T14:11:53.688800752+01:00","updated_at":"2025-12-22T14:40:56.802240457+01:00","closed_at":"2025-12-22T14:40:56.802240457+01:00","close_reason":"Implemented OAuthError m unified sum type with 4 constructors (OAuthValidation, OAuthAuthorization, OAuthLoginFlow, OAuthStore). Tests added and passing (509 total). hlint clean. Committed as 0ba551f. Review: PASS.","dependencies":[{"issue_id":"mcp-5wk.97","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T14:11:53.690776349+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.98","title":"Add oauthErrorToServerError function to Servant.OAuth2.IDP.Errors","description":"WHERE: src/Servant/OAuth2/IDP/Errors.hs\nWHAT: Define oauthErrorToServerError :: Show (OAuthStateError m) =\u003e OAuthError m -\u003e ServerError. Pure total function with exhaustive pattern match. Body rendering: OAuthAuthorization→JSON OAuthErrorResponse, OAuthValidation→text, OAuthLoginFlow→HTML, OAuthStore→generic 500. Add helper functions toServerErrorPlain, toServerErrorOAuth, toServerErrorLoginFlow (inline or where-clause).\nWHY: Single boundary function for OAuth error→HTTP response translation. No MCP dependencies - lives in Servant namespace.\nDONE WHEN: Function compiles, all 4 constructors handled, exported, hlint clean.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T14:12:05.179223722+01:00","updated_at":"2025-12-22T14:54:57.024465815+01:00","closed_at":"2025-12-22T14:54:57.024465815+01:00","close_reason":"Implemented oauthErrorToServerError function with exhaustive pattern matching. All 4 OAuthError constructors handled: OAuthValidation→400+text, OAuthAuthorization→varies+JSON, OAuthLoginFlow→400+HTML, OAuthStore→500+generic. 9 new tests, all 518 tests pass, hlint clean. TDD commits: 7cd6d42 (RED), 1a87369 (GREEN).","dependencies":[{"issue_id":"mcp-5wk.98","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T14:12:05.181545729+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.98","depends_on_id":"mcp-5wk.97","type":"blocks","created_at":"2025-12-22T14:12:13.37120134+01:00","created_by":"daemon"}]} +{"id":"mcp-5wk.99","title":"Update MCP.Server.HTTP.AppEnv to use oauthErrorToServerError","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs\nWHAT: 1) Import oauthErrorToServerError from Servant.OAuth2.IDP.Errors. 2) Create appErrorToServerError that maps AppError→ServerError: For OAuthStoreErr/ValidationErr/AuthorizationErr/LoginFlowErr → construct OAuthError and call oauthErrorToServerError. For AuthBackendErr → handle directly (log + 401). 3) Update runAppM to use appErrorToServerError instead of domainErrorToServerError.\nWHY: Clean separation - OAuth errors handled by Servant module, MCP-specific (AuthBackendErr) handled in MCP namespace.\nDONE WHEN: runAppM compiles with new error handling, build succeeds, tests pass.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-22T14:12:46.743074437+01:00","updated_at":"2025-12-22T15:09:40.40274765+01:00","closed_at":"2025-12-22T15:09:40.40274765+01:00","close_reason":"Implemented: Added appErrorToServerError function mapping AppError→ServerError via oauthErrorToServerError. Updated runAppM to use it. TDD cycle: RED (b3aaabb) → GREEN (aec3297) → fix (e13f932). Verified: 528 tests pass, 0 failures, hlint clean. Review: PASS (2nd iteration).","dependencies":[{"issue_id":"mcp-5wk.99","depends_on_id":"mcp-5wk","type":"parent-child","created_at":"2025-12-22T14:12:46.745002612+01:00","created_by":"daemon"},{"issue_id":"mcp-5wk.99","depends_on_id":"mcp-5wk.98","type":"blocks","created_at":"2025-12-22T14:12:53.128353121+01:00","created_by":"daemon"}]} {"id":"mcp-6k9","title":"Epic: Structured Tracing with plow-log","description":"Add comprehensive richly-typed structured logging/tracing to the MCP library using plow-log and plow-log-async.\n\nSpec: specs/003-structured-tracing/spec.md\nPlan: specs/003-structured-tracing/plan.md\nTasks: specs/003-structured-tracing/tasks.md\nData Model: specs/003-structured-tracing/data-model.md\n\nKey constraint: Implement composite trace types and plumbing first (skeleton), then fill in leaf traces incrementally.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-10T11:37:06.7165381+01:00","updated_at":"2025-12-11T13:31:08.445917142+01:00","closed_at":"2025-12-11T13:31:08.445917142+01:00"} {"id":"mcp-6k9.1","title":"Phase 1: Setup","description":"Project initialization: add plow-log dependencies, create Trace directory structure.\n\nTasks:\n- T001: Add plow-log dependencies to mcp.cabal\n- T002: Create src/MCP/Trace/ directory\n- T003: Verify dependencies resolve\n\nRef: specs/003-structured-tracing/tasks.md Phase 1","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-10T11:37:14.074275157+01:00","updated_at":"2025-12-10T12:06:29.332162176+01:00","closed_at":"2025-12-10T12:06:29.332162176+01:00","dependencies":[{"issue_id":"mcp-6k9.1","depends_on_id":"mcp-6k9","type":"parent-child","created_at":"2025-12-10T11:37:14.074815506+01:00","created_by":"daemon"}]} {"id":"mcp-6k9.1.1","title":"T001: Add plow-log dependencies to mcp.cabal","description":"Add to mcp.cabal build-depends:\n- plow-log \u003e= 0.1.6 \u0026\u0026 \u003c 0.2\n- plow-log-async \u003e= 0.1.4 \u0026\u0026 \u003c 0.2\n- unliftio-core \u003e= 0.2 \u0026\u0026 \u003c 0.3\n\nFile: mcp.cabal","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T11:37:24.353860371+01:00","updated_at":"2025-12-10T12:11:39.22546301+01:00","closed_at":"2025-12-10T12:11:39.22546301+01:00","dependencies":[{"issue_id":"mcp-6k9.1.1","depends_on_id":"mcp-6k9.1","type":"parent-child","created_at":"2025-12-10T11:37:24.354181702+01:00","created_by":"daemon"}]} @@ -145,6 +238,7 @@ {"id":"mcp-7ef","title":"Phase 7: Polish and Validation","description":"Final cleanup and validation.\n\n**Tasks** (T042-T046):\n- Update http-server.hs to log demo credentials\n- Verify cabal build succeeds\n- Run cabal test\n- Run manual test with oauth-client-demo.sh\n- Update CLAUDE.md if needed\n\n**Files**: examples/http-server.hs, CLAUDE.md\n**Validation**: specs/002-login-auth-page/quickstart.md","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-08T17:20:19.446656394+01:00","updated_at":"2025-12-08T17:49:32.693133357+01:00","closed_at":"2025-12-08T17:49:32.693133357+01:00","dependencies":[{"issue_id":"mcp-7ef","depends_on_id":"mcp-9k8","type":"parent-child","created_at":"2025-12-08T17:20:19.447140413+01:00","created_by":"daemon"},{"issue_id":"mcp-7ef","depends_on_id":"mcp-qne","type":"blocks","created_at":"2025-12-08T17:20:19.447685536+01:00","created_by":"daemon"},{"issue_id":"mcp-7ef","depends_on_id":"mcp-nbp","type":"blocks","created_at":"2025-12-08T17:20:19.448233943+01:00","created_by":"daemon"},{"issue_id":"mcp-7ef","depends_on_id":"mcp-226","type":"blocks","created_at":"2025-12-08T17:20:19.448754305+01:00","created_by":"daemon"}]} {"id":"mcp-7sd","title":"Prerequisite: Migrate HTTP.hs handlers from Text to typed domain model","description":"BLOCKER FOR mcp-nyr.13: The HTTP.hs handlers use raw Text for all OAuth parameters (client_id, redirect_uri, code_challenge, etc.) but the typeclass implementations (OAuthStateStore, AuthBackend) use newtypes (ClientId, RedirectUri, CodeChallenge, etc.).\n\nREQUIRED WORK:\n1. Create conversion functions at HTTP boundary: Text → ClientId, Text → RedirectUri, etc.\n2. Update all handler parameters to convert from Text to newtypes on entry\n3. Update response construction to convert back to Text for JSON serialization\n4. Approximately 50+ conversions needed across all OAuth endpoints\n\nWHY THIS IS NEEDED:\n- OAuthStateStore methods expect typed parameters (AuthCodeId, ClientId, etc.)\n- HTTP.hs currently passes raw Text to store operations\n- Type mismatch prevents using typeclass constraints in handlers\n\nFILES AFFECTED:\n- src/MCP/Server/HTTP.hs (main conversion work)\n- May need smart constructor exports from OAuth/Types.hs\n\nPROGRESS MADE:\n- HTTPServerConfig moved to AppEnv.hs to break circular imports\n- Build compiles, all 141 tests pass\n- Foundation ready for type migration","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-11T18:50:33.277706397+01:00","updated_at":"2025-12-11T19:00:45.267577248+01:00","closed_at":"2025-12-11T19:00:45.267577248+01:00","dependencies":[{"issue_id":"mcp-7sd","depends_on_id":"mcp-nyr.13","type":"discovered-from","created_at":"2025-12-11T18:50:33.283752046+01:00","created_by":"daemon"}]} {"id":"mcp-84r","title":"Propagate Scope newtype consistently across codebase (FR-060)","description":"WHERE: src/Servant/OAuth2/IDP/API.hs, src/Servant/OAuth2/IDP/Types.hs, src/MCP/Server/Auth.hs, src/Servant/OAuth2/IDP/Handlers/Token.hs\nWHAT: Use existing Scope newtype consistently everywhere OAuth scope values appear.\nWHY: Scope newtype exists but several places still use raw Text, defeating type safety.\nHOW:\n1. API.hs:193 - Change QueryParam \"scope\" Text to QueryParam \"scope\" Scope (or Set Scope with custom FromHttpApiData that parses space-delimited)\n2. API.hs:304 - Change TokenResponse.scope from Maybe Text to Maybe (Set Scope) or keep Text but ensure it is derived from Set Scope\n3. Auth.hs:241 - Update scope field to use Scope newtype\n4. Token.hs:237 - Ensure scope serialization uses unScope properly\n5. Update FromHttpApiData for Scope to handle space-delimited format per RFC 6749 Section 3.3\n6. Add round-trip property test","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-18T16:15:15.567832183+01:00","updated_at":"2025-12-18T17:08:50.068554385+01:00","closed_at":"2025-12-18T17:08:50.068554385+01:00","close_reason":"Implemented FR-060: Propagated Scope newtype consistently across codebase. Added ScopeList newtype with FromHttpApiData/ToHttpApiData instances for space-delimited scope parsing per RFC 6749 Section 3.3. Updated authorize endpoint API to use ScopeList, updated handler signatures, removed manual parsing. Added 13 tests for scope handling. Verified: 348 tests pass, 0 failures, 0 pending.","labels":["feature:004-oauth-auth-typeclasses","phase:polish","story:newtypes"],"dependencies":[{"issue_id":"mcp-84r","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-18T16:15:21.498111076+01:00","created_by":"daemon"}]} +{"id":"mcp-8bi","title":"Update handler tracer constraints to OAuthTrace (Q16)","description":"WHERE: src/Servant/OAuth2/IDP/Server.hs, src/Servant/OAuth2/IDP/Handlers/Registration.hs\n\nWHAT: Change handler type constraints from HasType (IOTracer HTTPTrace) to HasType (IOTracer OAuthTrace) per Q16. Remove MCP.Trace.HTTP imports.\n\nWHY: Eliminates last MCP imports from Servant modules. Handlers trace directly with OAuthTrace, no wrapping needed.\n\nHOW:\n1. Server.hs:\n - Remove: import MCP.Trace.HTTP (HTTPTrace)\n - Change constraint: HasType (IOTracer HTTPTrace) env -\u003e HasType (IOTracer OAuthTrace) env\n - Import OAuthTrace from Servant.OAuth2.IDP.Trace (if not already)\n\n2. Registration.hs:\n - Remove: import MCP.Trace.HTTP (HTTPTrace (..))\n - Change constraint: HasType (IOTracer HTTPTrace) env -\u003e HasType (IOTracer OAuthTrace) env\n - Remove contramap HTTPOAuth wrapper (line 126) - trace directly with OAuthTrace\n - Update tracer extraction: asks (getTyped @(IOTracer OAuthTrace))\n\nVERIFY: rg '^import MCP\\.' src/Servant/ returns empty for these files","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T19:48:23.775504063+01:00","updated_at":"2025-12-20T16:56:23.306424231+01:00","closed_at":"2025-12-20T16:56:23.306424231+01:00","close_reason":"Implemented: Removed MCP.Trace.HTTP imports from Server.hs and Registration.hs. Changed constraints from HasType (IOTracer HTTPTrace) to HasType (IOTracer OAuthTrace). Removed contramap wrapper in Registration.hs. Verified: 494 tests pass, 0 failures. Build succeeds.","labels":["clarification:Q16","phase:us1"],"dependencies":[{"issue_id":"mcp-8bi","depends_on_id":"mcp-nh5","type":"blocks","created_at":"2025-12-19T19:48:23.78170823+01:00","created_by":"daemon"}]} {"id":"mcp-8dn","title":"T007: Create StdIOTrace skeleton in src/MCP/Trace/StdIO.hs","description":"Create MCP.Trace.StdIO module with StdIOTrace type (includes StdIOProtocol composite) and renderStdIOTrace stub. Depends on T005 (ProtocolTrace). Ref: data-model.md StdIOTrace section.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T11:33:45.385562241+01:00","updated_at":"2025-12-10T12:17:29.635119925+01:00","closed_at":"2025-12-10T12:17:29.635119925+01:00"} {"id":"mcp-8fc","title":"US2: Dynamic Client Registration Verification","description":"User Story 2: Dynamic Client Registration\n\n## Goal\nVerify DCR endpoint works correctly for Claude.ai client registration per RFC7591.\n\n## Tasks (T019-T021)\n- T019: Verify /register endpoint returns correct RFC7591 response format\n- T020: Verify ClientRegistrationResponse includes all required fields\n- T021: Document DCR endpoint in startup output\n\n## Files to Review/Modify\n- src/MCP/Server/HTTP.hs (verification)\n- examples/http-server.hs (documentation)\n\n## Note\nDCR is already implemented. This is verification and documentation.\n\n## Independent Test\nPOST /register with client metadata → returns client_id\n\n## Acceptance Scenarios (from spec.md)\n1. Claude.ai can POST client metadata and receive client_id\n2. Registered client_id is accepted in authorization flow","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-08T15:03:36.862450647+01:00","updated_at":"2025-12-08T16:06:27.087549382+01:00","closed_at":"2025-12-08T16:06:27.087549382+01:00","dependencies":[{"issue_id":"mcp-8fc","depends_on_id":"mcp-2ij","type":"parent-child","created_at":"2025-12-08T15:03:36.862910609+01:00","created_by":"daemon"},{"issue_id":"mcp-8fc","depends_on_id":"mcp-02c","type":"blocks","created_at":"2025-12-08T15:03:36.863444313+01:00","created_by":"daemon"}]} {"id":"mcp-8oc","title":"Migrate HTML content type to servant-lucid with Lucid templates","description":"FIXME at src/Servant/OAuth2/IDP/API.hs:92. Replace custom HTML content type with servant-lucid. Create Lucid templates for login page, error pages, and success redirects.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-18T11:04:25.24082622+01:00","updated_at":"2025-12-18T11:46:52.721854006+01:00","closed_at":"2025-12-18T11:46:52.721854006+01:00","close_reason":"Implemented: Complete Lucid migration for HTML rendering. Added servant-lucid (0.9) and lucid (2.11) dependencies. Created LoginPage and ErrorPage types with ToHtml instances. Replaced legacy renderErrorPage with HTMLErrorPage error type. Added 13 tests for Lucid rendering. Verified: 295 tests pass, 0 failures. Review: PASS after fixes.","labels":["feature:004-oauth-auth-typeclasses","phase:polish","tech-debt"],"dependencies":[{"issue_id":"mcp-8oc","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-18T11:04:52.659199833+01:00","created_by":"daemon"}]} @@ -179,9 +273,11 @@ {"id":"mcp-di0.8","title":"Create referenceTestConfig for in-memory implementation","description":"Create TestConfig for reference TVar-based implementation:\n\n```haskell\nreferenceTestConfig :: IO (TestConfig AppM)\nreferenceTestConfig = do\n timeTVar \u003c- newTVarIO defaultTestTime\n env \u003c- mkTestEnv timeTVar -- Fresh OAuth state, demo creds\n let makeApp = do\n let app = serveWithContext api ctx (hoistServer api (runAppM env) server)\n return (app, \\dt -\u003e atomically $ modifyTVar timeTVar (addUTCTime dt))\n return TestConfig\n { tcMakeApp = makeApp\n , tcRunM = runReaderT (runAppM env)\n , tcCredentials = TestCredentials \"demo\" \"demo123\"\n }\n```\n\nFile: test/Functional/OAuthFlowSpec.hs (NEW) or test/TestConfig.hs\nKey: Time advancement via TVar modification\nVerify: Can instantiate TestConfig and create Application","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-12T11:07:44.874126901+01:00","updated_at":"2025-12-12T12:54:34.063470146+01:00","closed_at":"2025-12-12T12:54:34.063470146+01:00","labels":["phase:foundational"],"dependencies":[{"issue_id":"mcp-di0.8","depends_on_id":"mcp-di0","type":"parent-child","created_at":"2025-12-12T11:07:44.875228413+01:00","created_by":"daemon"},{"issue_id":"mcp-di0.8","depends_on_id":"mcp-di0.2","type":"blocks","created_at":"2025-12-12T11:09:10.580070713+01:00","created_by":"daemon"}]} {"id":"mcp-di0.9","title":"Implement clientRegistrationSpec","description":"Create client registration conformance tests:\n\n```haskell\nclientRegistrationSpec :: TestConfig m -\u003e Spec\nclientRegistrationSpec config = describe \"Client Registration\" $ do\n it \"registers a new client with valid request\" $ do\n let body = object\n [ \"client_name\" .= (\"test-client\" :: Text)\n , \"redirect_uris\" .= [\"http://localhost/callback\" :: Text]\n ]\n post \"/register\" (encode body)\n \\`shouldRespondWith\\` 201 { matchHeaders = [\"Content-Type\" \u003c:\u003e \"application/json\"] }\n\n it \"returns client_id in response\" $ do\n let body = object [\"client_name\" .= (\"test\" :: Text), \"redirect_uris\" .= [\"http://x\"]]\n resp \u003c- post \"/register\" (encode body)\n liftIO $ decode (simpleBody resp) \u003e\u003e= (.: \"client_id\") \\`shouldSatisfy\\` isJust\n\n it \"returns 400 for invalid JSON\" $ do\n post \"/register\" \"not json\" \\`shouldRespondWith\\` 400\n\n it \"returns 400 for empty redirect_uris\" $ do\n let body = object [\"client_name\" .= (\"test\" :: Text), \"redirect_uris\" .= ([] :: [Text])]\n post \"/register\" (encode body) \\`shouldRespondWith\\` 400\n```\n\nFile: src/MCP/Server/OAuth/Test/Internal.hs\nVerify: All tests pass with reference implementation","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-12T11:07:55.486549929+01:00","updated_at":"2025-12-12T13:01:33.566273669+01:00","closed_at":"2025-12-12T13:01:33.566273669+01:00","labels":["phase:us1","story:client-registration"],"dependencies":[{"issue_id":"mcp-di0.9","depends_on_id":"mcp-di0","type":"parent-child","created_at":"2025-12-12T11:07:55.488350956+01:00","created_by":"daemon"},{"issue_id":"mcp-di0.9","depends_on_id":"mcp-di0.5","type":"blocks","created_at":"2025-12-12T11:09:10.591712365+01:00","created_by":"daemon"}]} {"id":"mcp-e7d","title":"US1: Protected Resource Discovery (MVP)","description":"User Story 1: Add MCP Server as Claude Connector\n\n## Goal\nEnable Claude.ai to discover MCP server via RFC9728 Protected Resource Metadata endpoint. The ProtectedResourceAuth combinator handles 401 responses with WWW-Authenticate header automatically.\n\n## Tasks (T015-T020)\n- T015: Add ProtectedResourceAPI type for endpoint\n- T016: Update OAuthAPI to include ProtectedResourceAPI\n- T017: Implement handleProtectedResourceMetadata handler\n- T018: Wire handler into oauthServer\n- T019: Update MCPAPI type to use ProtectedResourceAuth combinator\n- T020: Add ProtectedResourceAuthConfig to server context\n\n## Key Change\nThe combinator handles 401 + WWW-Authenticate at framework level. No manual 401 handling needed in app code.\n\n## Files to Modify\n- src/MCP/Server/HTTP.hs\n\n## Contract\n- specs/001-claude-mcp-connector/contracts/oauth-protected-resource.yaml\n- specs/001-claude-mcp-connector/contracts/mcp-401-response.yaml\n\n## Independent Test\n1. Start mcp-http with --oauth\n2. GET /.well-known/oauth-protected-resource → valid RFC9728 JSON\n3. POST /mcp without auth → 401 with WWW-Authenticate header (automatic)","status":"closed","priority":1,"issue_type":"feature","created_at":"2025-12-08T15:03:26.309888358+01:00","updated_at":"2025-12-08T16:02:59.175594015+01:00","closed_at":"2025-12-08T16:02:59.175594015+01:00","dependencies":[{"issue_id":"mcp-e7d","depends_on_id":"mcp-2ij","type":"parent-child","created_at":"2025-12-08T15:03:26.310372296+01:00","created_by":"daemon"},{"issue_id":"mcp-e7d","depends_on_id":"mcp-02c","type":"blocks","created_at":"2025-12-08T15:03:26.311037778+01:00","created_by":"daemon"}]} +{"id":"mcp-e7z","title":"Update HTML.hs to use OAuthEnv branding config (Q17)","description":"WHERE: src/Servant/OAuth2/IDP/Handlers/HTML.hs\n\nWHAT: Replace hardcoded 'MCP Server' with configurable values from OAuthEnv per Q17.\n\nWHY: Enables custom branding for different OAuth server deployments. MCP can set 'MCP Server', others can customize.\n\nHOW:\n1. Update renderLoginPage to take OAuthEnv (or just serverName :: Text):\n - Line 88: title_ 'Sign In - MCP Server' -\u003e title_ ('Sign In - ' \u003c\u003e oauthServerName env)\n - Line 132: title_ 'Error - MCP Server' -\u003e title_ ('Error - ' \u003c\u003e oauthServerName env)\n\n2. Update scopeToDescription function (lines 147-149):\n - Change signature: scopeToDescription :: Map Scope Text -\u003e Scope -\u003e Text\n - Lookup in map first, fall back to generic description\n - Remove hardcoded mcp:read, mcp:write, mcp:tools descriptions\n\n3. Update all callers to pass OAuthEnv or extracted fields\n\n4. Handler functions that call HTML rendering need HasType OAuthEnv env constraint\n\nVERIFY: cabal build succeeds, grep 'MCP Server' src/Servant/ returns only doc comments","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T19:48:55.869500946+01:00","updated_at":"2025-12-20T17:16:05.610077934+01:00","closed_at":"2025-12-20T17:16:05.610077934+01:00","close_reason":"Implemented: HTML.hs uses configurable branding from OAuthEnv (oauthServerName, oauthScopeDescriptions). LoginPage/ErrorPage now have serverName fields populated from OAuthEnv in handlers. Verified: 504 tests pass, 0 failures. grep 'MCP Server' src/Servant/ returns empty. Review: PASS.","labels":["clarification:Q17","phase:us1"],"dependencies":[{"issue_id":"mcp-e7z","depends_on_id":"mcp-5pf","type":"blocks","created_at":"2025-12-19T19:48:55.875105955+01:00","created_by":"daemon"}]} {"id":"mcp-ebg","title":"POST /register should return 201 Created and validate redirect_uris","description":"WHERE: src/MCP/Server/HTTP.hs:758-791 (handleRegister)\nWHAT: Registration endpoint returns 200 OK instead of 201 Created, and accepts empty redirect_uris array without validation.\nWHY: RFC 7591 (OAuth Dynamic Client Registration) specifies 201 Created for successful registration. Empty redirect_uris will cause authorization to fail later.\nEXPECTED: 201 status code on success, 400 on empty redirect_uris\nACTUAL: 200 status code on success, accepts empty redirect_uris","status":"closed","priority":2,"issue_type":"bug","created_at":"2025-12-12T13:01:23.957866641+01:00","updated_at":"2025-12-12T16:39:36.032840422+01:00","closed_at":"2025-12-12T16:39:36.032840422+01:00","labels":["conformance"],"dependencies":[{"issue_id":"mcp-ebg","depends_on_id":"mcp-di0.9","type":"discovered-from","created_at":"2025-12-12T13:01:32.179438049+01:00","created_by":"daemon"}]} {"id":"mcp-es2","title":"US3: OAuth Flow with Resource Parameter","description":"User Story 3: OAuth Authorization Flow with PKCE\n\n## Goal\nAccept resource parameter in OAuth authorization and token endpoints per RFC8707.\n\n## Tasks (T022-T026)\n- T022: Add resource parameter to authorize endpoint in OAuthAPI type\n- T023: Update handleAuthorize function signature\n- T024: Log resource parameter in handleAuthorize\n- T025: Accept resource parameter in token request\n- T026: Log resource parameter from token request\n\n## Files to Modify\n- src/MCP/Server/HTTP.hs\n\n## Reference\n- RFC8707: https://www.rfc-editor.org/rfc/rfc8707.html\n- Research: specs/001-claude-mcp-connector/research.md\n\n## Independent Test\nFull PKCE flow with resource parameter succeeds\n\n## Acceptance Scenarios (from spec.md)\n1. Server accepts code_challenge and returns authorization code\n2. Valid code_verifier exchanges for access_token + refresh_token\n3. Invalid code_verifier rejected with invalid_grant","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-08T15:03:50.546778523+01:00","updated_at":"2025-12-08T16:06:47.470235822+01:00","closed_at":"2025-12-08T16:06:47.470235822+01:00","dependencies":[{"issue_id":"mcp-es2","depends_on_id":"mcp-2ij","type":"parent-child","created_at":"2025-12-08T15:03:50.547605186+01:00","created_by":"daemon"},{"issue_id":"mcp-es2","depends_on_id":"mcp-e7d","type":"blocks","created_at":"2025-12-08T15:03:50.548448864+01:00","created_by":"daemon"}]} {"id":"mcp-ghv","title":"Phase 8: Testing and documentation updates","description":"","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T16:01:01.24137995+01:00","updated_at":"2025-12-08T16:06:25.937545169+01:00","closed_at":"2025-12-08T16:06:25.937545169+01:00"} +{"id":"mcp-h6y","title":"Update MCPOAuthConfig in MCP.Server.Auth to set MCP branding (Q17)","description":"WHERE: src/MCP/Server/Auth.hs (MCPOAuthConfig or OAuthEnv construction), src/MCP/Server/HTTP/AppEnv.hs (mkOAuthEnv)\n\nWHAT: Configure MCP-specific branding values when building OAuthEnv for MCP server.\n\nWHY: MCP server should display 'MCP Server' branding and provide MCP-specific scope descriptions.\n\nHOW:\n1. In mkOAuthEnv or AppEnv construction:\n oauthServerName = 'MCP Server'\n oauthScopeDescriptions = Map.fromList\n [ (Scope 'mcp:read', 'Read MCP resources')\n , (Scope 'mcp:write', 'Write MCP resources')\n , (Scope 'mcp:tools', 'Execute MCP tools')\n ]\n\n2. Ensure these values propagate to OAuthEnv in AppEnv\n\nVERIFY: Run mcp-http --oauth, login page shows 'MCP Server' in title","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-19T19:49:07.98016254+01:00","updated_at":"2025-12-20T17:20:35.701825542+01:00","closed_at":"2025-12-20T17:20:35.701825542+01:00","close_reason":"Added MCP-specific scope descriptions (mcp:read, mcp:write, mcp:tools) to oauthScopeDescriptions in defaultDemoOAuthBundle. Tests: 504 passed, 0 failed.","labels":["clarification:Q17","phase:us2"],"dependencies":[{"issue_id":"mcp-h6y","depends_on_id":"mcp-e7z","type":"blocks","created_at":"2025-12-19T19:49:07.989046828+01:00","created_by":"daemon"}]} {"id":"mcp-i3w","title":"Phase 14: Remove AuthBackendUserId Associated Type (Spec Refinement 2025-12-17)","description":"Spec refinement (2025-12-17): Remove AuthBackendUserId m and OAuthUserId m associated types. validateCredentials returns Maybe (AuthBackendUser m) instead of tuple. User IDs are fields within user types, encoded into JWT via ToJWT. Simplifies API surface, eliminates unused types. See plan.md Phase 14 for details.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-17T17:13:15.371812963+01:00","updated_at":"2025-12-18T10:46:31.293210711+01:00","closed_at":"2025-12-18T10:46:31.293210711+01:00","close_reason":"Phase 14 complete: Removed AuthBackendUserId and OAuthUserId associated types. validateCredentials now returns Maybe (AuthBackendUser m). All 15 child tasks closed. Documentation updated. Verified: 271 tests pass, 0 failures, 0 pending.","labels":["feature:004-oauth-auth-typeclasses","phase:us14"],"dependencies":[{"issue_id":"mcp-i3w","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-17T17:13:22.380509353+01:00","created_by":"daemon"}]} {"id":"mcp-i3w.1","title":"Remove OAuthUserId m associated type from OAuthStateStore","description":"WHERE: src/Servant/OAuth2/IDP/Store.hs\nWHAT: Remove the 'type OAuthUserId m :: Type' associated type declaration from OAuthStateStore typeclass.\nWHY: Unused - AuthorizationCode stores full OAuthUser m, not a separate userId type.\nHOW: Delete the associated type family declaration. Typeclass should only have OAuthStateError, OAuthStateEnv, and OAuthUser.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-17T17:13:41.517885963+01:00","updated_at":"2025-12-17T17:25:48.647004466+01:00","closed_at":"2025-12-17T17:25:48.647004466+01:00","close_reason":"Already completed in commit 251bc9e. OAuthUserId associated type was removed from OAuthStateStore typeclass. Verified: 270 tests pass, 0 failures.","labels":["parallel:true","phase:us14"],"dependencies":[{"issue_id":"mcp-i3w.1","depends_on_id":"mcp-i3w","type":"parent-child","created_at":"2025-12-17T17:13:41.519356932+01:00","created_by":"daemon"}]} {"id":"mcp-i3w.10","title":"Update TestM instance - remove AuthBackendUserId type","description":"WHERE: test/TestMonad.hs\nWHAT: Remove 'type AuthBackendUserId TestM = UserId' from the AuthBackend TestM instance. Update validateCredentials implementation.\nWHY: AuthBackendUserId associated type no longer exists after task mcp-i3w.2.\nHOW: Delete the type family instance. Change return from 'Just (userId, user)' to 'Just user'.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-17T17:15:09.583550202+01:00","updated_at":"2025-12-17T18:01:06.623272597+01:00","closed_at":"2025-12-17T18:01:06.623272597+01:00","close_reason":"Removed 'type AuthBackendUserId TestM = UserId' and changed validateCredentials to return 'Just authUser' instead of 'Just (userId, authUser)'. Verified: 271 tests pass, 0 failures.","labels":["phase:us14"],"dependencies":[{"issue_id":"mcp-i3w.10","depends_on_id":"mcp-i3w","type":"parent-child","created_at":"2025-12-17T17:15:09.585124061+01:00","created_by":"daemon"},{"issue_id":"mcp-i3w.10","depends_on_id":"mcp-i3w.2","type":"blocks","created_at":"2025-12-17T17:16:09.291302197+01:00","created_by":"daemon"},{"issue_id":"mcp-i3w.10","depends_on_id":"mcp-i3w.3","type":"blocks","created_at":"2025-12-17T17:16:09.309483867+01:00","created_by":"daemon"}]} @@ -214,7 +310,8 @@ {"id":"mcp-nbf.8","title":"Add SSRF prevention tests for mkRedirectUri","description":"WHERE: test/Servant/OAuth2/IDP/TypesSpec.hs (or create new test module)\nWHAT: Add comprehensive tests for redirect URI validation security\nWHY: Verify SSRF protections work correctly. Document expected security behavior.\nHOW: Add test cases from plan.md Phase 15:\n - 'rejects substring localhost bypass' (http://evil.com?localhost=bypass)\n - 'rejects private IP 10.x.x.x' (https://10.0.0.1/callback)\n - 'rejects cloud metadata IP' (https://169.254.169.254/latest/meta-data)\n - 'accepts exact localhost' (http://localhost:3000/callback)\n - 'accepts HTTPS external' (https://example.com/callback)\n - 'rejects HTTP external' (http://example.com/callback)\n - 'rejects IPv6 private ranges'\nDepends on: mkRedirectUri fixes (mcp-nbf.2, mcp-nbf.3)","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-18T14:25:39.162065752+01:00","updated_at":"2025-12-18T15:16:07.81963489+01:00","closed_at":"2025-12-18T15:16:07.81963489+01:00","close_reason":"Added IPv6 private range tests (fe80::/10 link-local, fc00::/7 unique local) and implementation. All 319 tests pass. TDD cycle: RED (tests added, failed) -\u003e GREEN (implementation added). No regressions.","labels":["phase:us15","security","testing"],"dependencies":[{"issue_id":"mcp-nbf.8","depends_on_id":"mcp-nbf","type":"parent-child","created_at":"2025-12-18T14:25:39.163624863+01:00","created_by":"daemon"},{"issue_id":"mcp-nbf.8","depends_on_id":"mcp-nbf.2","type":"blocks","created_at":"2025-12-18T14:26:05.809410483+01:00","created_by":"daemon"},{"issue_id":"mcp-nbf.8","depends_on_id":"mcp-nbf.3","type":"blocks","created_at":"2025-12-18T14:26:05.8287568+01:00","created_by":"daemon"}]} {"id":"mcp-nbf.9","title":"Add cryptographic RNG entropy tests (FR-055)","description":"WHERE: test/Servant/OAuth2/IDP/HandlersSpec.hs or token generation test module\nWHAT: Add property tests verifying token generation entropy\nWHY: Verify CSPRNG produces sufficient randomness. Catch regression to weak RNG.\nHOW: Add tests from plan.md Phase 15:\n - property: 'generates sufficient entropy' - 1000 tokens, all unique\n - 'tokens are 32+ bytes of entropy' - base64url of 32 bytes = 43 chars\n - 'no predictable patterns' - statistical randomness tests\nDepends on: RNG audit (mcp-nbf.7)","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-18T14:25:48.131105962+01:00","updated_at":"2025-12-18T15:48:46.677889145+01:00","closed_at":"2025-12-18T15:48:46.677889145+01:00","close_reason":"Implemented: Added 9 CSPRNG entropy verification tests (FR-055) in test/Servant/OAuth2/IDP/CryptoEntropySpec.hs. Tests verify: 1000 tokens all unique (collision-free), 32 bytes entropy (43 chars base64url), valid charset, character diversity, and PKCE pair generation. Review: PASS. Verified: 328 tests pass, 0 failures, 0 pending.","labels":["phase:us15","security","testing"],"dependencies":[{"issue_id":"mcp-nbf.9","depends_on_id":"mcp-nbf","type":"parent-child","created_at":"2025-12-18T14:25:48.132618443+01:00","created_by":"daemon"},{"issue_id":"mcp-nbf.9","depends_on_id":"mcp-nbf.7","type":"blocks","created_at":"2025-12-18T14:26:05.845633423+01:00","created_by":"daemon"}]} {"id":"mcp-nbp","title":"Phase 4: User Story 2 - User Views Login Context","description":"Login page displays requesting application name and requested permissions.\n\n**Goal**: Security transparency - user sees what app is requesting access and what permissions.\n\n**Independent Test**: Register client with name → authorize → see client name and scopes on login page\n\n**Tasks** (T029-T032):\n- Extend renderLoginPage to display client name\n- Look up client name from registeredClients\n- Display human-readable scope descriptions\n- Add scope-to-description mapping\n\n**Files**: src/MCP/Server/HTTP.hs\n**Spec**: specs/002-login-auth-page/spec.md#user-story-2\n**Acceptance**: 2 scenarios defined in spec","status":"closed","priority":2,"issue_type":"feature","created_at":"2025-12-08T17:19:51.065226589+01:00","updated_at":"2025-12-08T17:42:21.911456968+01:00","closed_at":"2025-12-08T17:42:21.911456968+01:00","dependencies":[{"issue_id":"mcp-nbp","depends_on_id":"mcp-9k8","type":"parent-child","created_at":"2025-12-08T17:19:51.066010379+01:00","created_by":"daemon"},{"issue_id":"mcp-nbp","depends_on_id":"mcp-1q9","type":"blocks","created_at":"2025-12-08T17:19:51.066837701+01:00","created_by":"daemon"}]} -{"id":"mcp-nyr","title":"Epic: OAuth State and Authentication Typeclasses","description":"Feature branch: 004-oauth-auth-typeclasses. Design two typeclasses (OAuthStateStore for OAuth 2.1 state persistence, AuthBackend for user credential validation) using three-layer cake architecture with polymorphic m monad parameter. Each typeclass defines associated error and environment types. Provide in-memory (TVar) and hard-coded credential implementations preserving current demo behavior. Use generic-lens (AsType/HasType) for composable error/environment handling, hoistServerWithContext for Servant boundary translation.","status":"in_progress","priority":1,"issue_type":"epic","created_at":"2025-12-11T17:31:02.796497281+01:00","updated_at":"2025-12-18T16:13:41.387515202+01:00","labels":["feature:004-oauth-auth-typeclasses"],"dependencies":[{"issue_id":"mcp-nyr","depends_on_id":"mcp-di0","type":"blocks","created_at":"2025-12-12T11:49:15.989367359+01:00","created_by":"daemon"}]} +{"id":"mcp-nh5","title":"Add envOAuthTracer field to AppEnv (Q16)","description":"WHERE: src/MCP/Server/HTTP/AppEnv.hs (AppEnv type definition)\n\nWHAT: Add IOTracer OAuthTrace field to AppEnv per clarification Q16. Handlers use HasType (IOTracer OAuthTrace) env constraint, so AppEnv must provide this field.\n\nWHY: Enables Servant handlers to trace without importing MCP.Trace.HTTP. Tracer is constructed via contramap HTTPOAuth from main HTTPTrace tracer.\n\nHOW:\n1. Add field: envOAuthTracer :: IOTracer OAuthTrace\n2. Update AppEnv construction: envOAuthTracer = contramap HTTPOAuth envTracer\n3. Import OAuthTrace from Servant.OAuth2.IDP.Trace\n4. Import contramap from Data.Functor.Contravariant\n\nVERIFY: cabal build succeeds, no new warnings","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T19:48:09.315484275+01:00","updated_at":"2025-12-19T20:56:06.973161773+01:00","closed_at":"2025-12-19T20:56:06.973161773+01:00","close_reason":"Implemented envOAuthTracer field in AppEnv. Added field to AppEnv type, connected to HTTPTrace via contramap HTTPOAuth in all construction sites (production, demo, examples, tests). Added unit test verifying contramap behavior. 494 tests pass, 0 failures. Review: PASS.","labels":["clarification:Q16","phase:foundational"],"dependencies":[{"issue_id":"mcp-nh5","depends_on_id":"mcp-5wk","type":"discovered-from","created_at":"2025-12-19T19:48:09.330831004+01:00","created_by":"daemon"}]} +{"id":"mcp-nyr","title":"Epic: OAuth State and Authentication Typeclasses","description":"Feature branch: 004-oauth-auth-typeclasses. Design two typeclasses (OAuthStateStore for OAuth 2.1 state persistence, AuthBackend for user credential validation) using three-layer cake architecture with polymorphic m monad parameter. Each typeclass defines associated error and environment types. Provide in-memory (TVar) and hard-coded credential implementations preserving current demo behavior. Use generic-lens (AsType/HasType) for composable error/environment handling, hoistServerWithContext for Servant boundary translation.","status":"closed","priority":1,"issue_type":"epic","created_at":"2025-12-11T17:31:02.796497281+01:00","updated_at":"2025-12-19T12:49:57.386770064+01:00","closed_at":"2025-12-19T12:49:57.386770064+01:00","close_reason":"DONE","labels":["feature:004-oauth-auth-typeclasses"],"dependencies":[{"issue_id":"mcp-nyr","depends_on_id":"mcp-di0","type":"blocks","created_at":"2025-12-12T11:49:15.989367359+01:00","created_by":"daemon"}]} {"id":"mcp-nyr.1","title":"Add generic-lens, memory, QuickCheck, hspec-quickcheck to mcp.cabal","description":"Add required dependencies to mcp.cabal build-depends:\n- generic-lens ^\u003e=2.2 (AsType prisms, HasType lenses)\n- memory ^\u003e=0.18 (ScrubbedBytes for secure credential handling)\n- QuickCheck ^\u003e=2.14 (property-based testing)\n- hspec-quickcheck ^\u003e=0.2 (prop combinator for hspec integration)\n- quickcheck-instances ^\u003e=0.3 (Arbitrary instances for common types)\n- network-uri ^\u003e=2.6 (URI type for RedirectUri validation)\nFile: mcp.cabal","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-11T17:31:24.481685724+01:00","updated_at":"2025-12-11T17:42:49.036545539+01:00","closed_at":"2025-12-11T17:42:49.036545539+01:00","labels":["parallel:true","phase:setup"],"dependencies":[{"issue_id":"mcp-nyr.1","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-11T17:31:24.482950054+01:00","created_by":"daemon"}]} {"id":"mcp-nyr.10","title":"Create src/MCP/Server/OAuth/InMemory.hs with TVar-based OAuthStateStore instance","description":"Create src/MCP/Server/OAuth/InMemory.hs with TVar-based implementation:\n\nENVIRONMENT TYPE:\ndata OAuthTVarEnv = OAuthTVarEnv\n { oauthStateVar :: TVar OAuthState\n , oauthExpiryConfig :: ExpiryConfig\n }\n\ndata ExpiryConfig = ExpiryConfig\n { authCodeExpiry :: NominalDiffTime\n , loginSessionExpiry :: NominalDiffTime\n }\n\nERROR TYPE:\ndata OAuthStoreError\n = StoreUnavailable Text\n | StoreInternalError Text\n\nINSTANCE:\ninstance (MonadIO m, MonadTime m) =\u003e OAuthStateStore (ReaderT OAuthTVarEnv m) where\n type OAuthStateError (ReaderT OAuthTVarEnv m) = OAuthStoreError\n type OAuthStateEnv (ReaderT OAuthTVarEnv m) = OAuthTVarEnv\n -- Implement all 13 methods using TVar + atomically\n -- lookupAuthCode and lookupPendingAuth MUST filter expired entries using getCurrentTime\n\nPreserve existing OAuthState internal structure (Map-based).\nReference: research.md In-Memory Implementation Strategy section\nFile: src/MCP/Server/OAuth/InMemory.hs","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-11T17:32:53.341432777+01:00","updated_at":"2025-12-11T18:28:15.708005815+01:00","closed_at":"2025-12-11T18:28:15.708005815+01:00","labels":["phase:us3","story:us3"],"dependencies":[{"issue_id":"mcp-nyr.10","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-11T17:32:53.343197294+01:00","created_by":"daemon"},{"issue_id":"mcp-nyr.10","depends_on_id":"mcp-nyr.7","type":"blocks","created_at":"2025-12-11T17:34:30.23219657+01:00","created_by":"daemon"}]} {"id":"mcp-nyr.11","title":"Create src/MCP/Server/Auth/Demo.hs with demo credential AuthBackend instance","description":"Create src/MCP/Server/Auth/Demo.hs with hard-coded credential implementation:\n\nENVIRONMENT TYPE:\ndata DemoCredentialEnv = DemoCredentialEnv\n { credentialStore :: CredentialStore\n }\n\nERROR TYPE:\ndata DemoAuthError\n = InvalidCredentials\n | UserNotFound Username\n deriving (Eq, Show, Generic)\n\nINSTANCE:\ninstance MonadIO m =\u003e AuthBackend (ReaderT DemoCredentialEnv m) where\n type AuthBackendError (ReaderT DemoCredentialEnv m) = DemoAuthError\n type AuthBackendEnv (ReaderT DemoCredentialEnv m) = DemoCredentialEnv\n\n validateCredentials username password = do\n store \u003c- asks credentialStore\n let storedHash = Map.lookup username (storeCredentials store)\n case storedHash of\n Nothing -\u003e pure False\n Just hash -\u003e pure $ constantTimeCompare hash (mkHashedPassword (storeSalt store) password)\n\nDEFAULT CREDENTIALS:\ndefaultDemoCredentialStore :: CredentialStore -- demo/demo123, admin/admin456\n\nReference: contracts/AuthBackend.hs, existing MCP.Server.Auth module\nFile: src/MCP/Server/Auth/Demo.hs","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-11T17:33:02.205221646+01:00","updated_at":"2025-12-11T18:33:36.958584147+01:00","closed_at":"2025-12-11T18:33:36.958584147+01:00","labels":["phase:us3","story:us3"],"dependencies":[{"issue_id":"mcp-nyr.11","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-11T17:33:02.20733125+01:00","created_by":"daemon"},{"issue_id":"mcp-nyr.11","depends_on_id":"mcp-nyr.6","type":"blocks","created_at":"2025-12-11T17:34:30.245153574+01:00","created_by":"daemon"}]} @@ -313,4 +410,5 @@ {"id":"mcp-psg","title":"US4: Token Refresh Verification","description":"User Story 4: Token Refresh\n\n## Goal\nVerify token refresh works correctly for long-running Claude.ai sessions.\n\n## Tasks (T027-T028)\n- T027: Verify handleRefreshTokenGrant returns correct TokenResponse\n- T028: Verify refresh_token rotation works correctly\n\n## Files to Review\n- src/MCP/Server/HTTP.hs\n\n## Note\nToken refresh is already implemented. This is verification only.\n\n## Independent Test\nPOST /token with refresh_token grant → returns new access_token\n\n## Acceptance Scenario (from spec.md)\nGiven valid refresh_token, when client requests grant_type=refresh_token, then server issues new access_token","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T15:04:00.399566+01:00","updated_at":"2025-12-08T16:06:27.786563406+01:00","closed_at":"2025-12-08T16:06:27.786563406+01:00","dependencies":[{"issue_id":"mcp-psg","depends_on_id":"mcp-2ij","type":"parent-child","created_at":"2025-12-08T15:04:00.400051469+01:00","created_by":"daemon"},{"issue_id":"mcp-psg","depends_on_id":"mcp-02c","type":"blocks","created_at":"2025-12-08T15:04:00.400601992+01:00","created_by":"daemon"}]} {"id":"mcp-py8","title":"Add ToHtml instance for authorize endpoint response type","description":"FIXME at src/Servant/OAuth2/IDP/API.hs:220. Create richer response type implementing ToHtml from lucid for type-safe HTML generation. Depends on lucid migration.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-18T11:04:36.098253756+01:00","updated_at":"2025-12-18T11:50:25.279699643+01:00","closed_at":"2025-12-18T11:50:25.279699643+01:00","close_reason":"Work already complete: ToHtml instances for LoginPage and ErrorPage implemented in Handlers/HTML.hs during Lucid migration (mcp-8oc). No FIXME at API.hs:220 - line contains Show instance. Verified: 295/295 tests pass, 0 failures, including 10+ HTML/ToHtml-specific tests.","labels":["feature:004-oauth-auth-typeclasses","phase:polish","tech-debt"],"dependencies":[{"issue_id":"mcp-py8","depends_on_id":"mcp-nyr","type":"parent-child","created_at":"2025-12-18T11:04:52.679275606+01:00","created_by":"daemon"},{"issue_id":"mcp-py8","depends_on_id":"mcp-8oc","type":"blocks","created_at":"2025-12-18T11:04:52.719040249+01:00","created_by":"daemon"}]} {"id":"mcp-qne","title":"Phase 6: Edge Cases and Error Handling","description":"Handle error scenarios from spec edge cases.\n\n**Tasks** (T037-T041):\n- Handle invalid/missing OAuth parameters\n- Handle expired sessions (check pendingCreatedAt)\n- Handle cookies disabled\n- Handle unregistered client_id\n- Handle invalid redirect_uri\n\n**Files**: src/MCP/Server/HTTP.hs\n**Spec**: specs/002-login-auth-page/spec.md#edge-cases","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-08T17:20:11.975638094+01:00","updated_at":"2025-12-08T17:46:21.331164293+01:00","closed_at":"2025-12-08T17:46:21.331164293+01:00","dependencies":[{"issue_id":"mcp-qne","depends_on_id":"mcp-9k8","type":"parent-child","created_at":"2025-12-08T17:20:11.97612816+01:00","created_by":"daemon"},{"issue_id":"mcp-qne","depends_on_id":"mcp-1q9","type":"blocks","created_at":"2025-12-08T17:20:11.976664282+01:00","created_by":"daemon"}]} +{"id":"mcp-xpt","title":"Fix all hlint warnings after refactor (principled)","description":"After OAuth extraction refactor completes, systematically fix ALL hlint warnings. Fixes must be principled: understand why hlint recommends each change before applying. Verify warning-free state with 'hlint src/ test/' before closing.","status":"closed","priority":1,"issue_type":"task","created_at":"2025-12-19T18:26:57.933544198+01:00","updated_at":"2025-12-19T18:55:30.735038323+01:00","closed_at":"2025-12-19T18:55:30.735038323+01:00","close_reason":"Fixed all 24 hlint warnings systematically. Phase 1: Removed 3 unused LANGUAGE pragmas. Phase 2: Fixed 2 redundant $ operators. Phase 3: Consolidated imports. Phase 4: Addressed 11 unsafeCoerce warnings (added HLint ignore annotations with justification - smart constructor pattern requires unsafeCoerce). Phase 5: Replaced 8 fromJust calls in tests with safe helper functions. Verified: hlint shows 0 warnings, 203 tests pass with 0 failures.","dependencies":[{"issue_id":"mcp-xpt","depends_on_id":"mcp-5wk.65","type":"discovered-from","created_at":"2025-12-19T18:26:57.938315477+01:00","created_by":"daemon"}]} {"id":"mcp-zed","title":"T005: Create ProtocolTrace skeleton in src/MCP/Trace/Protocol.hs","description":"[P] Create MCP.Trace.Protocol module with ProtocolTrace type (composite placeholder only) and renderProtocolTrace stub. Ref: data-model.md ProtocolTrace section.","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-10T11:33:29.982395309+01:00","updated_at":"2025-12-10T12:17:43.317502384+01:00","closed_at":"2025-12-10T12:17:43.317502384+01:00"} diff --git a/.claude/hooks/check-haskell.sh b/.claude/hooks/check-haskell.sh index 0e7c693..88e0ac3 100755 --- a/.claude/hooks/check-haskell.sh +++ b/.claude/hooks/check-haskell.sh @@ -11,7 +11,7 @@ if [[ ! "$file_path" == *.hs ]]; then exit 0 fi -cd "$CLAUDE_PROJECT_DIR" || exit 1 +cd "$CLAUDE_PROJECT_DIR" || exit 0 output=$(cabal build 2>&1) result=$? diff --git a/.gitignore b/.gitignore index 0596e9b..941968a 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,9 @@ core-reviews cabal.project.freeze code-reviews *.log +.env* +.DS_Store +Thumbs.db +.vscode/ +.idea/ +*.tix diff --git a/.hlint.yaml b/.hlint.yaml index ce741e7..32d6bb6 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -132,7 +132,7 @@ - package base rules: - - warn: {lhs: unsafeCoerce, rhs: coerce, name: Avoid unsafeCoerce} + - error: {lhs: unsafeCoerce, rhs: coerce, name: Avoid unsafeCoerce} # Data.Bifoldable diff --git a/.specify/memory/constitution.md b/.specify/memory/constitution.md index 212c539..439707f 100644 --- a/.specify/memory/constitution.md +++ b/.specify/memory/constitution.md @@ -1,11 +1,13 @@