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.vuesrc/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-keysCreate 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.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions