fix: improve MCP page setup UX and remove automation credit quotas (#821)

* Remove MCP credit quotas and improve MCP setup page

- Always show client setup snippets with placeholder keys
- Add View Docs link to MCP page header
- Remove monthly automation credit enforcement and UI
- Update plan feature text to reflect free MCP access

Co-authored-by: Rotimi Best <[email protected]>

* fix: address PR review feedback for MCP page changes

- Clear generatedSecret when revoking MCP keys
- Use Button link mode for View Docs with rel noopener noreferrer
- Update all dashboard locale files for MCP translations
- Make MCP rate-limit admission atomic with transactional reservations
- Wrap MCP route handlers with withMcpAutomationUsage helper

Co-authored-by: Rotimi Best <[email protected]>

* revert: remove atomic MCP rate-limit reservations

The transactional advisory-lock reservation was unnecessary complexity
for our MCP usage model. Restore the simpler check-then-record flow.

Also only clear generatedSecret when revoking the key it belongs to.

Co-authored-by: Rotimi Best <[email protected]>

* fix: address remaining MCP page bot review feedback

- Add blank lines after confirm guards in key handlers
- Skip showing rotated secret if key was revoked during rotation
- Fix vi keys_title and de rate_limits_title translations

Co-authored-by: Rotimi Best <[email protected]>

* fix: prevent late key rotation from un-revoking or exposing secrets

- Rotate only when revoked_at IS NULL at update time (DB)
- Reject rotate requests for already-revoked keys (API)
- Ignore stale rotate responses in automation client state
- Guard MCP UI against showing secrets for revoked keys

Co-authored-by: Rotimi Best <[email protected]>

---------
This commit is contained in:
Rotimi Best
2026-08-16 22:12:04 +01:00
committed by GitHub
co-authored by Rotimi Best
parent 1cb752d229
commit 9fb75e11d2
18 changed files with 120 additions and 94 deletions
@@ -119,3 +119,33 @@ export const updateOrganizationApiKey = async (
throw new Error('Failed to update organization API key');
}
};
export const rotateOrganizationApiKeyIfActive = async (
organizationId: string,
keyId: string,
data: Pick<TOrganizationApiKey, 'secretPrefix' | 'secretHash'>
): Promise<TOrganizationApiKey | null> => {
try {
const [row] = await db
.update(schema.organizationApiKey)
.set({
secretPrefix: data.secretPrefix,
secretHash: data.secretHash,
lastUsedAt: null,
updatedAt: new Date().toISOString()
})
.where(
and(
eq(schema.organizationApiKey.organizationId, organizationId),
eq(schema.organizationApiKey.id, keyId),
isNull(schema.organizationApiKey.revokedAt)
)
)
.returning();
return row || null;
} catch (error) {
console.error('rotateOrganizationApiKeyIfActive error:', error);
throw new Error('Failed to rotate organization API key');
}
};
-4
View File
@@ -36,7 +36,6 @@ export type TMcpToolName = keyof typeof MCP_TOOL_CREDIT_COST;
export type TAutomationUsageCategory = (typeof AUTOMATION_USAGE_CATEGORY)[keyof typeof AUTOMATION_USAGE_CATEGORY];
export type McpAutomationLimits = {
monthlyCredits: number;
maxActiveKeys: number;
rateLimits: {
perKey: {
@@ -54,7 +53,6 @@ export type McpAutomationLimits = {
export const MCP_AUTOMATION_LIMITS_BY_PLAN: Record<string, McpAutomationLimits> = {
[PLAN.BASIC]: {
monthlyCredits: 20,
maxActiveKeys: 1,
rateLimits: {
perKey: {
@@ -70,7 +68,6 @@ export const MCP_AUTOMATION_LIMITS_BY_PLAN: Record<string, McpAutomationLimits>
}
},
[PLAN.EARLY_ADOPTER]: {
monthlyCredits: 500,
maxActiveKeys: 5,
rateLimits: {
perKey: {
@@ -86,7 +83,6 @@ export const MCP_AUTOMATION_LIMITS_BY_PLAN: Record<string, McpAutomationLimits>
}
},
[PLAN.ENTERPRISE]: {
monthlyCredits: 5000,
maxActiveKeys: 25,
rateLimits: {
perKey: {
+2 -2
View File
@@ -15,7 +15,7 @@ export default {
'20 Students',
'Advanced Course Builder (no video upload)',
'500K AI credits / month',
'MCP access with 20 automation credits / month',
'MCP access',
'ClassroomIO branding'
],
CTA: {
@@ -41,7 +41,7 @@ export default {
'10K Students',
'Course Builder with Video Upload & Certificate',
'3M AI credits / month',
'MCP access with 500 automation credits / month',
'MCP access',
'Custom Branding',
'Custom Domain',
'API with limits',