n8n-io/n8n · error · Error
MCP api-key rotate endpoint returned a redacted key — cannot
Error message
MCP api-key rotate endpoint returned a redacted key — cannot stage it for `claude` MCP auth
What it means
After rotating the MCP key, the client checks whether the returned value contains '*' — a marker that the server redacted it (e.g. `******abcd`). JWTs are base64url and never contain '*', so its presence means the key is unusable for staging claude MCP auth. This guard exists because rotate is supposed to always return unredacted keys.
Source
Thrown at packages/@n8n/instance-ai/evaluations/clients/n8n-client.ts:663
* POST /rest/mcp/api-key/rotate
*
* Uses rotate rather than GET /rest/mcp/api-key because the GET only returns
* the raw JWT when it creates the key; a pre-existing key comes back redacted
* (`******abcd`), which would silently break MCP auth if staged into a
* `claude` config. Rotate deletes + recreates, so the response is always
* unredacted — at the cost of invalidating any prior MCP key for this user.
*/
async rotateMcpApiKey(): Promise<string> {
const data = this.unwrapRestData<{ apiKey?: string }>(
await this.fetch('/rest/mcp/api-key/rotate', { method: 'POST' }),
);
if (!data.apiKey) {
throw new Error('MCP api-key rotate endpoint returned no apiKey');
}
// JWTs are base64url segments and never contain "*" — its presence means
// the server redacted the key, which would fail MCP auth downstream.
if (data.apiKey.includes('*')) {
throw new Error(
'MCP api-key rotate endpoint returned a redacted key — cannot stage it for `claude` MCP auth',
);
}
return data.apiKey;
}
/**
* Delete a credential by ID.
* DELETE /rest/credentials/:id
*/
async deleteCredential(id: string): Promise<void> {
await this.fetch(`/rest/credentials/${id}`, { method: 'DELETE' });
}
/**
* Invite member users in one batched request. Requires an owner session.
* Returns one row per invitee, reporting rather than throwing on failure:
* n8n creates the user shells before it reports per-invite errors, so theView on GitHub (pinned to 5ac6606e81)
Solutions
- Upgrade n8n to a version where rotate reliably returns the raw key.
- File a backend bug — the rotate contract was violated; do not attempt to unredact.
- As a workaround, create a brand-new MCP key via the UI/API and stage that manually.
Defensive patterns
Strategy: type-guard
Validate before calling
const key = data.apiKey;
if (typeof key !== 'string' || key.includes('*'))
throw new Error('redacted key returned; cannot stage for claude MCP'); Type guard
const isUnredactedKey = (v: unknown): v is string =>
typeof v === 'string' && v.length > 0 && !v.includes('*'); Try / catch
try { return await client.rotateMcpApiKey(); }
catch (e) {
if (e instanceof Error && e.message.includes('redacted')) { /* file backend bug, do not use */ }
else throw e;
} Prevention
- Never attempt to unredact a returned key; treat '*' as poison.
- Track the backend version that fixes the rotate redaction bug.
- Add a regression test asserting rotate returns a JWT-shaped string.
When it happens
Trigger: Server bug returning a redacted key despite the rotate contract; a backend that returns the GET-style redacted representation from the rotate endpoint.
Common situations: Pre-release n8n with a rotate bug; a fork that altered the rotate handler; race where rotate returns the cached redacted form.
Related errors
- MCP api-key rotate endpoint returned no apiKey
- Failed to authenticate with n8n — no session cookie received
- Failed to enable MCP access (server reported mcpAccessEnable
- Invitation accepted but no session cookie received
- Could not determine personal project ID
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/fc0143fc6fb92d33.
Report an issue: GitHub.