# Catalog Discovery — Tools vs Resources

The MCP exposes the Dynamic UI component catalog and pattern stories through two parallel layers — kept side by side for backward compatibility and ergonomic flexibility.

## Two surfaces

### Tools (legacy paths)

| Tool | Source | Returns |
|------|--------|---------|
| `widgets-list-components` | `api.json` from CDN (manifest-discovered) | Component list with shallow prop info |
| `widgets-get-component-props` | `api.json` | Full props of one component |
| `widgets-list-patterns` | Storybook `index.json` (story listing) | Pattern story ids, titles and names. For a pattern's full content, read the `modyo://widgets/catalog/patterns/{patternId}` Resource. |

These existed before the SC22 catalog Resources and remain available. Driven by tool invocations (tool-call ergonomics).

### Resources (`modyo://widgets/catalog/*`)

Added in SC22, backed by the Storybook 10.x AI-ready manifests served from `cdn.dynamicframework.dev/assets/{WIDGETS_COMPAT.dynamicUi}/ui-react/manifests/`. URI-addressable — agents read with `resources/read`, not `tools/call`.

| URI | Shape |
|-----|-------|
| `modyo://widgets/catalog/components` | Lightweight component list |
| `modyo://widgets/catalog/components/{componentId}` | Full component detail (stories with snippet code, props with TS types, JSDoc, import statement). The `{componentId}` is the Storybook id (e.g. `design-system-components-alert`), NOT the React displayName (`DAlert`). |
| `modyo://widgets/catalog/patterns` | Unified pattern list combining MDX patterns from `docs.json` (titles starting with `Design System/Patterns/`) and pattern components from `components.json` (ids starting with `patterns-`). Each entry carries a `source` field discriminating `mdx` / `pattern-component` / `pattern-story`. |
| `modyo://widgets/catalog/patterns/{patternId}` | Full detail of a pattern, resolved via 3-step ordered lookup (`docs.json` MDX → split-id story → exact-id pattern component). Wrapped output is consistent across sources via a `source` discriminator. |

## When to use which

| Need | Preferred path |
|------|----------------|
| Quick listing for discovery | Either — both have lightweight projections |
| Working snippet code for a component | Resource `catalog/components/{name}` — Tools only expose props, not story code |
| Prop types in machine-readable form | Either — both have full prop data |
| Pattern listing for discovery | Either — the Resource gives a unified view across `docs.json` + `components.json`; the Tool `widgets-list-patterns` lists ids from `index.json` filtered by the `Patterns/` title prefix. For a pattern's content, use the Resource detail (below). |
| Full content of a pattern | Resource `catalog/patterns/{id}` — only the Resource resolves all three sources (MDX, pattern-story, pattern-component) via the 3-step fallback. The Tool lists ids only; it does not return content. |
| Linking from instructions / docs | Resources — URIs are stable references |
| Inside a multi-step tool flow | Tools — already making tool calls |

## Output shapes

### Components list

```json
{
  "dynamicUiVersion": "2.8.0",
  "components": [
    {
      "id": "design-system-actions-d-button",
      "name": "DButton",
      "key": "design-system-actions-d-button",
      "description": "Primary action button.",
      "storyCount": 3
    }
  ]
}
```

The `key` field is the Record key in `components.json` and equals `id` (the upstream manifest keys entries by their Storybook id, not by the React displayName — verified live against CDN 2.5.2, 60/60 entries). Either field can be passed to `{componentId}` in the detail URI.

### Component detail

```json
{
  "id": "design-system-actions-d-button",
  "name": "DButton",
  "path": "src/components/DButton/DButton.tsx",
  "stories": [
    {
      "id": "design-system-actions-d-button--primary",
      "name": "Primary",
      "snippet": "<DButton color=\"primary\" text=\"Save\" />"
    }
  ],
  "reactDocgen": {
    "displayName": "DButton",
    "props": {
      "color": { "required": false, "tsType": { "name": "string" }, "description": "Bootstrap color variant." }
    }
  },
  "jsDocTags": { "category": ["actions"] },
  "import": "import { DButton } from '@dynamic-framework/ui-react';"
}
```

### Patterns list (unified)

Each entry has `id`, `title`, and a `source` discriminator. `name` and `parentId` and `snippetSize` are present when relevant to the source.

```json
{
  "dynamicUiVersion": "2.8.0",
  "patterns": [
    {
      "id": "design-system-patterns-modal--docs",
      "title": "Design System/Patterns/Modal",
      "name": "Docs",
      "source": "mdx"
    },
    {
      "id": "patterns-list-group-patterns",
      "title": "ListGroupPatterns",
      "source": "pattern-component"
    },
    {
      "id": "patterns-list-group-patterns--transaction-history",
      "title": "ListGroupPatterns — Transaction History",
      "name": "Transaction History",
      "source": "pattern-story",
      "parentId": "patterns-list-group-patterns",
      "snippetSize": 2734
    }
  ]
}
```

The `id` of any entry is what `{patternId}` accepts in the detail URI. Listing both the parent (`pattern-component`) and each of its stories (`pattern-story`) is intentional — the agent can prefer the component (all variants together) or a single story (one specific example).

### Pattern detail (three variants per source)

The detail Resource resolves `{patternId}` through three ordered lookups (first match wins) and returns a discriminated shape:

**Source: `mdx`** — id exists in `docs.json`:

```json
{
  "source": "mdx",
  "mdxEntry": {
    "id": "design-system-patterns-modal--docs",
    "name": "Docs",
    "path": "src/components/DModal/DModal.mdx",
    "title": "Design System/Patterns/Modal",
    "content": "# Modal Pattern\n\nUse for confirmation dialogs...\n\n```tsx\n<DModal>...\n```"
  }
}
```

**Source: `pattern-story`** — id splits on `--`, parent component exists in `components.json` with the matching story:

```json
{
  "source": "pattern-story",
  "parentId": "patterns-list-group-patterns",
  "parentName": "ListGroupPatterns",
  "story": {
    "id": "patterns-list-group-patterns--transaction-history",
    "name": "Transaction History",
    "snippet": "<DListGroup>...</DListGroup>",
    "description": "A list-group composition for transaction listings."
  }
}
```

**Source: `pattern-component`** — id matches a `components.json` entry whose own id starts with `patterns-`:

```json
{
  "source": "pattern-component",
  "component": {
    "id": "patterns-list-group-patterns",
    "name": "ListGroupPatterns",
    "path": "src/patterns/listGroup/ListGroupPatterns.mdx",
    "stories": [
      { "id": "...--transaction-history", "name": "Transaction History", "snippet": "..." }
    ],
    "import": "import { DListGroup } from '@dynamic-framework/ui-react';",
    "reactDocgen": { ... }
  }
}
```

## Error handling

> The version strings in the examples below are **illustrative** and quoted from the
> Dynamic UI 2.5.2 era (the version that actually exhibited the missing-manifest case).
> At runtime every message interpolates the version pinned in `WIDGETS_COMPAT.dynamicUi`.

### HTTP 403 / 404 — version not backfilled

```
Storybook manifest "components.json" is not available for Dynamic UI 2.5.2 (HTTP 404).
This usually means the version predates manifests CDN publishing (added to
dynamic-ui in cdn.yml) or has not been backfilled yet.
Backfill: at the dynamic-ui repo checkout v2.5.2, run `npm ci && npm run build:storybook`,
then upload `docs/manifests/components.json` to
`s3://dynamicframework-cdn/assets/2.5.2/ui-react/manifests/components.json`.
```

Cause: the `cdn.yml` workflow extension hasn't published manifests for the pinned version. Either the workflow PR isn't merged + released yet, or the operator needs to backfill manually for an older version.

### Component not found

```
Component "DNonexistent" not found in Dynamic UI 2.5.2 catalog.
Available: DButton, DInput, DSelect, ... (60 total).
Full list: modyo://widgets/catalog/components.
```

Cause: the URI parameter doesn't match a Record key. Use the corresponding list resource to discover valid ids.

### Pattern not found (three-step resolver exhausted)

```
Pattern "totally-bogus--id" not found in Dynamic UI 2.5.2.
Looked in: docs.json (MDX patterns), components.json (story id),
components.json (component id).
Use the catalog list at modyo://widgets/catalog/patterns to see
available IDs.
```

Cause: the id doesn't resolve through any of the three lookup paths. Either the id is malformed, the version doesn't expose that pattern, or the id was constructed by hand (instead of being read from the list resource).

## Version pinning

The version consumed is always `WIDGETS_COMPAT.dynamicUi` (declared in `src/tools/widgets/_compatibility.ts`). The operator does not choose. To consume a different version, install a different MCP release. Bumping the pin is a deliberate act — audit docs, refresh tests, commit with rationale.

The same pin drives:

- `api.json` URL resolved via manifest discovery
- Storybook `components.json` and `docs.json` (direct versioned path)
- Stack alignment check inside the `widgets-validate` Tool wrapper
