fix(site): fix MCP page interactions and links#7756
Conversation
- Agent cards: add tooltips, copy-to-clipboard, correct deep links for Cursor/VS Code, and proper external links - Prompt bubbles: make copyable with tooltip feedback - CTA section: differentiate "Add MCP Server" and "Read Docs" hrefs - "Want to see your tool listed?": open Tally form modal instead of broken link
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
WalkthroughConverted several MCP UI components to client components, added copy-to-clipboard and tooltip behavior, introduced a Tally feedback dialog, updated types to allow optional Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
|
The latest updates on your projects. Learn more about Argos notifications ↗︎
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
apps/site/src/app/mcp/_components/mcp-bubble.tsx (1)
104-112: Same clipboard and timeout concerns apply here.This follows the same pattern as
agent-card.tsx. For consistency, consider applying the same improvements: handle the clipboard Promise rejection and clean up the timeout on unmount.♻️ Proposed fix mirroring agent-card.tsx
-import { useId, useState, type ReactNode } from "react"; +import { useEffect, useId, useRef, useState, type ReactNode } from "react"; // Inside McpPromptBubble: + const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); + + useEffect(() => { + return () => { + if (timeoutRef.current) clearTimeout(timeoutRef.current); + }; + }, []); const handleCopy = () => { if (typeof children === "string") { - navigator.clipboard.writeText(children); - setCopied(true); - setTimeout(() => setCopied(false), 1500); + navigator.clipboard.writeText(children).then(() => { + setCopied(true); + timeoutRef.current = setTimeout(() => setCopied(false), 1500); + }).catch((err) => { + console.error("Failed to copy:", err); + }); } };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/app/mcp/_components/mcp-bubble.tsx` around lines 104 - 112, The handleCopy logic in mcp-bubble.tsx should mirror agent-card.tsx: make navigator.clipboard.writeText(children) asynchronous and handle Promise rejection (catch and log/handle error) instead of assuming success, store the timeout ID returned by setTimeout in a ref (or variable) so you can clearTimeout on unmount, and add a useEffect cleanup that clears the timeout to avoid state updates after unmount; update the copied state only on successful write and ensure handleCopy early-returns if children is not a string as currently checked.apps/site/src/app/mcp/_components/mcp-agents-section.tsx (2)
59-65: Consider adding a loading state for the iframe.The Tally iframe may take a moment to load, especially on slower connections. Users might see a blank area inside the dialog initially. A loading skeleton or spinner could improve the perceived experience.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/app/mcp/_components/mcp-agents-section.tsx` around lines 59 - 65, The iframe in the MCP Agents Section should show a loading state: add a local loading boolean (e.g., useState(true)) in the MCPAgentsSection component, render a spinner/skeleton overlay while loading, attach an onLoad handler to the iframe element to set loading to false, and ensure the iframe has aria-busy/aria-label updates for accessibility; reference the existing iframe JSX (data-tally-src="https://tally.so/r/wA1R1N", title="Tool listing request") to add the onLoad and conditional rendering so users see the spinner until the iframe finishes loading.
40-42: Consider using a dedicated identifier or index as the React key instead ofagent.alt.While all current
altvalues are unique,altis semantically for accessibility text, not identification. For a static list like this, using the index is acceptable; for dynamic lists, add anidfield to each agent object. This ensures keys reflect the component's identity rather than relying on human-readable labels that could change without breaking React's reconciliation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/app/mcp/_components/mcp-agents-section.tsx` around lines 40 - 42, The list currently uses agent.alt as the React key which is meant for accessibility, not stable identification; update the map to use a stable identifier (preferably an id field) or the index for this static list: modify the agents data to include an id for each agent and use key={agent.id} in the AgentCard render (or if truly static use key={index} temporarily), ensuring the change is applied where agents.map and <AgentCard ... /> are used so keys reflect component identity rather than the alt text.apps/site/src/app/mcp/_components/agent-card.tsx (1)
26-32: Consider handling clipboard API failures and cleaning up the timeout.Two potential issues here:
navigator.clipboard.writeText()returns a Promise and can fail (e.g., permission denied, insecure context). Silently ignoring this could leave users confused when copy doesn't work.The
setTimeoutisn't cleaned up on unmount. If the component unmounts before 1500ms elapse, React will warn about setting state on an unmounted component.♻️ Proposed fix with error handling and cleanup
+import { useEffect, useRef, useState } from "react"; -import { useState } from "react"; // Inside the component: + const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); + + useEffect(() => { + return () => { + if (timeoutRef.current) clearTimeout(timeoutRef.current); + }; + }, []); const handleClick = (e: React.MouseEvent) => { if (!isCopyAction) return; e.preventDefault(); - navigator.clipboard.writeText(copyText); - setCopied(true); - setTimeout(() => setCopied(false), 1500); + navigator.clipboard.writeText(copyText).then(() => { + setCopied(true); + timeoutRef.current = setTimeout(() => setCopied(false), 1500); + }).catch((err) => { + console.error("Failed to copy:", err); + }); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/site/src/app/mcp/_components/agent-card.tsx` around lines 26 - 32, handleClick currently calls navigator.clipboard.writeText without handling failures and starts a timeout that isn't cleared on unmount; update handleClick to await or handle the Promise returned by navigator.clipboard.writeText (wrap in try/catch or use .then/.catch) and only call setCopied(true) on success (log or surface an error on failure), store the timeout id in a ref (e.g., timeoutRef) instead of a plain setTimeout call, and add a useEffect cleanup that clears the timeout (clearTimeout(timeoutRef.current)) to avoid setting state after unmount; reference the handleClick function, navigator.clipboard.writeText, setCopied, and the new timeoutRef/useEffect cleanup when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/site/src/app/mcp/_components/mcp-agents-section.tsx`:
- Line 24: The McpAgentsSection component's props type includes an unused
docsHref string; remove docsHref from the props signature of McpAgentsSection
(change from { docsHref: string; agents: readonly McpAgent[] } to only the
agents prop) and update any call sites that pass docsHref (e.g., the page.tsx
invocation around where McpAgentsSection is used) to stop supplying that
argument or to pass only agents; ensure the exported function signature and its
usages (McpAgentsSection) are consistent so TypeScript errors are resolved.
---
Nitpick comments:
In `@apps/site/src/app/mcp/_components/agent-card.tsx`:
- Around line 26-32: handleClick currently calls navigator.clipboard.writeText
without handling failures and starts a timeout that isn't cleared on unmount;
update handleClick to await or handle the Promise returned by
navigator.clipboard.writeText (wrap in try/catch or use .then/.catch) and only
call setCopied(true) on success (log or surface an error on failure), store the
timeout id in a ref (e.g., timeoutRef) instead of a plain setTimeout call, and
add a useEffect cleanup that clears the timeout
(clearTimeout(timeoutRef.current)) to avoid setting state after unmount;
reference the handleClick function, navigator.clipboard.writeText, setCopied,
and the new timeoutRef/useEffect cleanup when making the change.
In `@apps/site/src/app/mcp/_components/mcp-agents-section.tsx`:
- Around line 59-65: The iframe in the MCP Agents Section should show a loading
state: add a local loading boolean (e.g., useState(true)) in the
MCPAgentsSection component, render a spinner/skeleton overlay while loading,
attach an onLoad handler to the iframe element to set loading to false, and
ensure the iframe has aria-busy/aria-label updates for accessibility; reference
the existing iframe JSX (data-tally-src="https://tally.so/r/wA1R1N", title="Tool
listing request") to add the onLoad and conditional rendering so users see the
spinner until the iframe finishes loading.
- Around line 40-42: The list currently uses agent.alt as the React key which is
meant for accessibility, not stable identification; update the map to use a
stable identifier (preferably an id field) or the index for this static list:
modify the agents data to include an id for each agent and use key={agent.id} in
the AgentCard render (or if truly static use key={index} temporarily), ensuring
the change is applied where agents.map and <AgentCard ... /> are used so keys
reflect component identity rather than the alt text.
In `@apps/site/src/app/mcp/_components/mcp-bubble.tsx`:
- Around line 104-112: The handleCopy logic in mcp-bubble.tsx should mirror
agent-card.tsx: make navigator.clipboard.writeText(children) asynchronous and
handle Promise rejection (catch and log/handle error) instead of assuming
success, store the timeout ID returned by setTimeout in a ref (or variable) so
you can clearTimeout on unmount, and add a useEffect cleanup that clears the
timeout to avoid state updates after unmount; update the copied state only on
successful write and ensure handleCopy early-returns if children is not a string
as currently checked.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 3bb9dfdf-60c7-4e2b-9cc5-747015f776a2
📒 Files selected for processing (5)
apps/site/src/app/mcp/_components/agent-card.tsxapps/site/src/app/mcp/_components/mcp-agents-section.tsxapps/site/src/app/mcp/_components/mcp-bubble.tsxapps/site/src/app/mcp/_components/mcp-cta-section.tsxapps/site/src/app/mcp/page.tsx
|
Caution Review failedAn error occurred during the review process. Please try again later. WalkthroughConverted several MCP UI components to client components, added copy-to-clipboard and tooltip behavior, introduced a Tally feedback dialog, updated types to allow optional Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Summary
https://www.prisma.io/docs/postgres/integrations/mcp-serverandhttps://www.prisma.io/docs/ai)Summary by CodeRabbit
Release Notes
New Features
UI/UX Improvements