Skip to content

Add fetch timeouts to MCP server HTTP calls#1111

Open
salarkhannn wants to merge 4 commits into
supermemoryai:mainfrom
salarkhannn:fix/mcp-fetch-timeouts
Open

Add fetch timeouts to MCP server HTTP calls#1111
salarkhannn wants to merge 4 commits into
supermemoryai:mainfrom
salarkhannn:fix/mcp-fetch-timeouts

Conversation

@salarkhannn

@salarkhannn salarkhannn commented Jun 13, 2026

Copy link
Copy Markdown

5 fetch() calls in the MCP server were missing timeouts — auth validation, project listing, document fetching, OAuth metadata proxy. In CF Workers a hanging request blocks the Durable Object and eats CPU time.

Added AbortSignal.timeout() to each one. 10s for lightweight calls (auth, projects, metadata), 30s for document listing. Standard Web API, no new deps. Existing try/catch handles the TimeoutError that gets thrown.

@salarkhannn

Copy link
Copy Markdown
Author

I took a look at this PR and I think we should go a step further on the auth timeouts and error handling.

  1. 2s Auth Limit: 10s is way too long for auth validation in a tool loop. If the user is waiting on a response and the auth check hangs for 10s, they'll think the whole thing is broken. For auth, we should fail fast (2s) so the client can retry or the user can be notified immediately.
  2. Stop "Gaslighting" on Timeout: Currently, if the request times out, it hits a generic catch block that returns null. This makes it look like the user's credentials are invalid, which is super frustrating if the actual problem is just a temporary network hiccup or backend latency. We should explicitly catch TimeoutError / AbortError and throw a clear "Authentication timed out" error instead.

Suggested changes for apps/mcp/src/auth.ts:

// For validateApiKey and validateOAuthToken
try {
    const sessionResponse = await fetch(`${apiUrl}/v3/session`, {
        // ...
        signal: AbortSignal.timeout(2000), // Tighten to 2s
    })
    // ...
} catch (error: any) {
    if (error.name === 'TimeoutError' || error.name === 'AbortError') {
        throw new Error("Authentication request timed out. Please check your connection or try again.");
    }
    console.error("API key validation error:", error)
    return null;
}

And in apps/mcp/src/client.ts, we should update the handleError helper to recognize these aborts so we don't just dump a "Network error" or "Unexpected error" on the user:

private handleError(error: unknown): never {
    if (error instanceof Error && (error.name === 'TimeoutError' || error.name === 'AbortError')) {
        throw new Error("Request timed out. The backend might be overloaded, please try again in a moment.");
    }
    // ... rest of handler
}

Let's make these errors explicit so the user knows exactly why the request failed!

@ishaanxgupta ishaanxgupta left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The timeout handling in validateApiKey/validateOAuthToken should preserve the existing auth failure contract instead of throwing out of the validator. Before this change all validation failures returned null, letting callers respond through the normal unauthorized path; now a timeout throws Authentication request timed out..., which can bubble as a server error depending on the transport caller. Please convert timeout/abort into the same handled auth result, or update every caller to catch this new exception and return the intended MCP auth response.

@salarkhannn

Copy link
Copy Markdown
Author

Suggest refactoring validateApiKey and validateOAuthToken to return a typed result:
{ ok: true, user: AuthUser } | { ok: false, error: 'timeout' | 'unauthorized' }

This preserves the existing contract by avoiding throw and null. It allows callers in apps/mcp/src/index.ts to return a 504 on timeout and 401 on bad credentials, fixing the "gaslighting" issue while staying architecturally clean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants