Skip to content

host-context-changed replaces the context wholesale, wiping the host's tokens on a partial update #46

Description

@mgoldsborough

Problem

The ext-apps spec types the notification's params as a partial update:

export interface McpUiHostContextChangedNotification {
    method: "ui/notifications/host-context-changed";
    /** @description Partial context update containing only changed fields. */
    params: McpUiHostContext;
}

createSynapse (src/core.ts) replaces currentHostContext wholesale on every notification, so any field the host omits is re-derived as absent. A host that toggles dark mode with a bare { theme: "dark" } therefore loses its entire palette mid-session.

Reproduction

Handshake with styles.variables: { "--color-text-primary": "#ff00ff" }, then dispatch { theme: "dark" }:

AssertionError: expected '#fafafa' to be '#ff00ff'

#fafafa is the SDK's own neutral dark default — the host's value is gone, and getTheme().tokens is {}.

Why this is filed rather than fixed in #45

Pre-existing; the handler shape is unchanged from main. #45 pinned the fonts half of this by test (an absent synapse/fontFaces means "unchanged"), because unloading a typeface on an unrelated toggle is a visible break. The same argument applies with more force to colour, but fixing it changes what every onHostContextChanged subscriber observes — a wider blast radius than that PR's charter.

Note connect() (src/connect.ts) and the mcpapps adapter both already merge tokens. createSynapse is the lone outlier of the three paths, which is also the one most apps use.

Suggested fix

Merge the incoming partial into currentHostContext rather than replacing it, matching the other two paths and the spec. Decide deliberately what subscribers should receive — the merged snapshot or the notification as sent — since that is the actual behaviour change.

Acceptance

  • A partial host-context-changed preserves unmentioned spec fields (styles.variables, toolInfo, containerDimensions)
  • Explicit values still replace
  • Documented choice for what onHostContextChanged delivers
  • Regression test covering the repro above

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions