Skip to content

OAuth client cannot connect to remote MCPs that publish only RFC 8414 metadata (e.g. mcp.atlassian.com) #599

@niklasbeinghaus

Description

@niklasbeinghaus

Summary

Muster's OAuth client (oauth.mcpClient) cannot authenticate to remote MCP servers that expose only RFC 8414 Authorization Server Metadata at /.well-known/oauth-authorization-server, because discoverProtectedResourceMetadata in internal/aggregator/server.go requires RFC 9728 Protected Resource Metadata at /.well-known/oauth-protected-resource and does not fall back.

A concrete victim of this is Atlassian's hosted Remote MCP at https://mcp.atlassian.com/v1/mcp, which is a real endpoint many users want to connect to.

Reproduction

  1. Configure muster with the OAuth proxy enabled:
    # ~/.config/muster/config.yaml
    aggregator:
      oauth:
        mcpClient:
          enabled: true
          publicUrl: http://localhost:8090
  2. Add an OAuth-protected MCP server pointing at Atlassian's hosted MCP:
    # ~/.config/muster/mcpservers/atlassian.yaml
    apiVersion: muster.giantswarm.io/v1alpha1
    kind: MCPServer
    metadata:
      name: atlassian
    spec:
      auth:
        type: oauth
      autoStart: true
      type: streamable-http
      url: https://mcp.atlassian.com/v1/mcp
  3. muster serve (v0.1.130).
  4. muster auth login --server atlassian

Expected

Browser-based OAuth flow opens against Atlassian's authorization server, completes via DCR, server reaches Connected state.

Actual

Authenticating to atlassian...
Error: failed to call auth tool: meta-tool error for core_auth_login:
  {"isError":true,"content":[{"text":"Cannot authenticate to 'atlassian':
   unable to discover OAuth authorization server. The server's
   /.well-known/oauth-protected-resource endpoint may not be available."}]}

Server log:

level=WARN msg="Failed to discover protected resource metadata for atlassian:
  resource metadata returned status 404" subsystem=AuthTools
level=WARN msg="Login failure for server atlassian by user default-...:
  issuer_discovery_failed (failures: 1)" subsystem=AuthMetrics

Why discovery fails

Atlassian doesn't publish RFC 9728 Protected Resource Metadata at any unauthenticated path:

Path Status
https://mcp.atlassian.com/.well-known/oauth-protected-resource 404
https://mcp.atlassian.com/v1/.well-known/oauth-protected-resource 404
https://mcp.atlassian.com/v1/mcp/.well-known/oauth-protected-resource 401 (catch-22: requires the very token we're trying to obtain)

But Atlassian does publish full RFC 8414 Authorization Server Metadata at the root:

$ curl -sS https://mcp.atlassian.com/.well-known/oauth-authorization-server | jq .
{
  "issuer": "https://cf.mcp.atlassian.com",
  "authorization_endpoint": "https://mcp.atlassian.com/v1/authorize",
  "token_endpoint": "https://cf.mcp.atlassian.com/v1/token",
  "registration_endpoint": "https://cf.mcp.atlassian.com/v1/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post", "none"],
  "code_challenge_methods_supported": ["plain", "S256"],
  ...
}

This is enough to complete the OAuth flow:

  • DCR endpoint is advertised → muster's CIMD-based public-client registration would succeed.
  • Authorization + token endpoints are advertised → the standard auth-code + PKCE flow would work.
  • token_endpoint_auth_methods_supported: ["none"] → public-client (no client secret) is supported, matching muster's CIMD model.

Proposed Fix

Augment discoverProtectedResourceMetadata (internal/aggregator/server.go:2238) with a fallback chain when the RFC 9728 path returns 404:

  1. RFC 9728: <base>/.well-known/oauth-protected-resource (current behavior)
  2. NEW — Parse WWW-Authenticate header on the 401 from the resource itself for resource_metadata=... parameter (per MCP Auth spec 2025-06-18, §2.1) and follow it.
  3. NEW — RFC 8414 fallback: <base>/.well-known/oauth-authorization-server — if it parses, treat its issuer as the authorization server and the response itself as AS metadata, skipping the protected-resource indirection.
  4. NEW — OpenID Connect Discovery fallback: <base>/.well-known/openid-configuration — same shape as RFC 8414 in practice for OIDC providers.

Alternatively (simpler MVP): allow operators to manually specify the authorization server in the MCPServer spec, bypassing discovery:

spec:
  auth:
    type: oauth
    authorizationServer:           # NEW
      issuer: https://cf.mcp.atlassian.com
      scopes: "openid offline_access"

When set, skip discovery entirely and use these values. This unblocks users today without re-engineering the discovery code.

Impact

Without one of the above, muster cannot connect to:

  • Atlassian Remote MCP (mcp.atlassian.com)
  • Any other future hosted MCP that follows the RFC 8414 / OIDC Discovery convention without ALSO publishing RFC 9728 metadata

Muster's documentation should be updated either way to call out this constraint, but the codebase fix is preferable.

Workaround used today

Switched to the local stdio variant (mcp-atlassian Python package via uvx) authenticated with API tokens. Functional but ties auth to a per-user PAT instead of OAuth-flow-issued credentials.

Environment

  • muster version 0.1.106 (initial repro), muster version 0.1.130 (latest, same behavior)
  • macOS, single-user local install (muster serve against ~/.config/muster)
  • Endpoint: https://mcp.atlassian.com/v1/mcp (Atlassian hosted Remote MCP)

References

  • RFC 9728 — OAuth 2.0 Protected Resource Metadata
  • RFC 8414 — OAuth 2.0 Authorization Server Metadata
  • MCP Authorization Spec 2025-06-18, §2 Discovery
  • Affected code: internal/aggregator/server.go:2238 (discoverProtectedResourceMetadata)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions