diff --git a/.trinity/seals/t27mcp_T27mcpVisualOutput.json b/.trinity/seals/t27mcp_T27mcpVisualOutput.json index 53bca11e6d..a6e39b09ed 100644 --- a/.trinity/seals/t27mcp_T27mcpVisualOutput.json +++ b/.trinity/seals/t27mcp_T27mcpVisualOutput.json @@ -2,23 +2,23 @@ "built_by": "t27c-bootstrap@0.5.2+9448ab4be", "closure": [], "config": "gen=c,rust,verilog,zig;tests=zig", - "gen_hash_c": "sha256:076a0683dcc4e8487922bd6ff561422a1dfa707069e639fffaafea9d70ad8e2d", - "gen_hash_rust": "sha256:6267998500edaecfe3378c6ff7ed7482d1b0c239e1b8480fa697a8fd05b0d7b8", - "gen_hash_verilog": "sha256:241e62e3030919b4f540ff38480f8d726a4cc8301fbc30443369e7978adbbb1b", - "gen_hash_zig": "sha256:e7446390463513c4496f484f375ef59ae2f260172c8e46326f21008d84860411", + "gen_hash_c": "sha256:42e25ac4e6d33d72e11f45318478ef154bfc23b77daaa9a63e92d482718381c7", + "gen_hash_rust": "sha256:51c33ae8d38c5eebeaf38905c7577519df66fc057adee87a3d65c4eacf78818a", + "gen_hash_verilog": "sha256:a8af847801b01cfc44a3a88761714a6bf699fc91553ed72b5eaae7b40f60d5df", + "gen_hash_zig": "sha256:eb037cb00adb5f970d714f5c6a4d182289f326d3f8e890c124ebc5c3ef571b19", "module": "T27mcpVisualOutput", "ring": 12, "seal_schema": 2, - "sealed_at": "2026-10-18T15:31:37Z", + "sealed_at": "2026-10-18T17:13:49Z", "sealed_by": "t27c-bootstrap@0.5.2", - "spec_hash": "sha256:06c1c5e73142e2f79fa5d7be037eace63c1f20597a6e33274ebf8e1b428b7584", + "spec_hash": "sha256:2c44da44a1f662108a7b3558e763ff86e89db4bc9f49fe749dd7617051343960", "spec_path": "specs/t27mcp/visual_output.t27", "tests": { "failed": 0, "failing": [], "forced": false, - "passed": 9, - "total": 9, + "passed": 12, + "total": 12, "vacuous": 0 }, "toolchain": { diff --git a/specs/t27mcp/visual_output.t27 b/specs/t27mcp/visual_output.t27 index 95a2fd98a1..22ad5fda9d 100644 --- a/specs/t27mcp/visual_output.t27 +++ b/specs/t27mcp/visual_output.t27 @@ -25,6 +25,15 @@ ; readable when F * INLINE_W >= MIN_FONT_PX * W for its smallest text. A tool SVG is embedded as it is only ; when readable and at most INLINE_MAX_BYTES (the model re-emits it, so its bytes are output); otherwise it ; is redrawn at INLINE_W from t27f_outline rows. +; UI resource (MCP Apps, the extension UI_EXTENSION): a client says it renders MCP Apps by naming +; UI_EXTENSION in its initialize capabilities with UI_MIME among its mimeTypes. Only that client is +; HOST_MCP_APPS (client_host); a client that says nothing is served the file path, the floor every host +; reads, since the server cannot tell the desktop app from the CLI. On HOST_MCP_APPS t27f_view and +; t27f_graph add a ui:// resource to their tools/call result: the SVG between UI_PAGE[0..2], a page with +; no script and nothing fetched. Each tool names its URI (UI_URI_*) in its tools/list _meta.ui.resourceUri, +; and resources/read of that URI returns the tool's latest drawing, UI_EMPTY before the first. Other hosts +; get no resource: its bytes would reach the model as text. With no drawing there is nothing to carry, so +; HOST_MCP_APPS falls back to the markdown table. ; phi^2 + 1/phi^2 = 3 | TRINITY module T27mcpVisualOutput; @@ -68,6 +77,20 @@ pub const INLINE_W : u32 = 680; pub const MIN_FONT_PX : u32 = 11; pub const INLINE_MAX_BYTES : u32 = 16384; +/// The MCP Apps resource: the capability a client names, the page's mime type, one URI per t27f tool, +/// the page around the SVG (the SVG goes between [1] and [2], the title between [0] and [1]), and the +/// page served before a tool has drawn. +pub const UI_EXTENSION : str = "io.modelcontextprotocol/ui"; +pub const UI_MIME : str = "text/html;profile=mcp-app"; +pub const UI_URI_VIEW : str = "ui://t27f/view"; +pub const UI_URI_GRAPH : str = "ui://t27f/graph"; +pub const UI_PAGE : [3]str = [ + "