n8n-io/n8n · error · Error

MCP api-key rotate endpoint returned no apiKey

Error message

MCP api-key rotate endpoint returned no apiKey

What it means

rotateMcpApiKey POSTs to /rest/mcp/api-key/rotate, which should delete and recreate the key, returning an unredacted apiKey. If the response data has no apiKey field at all, the contract is broken and the caller cannot proceed — staging MCP auth would produce a broken config.

Source

Thrown at packages/@n8n/instance-ai/evaluations/clients/n8n-client.ts:658

		}
	}

	/**
	 * Mint a fresh MCP API key for the authenticated user.
	 * 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' });
	}

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Upgrade the n8n instance to a version that implements POST /rest/mcp/api-key/rotate.
  2. Check the raw response (network tab / logs) to confirm the endpoint exists and returns the expected shape.
  3. If rotation is unavailable, fall back to manually creating an MCP key and staging it.
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe endpoint capability before relying on rotate:
const probe = await fetch(`${baseUrl}/rest/mcp/api-key/rotate`, { method: 'OPTIONS' });
if (!probe.ok) throw new Error('rotate endpoint unavailable on this backend');

Type guard

const hasApiKey = (v: unknown): v is { apiKey: string } =>
  typeof v === 'object' && v !== null && typeof (v as any).apiKey === 'string';

Try / catch

try { return await client.rotateMcpApiKey(); }
catch (e) {
  if (e instanceof Error && e.message.includes('no apiKey')) { /* upgrade backend or stage manual key */ }
  else throw e;
}

Prevention

When it happens

Trigger: Backend that does not implement the rotate endpoint; a future API change removing/renaming the field; a proxy returning an empty body.

Common situations: Pointing the eval client at an older n8n that lacks the rotate endpoint; version skew between client and server.

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/a58d6a707414632f. Report an issue: GitHub.