skills/FORGE-mcp-gui/SKILL.md
Build and audit interactive MCP Apps, UI resources, sandbox messaging, and CSP-bound host integration.
npx skillsauth add ariffazil/openclaw-workspace FORGE-mcp-guiInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Forged: 2026-07-19 by FORGE (000Ω) for AAA Control Plane Hardened: 2026-07-20 — ChatGPT-native MCP Apps standard (sovereign blueprint:
/root/forge_work/2026-07-20/GEOX-CHATGPT-MCP-GUI-BLUEPRINT.md) Zen Name: FORGE-mcp-gui Axis: forge · Tier: AGI · Class: C2 Observe+Execute Spec: SEP-1865 (MCP Apps, ratified 2026-01-26) Doctrine: DITEMPA BUKAN DIBERI
The task involves:
_meta.ui.resourceUri on tool definitions@mcp-ui/server, @mcp-ui/client, @modelcontextprotocol/ext-appsmcp-ui-server (Python) or fastmcp Prefab_meta.ui.csp) for secure UI rendering["model"], ["app"], ["model","app"])MCP Tool (server) ──→ _meta.ui.resourceUri: "ui://org/widget"
↓
Host fetches resource via resources/read
↓
Sandboxed iframe renders HTML
↓
JSON-RPC over postMessage (View ↔ Host ↔ Server)
content: → model sees this (context window, keep small)
structuredContent → hidden from model, View hydrates with it (full data)
_meta: → hidden from model, metadata only
Model gets summary text. View gets full structured data. Save context tokens.
return {
"content": [{"type": "text", "text": "Summary..."}],
"structuredContent": {"fullData": ...},
"_meta": {"ui": {"resourceUri": "ui://org/widget"}}
}
Never UI-only — hosts may not support MCP Apps.
Two-layer: CSS light-dark() for first render, JS data-theme after hostContext arrives.
app.onhostcontextchanged = (ctx) => {
document.documentElement.setAttribute('data-theme', ctx.theme);
};
Tool A returns data → model processes → Tool B renders UI. Avoids remounts.
app.sendMessage("User did X. Respond."); // active trigger
app.updateModelContext({ cart: items }); // background awareness
"visibility": ["app"] // UI only — model can't call
"visibility": ["model"] // model only — UI can't call
"visibility": ["model", "app"] // both (default)
Register 5 widget templates. Tools fill them with data. Hosts prefetch.
You don't build the sandbox — you declare for it. CSP keys are domain lists under _meta.ui.csp (connectDomains, resourceDomains), NOT raw CSP header directives:
"_meta": {
"ui": {
"resourceUri": "ui://org/widget",
"csp": {
"connectDomains": ["api.example.com"],
"resourceDomains": ["cdn.example.com", "images.example.com"]
}
}
}
(The older connect-src / script-src header-style example previously shown here is superseded — see CHATGPT-NATIVE APPS §3 below.)
Missing CSP → silent block → broken app.
Inventory EVERY external dependency (APIs, CDNs, fonts, images). Declare all. Test with CSP enabled — not dev mode.
npm install vite-plugin-singlefile
One HTML file = one MCP resource. No path issues in iframe.
Skeleton on mount → partial on toolInput → full on toolResult → error on failure.
Models retry. Use idempotency keys. create_task(key=uuid) not create_task(name="x").
12 well-named tools > 60 poorly-named. Model picks by description string.
Layer 1: MCP protocol (server↔host) — stdio/SSE logs. Layer 2: JSON-RPC postMessage (host↔View) — iframe console. Switch Chrome DevTools frame dropdown to sandbox iframe.
app=True (Python)@server.tool(app=True)
def show_chart(data: list[float]) -> Chart:
return BarChart(data=data, title="Results")
fastmcp dev apps launches in-browser UI preview. No React needed.
import { registerAppTool, registerAppResource } from '@modelcontextprotocol/ext-apps/server';
import { App } from '@modelcontextprotocol/ext-apps';
import { createUIResource } from '@mcp-ui/server';
import { AppRenderer, UIResourceRenderer } from '@mcp-ui/client';
from mcp_ui_server import create_ui_resource
from fastmcp import FastMCP
server = FastMCP("my-server")
server.add_provider("FileUpload")
server.add_provider("Approval")
@server.tool(app=True)
def my_tool(...): ...
require 'mcp_ui_server'
McpUiServer.create_ui_resource(...)
| Host | MCP Apps | Notes |
|------|----------|-------|
| Claude (web+desktop) | ✅ Full | First adopter |
| ChatGPT | ✅ Full | 2026-07 standard: ship via Developer Mode first (golden prompts), then plugin submission package (verified publisher, exact CSP, unique widget domain, privacy policy, support contact, screenshots, rollback note). Alias _meta["openai/outputTemplate"] required alongside _meta.ui.resourceUri. |
| Goose | ✅ Full | Open source |
| VS Code Insiders | ✅ | Via Copilot |
| MCPJam | ✅ Full | Local inspector/debugger |
| LibreChat | ✅ Partial | |
| Postman | ✅ Partial | |
| Smithery | ✅ Render only | |
| | MCP Apps | A2UI | |---|----------|------| | Rendering | Sandboxed iframe | Host-native components | | Flexibility | Unlimited | Component catalog only | | Security | CSP + double-iframe | Capability-based | | Consistency | Manual (CSS vars) | Automatic (design system) | | Use when | Maps, 3D, PDFs, custom JS | Forms, structured data |
Three hybrid patterns:
Contract source: sovereign blueprint /root/forge_work/2026-07-20/GEOX-CHATGPT-MCP-GUI-BLUEPRINT.md (authoritative for the GEOX consolidation; the rules below generalize to any ChatGPT-targeted MCP App). Where this section disagrees with older material in this skill, this section wins.
_meta.ui.resourceUri on the tool definition._meta["openai/outputTemplate"] ALONGSIDE the primary key — never instead of it. Both point at the same ui:// resource.openai/toolInvocation/invoking and openai/toolInvocation/invoked status strings (tool-call spinner copy).text/html;profile=mcp-app. The host only enables the app bridge for this exact profile MIME — plain text/html renders nothing.ui:// URI — it is a cache key. Pattern: ui://geox/workbench-v1.html. Bump the version segment to invalidate stale caches._meta.ui.cspconnectDomains (fetch/XHR/WS targets) and resourceDomains (scripts, styles, images, fonts).domain (widget's own domain), prefersBorder (host chrome hint).frameDomains — third-party iframes draw review scrutiny at submission.connect-src / script-src header-style example (corrected in place at Tip #8).resourceDomains stays empty or near-empty.ui/* bridge FIRST: ui/initialize, ui/notifications/tool-input, ui/notifications/tool-result, tools/call, ui/message, ui/update-model-context.window.openai is an optional, feature-detected enhancement layer (if (window.openai) { ... }) — never a requirement.structuredContent — widget props + model narration data ONLY. No secrets, no trace IDs, no dense raw arrays.content — text fallback ALWAYS. Hosts without MCP Apps support still get the answer; model context stays small._meta — metadata and binding keys only.isError: true and a readable message — the model can self-correct and retry.isError keeps the loop alive.Pass all three in ChatGPT Developer Mode before any other surface:
After Developer Mode: API Playground instrumentation → web + Android + iOS render/state evidence → plugin submission package (see HOST SUPPORT MATRIX).
pr/geox-well-witness-v1): split into geox_well_ingest → geox_petrophysics → geox_well_view; only the view tool binds ui://geox/workbench-v1.html (MIME text/html;profile=mcp-app + exact CSP). Exit gate: resources/read returns valid app HTML and renders in Inspector.mcp_apps_bridge.py — enrich_response() injects _meta.ui.resourceUri on 24 tools; harden to also emit the _meta["openai/outputTemplate"] alias alongside (CHATGPT-NATIVE §1).mcp-ui-server 1.0.0 installed (Python: create_app_resource())geox_list_apps tool exposes app-bearing tools to hostsgeoxMcpClient.ts), outputSchema per tool (blueprint families: GeoxStatusResult, GeoxArtifactResult, GeoxWellResult, GeoxSeismicResult, GeoxMapResult, GeoxProspectResult, GeoxClaimResult, GeoxEvidenceResult)geox_map_render_preview, geox_seismic_cognition, geox_well_desk| Floor | Binding | MCP UI Application |
|-------|---------|-------------------|
| F1 AMANAH | HARD | UI resources are reversible. Text fallback ensures no data loss. |
| F2 TRUTH | HARD | structuredContent vs content prevents model hallucination on raw data. |
| F4 CLARITY | HARD | UI reduces entropy — visual > wall of JSON. |
| F6 MARUAH | HARD | Approval gates for destructive actions. Human in loop. |
| F7 HUMILITY | HARD | Sandbox isolation. Model delegates to UI, doesn't claim omniscience. |
| F8 GENIUS | DERIVED | visibility: ["app"] for high-risk tools prevents model misuse. |
| F9 ANTI-HANTU | HARD | UI is rendered HTML, not consciousness. Tool, not being. |
| F11 AUDIT | HARD | JSON-RPC messages are loggable. CSP enforces declared domains. |
| F12 INJECTION | HARD | Sandboxed iframe blocks host DOM access. CSP blocks undeclared origins. |
| F13 SOVEREIGN | HARD | Approval gate = Arif's veto in UI form. |
_meta.ui.csp?tools/list shows _meta.ui.resourceUri?cloudflared tunnel for remote host testing?/root/A-FORGE/forge_work/2026-07-19/MCP-GUI-COMPREHENSIVE-REPORT-2026-07-19.mdForged: 2026-07-19 by FORGE (000Ω). Hardened 2026-07-20 to the ChatGPT-native blueprint. DITEMPA BUKAN DIBERI. The forge knows the code. The kernel knows the law. The sovereign knows the way.
development
Federation-wide gold (XAUUSD) trading capability. Python stack, OANDA broker, backtesting, macro signals, RSI strategy. Every organ has a role.
development
Capital claim state management — tracks claim lifecycle across WEALTH organ.
development
Archived constitutional warga placeholder retained only for audit provenance. Do not use for active work; use the live arifOS governance and constitutional skills instead.
testing
Warga (citizen) agent skills for AAA federation members. See subdirectories for specialized warga skills.