fix(mcp): surface real API error messages instead of 'restricted or blocked' - #1406
fix(mcp): surface real API error messages instead of 'restricted or blocked'#1406Dhravya wants to merge 2 commits into
Conversation
…locked'
The client swallowed the API's 403 error body and showed a generic
'Access forbidden. Your account may be restricted or blocked.' — which
reads like an account ban. In T-1554 the actual cause was a read-only
OAuth grant ('This API key has read-only access'), but the user couldn't
tell.
- Unwrap JSON error bodies ({"error": ...}) in handleError and in the
raw-fetch list endpoints so the API's message reaches the user
- Reword the empty-body 403 fallback to point at read-only/scoped
connections before suggesting account restrictions
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-mcp | b0185ac | Aug 03 2026, 10:36 PM |
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
supermemory-app | b0185ac | Commit Preview URL Branch Preview URL |
Aug 03 2026, 10:38 PM |
|
Claude finished @Dhravya's task in 1m 45s —— View job Code Review Complete
Summary: This PR correctly fixes the error message handling for 403 responses. The Score: 9/10 — No bugs or security issues found. Good to ship. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 88bb89e. Configure here.
| const message = extractApiErrorMessage(await response.text()) | ||
| throw Object.assign(new Error(message ?? ""), { | ||
| status: response.status, | ||
| }) |
There was a problem hiding this comment.
Empty message on unhandled 4xx
Low Severity
Non-OK fetch paths now throw with message ?? "" instead of a local fallback like "Failed to fetch memory entries". handleError only maps specific status codes; for other 4xx with an empty body, it rethrows the original Error, so the user can see a blank message instead of any text.
Additional Locations (2)
Reviewed by Cursor Bugbot for commit 88bb89e. Configure here.
There was a problem hiding this comment.
Overview: Fixes error message handling in the MCP client to surface API error messages (especially read-only grant 403s) instead of a generic "restricted or blocked" fallback.
Issues found: None — this looks good to ship.
The extractApiErrorMessage function safely unwraps JSON error bodies with proper fallback to raw text on parse failure. The 403 case now has a scope-aware fallback message that correctly guides users toward the actual cause (read-only grants, scoped access) rather than suggesting account issues.
Regarding the Cursor Bugbot observation about empty messages on unhandled 4xx status codes: this is technically accurate but low-impact since the common status codes (400, 401, 402, 403, 404, 422, 429, 500+) all have explicit fallbacks in handleError. Unusual status codes like 418 or 451 would surface an empty message, but these are rare enough that this isn't a blocking concern for the targeted fix.
Tests cover the key scenarios: JSON body extraction and empty-body fallback.
Score: 9/10
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>


Why?
Plain T-1554: a user with a read-only MCP OAuth grant got 403s on memory listing, and the client rendered them as "Access forbidden. Your account may be restricted or blocked." The API's actual error body said
{"error": "This API key has read-only access"}— buthandleErrordiscarded it, so the user (and support) chased a nonexistent account ban.Two masking layers:
handleErrorused the raw errormessage, which for our raw-fetch endpoints was a hardcoded string ("Failed to fetch documents") or unparsed JSON, and fell back to the scary "restricted or blocked" text when empty.getDocumentsdidn't read the response body at all.What?
extractApiErrorMessage()unwraps JSON error bodies ({"error": ...}/{"message": ...}) so the API's real reason reaches the user.getDocumentsandlistMemoryEntriesnow pass the (unwrapped) response body through with the status, lettinghandleErrorapply status-aware fallbacks when the body is empty.Companion API-side fix (read-only grants couldn't call semantically-read POST list endpoints at all): supermemoryai/mono#2772.
Testing
vitest run src/server/client/index.test.ts— 3 passed.tsc --noEmit -p tsconfig.jsonclean. (Thecheck-typesscript also runstsconfig.widget.json, which fails on origin/main with a pre-existingUseAppOptions.stricterror, unrelated.)🤖 Generated with Claude Code
Note
Low Risk
User-facing error text only; no changes to auth, tokens, or request semantics beyond reading error response bodies.
Overview
MCP client errors now show the API’s real reason instead of generic “restricted or blocked” text or hardcoded fetch failures.
Adds
extractApiErrorMessage()to parse JSON bodies (error/message) and use that string in thrown errors.getDocumentsandlistMemoryEntriesread the response body on non-OK responses and pass the unwrapped message (with status) intohandleError, which applies the same parsing and uses a read-only / scoped-connection fallback when a 403 has no body.Tests cover a 403 with
{"error":"This API key has read-only access"}and an empty-body 403 matching the new fallback.Reviewed by Cursor Bugbot for commit 88bb89e. Bugbot is set up for automated code reviews on this repo. Configure here.