# Every MCP client rebuilds the same seven screens

> Source: <https://dev.to/mayurrawte/every-mcp-client-rebuilds-the-same-seven-screens-1764>
> Published: 2026-07-07 13:51:16+00:00

MCP went from 2M to 97M monthly SDK downloads in a year. There are over 9,400 servers in the registry. A lot of people are suddenly building MCP clients — and if you've built one, you already know where this is going, because you've built these screens:

None of these are hard the first time you describe them. All of them are annoying the third time you build them. The tool-call card alone is a state machine with six states (idle, pending, running, done, error, cancelled), retry logic, theme tokens, and accessibility work — call it a week if you do it properly, which is exactly why most clients don't.

The chat side of this stack is well served. Vercel's AI Elements, assistant-ui, CopilotKit — good projects. But they're React-only (CopilotKit also does Angular), and none of them ship the MCP-specific pieces. The one multi-framework option, Deep Chat, is a single monolithic widget, not primitives you can compose. When I went looking for a consent dialog I could copy into an Angular app, there wasn't one. So I built the set.

38 components you copy into your project with a CLI:

```
npx mcp-elements add mcp-tool-call
```

That drops the component source, its CSS, and the core state machine it uses into your repo, with imports rewritten to relative paths. There is no runtime dependency to upgrade or get broken by. If you want to change how the retry button works, you edit the file. It's the shadcn model, applied to MCP.

Seven components are MCP-specific — the list above. The other 31 are the base and AI pieces you need around them: chat bubble, streaming text, prompt input, source card, buttons, dialogs, the usual.

Here's a full MCP flow in three components:

``` js
import { McpServerStatus, McpToolCall, McpConsentDialog } from '@mcp-elements/react'
import { createToolState } from '@mcp-elements/core'

// 1. Connection state
<McpServerStatus status="connected" serverName="github-mcp" />

// 2. OAuth consent
<McpConsentDialog
  open={showConsent}
  serverName="GitHub MCP"
  scopes={['repo:read', 'user.email:read']}
  onApprove={handleApprove}
  onDeny={handleDeny}
/>

// 3. Tool execution
const toolState = createToolState()
toolState.start({ tool: 'search_repos', args: { query: 'mcp-elements' } })

<McpToolCall state={toolState} onRetry={() => toolState.reset()} />
```

The architecture is three layers, and the layering is the whole trick:

Because the state machine and the stylesheet are shared, the React and Angular versions of `McpToolCall`

don't just look the same — they *behave* the same, transition for transition. When I fixed a focus-management bug in the dialog last week, the fix was the same fix in all three frameworks, because the bug lived in one place.

This is also my answer to a complaint I kept seeing in issue trackers: the Svelte request on vercel/ai-elements has been open since September 2025. Framework-agnostic core plus thin adapters means adding a framework is a bounded amount of work, not a rewrite. Svelte and Lit adapters are on the roadmap.

Things that took longer than the happy path, and that you get for free by copying:

`aria-live`

so state changes are announced. Almost no AI component library handles this.It's not an MCP client SDK — you bring your own connection and wire its events into the state machines. It's not a chat framework; there's no runtime, no provider, no cloud anything. And it's v0.1: all seven MCP components ship for all three frameworks, the base set is complete in React and Angular, and Vue has ten of the base components so far, with the rest in progress.

The MCP Apps frame tracks the spec as published in January 2026. The spec is young. If it moves, the component moves — and since you own the copy in your repo, you decide when to take that update.

The docs site renders every component live on the page — the playground demos are the actual components running, not screenshots:

`npx mcp-elements add mcp-tool-call`

MIT licensed. If you've built an MCP client and something you needed isn't in the set, open an issue — the next batch of components gets picked from real gaps, not my guesses.
