siyuan-note/siyuan · warning

mcp oauth authorization required

Error message

mcp oauth authorization required

What it means

Sentinel error errOAuthAuthorizationRequired returned by mcpOAuthHandler.Authorize when the server returned a Bearer challenge, no usable stored credential exists (or refresh failed permanently and was cleared), and the current flow is non-interactive (e.g. background reconnect). It signals that a human-driven browser authorization is required and cannot be completed now.

Source

Thrown at kernel/mcp/client/oauth.go:47

	"net/url"
	"slices"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"github.com/modelcontextprotocol/go-sdk/auth"
	"github.com/modelcontextprotocol/go-sdk/oauthex"
	"github.com/siyuan-note/httpclient"
	"github.com/siyuan-note/logging"
	"github.com/siyuan-note/siyuan/kernel/conf"
	"github.com/siyuan-note/siyuan/kernel/util"
	"golang.org/x/oauth2"
)

const oauthAuthorizationTimeout = 5 * time.Minute

var errOAuthAuthorizationRequired = errors.New("mcp oauth authorization required")

type oauthCallbackResult struct {
	Code  string
	State string
	Error string
}

type oauthFlow struct {
	State   string
	Issuer  string
	Result  chan oauthCallbackResult
	Expires time.Time
}

var oauthFlows = struct {
	sync.Mutex
	items map[string]*oauthFlow
}{items: map[string]*oauthFlow{}}

View on GitHub (pinned to 251596fc0d)

Solutions

  1. Trigger an interactive connect from the UI so the OAuth handler can open the browser flow and capture the callback; the connect timeout automatically extends by oauthAuthorizationTimeout when interactive.
  2. Complete the browser authorization once; the resulting credential is stored and subsequent non-interactive reconnects will use refresh.
  3. If authorization keeps being required, check that the stored credential's Issuer matches the auth server's Issuer (mismatched issuers prevent refresh).
  4. Confirm the auth server supports PKCE S256 and the authorization_code grant, otherwise the interactive flow will also fail later in Authorize.
Defensive patterns

Strategy: validation

Validate before calling

// Determine whether OAuth will be required before non-interactive connect.
func needsOAuth(server conf.MCPServer) bool {
    return server.Type == "http" && !hasAuthorizationHeader(server.Headers)
}

Try / catch

// Compare with errors.Is against the sentinel.
if errors.Is(err, client.ErrOAuthAuthorizationRequired) { // (if exported)
    // trigger interactive connect from UI
}

Prevention

When it happens

Trigger: connectHTTP runs non-interactively (interactive == false), the MCP server responds 401 with an OAuth Bearer challenge, and either there is no stored credential, the stored credential's refresh failed permanently (credential was cleared), or the credential was rejected. Authorize sets runtime state 'authorization_required' and returns this sentinel.

Common situations: First time adding an OAuth-protected MCP server (no cached token) while the kernel reconnects in the background; refresh token expired/revoked and the user has not re-authorized; the credential was marked Rejected by the auth server.

Related errors


AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12). Data as JSON: /api/errors/9aad2bc8a65be829. Report an issue: GitHub.