Skip to content

Conversation

jhrozek
Copy link
Contributor

@jhrozek jhrozek commented Oct 20, 2025

Despite the PR guidelines asking for a single commit, I thought it would be easier to split the PR into several - I can rework the PR if there's general interest in accepting this work.

The motivation for creating an example client was both a user asking on Discord as well as me exploring a proposed client credentials flow extension and finally it seems that the upcoming SDK tier proposals put an emphasis on docs with examples.

For now, there is no example server, that would make the PR much more complex before I'm even sure upstream is interested, but I did test with the example server and AS from the Python SDK.

Provided you have a checkout of the Python SDK available, you'd do:

cd examples/servers/simple-auth
uv run mcp-simple-auth-as --port=9000 &
uv run mcp-simple-auth-rs --port=8001 --auth-server=http://localhost:9000  --transport=streamable-http --oauth-strict

And then run the client as:

MCP_ALLOW_HTTP_LOCALHOST=1 MCP_SERVER_PORT=8001 go run -tags mcp_go_client_oauth examples/client/simple-auth/main.go

I'd be happy to work on the PR further or split it if having a full OAuth example test is of interest to the SDK maintainers.

Add isSecureURL() function that allows HTTP connections to localhost
when MCP_ALLOW_HTTP_LOCALHOST environment variable is set to "1" or "true".

This enables local development and testing while maintaining security
requirements (HTTPS) for production use per RFC 8414 and RFC 9728.
Add a basic MCP client with interactive CLI that can:
- Connect to MCP servers via StreamableHTTP or SSE transport
- List available tools
- Call tools with JSON arguments
- Interactive command loop (list, call, quit)

This provides the foundation for adding OAuth support in subsequent commits.
Add CallbackServer to handle OAuth 2.0 authorization callbacks:
- Starts local HTTP server on configurable port
- Handles authorization code and error responses
- Returns HTML success/error pages to browser
- Thread-safe callback handling with timeout support
- Automatic server shutdown

This provides the infrastructure for receiving OAuth authorization codes.
Add registerClient() function implementing RFC 7591:
- Dynamically registers OAuth clients with authorization server
- Configures client metadata (name, redirect URIs, grant types)
- Uses client_secret_post authentication method
- Returns client ID and secret for OAuth flow

This enables the client to work with authorization servers that require
client registration.
Add complete OAuth 2.0 authorization code flow with PKCE:
- generatePKCE(): Uses golang.org/x/oauth2 for PKCE generation
- openBrowser(): Cross-platform browser launching
- performOAuthFlow(): Complete OAuth flow implementing auth.OAuthHandler
  - Fetches protected resource metadata (RFC 9728)
  - Fetches authorization server metadata (RFC 8414)
  - Performs dynamic client registration (RFC 7591)
  - Generates PKCE challenge (RFC 7636)
  - Builds authorization URL with resource parameter (RFC 8707)
  - Exchanges authorization code for access token
  - Returns oauth2.TokenSource for automatic token management

This provides the full OAuth implementation but is not yet wired into the transport.
Integrate OAuth flow with MCP transports:
- Create auth.NewHTTPTransport with performOAuthFlow handler
- Wrap in http.Client with 60-second timeout
- Pass OAuth-enabled HTTP client to MCP transports
- Supports both StreamableHTTP and SSE transports

The client now automatically handles OAuth 2.0 authentication when
connecting to protected MCP servers. On receiving a 401 response,
it triggers the OAuth flow and retries with the obtained token.

Completes the OAuth integration.
@jba
Copy link
Contributor

jba commented Oct 22, 2025

Thanks for doing this. I think you found a design flaw in our implementation. Please take a look at #600 and comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants