-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Description
Follow up issue for:
MCP auth doesn't work with Keycloak. #4611 and merge #5458
Describe the bug
The Goose Client doesn't follow the correct OAuth Discovery process flow correctly.
PR #511 (merged Nov 5, 2025) DOES implement RFC 9728 (Protected Resource Metadata Discovery) in the rmcp library. The PR:
- ✅ Adds discover_resource_metadata_url() method
- ✅ Implements two-step discovery:
- First: Queries /.well-known/oauth-protected-resource on MCP server
- Then: Extracts authorization_servers array
- Finally: Queries authorization server metadata
- ✅ Includes fallback discovery paths
- ✅ Targets version 0.8.5
Current flow
The rmcp library's OAuthState::new():
- ✅ Receives the 401 response (handled by transport layer)
- ❌ SKIPS Step 2 (protected resource metadata)
- ❌ Directly queries
{mcp_server_url}/.well-known/oauth-authorization-server(Step 3, but at wrong URL) - ❌ Assumes MCP server IS the authorization server
The Problem
Version 0.8.5 is NOT yet published to crates.io!
- Latest published version: 0.8.3 (per docs.rs)
- Goose is using: 0.8.3 (Cargo.toml:18)
- PR Adds 'instructions' field to InitializeResult #511 targets: 0.8.5 (not yet released)
Conclusion
-
❌ The fix is NOT yet published to crates.io as version 0.8.5
-
❌ Goose is using the older 0.8.3 which lacks RFC 9728 support
-
❌ OAuth code might require updating to point to the authorisation server, rather than the MCP server
-
✅ Once rmcp 0.8.5 is published, Goose can update
Current Operation: -
Client tries to connect → gets 401 ✅
-
rmcp 0.8.3 doesn't use protected-resource metadata ✅
-
Tries /.well-known/oauth-authorization-server on MCP server ✅
-
Fails because it doesn't have authorization_servers ✅
MCP Specification Compliance Analysis
Overview
This appendix compares Goose's OAuth implementation with the MCP OAuth 2.0 Authorization Specification to identify compliance gaps and differences.
Summary of Findings (Updated 2025-11-11)
Status: ❌ Non-Compliant - OAuth discovery does not follow MCP specification
Goose's OAuth implementation has two separate flows:
- MCP servers (mod.rs) - Uses
rmcplibrary for OAuth - Databricks (providers/oauth.rs) - Custom Databricks-specific implementation
Critical Issue: The MCP OAuth flow (via rmcp library v0.8.3) is NOT compliant with the MCP OAuth specification. It implements RFC 8414 (Authorization Server Metadata) but does NOT implement RFC 9728 (Protected Resource Metadata), which is required by the MCP specification.
Detailed Comparison
1. OAuth Discovery Endpoints (MCP Servers)
| Aspect | MCP Specification | rmcp Library (v0.8.3) | Goose/rmcp Implementation | Compliant? |
|---|---|---|---|---|
| Protected Resource Discovery | /.well-known/oauth-protected-resource (RFC 9728) |
❌ Not implemented | ❌ Skipped (mod.rs:76) | NO |
| Authorization Server Discovery | /.well-known/oauth-authorization-server (RFC 8414) |
✅ Implemented | ✅ Queries {mcp_server_url}/.well-known/oauth-authorization-server |
|
| Discovery sequence | Two-step: resource → auth server | Single-step: auth server only | Single-step: queries MCP server directly | NO |
| WWW-Authenticate header parsing | Extract protected resource metadata URL | ✅ Detects 401 | ❌ Ignores metadata URL | NO |
Analysis:
The MCP specification requires a two-step discovery process:
-
Step 1: Client connects to MCP server → receives 401 Unauthorized with
WWW-AuthenticateheaderHTTP/1.1 401 Unauthorized WWW-Authenticate: Bearer realm="MCP Server", oauth_protected_resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource"
-
Step 2: Client requests protected resource metadata from MCP server
GET https://mcp.example.com/.well-known/oauth-protected-resource Response: { "resource": "https://mcp.example.com", "authorization_servers": ["https://auth.example.com"] }
-
Step 3: Client requests authorization server metadata from the authorization server (NOT the MCP server)
GET https://auth.example.com/.well-known/oauth-authorization-server Response: { "authorization_endpoint": "https://auth.example.com/authorize", "token_endpoint": "https://auth.example.com/token", ... }
What rmcp/Goose Actually Does (mod.rs:76):
let mut oauth_state = OAuthState::new(mcp_server_url, None).await?;@zhaohuabing @romixch @botengyao @gazzadownunder @alexhancock