-
Notifications
You must be signed in to change notification settings - Fork 138
mcp: add client-side OAuth flow (preliminary) #176
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
base: main
Are you sure you want to change the base?
Conversation
Ignore the first two commits. They should be in separate PRs. |
/cc @RoyceLeonD |
For testing, Google supports DCR and there is an example of Spotify MCP server to include client id and client secret for the fallback here. This was used to support the vscode's client (currently in insider) at the moment to do exactly this fallback mechanism when DCR does not exist at the IDP. |
@jba Sorry It took so long for me to be active on this. Will take a deeper look at the code and revert back in the next day or so. |
Add a package for the extensions to OAuth 2.0 required by MCP. This first PR adds Protected Resource Metadata.
Implement the Authorization Server Metadata spec.
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: - 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. - There is no way for the user to provide a redirect URL. - 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.
Endpoint: oauth2.Endpoint{ | ||
AuthURL: asm.AuthorizationEndpoint, | ||
TokenURL: asm.TokenEndpoint, | ||
// DeviceAuthURL: "", |
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.
adding auth style should be necessary depending on the server metadata
https://pkg.go.dev/golang.org/x/oauth2#section-readme:~:text=type-,AuthStyle,-%C2%B6
depending on the AS's token_endpoint_auth_methods_supported.
|
||
// Get an access token from the auth server. | ||
config := &oauth2.Config{ | ||
ClientID: "TODO: from registration", |
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.
I think you should add two options, one for passed in client ids/secrets and one for PKCE for public clients, for a more AUTH2.1 compliant solution.
} | ||
// TODO: try more than one? | ||
authServer := prm.AuthorizationServers[0] | ||
// TODO: which scopes to ask for? All of them? |
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.
I don't think we should ask for all the scopes, I think the best solution would be for the client to specify in its options which scopes it wants and validate against the supported ones, failing if not supported.
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.
and we could default to all, if no scope is passed.
// AuthStyle: "from auth meta?", | ||
}, | ||
RedirectURL: "", // ??? | ||
Scopes: scopes, |
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.
If you also request openid, it needs to generate and pass a nonce and validate it in the ID Token.
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:
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.
There is no way for the user to provide a redirect URL.
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.