When a Chat Window Becomes an App, What Can You Trust?

Editorial illustration of a small interactive form and chart inside a conversation, with a few boundaries left visibly unfinished
This image was generated using Grok Imagine.

In the official sample program used to display embedded screens—a local reference host—I changed Review from 15 to 25 minutes on a weekly study form. The chart changed, and the total rose from 90 to 100 minutes. It looked like a small web app inside a conversation, but this did not happen inside ChatGPT, Claude Desktop, or VS Code. Displaying an interface, validating input, saving data, informing an AI's next answer, and working in another chat service are separate promises.

To examine those differences, I built a minimal app using only synthetic data. No production conversational product was tested.

In this article

The bridge that displays the interface

MCP Apps is an optional extension that connects a tool to an embedded HTML view. The specification supplies the bridge; a compatible host decides whether and how to display the interface. Forms and charts are not special MCP components. They are ordinary HTML and JavaScript running through that bridge. The design is documented in the stable MCP Apps specification and the official overview.

The app had two tools: one calculated the study record and returned readable text plus view data; the other validated and saved changes from the view. The fixed data was Reading 30 minutes, Practice 45 minutes, and Review 15 minutes, for a total of 90. It requested no device permissions and declared no external content domains.

On September 7, 2026, I tested with Node 24.19.0, MCP Apps 1.7.5, and MCP SDK 1.29.0. The run used commit 92f46a5 of the official local basic-host 1.7.5 reference host. All 25 build checks passed, with a recorded direct incremental cost of USD 0.00. The 25/25 figure covers implementation checks, not the verdicts for the 18 behavior tests below. Those behavior verdicts were judged separately, using browser captures and server logs.

The bilingual form worked, but it also exposed a defect

For both Korean and English, the baseline total of 90 and the edited total of 100 matched across the server result, embedded view, and accessible chart representation. In a separate fallback test (T1), a client that did not report support for an embedded screen received readable text containing the language, all three items, selected item, total, and a note that the interactive view was unavailable.

The unsupported language code zz, however, produced a real defect. The server returned an English fallback and a warning, while the view displayed Korean and showed no warning. A non-numeric value, negative number, over-limit value, and empty list were rejected, but the server-view mismatch meant that I2 was a FAIL. This run could not determine whether the mismatch originated in the app's language handling or the host's behavior.

Storage and AI context are different questions

The successful restoration was not chat memory. The view explicitly saved data under a synthetic session ID inside the local server process. A fresh view sent the same ID and restored the 100-minute total from server_store. This does not prove persistence after a server restart or across a real account, another device, another host, or production storage.

The same-view retention test did not produce changed server-validated state. The close-and-reopen test used the baseline value both before closing and when invoking the app again, so reset could not be distinguished from input overwrite. V1 and V2 were therefore INVALID: the procedures did not support a verdict, which is different from an app failure. The save-failure test S2 was not run and remained NOT TESTED.

A value visible in the view, a server-validated result, a context-update request sent to the host, and an AI's later answer also travel through different channels. This run confirmed only that the app sent the context request Review 25 minutes, total 100. In that narrow send-only sense, C1 was a PASS. Whether the host accepted or rejected the request, and whether an AI received or answered it, were not confirmed. So this run cannot claim the request caused an AI to know the value.

One blocked request is not a security certification

Permission and domain declarations were empty, and the requests I captured used only local test addresses. A control request reached a separate test listener. A request from the embedded view to that same undeclared local listener was blocked by this test setup's Content Security Policy (CSP), a browser rule that limits where a page may send requests, and never reached the listener. This is one observation in one local environment, not a safety certification or proof that data cannot leak. The host's handling of user consent was not tested either.

Results from all 18 tests

PASS means that the stated criterion was met within the scope shown. FAIL marks an observed mismatch, INVALID means the procedure could not support a verdict, and NOT TESTED means the test was not run.

Table 1 · Results from all 18 tests
Area Result What the evidence covers
I1
PASS
Form totals: Korean and English baseline 90 and edited 100 matched across server, view, and accessible representation
I2
FAIL
Unsupported language code: four other errors were rejected, but the server and view disagreed on the zz language and warning
V1, V2
INVALID
Unsaved state: changed state was not created for one test, and baseline input was resent in the other
S1
PASS
Explicit save: the process-local server store restored data using the same synthetic session ID
S2
NOT TESTED
Save failure was not run
C1
PASS (send only)
The context request left the app; host disposition and AI receipt remain unknown
C2–C4
NOT TESTED
No AI follow-up, matched control, or complete four-channel comparison
P1, P2
PASS
Local network checks: empty declarations and one CSP-blocked local request in the reference environment
P3
NOT TESTED
User-consent handling was not run
H0
PASS
The pinned official local reference host ran
H1
NOT TESTED
ChatGPT, Claude Desktop, VS Code, and other production conversational products were not run
A1
PASS
Tool visibility: the app-only update tool—the one the embedded view used to validate and save changes—was absent from this host's invocation list
T1
PASS
Text fallback: a client without UI capability received complete Korean and English text
T2
INVALID
Blocked-view fallback: the comparison inputs differed, so fallback behavior when the view was blocked could not be judged

The total was 8 PASS, 1 FAIL, 3 INVALID, and 6 NOT TESTED. The absence of an app-only update tool from one invocation list does not prove that every host hides it or enforces the same security boundary.

Four questions to ask when watching a demo

In this exact local reference environment, bilingual interaction, explicit restoration from server storage, and text fallback without a UI worked. The test also exposed an unsupported-language-code defect. Same-view and close-and-reopen state could not be judged, while save-failure behavior, AI follow-up, user consent, and production-product compatibility were not tested.

Before relying on a demo, ask four questions:

  1. Does a readable result exist without the interface?
  2. Who stores each value, where, and under which identifier?
  3. Can you inspect the server-validated result when the screen and answer disagree?
  4. Are tests that were never run left marked as NOT TESTED?

Because no AI follow-up was available here, this run cannot tell you which value to trust if a screen and a later AI answer disagree. A small chat app earns trust not through one impressive interaction, but by proving each separate promise.

AI was used to assist with research and drafting. The author independently verified and edited the final article.

댓글

“When a Chat Window Becomes an App, What Can You Trust?”에 대한 2개 응답

  1. […] 실험 노트 · 13Read in English →Grok Imagine을 사용해 생성한 AI […]

    좋아요

  2. […] Earlier articleWhat if a working app could run inside a conversation? […]

    좋아요

답글 남기기