@seed-ship/mcp-ui-spec 5.0.5 → 5.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/README.md +75 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,29 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [5.0.6] - 2026-05-05
|
|
9
|
+
|
|
10
|
+
Documentation-only patch — no schema changes. Closes Demande 1.1 + 1.2 of
|
|
11
|
+
deposium's `BRIEF-MCPUI-2026-05-10.md`.
|
|
12
|
+
|
|
13
|
+
### Documented — Runtime Payload Identity contract
|
|
14
|
+
|
|
15
|
+
The README now formalizes the identity contract for runtime `UILayout` /
|
|
16
|
+
`UIComponent` payloads (distinct from the registry-side `Component`
|
|
17
|
+
definitions documented previously) :
|
|
18
|
+
|
|
19
|
+
- **`id` is obligatoire** on every well-formed `UILayout` and `UIComponent`,
|
|
20
|
+
and MUST be stable across renders for the same logical content. Producers
|
|
21
|
+
that emit `wrap-${Date.now()}` or `Math.random()` ids are non-conformant.
|
|
22
|
+
- **Bare-payload fallback** : renderers MUST gracefully accept payloads
|
|
23
|
+
without `id` (e.g. a producer emitting a chart config directly) and
|
|
24
|
+
MUST derive a stable key from the content — not from a counter or
|
|
25
|
+
timestamp. The canonical implementation is `getUiResourceStableKey()`,
|
|
26
|
+
shipped in `@seed-ship/mcp-ui-solid@6.5.0`.
|
|
27
|
+
|
|
28
|
+
This codifies behavior that was previously implicit, so host apps and
|
|
29
|
+
producers can rely on it without reading renderer source.
|
|
30
|
+
|
|
8
31
|
## [5.0.5] - 2026-05-03
|
|
9
32
|
|
|
10
33
|
### Added — `TableComponentParamsSchema.maxHeight`
|
package/README.md
CHANGED
|
@@ -266,6 +266,81 @@ Individual components support semantic versioning:
|
|
|
266
266
|
}
|
|
267
267
|
```
|
|
268
268
|
|
|
269
|
+
## Runtime Payload Identity
|
|
270
|
+
|
|
271
|
+
> **Note** — this section concerns *runtime* payloads (`UILayout` / `UIComponent`
|
|
272
|
+
> objects emitted by an LLM and passed to a renderer), distinct from the
|
|
273
|
+
> `Component` *registry* definitions documented above. The runtime types live
|
|
274
|
+
> in [`@seed-ship/mcp-ui-solid`](../mcp-ui-solid) but the identity contract
|
|
275
|
+
> below is part of the spec.
|
|
276
|
+
|
|
277
|
+
### `id` is obligatoire on well-formed payloads
|
|
278
|
+
|
|
279
|
+
Every `UILayout` and every `UIComponent` emitted by a producer **MUST** carry
|
|
280
|
+
a non-empty string `id`. The id is used by renderers as the `<For>` key, by
|
|
281
|
+
host apps for telemetry correlation, and by debug tooling to detect
|
|
282
|
+
double-mounts of the same content.
|
|
283
|
+
|
|
284
|
+
```ts
|
|
285
|
+
// ✅ Well-formed
|
|
286
|
+
const layout: UILayout = {
|
|
287
|
+
id: 'dashboard-2024-Q3',
|
|
288
|
+
components: [
|
|
289
|
+
{ id: 'metric-revenue', type: 'metric', position: {...}, params: {...} },
|
|
290
|
+
{ id: 'chart-trend', type: 'chart', position: {...}, params: {...} },
|
|
291
|
+
],
|
|
292
|
+
grid: { columns: 12, gap: '1rem' },
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
The id should be **stable across renders for the same logical content** —
|
|
297
|
+
NOT a `Date.now()`-derived counter, NOT a `Math.random()` token, NOT a UUID
|
|
298
|
+
re-generated per render. A producer that cannot provide a stable id should
|
|
299
|
+
either derive one from the content hash or omit the field entirely (see
|
|
300
|
+
fallback policy below).
|
|
301
|
+
|
|
302
|
+
### Fallback policy for "bare" payloads
|
|
303
|
+
|
|
304
|
+
Renderers MUST gracefully accept payloads without an `id` (e.g. a producer
|
|
305
|
+
emitting a chart config directly, or a host app pre-shaping a third-party
|
|
306
|
+
JSON response). When `id` is missing or empty, the renderer **MUST** derive
|
|
307
|
+
a stable key from the content itself — typically a hash of the normalized
|
|
308
|
+
payload — and **MUST NOT** generate a timestamp- or counter-based identifier
|
|
309
|
+
that would change on every render.
|
|
310
|
+
|
|
311
|
+
`@seed-ship/mcp-ui-solid` exports the canonical implementation as
|
|
312
|
+
`getUiResourceStableKey(content): string` :
|
|
313
|
+
|
|
314
|
+
- If `content.id` is a non-empty string → returned verbatim
|
|
315
|
+
- Otherwise → FNV-1a hash of the content with `id` and `metadata.generatedAt`
|
|
316
|
+
stripped (the timestamp is excluded so the key is stable across re-emissions
|
|
317
|
+
of the same logical layout)
|
|
318
|
+
|
|
319
|
+
Host apps that pre-process payloads before passing them to a renderer (e.g.
|
|
320
|
+
to wrap a bare chart config into a layout) should reuse this helper so the
|
|
321
|
+
keys they produce match what the renderer would compute internally.
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
import { getUiResourceStableKey } from '@seed-ship/mcp-ui-solid'
|
|
325
|
+
|
|
326
|
+
const key = getUiResourceStableKey(barePayload)
|
|
327
|
+
// → 'dashboard-2024-Q3' (passthrough) or 'a4f3b91' (FNV-1a, 7 chars base36)
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Why this matters
|
|
331
|
+
|
|
332
|
+
Without a stable identity contract :
|
|
333
|
+
|
|
334
|
+
- `<For>` reconciliation re-mounts components on every render, blowing away
|
|
335
|
+
internal state (chart instances, expanded rows, scroll position).
|
|
336
|
+
- Double-mount detection is impossible — the same logical content gets a
|
|
337
|
+
new key every render and any registry-based guard sees only "new" entries.
|
|
338
|
+
- Cross-instance telemetry can't correlate events to a specific layout.
|
|
339
|
+
|
|
340
|
+
These are framework-parent concerns that cannot be papered over by the
|
|
341
|
+
renderer alone — the spec calls them out so producers and host apps wire
|
|
342
|
+
identity correctly upstream.
|
|
343
|
+
|
|
269
344
|
## Related Packages
|
|
270
345
|
|
|
271
346
|
| Package | Description |
|