MCP Capability Matrix
Which server provides which capability, and where two of them collide. MCP names are not namespaced by the protocol, so two servers exposing `search` is decided by your client’s merge order — silently. A per-server list can never show that.
src/components/ui/mcp-capability-matrix.tsxAbout
From the component's own source, where it was written.
Which server provides which capability, and where two of them collide.
The problem this exists for: MCP capability names are not namespaced by the protocol. Connect two servers that both expose search, and which one the model reaches is decided by your client's merge order — silently. A per-server list can never show that, because the collision only exists *between* lists.
So the grid is capabilities down, servers across, and any row with more than one provider is flagged. That flag is the entire reason to render a matrix rather than a set of cards.
Grid, not a table element: the header column is sticky while the server columns scroll, which <table> will not do without fighting it.
Install
npx astralyx-ui add mcp-capability-matrix
Usage
import { McpCapabilityMatrix } from '@/components/ui/mcp-capability-matrix'
<McpCapabilityMatrix servers={servers} capabilities={caps} resolve={(row) => row.providers[0]} />Composer
Change the props and the source below follows.
2 capability names provided by more than one server.
searchtoolShadowedread_filetoollist_issuestooldifftoolstatustoolShadowedreview_diffpromptNo props to configure.
<McpCapabilityMatrix
servers={servers}
capabilities={caps}
resolve={(row) => row.providers[0]}
/>Examples
Two servers both exposing `search`
<McpCapabilityMatrix servers={servers} capabilities={caps} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
McpCapabilityMatrix
Which server provides which capability, and where two of them collide.
Extends Omit<ComponentProps<'div'>, 'children'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| servers | { id: string; name: string }[] | required | CapabilityRow is { name, kind?, providers, description? }. More than one provider is a collision. |
| capabilities | CapabilityRow[] | required | CapabilityRow is { name, kind?, providers, description? }. More than one provider is a collision. |
| resolve | (row: CapabilityRow) => string | — | Which provider wins — usually your client’s merge order. The losers are marked Shadowed rather than looking equally available. |
| conflictLabel | string | 'Shadowed' | — |
| emptyLabel | string | 'Nothing exposed yet.' | — |
| label | string | 'Capability matrix' | — |
Types
CapabilityRow
| Field | Type | Description |
|---|---|---|
| name | string | — |
| kind? | 'tool' | 'resource' | 'prompt' | — |
| providers | string[] | Server ids that provide it. More than one is a collision. |
| description? | ReactNode | — |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| why a grid | collisions live between lists | The clash only exists across servers, so no per-server view can show it. That is the entire reason this renders a matrix. |