Skip to content

bug: Copy Config / Copy key buttons silently broken on /settings?tab=mcp-keys (regression from #700) #859

Description

@AndriiPasternak31

Summary

The Copy Config button (and the Copy button next to the raw key) on /settings?tab=mcp-keys is broken — clicking it does nothing visible. The handlers call copyToClipboard(...) but the function is never imported into the component, so the call throws ReferenceError: copyToClipboard is not defined and the button silently fails.

Regression from PR #700 ("refactor(settings): tabbed layout with role-gated MCP Keys absorption"), which moved the file from src/frontend/src/views/ApiKeys.vue → src/frontend/src/components/settings/McpKeysTab.vue and brought 5 of the 6 imports along. The missing import was added 4 days earlier by PR #677 (the fix for the previous incarnation of this bug).

Repro

  1. Log in as admin.
  2. /settings?tab=mcp-keys → Create API Key → name it → Create.
  3. The "Your MCP API Key is Ready!" modal opens with two copy buttons.
  4. Click Copy Config → nothing on the clipboard, button never flips to "Copied!".
  5. Click the Copy icon next to the raw key → same — nothing.
  6. DevTools console: Uncaught (in promise) ReferenceError: copyToClipboard is not defined.

Root cause

src/frontend/src/components/settings/McpKeysTab.vue:307-311 imports:

import { ref, reactive, onMounted, computed } from 'vue'
import axios from 'axios'
import ConfirmDialog from '../ConfirmDialog.vue'
import { useAuthStore } from '../../stores/auth'
import { useRole } from '../../composables/useRole'

It's missing:

import { copyToClipboard } from '../../utils/clipboard'

The function is referenced at line 506 (copyApiKey) and line 518 (copyMcpConfig); both fail.

Why CI didn't catch it

PR #677 shipped an e2e regression test (src/frontend/e2e/api-keys-copy.spec.js) that specifically exercises both copy buttons. But it's tagged @interactive, and .github/workflows/frontend-e2e.yml:80-82 only runs @smoke-tagged specs in CI ("@visual / @Interactive specs are local-only until their flake/baseline story is sorted (#596)").

So the regression test exists but is dormant. It also targets the old route /api-keys via page.goto('/api-keys'); that route now redirects to /settings?tab=mcp-keys, so the test would still land on the right page — but it never runs.

Fix

 import { ref, reactive, onMounted, computed } from 'vue'
 import axios from 'axios'
 import ConfirmDialog from '../ConfirmDialog.vue'
 import { useAuthStore } from '../../stores/auth'
 import { useRole } from '../../composables/useRole'
+import { copyToClipboard } from '../../utils/clipboard'

Single line. Verified locally — Vite HMR picked it up immediately; both copy buttons now write to clipboard and the visual "Copied!" / green-check state flips correctly.

CI gate to prevent recurrence

Pick one (both work — first is faster, second covers the visual UX):

Option A — promote the existing e2e test to @smoke. The test (src/frontend/e2e/api-keys-copy.spec.js) already covers both buttons; the only blocker was the @interactive flake story (#596). If the test is stable on dev, retag and run it in CI:

-test.describe('@interactive api-keys copy buttons (#677)', () => {
+test.describe('@smoke api-keys copy buttons (#677)', () => {

Option B — add a Vitest unit test that imports the component and asserts the bindings resolve. Catches any future "free identifier in script setup" bug, not just clipboard:

// src/frontend/test/components/settings/McpKeysTab.spec.js (new)
import { mount } from '@vue/test-utils'
import McpKeysTab from '../../../src/components/settings/McpKeysTab.vue'

test('McpKeysTab compiles with all script-setup references resolved', () => {
  // Mount throws ReferenceError if any free identifier (like copyToClipboard)
  // is referenced without an import.
  const wrapper = mount(McpKeysTab, { /* stubs as needed */ })
  expect(wrapper.exists()).toBe(true)
})

Recommend Option A — it's already written, exercises the actual user flow, and #596's flake question is the only thing keeping a real-browser regression test out of CI.

Acceptance criteria

  • McpKeysTab.vue imports copyToClipboard from ../../utils/clipboard.
  • Manual smoke: create a key, click both copy buttons, verify clipboard receives the raw key and the MCP JSON respectively.
  • CI has a gate that would catch the same regression on the new route (/settings?tab=mcp-keys) — either retag the existing e2e to @smoke (preferred) or add a Vitest mount test.
  • Any other components moved out of views/ in PR refactor(settings): tabbed layout with role-gated MCP Keys absorption (#302) #700 are audited for the same missing-import class of bug (low priority but cheap to grep).

Why P1

  • Every operator hits this on first login after onboarding — Settings → MCP Keys is the canonical place to mint a key for Claude Code / external clients.
  • Silent failure (no error toast, no DevTools dialog unless console is open) — looks like the platform "doesn't work" to a new user.
  • Same bug class as the original bug: Copy Config and Copy Key buttons on API Keys page do not copy to clipboard #677 it's regressing — we already learned this lesson once.

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions