Skip to content

fix(mcp): map HTTP 4xx auth errors to non-retryable McpError::HttpAuth#3587

Merged
bug-ops merged 1 commit intomainfrom
fix/3579-mcp-http-4xx-auth-non-retryable
May 4, 2026
Merged

fix(mcp): map HTTP 4xx auth errors to non-retryable McpError::HttpAuth#3587
bug-ops merged 1 commit intomainfrom
fix/3579-mcp-http-4xx-auth-non-retryable

Conversation

@bug-ops
Copy link
Copy Markdown
Owner

@bug-ops bug-ops commented May 4, 2026

Summary

  • HTTP 401/403/404/410/422 from remote MCP endpoints were wrapped into McpError::Connection (retryable), causing up to 47 s of backoff delay when credentials were misconfigured
  • Add McpError::HttpAuth { server_id, status: u16 } mapped to McpErrorCode::AuthFailure (is_retryable = false)
  • Replace the generic map_err in connect_url / connect_url_with_headers with classify_connect_error helper that downcasts StreamableHttpError and emits McpError::HttpAuth for non-retryable 4xx
  • Statuses 408, 425, 429 remain McpError::Connection (retryable)
  • 18 new unit tests covering all non-retryable and retryable paths

Test plan

  • cargo nextest run -p zeph-mcp --lib — 453 tests pass
  • cargo clippy --workspace -- -D warnings — clean
  • cargo +nightly fmt --check — clean
  • Configure MCP server with wrong bearer token → startup fails immediately with auth failed log, no retries
  • Configure MCP server with correct credentials → startup succeeds normally
  • Statuses 408/429 still trigger retries (transient path unchanged)

Follow-up

OAuth handshake paths (connect_url_oauth, complete_oauth) tracked in #3586.

Closes #3579

@github-actions github-actions Bot added bug Something isn't working size/L Large PR (201-500 lines) labels May 4, 2026
HTTP 401/403/404/410/422 responses from remote MCP endpoints were
previously wrapped into McpError::Connection, which is classified as
retryable (McpErrorCode::Transient). This caused up to 47 s of
exponential-backoff delay on startup when bearer tokens or credentials
were misconfigured.

Add McpError::HttpAuth { server_id, status: u16 } mapped to
McpErrorCode::AuthFailure (is_retryable = false). Replace the generic
map_err in connect_url / connect_url_with_headers with a typed
classify_connect_error helper that downcasts StreamableHttpError and
emits McpError::HttpAuth for non-retryable 4xx codes. Statuses 408,
425, and 429 remain McpError::Connection (retryable).

Adds 18 unit tests covering all non-retryable and retryable paths.
OAuth connection paths are tracked as a follow-up in #3586.

Closes #3579
@bug-ops bug-ops enabled auto-merge (squash) May 4, 2026 17:12
@bug-ops bug-ops force-pushed the fix/3579-mcp-http-4xx-auth-non-retryable branch from ba845ce to 90b40d7 Compare May 4, 2026 17:12
@github-actions github-actions Bot added documentation Improvements or additions to documentation rust Rust code changes labels May 4, 2026
@bug-ops bug-ops merged commit 0a3285e into main May 4, 2026
32 checks passed
@bug-ops bug-ops deleted the fix/3579-mcp-http-4xx-auth-non-retryable branch May 4, 2026 17:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation rust Rust code changes size/L Large PR (201-500 lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(mcp): HTTP 4xx auth errors wrapped into McpError::Connection are retried as transient

1 participant