Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
afcc59a
Fix MCP widget dark mode readability
ved015 Jun 30, 2026
677b9d4
Fix Biome CSS formatting in tokens.css
github-actions[bot] Jun 30, 2026
f7d2bb7
style(mcp): align widget UI with Nova theme
ishaanxgupta Jul 1, 2026
0d7e231
style(mcp): solidify widget form surfaces
ishaanxgupta Jul 1, 2026
a8f3644
style(mcp): align graph widget surface
ishaanxgupta Jul 1, 2026
c811b40
fix(mcp): resolve Biome lint and format errors
github-actions[bot] Jul 1, 2026
d5d0cb7
Align MCP widget cards with web theme
ishaanxgupta Jul 2, 2026
645a440
Preview Cursor MCP widget shell in studio
ishaanxgupta Jul 2, 2026
a09b5b6
Use neutral hover states for MCP cards
ishaanxgupta Jul 2, 2026
6a85341
Use Supermemory loader in MCP widget
ishaanxgupta Jul 2, 2026
ef3762d
Remove icons from MCP workspace cards
ishaanxgupta Jul 2, 2026
d7e2991
Match MCP workspace cards to web style
ishaanxgupta Jul 2, 2026
a81a7ed
Match MCP permission pill to web card
ishaanxgupta Jul 2, 2026
ca71ed6
Remove MCP status card borders
ishaanxgupta Jul 2, 2026
f0023bb
Match MCP confirmation card style
ishaanxgupta Jul 2, 2026
649d985
Polish MCP widget UI
ishaanxgupta Jul 3, 2026
1e81a3e
Fix Biome formatting in Button.tsx
github-actions[bot] Jul 3, 2026
2f391cf
Match MCP widget typography to web
ishaanxgupta Jul 3, 2026
af0bc63
Avoid picker scroll for short workspace lists
ishaanxgupta Jul 3, 2026
e72f775
Hide picker scrollbar chrome
ishaanxgupta Jul 3, 2026
166317b
Tighten MCP picker card spacing
ishaanxgupta Jul 3, 2026
440e9e9
Constrain MCP picker card width
ishaanxgupta Jul 3, 2026
a0dd93f
Revert "Constrain MCP picker card width"
ishaanxgupta Jul 3, 2026
1af2e85
Add MCP widget design variants
ishaanxgupta Jul 6, 2026
d4e978e
Fix Biome formatting and lint issues in MCP widget
github-actions[bot] Jul 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 61 additions & 5 deletions apps/mcp/src/widget/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from "react"
import { type ReactNode, useEffect } from "react"
import type { ViewMessage } from "../shared/types"
import { useApplyHostTheme } from "./hooks/useApplyHostTheme"
import { useLog } from "./hooks/useLog"
Expand All @@ -25,15 +25,71 @@ export function App() {
}
}, [state, log])

if (state.kind === "loading") return <Loading />
if (state.kind === "error") return <ErrorView message={state.message} />
if (state.kind === "loading") {
return (
<WidgetShell>
<Loading />
</WidgetShell>
)
}
if (state.kind === "error") {
return (
<WidgetShell>
<ErrorView message={state.message} />
</WidgetShell>
)
}
if (state.kind === "raw") {
return (
<ErrorView message="Received unrecognized response from server. Try again." />
<WidgetShell>
<ErrorView message="Received unrecognized response from server. Try again." />
</WidgetShell>
)
}

return renderView(state.message, setView, setError)
const isGraphView = state.message.view === "graph"
return (
<WidgetShell immersive={isGraphView}>
{renderView(state.message, setView, setError)}
</WidgetShell>
)
}

export function WidgetShell({
children,
immersive = false,
}: {
children: ReactNode
immersive?: boolean
}) {
const shellClassName = immersive
? "mcp-widget-shell mcp-widget-shell-graph"
: "mcp-widget-shell"

return (
<div className={shellClassName}>
<div aria-hidden className="mcp-widget-glow" />
<header className="mcp-widget-brand">
<span aria-hidden className="mcp-widget-brand-mark">
<svg aria-hidden="true" viewBox="0 0 314 256">
<path
d="M313.728 100.982H197.297V0H159.68V109.567C159.68 121.205 164.284 132.381 172.466 140.615L267.535 236.283L294.134 209.517L223.917 138.858H313.75V101.004L313.728 100.982Z"
fill="currentColor"
/>
<path
d="M19.616 46.5043L89.8323 117.163H0V155.017H116.431V255.999H154.048V146.432C154.048 134.795 149.444 123.618 141.262 115.384L46.2144 19.7383L19.616 46.5043Z"
fill="currentColor"
/>
</svg>
</span>
<span className="mcp-widget-brand-copy">
<span className="mcp-widget-brand-name">supermemory</span>
<span className="mcp-widget-brand-mode">MCP</span>
</span>
</header>
<main className="mcp-widget-content">{children}</main>
</div>
)
}

function renderView(
Expand Down
12 changes: 5 additions & 7 deletions apps/mcp/src/widget/components/PermissionBadge.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Badge } from "../design/ui"

interface Props {
permission: string
}

export function PermissionBadge({ permission }: Props) {
const isWrite = permission === "write"
return (
<Badge
className="mt-2 self-start uppercase"
variant={isWrite ? "accent" : "neutral"}
<span
className="text-text-muted"
style={{ fontFamily: "var(--font-brand)" }}
>
{isWrite ? "read/write" : "read only"}
</Badge>
{isWrite ? "Read/write" : "Read only"}
</span>
)
}
70 changes: 36 additions & 34 deletions apps/mcp/src/widget/components/WorkspaceCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ContainerTag, ContainerTagAccess } from "../../shared/types"
import { Card, Stack } from "../design/ui"
import { Check, Package } from "../lib/icons"
import { Card } from "../design/ui"
import { Check } from "../lib/icons"
import { formatTagLabel } from "../lib/formatTag"
import { PermissionBadge } from "./PermissionBadge"

interface Props {
Expand All @@ -16,51 +17,52 @@ export function WorkspaceCard({
access,
onClick,
}: Props) {
const name = containerTag.name || containerTag.containerTag
const name = containerTag.name || formatTagLabel(containerTag.containerTag)
return (
<Card
as="button"
className="w-full"
className="workspace-card w-full p-3"
onClick={() => onClick(containerTag.containerTag)}
variant={active ? "active" : "interactive"}
>
<Stack gap="sm">
<Stack align="center" direction="row" gap="sm" justify="between">
<span className="flex min-w-0 items-center gap-(--space-2)">
{containerTag.emoji ? (
<span aria-hidden className="text-base leading-none">
{containerTag.emoji}
</span>
) : (
<Package className="size-4 shrink-0 text-text-secondary" />
)}
<div className="workspace-card-inner">
<div className="workspace-card-main">
<div className="workspace-card-heading">
<span
className="truncate text-(length:--text-sm) font-semibold text-text-primary"
className="workspace-card-title truncate text-sm font-medium text-text-primary"
style={{ fontFamily: "var(--font-brand)" }}
>
{name}
</span>
</span>
{active ? <Check className="size-4 shrink-0 text-accent" /> : null}
</Stack>
<div className="truncate font-mono text-(length:--text-xs) text-text-muted">
{containerTag.containerTag}
{active ? (
<Check
aria-hidden
className="workspace-card-check size-3 shrink-0 text-accent"
/>
) : null}
</div>
{(containerTag.documentCount > 0 || containerTag.memoryCount > 0) && (
<div className="workspace-card-meta flex items-center gap-(--space-2) text-[11px] leading-normal text-text-muted">
<span>
{containerTag.documentCount} doc
{containerTag.documentCount === 1 ? "" : "s"}
</span>
<span aria-hidden className="opacity-40">
·
</span>
<span>
{containerTag.memoryCount}{" "}
{containerTag.memoryCount === 1 ? "memory" : "memories"}
</span>
</div>
)}
</div>
{(containerTag.documentCount > 0 || containerTag.memoryCount > 0) && (
<div className="flex items-center gap-(--space-3) text-(length:--text-xs) text-text-muted">
<span>
{containerTag.documentCount} doc
{containerTag.documentCount === 1 ? "" : "s"}
</span>
<span aria-hidden>·</span>
<span>
{containerTag.memoryCount} mem
{containerTag.memoryCount === 1 ? "" : "s"}
</span>
{access ? (
<div className="workspace-card-trailing">
<PermissionBadge permission={access.permission} />
</div>
)}
{access ? <PermissionBadge permission={access.permission} /> : null}
</Stack>
) : null}
</div>
</Card>
)
}
Loading
Loading