Skip to content

rsc-runtime: first-class MCP Apps, listing title/_meta passthrough, SDK wire semantics for undefined - #48

Merged
ScriptedAlchemy merged 4 commits into
mainfrom
fix/rsc-runtime-consumer-gaps
Aug 30, 2026
Merged

rsc-runtime: first-class MCP Apps, listing title/_meta passthrough, SDK wire semantics for undefined#48
ScriptedAlchemy merged 4 commits into
mainfrom
fix/rsc-runtime-consumer-gaps

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Fixes the three sibling framework gaps surfaced by the movie-library consumer port. They interact — one JSON wire boundary feeds all three — so they ship as one change set with one commit per issue.

Closes #42, Closes #43, Closes #44

#42 — MCP Apps in the RSC element tree, one app shared across servers

  • New <McpApp> element as a child of <McpServer>: lowered into the owning server's mcp.servers[<name>].apps record, so defineRscAgentBundle stays the single source of truth for widget-bearing plugins (no more config-side splice). Lowering validates app names (kebab-case), entry/template paths, ui:// resource URIs, target subsets of the owning server, and JSON _meta (cloned and deep-frozen through the same wire boundary as results).
  • The documented runtime extension: one widget can now be served by several servers. Identical same-name declarations (same entry, resourceUri, template, _meta; per-server targets may differ) compile once into one mcp-apps/<name>.html output, and the per-server agent-bundle/mcp-apps virtual registry includes it for every declaring server (CompiledMcpApp.serverIdserverIds). Source validation now flags only conflicting redeclarations (AB4325) and resource URIs spread across different app names (AB4330); identical shared declarations pass.

#43 — listing-level title and _meta, annotations verbatim

  • RscMcpDefinition gains optional title and _meta; defineOperation preserves them (JSON-boundary validated, deep-frozen) and createRscMcpServer forwards both verbatim into registerTool, so hosts can bind widgets through _meta.ui.resourceUri.
  • The framework factory was synthesizing annotation defaults (destructiveHint ?? false, idempotentHint ?? readOnly, openWorldHint ?? false), which rewrites MCP-spec semantics — an absent hint means the spec default applies host-side. It now emits exactly the declared hints; readOnlyHint always (required by the definition), the rest only when the author declared them.
  • Wire-level regression test: a real client over InMemoryTransport, with the server transport's send tapped to capture the serialized JSON-RPC payload (the client-side parse rehydrates optional keys as undefined, so only the serialized listing proves byte shape).

#44undefined follows SDK wire semantics in lowerMcpResult

  • structuredContent/_meta cloning now matches JSON.stringify: object properties with undefined values are dropped, undefined array elements lower to null. Everything else stays strict (cycles, accessors, sparse arrays, non-finite numbers, non-plain objects, symbol keys), and the JSON-boundary error now names the offending key path (… must be JSON-serializable (cyclic value at self.inner)).
  • The rsc-agent-runtime example suite is updated to encode the new contract.

Verification

…McpResult (#44)

Object properties whose value is undefined are dropped and undefined array
elements lower to null, exactly as JSON.stringify serializes them, so
handlers written against SDK serialization stop failing when an optional
field stays undefined. Cycles, accessors, sparse arrays, non-finite numbers,
and non-plain objects are still rejected, and the JSON-boundary error now
names the offending key path.
…RscMcpServer, annotations verbatim (#43)

RscMcpDefinition gains optional title and _meta; defineOperation preserves
them through the JSON wire boundary (deep-frozen) and createRscMcpServer
forwards both into registerTool, so MCP Apps hosts can bind widgets via
_meta.ui.resourceUri. The factory also stops synthesizing annotation
defaults - only declared hints reach the wire, where absent hints keep
MCP-spec default semantics. Wire-level regression test taps the transport
send to assert the serialized listing byte shape.
…ss servers (#42)

McpApp children of McpServer lower into the owning server's apps record, so
defineRscAgentBundle stays the single source of truth for widget-bearing
plugins instead of a config-side splice. Lowering validates names, paths,
ui:// resource URIs, target subsets, and JSON _meta, and admits the same
app on several servers only as one identical shared declaration.

The compiler now supports that shared case end to end: identical same-name
declarations compile once into one mcp-apps/<name>.html output whose
registry entry reaches every declaring server's agent-bundle/mcp-apps
virtual module (CompiledMcpApp.serverId becomes serverIds), and source
validation flags only conflicting redeclarations (AB4325) or resource URIs
spread across app names (AB4330).
…owering suite (#44)

The rsc-agent-runtime example asserted the old strict rejection of
undefined inside structuredContent; lowerMcpResult now follows SDK
serialization (drop object properties, null array elements), so the suite
demonstrates the wire contract and keeps the strict rejections for
functions, symbols, non-finite numbers, non-plain objects, sparse arrays,
and cycles.
@changeset-bot

changeset-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5bc190c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@agent-bundle/rsc-runtime Minor
agent-bundle Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T17:52:17.861648Z 5bc190c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@pkg-pr-new

pkg-pr-new Bot commented Aug 30, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle@48
npm i https://pkg.pr.new/ScriptedAlchemy/agent-bundle/@agent-bundle/rsc-runtime@48

commit: 5bc190c

@ScriptedAlchemy
ScriptedAlchemy merged commit 77aadd2 into main Aug 30, 2026
9 checks passed
@ScriptedAlchemy
ScriptedAlchemy deleted the fix/rsc-runtime-consumer-gaps branch August 30, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant