Repository navigation
Conversation
nuttycom
force-pushed
the
feat/auth-multiverb
branch
from
October 13, 2026 14:40
00553c2 to
b2cfaa7
Compare
nuttycom
added a commit
to nuttycom/mcp
that referenced
this pull request
Oct 13, 2026
The Streamable HTTP transport requires a server to answer a POST that
carries only a notification or a response with 202 Accepted and no body.
The POST route answered every message with a 200 event stream: a
notification got an invented `{"method":"ok"}` notification, and a
response got an empty stream. Clients that follow the specification,
such as Codex, close the connection after `notifications/initialized`.
The POST route of `MCPAPI` and `SimpleHTTPAPI` is now a `MultiVerb` over
`MCPPostResponses`: 202 with no body for a notification or a response,
and 200 with the JSON-RPC messages as Server-Sent Events for a request.
A response to a request the server never sent gets 400, instead of an
error inside a 200 stream.
servant-auth-server has no instances for `MultiVerb`, so the internal
module `MCP.Server.HTTP.AuthMultiVerb` gives them until a release
includes them
(haskell-servant/servant#1922). The `servant-auth-server < 0.4.11`
bound keeps the two from clashing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
LaurentRDC
reviewed
Oct 13, 2026
Comment on lines
+582
to
+584
| :<|> "multiverb" :> MultiVerb 'GET '[JSON] MaybeLength (Maybe Int) | ||
| :<|> "multiverb" :> "empty" :> MultiVerb 'GET '[JSON] MaybeLength (Maybe Int) | ||
| :<|> "multiverb1" :> MultiVerb1 'GET '[JSON] (Respond 200 "The length of the name" Int) |
Contributor
There was a problem hiding this comment.
Can we see a test case with the use of other headers? I want to make sure that the addition in the PR composes correctly with either other random headers, or even with another SetCookie
Author
There was a problem hiding this comment.
Added in 1c0095a. Every MultiVerb test now checks the full set of cookie names. Auth always sets two cookies (session and XSRF), so each endpoint stacks two Set-Cookie layers. New cases:
/multiverb/header: aMultiVerb1whose response has its ownBlahheader. The header comes back next to bothAuthcookies./multiverb/cookie: a two-responseMultiVerbwhose 200 response sets its ownSet-Cookie. The handler's cookie arrives with its value, next to bothAuthcookies./multiverb-auth: aMultiVerbbehindAuthwhose handler answers unauthenticated requests itself with a 401 that has aBlahheader. That response keepsBlahand has noSet-Cookieheader (the case where both cookies areNothing). An authenticated request gets the 200 with both cookies.
Reply drafted with Claude Code assistance.
An API with a `MultiVerb` endpoint under `Auth` did not compile: `AddSetCookieApi` and `AddSetCookies` had no instances for `MultiVerb`. Each response of a `MultiVerb` endpoint now gets an optional `Set-Cookie` header. The handler is written as before; `Auth` pairs its result with the cookie. An endpoint with one response takes the pair directly, because servant's own `AsUnion '[r] a` instance converts it. An endpoint with several responses takes `WithSetCookie as r`, whose `AsUnion` instance moves the cookie into whichever response the handler gives. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
nuttycom
force-pushed
the
feat/auth-multiverb
branch
from
October 16, 2026 05:36
b2cfaa7 to
1c0095a
Compare
LaurentRDC
reviewed
Oct 16, 2026
LaurentRDC
left a comment
Contributor
There was a problem hiding this comment.
Very close, just one more check for completeness
| opts <- addJwtToHeader jwt | ||
| resp <- getWith opts (url port ++ "/multiverb-auth") | ||
| resp ^. responseStatus `shouldBe` status200 | ||
| resp ^? responseBody . _JSON `shouldBe` Just (length $ name user) |
Contributor
There was a problem hiding this comment.
Can we add a check that response header "Blah" is missing?
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
An API with a
MultiVerbendpoint underAuthdoes not compile today:Authadds itsSet-Cookieheaders to every endpoint below it throughAddSetCookieApiandAddSetCookies, and neither has an instance forMultiVerb.This adds them.
MultiVerbendpoint gets an optionalSet-Cookieheader:WithHeaders '[OptHeader (Header "Set-Cookie" SetCookie)] (ResponseType a, Maybe SetCookie) a.Authpairs its result with the cookie (AddSetCookies), one layer per cookie, like theVerbcase.(r, Maybe SetCookie). servant's ownAsUnion '[r] ainstance converts it, which is also why a wrapper type cannot be used here: anAsUnion bs (Wrapper r)instance would overlap withAsUnion '[r] a.WithSetCookie as r, whoseAsUnioninstance convertsrwithAsUnion as rand moves the cookie into whichever response the handler gives (AddSetCookieUnion).sop-corebecomes a direct dependency of servant-auth-server, forNSandI; servant already depends on it.Tests
Servant.Auth.ServerSpecgains routes behindAuth, with examples that check the cookie namesAuthsets (session and XSRF, so every endpoint stacks twoSet-Cookielayers):MultiVerb(RespondEmpty 204/Respond 200 Int, handler resultMaybe Int), on both of its responses;MultiVerb1;MultiVerb1whose response has its ownBlahheader, which is kept;MultiVerbwhose 200 response sets its ownSet-Cookie, which is kept with its value;MultiVerbwhose handler answers unauthenticated requests itself: the 401 response keeps its own header and has noSet-Cookieheader, and the authenticated 200 response has both cookies.cabal test servant-auth-server:specwith GHC 9.12: 39 examples, 0 failures, 2 pending (pending before this change).Filed with Claude Code assistance.