-
Notifications
You must be signed in to change notification settings - Fork 235
mcp: add client-side OAuth flow #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mcp: add client-side OAuth flow #544
Conversation
This is a preliminary implementation of OAuth 2.1 for the client. It provides an http.RoundTripper, auth.HTTPTransport, that invokes a user-provided callback of type auth.OAuthHandler. The latter is responsible for all the OAuth work. We will add code to make that easier in later PRs. Much remains to be done : Dynamic client registration is not implemented. Since it is optional, we also need another way of supplying the client ID and secret to this code. Resource Indicators, as described in section 2.5.1 of the MCP spec. And, of course, tests. We should test against fake implementations but also, if we can find any, real reference implementations.
c12efd0 to
a2c7f17
Compare
a2c7f17 to
8f3713d
Compare
|
Let's not submit until after the release.
…On Tue, Sep 30, 2025, 10:34 AM Sam Thanawalla ***@***.***> wrote:
***@***.**** commented on this pull request.
------------------------------
In auth/client.go
<#544 (comment)>
:
> + return resp, nil
+ }
+ if _, ok := base.(*oauth2.Transport); ok {
+ // We failed to authorize even with a token source; give up.
+ return resp, nil
+ }
+
+ resp.Body.Close()
+ // Try to authorize.
+ t.mu.Lock()
+ defer t.mu.Unlock()
+ // If we don't have a token source, get one by following the OAuth flow.
+ // (We may have obtained one while t.mu was not held above.)
+ if _, ok := t.opts.Base.(*oauth2.Transport); !ok {
+ authHeaders := resp.Header[http.CanonicalHeaderKey("WWW-Authenticate")]
+ ts, err := t.handler(req.Context(), OAuthHandlerArgs{
Done
------------------------------
In go.mod
<#544 (comment)>
:
> @@ -1,6 +1,8 @@
module github.com/modelcontextprotocol/go-sdk
-go 1.23.0
+go 1.24.0
Done
—
Reply to this email directly, view it on GitHub
<#544 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AENAOZKQNJW6RLLWIA22MDT3VKIG7AVCNFSM6AAAAACH2NKQZ6VHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTEOBVGI4TSNJXHA>
.
You are receiving this because your review was requested.Message ID:
***@***.***>
|
8f3713d to
5e8bfda
Compare
| } | ||
| t.opts.Base = &oauth2.Transport{Base: t.opts.Base, Source: ts} | ||
| } | ||
| return t.opts.Base.RoundTrip(req.Clone(req.Context())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In cagent we use the same trick for OAuth. I just spent the morning debugging and fixing our code for streamable mcp servers and thought I'd tell you what was wrong, might be useful for you.
This second request that comes after the oauth flow has a half-broken request, the body of the request was already read by the first call on line 70, so you would get a 400 Bad Request back from the server. You need to hold on the original body and put it back here before sending a second RoundTrip.
This is a preliminary implementation of OAuth 2.1 for the client.
When a StreamableClientTransport encounters a 401 Unauthorized response
from the server, it initiates the OAuth flow described in thec
authorization section of the MCP spec
(https://modelcontextprotocol.io/specification/2025-06-18/basic/authorization).
On success, the transport obtains an access token which it passes
to all subsequent requests.
Much remains to be done here:
Resource Indicators, as described in section 2.5.1 of the MCP spec.
All of this is unexported, so it is available only to our own
StreamingClientTransport. We should add API so people can use it
with their own transports.
And, of course, tests. We should test against fake implementations
but also, if we can find any, real reference implementations.
For #19
Co-authored-by: Jonathan Amsterdam jba@google.com