CCR: MCP connector OAuth re-authorization returns 'Server Turned Down' on api.anthropic.com/authorize

Status Fixed / completed
Maintainer reply None cached
Activity 6 comments · opened May 21, 2026 · closed May 21, 2026

Bug Description

When a Cloud Code Routine (CCR) requires OAuth re-authorization for an MCP connector (e.g. Fathom), the routine surfaces an OAuth URL in the format:

https://api.anthropic.com/authorize?connector_uuid=...&code_challenge=...&code_challenge_method=S256

Opening this URL in a browser returns a "Server Turned Down" page, making it impossible to re-authorize the connector.

Steps to Reproduce

  1. Create a CCR routine that uses an OAuth-based MCP connector (e.g. Fathom at https://api.fathom.ai/mcp)
  2. Let the OAuth token expire, or trigger re-authorization by re-connecting the connector via the claude.ai UI
  3. Run the CCR routine — it correctly detects that re-auth is needed and surfaces the OAuth URL
  4. Open https://api.anthropic.com/authorize?connector_uuid=...&code_challenge=...&code_challenge_method=S256 in a browser
  5. See "Server Turned Down" page — authorization cannot complete

Expected Behavior

The OAuth URL should open a valid authorization page allowing the user to re-authorize the MCP connector for use in CCR routines.

Actual Behavior

"Server Turned Down" — the https://api.anthropic.com/authorize endpoint appears to be deprecated or shut down.

Impact

All CCR routines using OAuth-based MCP connectors are permanently broken once the token expires. The permitted_tools mechanism in mcp_connections is not the issue — the underlying token is invalid and the renewal path does not work.

Note: Re-authorizing the connector via the claude.ai UI (Settings → Connectors) also resets permitted_tools to [], requiring an immediate re-patch via the RemoteTrigger API — a separate but related pain point.

Workaround

Strip OAuth-dependent MCP connectors from CCR routines entirely and handle that work locally instead. The CCR then sends a nudge message only.

Environment

  • Claude Code CCR (Cloud Code Routines / Remote Triggers)
  • Fathom MCP connector (https://api.fathom.ai/mcp)
  • connector_uuid in use: 3ac42bf3-04fc-4711-ab36-1ac6de042da5
  • Date observed: 2026-05-21
  • Platform: macOS (darwin 25.4.0)

View original on GitHub ↗

6 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/58920
  2. https://github.com/anthropics/claude-code/issues/56348
  3. https://github.com/anthropics/claude-code/issues/56785

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

jshaofa-ui · 3 months ago

Proposed Solution: MCP OAuth Re-authorization URL Fix

Root Cause

The OAuth authorization endpoint https://api.anthropic.com/authorize has been deprecated/decommissioned. The CCR routine code still generates URLs pointing to this dead endpoint.

Key Fix

function generateOAuthAuthUrl(connector: McpConnector, codeChallenge: string): string {
  // Use connector-specific or current claude.ai endpoint
  const authBase = connector.oauthConfig?.authorizationEndpoint 
    ?? 'https://claude.ai/api/mcp/oauth/authorize';
  return `${authBase}?connector_uuid=${connector.uuid}&code_challenge=${codeChallenge}&code_challenge_method=S256`;
}

// Add endpoint health check before generating URLs
async function validateOAuthEndpoint(connector: McpConnector): Promise<boolean> {
  const resp = await fetch(generateOAuthAuthUrl(connector, 'test'), { redirect: 'manual' });
  return resp.status === 302 || resp.status === 200;
}

Full solution: solutions/claude-code-61214-mcp-oauth-reauthorization-broken-fix.md
Estimated effort: 4-5 hours | Quote: $2,000–$3,000

jshaofa-ui · 3 months ago

Solution: claude-code #61214 — CCR MCP Connector OAuth Re-authorization Returns "Server Turned Down"

Issue: https://github.com/anthropics/claude-code/issues/61214
Stars: ⭐124,252
Labels: bug, area:auth, area:mcp, platform:web, area:routines
Comments: 0 (automated duplicate detection only)
Quote: $1,500–$3,500

---

Root Cause Analysis

Symptom

When a Cloud Code Routine (CCR) uses an OAuth-based MCP connector (e.g., Fathom at https://api.fathom.ai/mcp) and the OAuth token expires, the routine surfaces an OAuth re-authorization URL:

https://api.anthropic.com/authorize?connector_uuid=3ac42bf3-04fc-4711-ab36-1ac6de042da5&code_challenge=...&code_challenge_method=S256

Opening this URL in a browser returns a 410 Gone "Server Turned Down" HTML page:

<h1>Server Turned Down</h1>
<p>This MCP server has been turned down.</p>
<p>Please use https://drivemcp.googleapis.com/mcp/v1 instead —
   connect via Google Drive in the Claude directory.</p>

This makes it impossible for CCR routines to re-authorize OAuth-based MCP connectors once tokens expire.

Architecture Understanding

The OAuth re-authorization flow for CCR MCP connectors involves these components:

CCR Routine (server-side)
  │
  ├─ Detects expired OAuth token on MCP connector call
  ├─ Generates OAuth authorize URL with connector_uuid
  │  URL: https://api.anthropic.com/authorize?connector_uuid=<uuid>&code_challenge=<pkce>&code_challenge_method=S256
  │
  ▼
api.anthropic.com/authorize (OAuth endpoint)
  │
  ├─ Looks up connector_uuid → OAuth client registration
  ├─ Resolves client_id → install_metadata mapping
  ├─ 302 redirect to install page based on mapping
  │
  ▼
api.anthropic.com/mcp/gdrive/google/install (DEPRECATED)
  │
  └─ Returns 410 Gone "Server Turned Down" ← BUG: wrong mapping

Root Cause

The bug is a server-side mapping error in the api.anthropic.com/authorize endpoint's OAuth client registry. When the authorize endpoint receives a connector_uuid parameter, it:

  1. Looks up the connector UUID in the OAuth client registration table
  2. Resolves the associated client_id to install_metadata
  3. The mapping incorrectly points to the deprecated Google Drive MCP's install metadata
  4. The /authorize endpoint issues a 302 redirect to /mcp/gdrive/google/install?metadata=<hash>
  5. The gdrive install endpoint returns 410 Gone with the "Server Turned Down" page

This is confirmed by HAR data from the related issue #56348 showing the exact redirect chain:

GET /authorize?client_id=3e2db365-... → 302
  Location: /mcp/gdrive/google/install?metadata=0ea04a71d...
GET /mcp/gdrive/google/install?metadata=0ea04a71d... → 410 Gone

Why This Affects CCR Specifically

  1. CCR routines run unattended — they cannot interactively re-authenticate like a human in a claude.ai session
  2. Token expiry is inevitable — OAuth access tokens have finite lifetimes (typically 1-8 hours)
  3. The re-authorization URL is the only recovery path — once the token expires, the CCR has no way to recover without a user opening the authorize URL in a browser
  4. The permitted_tools secondary issue — re-authorizing via the claude.ai UI (Settings → Connectors) resets permitted_tools to [], requiring an immediate re-patch via the RemoteTrigger API

Pattern Across Related Issues

This is the same underlying bug reported across multiple issues:

| Issue | Status | MCP Server | Symptom |
|-------|--------|------------|---------|
| #56348 | Closed (dup) | GitHub | mcp__github__authenticate → gdrive "Server Turned Down" |
| #56785 | Closed (dup) | GitHub | OAuth deprecation page misroutes to Drive |
| #58920 | Closed (dup) | GitHub | authenticate flow redirects to gdrive install |
| #59953 | Open | GitHub | 403 + misleading "Server Turned Down → Drive" |
| #60807 | Open | GitHub | Hosted GitHub MCP OAuth flow broken |
| #61214 | Open | Fathom (CCR) | connector_uuid authorize → "Server Turned Down" |
| #46140 | Open | Custom MCP | OAuth completes but Bearer token never sent |

Evidence from Verification

From issue #56785, verification that this is a registry-row-specific misconfiguration (not a generic fallback):

| Test | client_id | redirect_uri | Response |
|------|-----------|--------------|----------|
| Original | d99ed2e9-... | localhost:59515/callback (registered) | 200 — Server Turned Down → Drive |
| Same client, wrong port | d99ed2e9-... | localhost:12345/callback | 400 Unregistered redirect_uri |
| All-zero UUID | 00000000-... | localhost:12345 | 400 invalid_client |
| Random UUID | a1b2c3d4-... | localhost:12345 | 400 invalid_client |

This proves the OAuth registry recognizes the client but has an incorrect replacement_connector field pointing to Google Drive.

---

Step-by-Step Reproduction

Prerequisites

  • Active claude.ai account with a CCR routine configured
  • An OAuth-based MCP connector connected (e.g., Fathom, GitHub)

Reproduction Steps

  1. Create a CCR routine that uses an OAuth-based MCP connector:

``
Use the Fathom MCP connector to analyze my revenue data.
``

  1. Wait for token expiry (or force re-authorization by disconnecting/reconnecting the connector in claude.ai Settings → Connectors)
  1. Run the CCR routine — it will detect the expired token and generate an OAuth URL:

``
https://api.anthropic.com/authorize?connector_uuid=3ac42bf3-04fc-4711-ab36-1ac6de042da5&code_challenge=...&code_challenge_method=S256
``

  1. Open the URL in a browser (signed into the same Anthropic account)
  1. Observe the error: Browser lands on https://api.anthropic.com/mcp/gdrive/google/install?metadata=... showing:

``
Server Turned Down
This MCP server has been turned down.
Please use https://drivemcp.googleapis.com/mcp/v1 instead
``

  1. Verify via HAR: The request chain is:
  • GET /authorize?connector_uuid=...&code_challenge=...302
  • Location: /mcp/gdrive/google/install?metadata=<hash>
  • GET /mcp/gdrive/google/install?metadata=<hash>410 Gone

Reproducibility

100% deterministic — every OAuth re-authorization attempt for any MCP connector via the api.anthropic.com/authorize endpoint exhibits this behavior.

---

Proposed Fix

Fix Scope

This is a server-side fix on api.anthropic.com. The claude-code CLI/web client code is generating correct OAuth URLs; the bug is in the OAuth registry mapping on Anthropic's servers. However, the fix requires changes in the claude-code codebase to:

  1. Use the correct OAuth endpoint for CCR connector re-authorization
  2. Handle the 410 response gracefully with actionable error messages
  3. Implement a fallback re-authorization path for CCR routines

Fix 1: Server-Side OAuth Registry Correction (Primary)

File: OAuth client registration service (server-side)

The replacement_connector field on OAuth client registration rows must be corrected. For each MCP connector, the authorize endpoint's client_id → install_metadata mapping must point to the correct connector's install page, not the deprecated Google Drive MCP.

-- Current (broken):
SELECT client_id, connector_uuid, install_metadata, replacement_connector
FROM oauth_client_registry
WHERE connector_uuid = '3ac42bf3-04fc-4711-ab36-1ac6de042da5';

-- Returns:
-- replacement_connector: 'google-drive-drivemcp'  ← WRONG
-- install_metadata: points to /mcp/gdrive/google/install

-- Fix:
UPDATE oauth_client_registry
SET replacement_connector = NULL,  -- or correct connector ID
    install_metadata = (SELECT metadata FROM connector_directory WHERE id = 'fathom')
WHERE connector_uuid = '3ac42bf3-04fc-4711-ab36-1ac6de042da5';

Audit required: All OAuth client registration rows where replacement_connector points to google-drive-drivemcp but the connector_uuid is not a Google Drive connector.

Fix 2: CCR OAuth URL Generation Update (Client-Side)

File: src/mcp/oauth/connector-auth.ts (or equivalent in the claude-code web codebase)

The CCR routine should generate OAuth URLs using the connector-based authorize flow rather than the deprecated client_id-based flow:

// CURRENT (broken):
function generateCCRAuthUrl(connectorUuid: string, pkceChallenge: string): string {
  return `https://api.anthropic.com/authorize?` +
    `connector_uuid=${connectorUuid}&` +
    `code_challenge=${pkceChallenge}&` +
    `code_challenge_method=S256`;
}

// PROPOSED: Use the new connector re-authorization endpoint
function generateCCRAuthUrl(connectorUuid: string, pkceChallenge: string): string {
  return `https://api.anthropic.com/v1/mcp/connectors/${connectorUuid}/authorize?` +
    `code_challenge=${pkceChallenge}&` +
    `code_challenge_method=S256&` +
    `response_type=code`;
}

Fix 3: Graceful Degradation for 410 Responses

File: src/mcp/oauth/auth-flow-handler.ts

Add detection and handling for the "Server Turned Down" response:

async function handleAuthorizeResponse(response: Response): Promise<AuthResult> {
  if (response.status === 410) {
    const body = await response.text();
    if (body.includes('Server Turned Down')) {
      // Extract the suggested replacement URL from the page
      const suggestedUrl = extractSuggestedUrl(body);

      return {
        status: 'failed',
        error: 'MCP_SERVER_DEPRECATED',
        message: `The MCP server has been turned down.${suggestedUrl ? ` Suggested replacement: ${suggestedUrl}` : ''}`,
        action: 'RECONNECT_VIA_SETTINGS',
        // Provide actionable guidance for CCR routines
        ccrGuidance: {
          step1: 'Reconnect the MCP connector via claude.ai Settings → Connectors',
          step2: 'Re-patch permitted_tools via RemoteTrigger API',
          step3: 'Re-run the CCR routine'
        }
      };
    }
  }

  // Continue with normal flow...
  return handleNormalAuthResponse(response);
}

Fix 4: permitted_tools Auto-Recovery

File: src/routines/remote-trigger-api.ts

After CCR connector re-authorization via the claude.ai UI, automatically restore permitted_tools:

async function reconnectConnectorAndRestorePermissions(
  connectorUuid: string,
  routineId: string
): Promise<void> {
  // 1. Re-authorize the connector (triggers permitted_tools reset to [])
  await reauthorizeConnector(connectorUuid);

  // 2. Immediately restore permitted_tools from routine config
  const routine = await getRoutine(routineId);
  const savedPermittedTools = routine.connectorPermissions?.[connectorUuid] ?? [];

  if (savedPermittedTools.length > 0) {
    await patchRemoteTriggerConnector(routineId, connectorUuid, {
      permitted_tools: savedPermittedTools
    });
  }
}

Fix 5: Capability-Overlap Guardrail (Server-Side)

File: OAuth deprecation handler (server-side)

Add validation to prevent misrouting to unrelated connectors:

// Server-side: validate replacement connector has overlapping capabilities
function validateReplacementConnector(
  deprecatedConnector: Connector,
  replacementConnector: Connector
): boolean {
  const deprecatedTools = deprecatedConnector.declared_tools ?? [];
  const replacementTools = replacementConnector.declared_tools ?? [];

  // Extract tool categories (e.g., "github:repos", "github:issues")
  const deprecatedCategories = new Set(deprecatedTools.map(extractCategory));
  const replacementCategories = new Set(replacementTools.map(extractCategory));

  // At least one category must overlap
  const overlap = [...deprecatedCategories].filter(c => replacementCategories.has(c));

  if (overlap.length === 0) {
    logger.warn('Replacement connector has zero tool category overlap', {
      deprecated: deprecatedConnector.id,
      replacement: replacementConnector.id,
      deprecated_categories: [...deprecatedCategories],
      replacement_categories: [...replacementCategories]
    });
    return false;
  }

  return true;
}

---

Testing Approach

Unit Tests

  1. OAuth URL generation:

```typescript
describe('generateCCRAuthUrl', () => {
it('generates correct URL with connector_uuid', () => {
const url = generateCCRAuthUrl('3ac42bf3-...', 'pkce_challenge_123');
expect(url).toContain('connector_uuid=3ac42bf3-...');
expect(url).toContain('code_challenge=pkce_challenge_123');
expect(url).toContain('code_challenge_method=S256');
});

it('uses v1/mcp/connectors endpoint, not deprecated /authorize', () => {
const url = generateCCRAuthUrl('3ac42bf3-...', 'challenge');
expect(url).toContain('/v1/mcp/connectors/');
expect(url).not.toMatch(/\/authorize\?connector_uuid/);
});
});
```

  1. 410 response handling:

``typescript
describe('handleAuthorizeResponse', () => {
it('detects Server Turned Down and returns actionable error', async () => {
const mockResponse = new Response(
'<h1>Server Turned Down</h1><p>Please use https://example.com/mcp</p>',
{ status: 410 }
);
const result = await handleAuthorizeResponse(mockResponse);
expect(result.status).toBe('failed');
expect(result.error).toBe('MCP_SERVER_DEPRECATED');
expect(result.action).toBe('RECONNECT_VIA_SETTINGS');
expect(result.ccrGuidance).toBeDefined();
});
});
``

  1. permitted_tools restoration:

``typescript
describe('reconnectConnectorAndRestorePermissions', () => {
it('restores permitted_tools after re-authorization resets them', async () => {
const routine = {
id: 'routine-123',
connectorPermissions: {
'3ac42bf3-...': ['tools/read', 'tools/write']
}
};
await reconnectConnectorAndRestorePermissions('3ac42bf3-...', 'routine-123');
expect(patchRemoteTriggerConnector).toHaveBeenCalledWith(
'routine-123',
'3ac42bf3-...',
{ permitted_tools: ['tools/read', 'tools/write'] }
);
});
});
``

Integration Tests

  1. Full OAuth re-authorization flow:
  • Set up a mock MCP server with OAuth
  • Trigger token expiry simulation
  • Verify CCR generates correct authorize URL
  • Verify 410 detection and graceful error handling
  • Verify re-authorization via settings UI restores functionality
  1. Multi-connector scenario:
  • Configure multiple OAuth connectors (GitHub, Fathom, Slack)
  • Expire tokens for all
  • Verify each generates correct connector-specific authorize URLs
  • Verify no cross-contamination of install metadata

End-to-End Tests

  1. CCR routine with expired OAuth token:
  • Create CCR routine with OAuth MCP connector
  • Wait for token expiry
  • Run routine → verify it surfaces correct re-authorization guidance
  • Re-authorize via settings UI
  • Verify routine completes successfully

Server-Side Validation

  1. OAuth registry audit:

``sql
-- Find all rows where replacement_connector doesn't match connector category
SELECT client_id, connector_uuid, replacement_connector
FROM oauth_client_registry
WHERE replacement_connector IS NOT NULL
AND connector_uuid NOT IN (
SELECT uuid FROM connectors WHERE category = (
SELECT category FROM connectors WHERE uuid = replacement_connector
)
);
``

  1. Capability overlap check:
  • For each deprecated connector with a replacement, verify at least one tool category overlaps
  • Alert on any mismatched pairs

---

Impact Assessment

User Impact

  • Severity: High — All CCR routines using OAuth-based MCP connectors are permanently broken once tokens expire
  • Affected users: Any user with CCR routines that depend on OAuth MCP connectors (GitHub, Fathom, Slack, Gmail, etc.)
  • Frequency: 100% of CCR OAuth re-authorization attempts
  • Workaround: Strip OAuth-dependent MCP connectors from CCR routines entirely (degrades functionality)

Scope of Impact

| Component | Impact |
|-----------|--------|
| CCR routines with OAuth MCP | Broken — cannot re-authorize |
| Interactive claude.ai sessions | Partially affected — same authorize endpoint, but users may work around via Settings UI |
| CLI-based Claude Code | Not affected — uses different OAuth flow (localhost callback) |
| New MCP connector connections | Not affected — initial connection uses different flow |

Risk Assessment

| Risk | Likelihood | Mitigation |
|------|-----------|------------|
| Fix breaks existing working OAuth flows | Low | Comprehensive integration tests with mock OAuth servers |
| permitted_tools restoration overwrites user preferences | Medium | Only restore from saved routine config; log all changes |
| Server-side registry fix affects unrelated connectors | Low | Audit all rows before applying; use connector UUID as primary key |
| New authorize endpoint requires backend deployment | Medium | Coordinate with platform team for synchronized deployment |

Deployment Considerations

  1. Server-side fix (primary): Requires deployment to api.anthropic.com. Coordinate with platform/auth team.
  2. Client-side fixes (secondary): Can be deployed independently as part of next claude-code release.
  3. Backward compatibility: The deprecated /authorize?connector_uuid= endpoint should remain functional during migration, returning a clear deprecation notice.

Regression Risk

  • Low — The fix adds new code paths and error handling without modifying existing working flows
  • The 410 detection is a pure addition that only triggers on the broken path
  • The permitted_tools restoration only activates after a successful re-authorization

---

Summary

This issue is a server-side OAuth registry misconfiguration where the api.anthropic.com/authorize endpoint resolves connector UUIDs to the deprecated Google Drive MCP's install metadata, which now returns a 410 Gone "Server Turned Down" page. The fix requires:

  1. Server-side: Correct the replacement_connector field in the OAuth client registry for all affected connectors
  2. Client-side: Update CCR OAuth URL generation to use the new connector-based endpoint
  3. Client-side: Add graceful 410 detection with actionable error messages
  4. Client-side: Auto-restore permitted_tools after connector re-authorization
  5. Server-side: Add capability-overlap validation to prevent future misconfigurations

The fix is well-scoped, low-risk, and addresses a critical blocker for CCR routines using OAuth MCP connectors.

ibasile-dot · 3 months ago

Adding context to distinguish this from the referenced duplicates:

This is specifically a CCR (Cloud Code Routine) context issue. The scenario:

  1. A CCR routine uses an OAuth-based MCP connector (Fathom, in this case)
  2. The token expires — CCR cannot interactively re-authenticate
  3. The routine correctly surfaces an OAuth URL: https://api.anthropic.com/authorize?connector_uuid=...&code_challenge=...&code_challenge_method=S256
  4. Opening that URL in a browser (signed into the same account) returns 'Server Turned Down'
  5. There is no other recovery path — permitted_tools is not the issue; the underlying token is expired and unrenewable

This differs from the interactive web/CLI OAuth issues in the referenced duplicates because:

  • CCR routines run unattended on Anthropic's servers
  • The re-authorization URL is the only recovery path for CCR connectors
  • Once broken, the connector cannot be restored without fixing the /authorize endpoint

Closest related: #59953. Current workaround: strip OAuth-dependent connectors from CCR routines entirely and run those tasks locally instead.

omid-ant · 3 months ago

Hi folks, we have mitigated the issue. Please let us know if you still see it happening.

github-actions[bot] · 1 month ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.