siyuan-note/siyuan · warning
mcp oauth authorization required
Error message
mcp oauth authorization required
What it means
errOAuthAuthorizationRequired is a sentinel error signaling that the remote MCP server responded with an OAuth challenge and the client needs the user to complete interactive authorization before the connection can succeed. Callers detect it with errors.Is to treat it as a control-flow signal (abort this connect attempt quietly, prompt for authorization, or mark credentials rejected) rather than a hard failure.
Solutions
- Trigger the interactive OAuth authorization flow for this server (reconnect with interactive mode so the browser authorization can run)
- If stored credentials are rejected, clear/re-authorize the server's OAuth credentials (markOAuthCredentialRejected path) and authorize again
- Check that the server's authorization/redirect endpoints are reachable from the browser
Example fix
// caller pattern
if errors.Is(err, errOAuthAuthorizationRequired) {
// prompt the user to authorize, then retry the connection
return nil
} Defensive patterns
Strategy: try-catch
Validate before calling
// before connecting: check whether the server needs OAuth and whether a token exists
if !hasAuthorizationHeader(server.Headers) && serverRequiresOAuth(server.URL) && !hasStoredToken(server.ID) {
// plan an interactive authorization step
} Try / catch
err := connectOneServer(ctx, server, false)
switch {
case errors.Is(err, errOAuthAuthorizationRequired):
// run interactive OAuth authorization, then retry the connect
retryWithAuthorization(server)
case err != nil && setOAuthRetryStateForError(ctx, server.ID, err.Error()):
markOAuthCredentialRejected(server.ID, server.URL)
} Prevention
- Always compare with errors.Is(err, errOAuthAuthorizationRequired), never string equality
- Proactively refresh tokens before they expire
- Keep an interactive re-authorization path available for OAuth-protected servers
- Detect and clear rejected credentials so the next connect triggers a fresh flow
When it happens
Trigger: During connectOneServer the HTTP transport's OAuth handler receives a 401/403 with a WWW-Authenticate Bearer challenge and no valid cached token; the handler returns this sentinel so the connect loop can pause for interactive authorization.
Common situations: First connection to an OAuth-protected MCP server with no stored token; a stored access token expired or was revoked; the server rotated its authorization requirements; running non-interactively so the browser-based flow cannot complete.
Related errors
- server returned without an OAuth Bearer challenge
- configuration is not initialized
- discover OAuth authorization server
- exchange OAuth authorization code
- OAuth authorization failed
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/9aad2bc8a65be829.
Report an issue: GitHub.
Appendix: 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 9f775e8a12)