Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,9 @@ jobs:
mkdir -p docs/public/specification/v1_0/catalogs/basic
cp catalogs/basic/v1/catalog.json docs/public/specification/v1_0/catalogs/basic/
cp -R catalogs/basic/v1/examples docs/public/specification/v1_0/catalogs/basic/
# The MCP catalog v1 targets protocol v1.0.
# The iframe and MCP catalogs target protocol v1.0.
mkdir -p docs/public/specification/v1_0/catalogs/iframe
cp catalogs/iframe/catalog.json docs/public/specification/v1_0/catalogs/iframe/
mkdir -p docs/public/specification/v1_0/catalogs/mcp
cp catalogs/mcp/v1/catalog.json docs/public/specification/v1_0/catalogs/mcp/
cp -R catalogs/mcp/v1/examples docs/public/specification/v1_0/catalogs/mcp/
Expand Down
3 changes: 3 additions & 0 deletions catalogs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ catalogs/
│ ├── catalog.json
│ ├── examples/
│ └── basic_catalog_implementation_guide.md
├── iframe/ # iframe catalog
│ ├── catalog.json
│ └── web_app_frame_specification.md
├── mcp/ # MCP catalog
│ ├── catalog.json # Pre-1.0 MCP catalog, protocol v0.9
│ └── v1/ # MCP catalog, major version 1 (protocol v1.0)
Expand Down
32 changes: 32 additions & 0 deletions catalogs/iframe/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# A2UI iframe catalog

The A2UI iframe catalog lets A2UI surfaces embed sandboxed web applications, from remote widgets to model-generated HTML, next to regular components. It defines the `WebAppFrameUrl` and `WebAppFrameSrcdoc` components, which render an iframe and connect it to the surface through a message protocol, so the embedded application can dispatch actions, share data model state in both directions, call host functions and request its own size.

## Catalog specification

The catalog ID is `https://a2ui.org/specification/v1_0/catalogs/iframe/catalog.json`.

The catalog declares two components in [catalog.json](catalog.json) and no functions:

| Component | Content | Description |
| :------------------ | :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------ |
| `WebAppFrameUrl` | `url` (`DynamicString`, required) | Loads an external http or https application in a sandboxed iframe. The remote server is responsible for its Content Security Policy. |
| `WebAppFrameSrcdoc` | `htmlContent` (`string`, required) | Renders inline HTML through `srcdoc` in a sandboxed iframe without network access. The host injects a strict Content Security Policy. |

Both components share the properties below.

| Property | Type | Description |
| :------------------------ | :----------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------- |
| `height` | `DynamicNumber` | The height of the iframe in pixels. |
| `config` | `object` | Static key-value settings passed once to the application, in the handshake. |
| `data.paths` | `object` of `string` | A map of state keys to JSON Pointer paths in the data model. The host sends the current values in the handshake and pushes every later change. |
| `allowedEvents` | `object` of JSON Schemas | The actions the application may dispatch, each mapped to the schema of its payload. |
| `allowedFunctions` | `object` of JSON Schemas | The catalog functions the application may call, each mapped to the schema of its arguments. |
| `mutableData` | `object` of JSON Schemas | The `data.paths` keys the application may write back, each mapped to the schema of the allowed values. |
| `disableSchemaValidation` | `boolean` | Skips the schema validation of the three allowlists above. Reserved for trusted first-party applications; the allowlists themselves still apply. |

The allowlists deny by default: the host drops any action, function call or data change that is not listed or whose payload fails validation. The messages exchanged between the host and the embedded application (`a2ui_app_frame_ready`, `a2ui_app_frame_init`, `a2ui_action`, `a2ui_data_model_change`, `a2ui_function_call`, `a2ui_size_changed` and their host-to-app counterparts) are defined in the [WebApp iframe component specification](web_app_frame_specification.md).

## Implementations

The components originated in the [Angular MCP calculator sample](../../samples/community/client/angular/projects/mcp_calculator/src/a2ui-catalog/), which implements a v0.9 predecessor of this catalog under its own sample catalog ID.
162 changes: 162 additions & 0 deletions catalogs/iframe/catalog.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://a2ui.org/specification/v1_0/catalogs/iframe/catalog.json",
Comment thread
josemontespg marked this conversation as resolved.
Resolved
"protocolVersion": "1.0",
"title": "A2UI iframe catalog",
"description": "A2UI catalog for embedding sandboxed web applications in a surface. `WebAppFrameUrl` loads an external URL and `WebAppFrameSrcdoc` renders inline HTML. Both components exchange `a2ui_*` messages with the host over a dedicated MessagePort to dispatch actions, keep bound data in sync in both directions, call host functions and request frame resizes. See web_app_frame_specification.md for the protocol and the security controls.",
"catalogId": "https://a2ui.org/specification/v1_0/catalogs/iframe/catalog.json",
"components": {
"WebAppFrameUrl": {
"type": "object",
"description": "Renders an external web application, loaded from an http or https URL, in a sandboxed iframe. The remote server is responsible for the application's Content Security Policy.",
"properties": {
"component": {
"const": "WebAppFrameUrl"
},
"url": {
"$ref": "common_types.json#/$defs/DynamicString",
"description": "The external URL to load inside the iframe. Only http and https URLs are loaded. The host appends its own origin as the `origin` query parameter so the application can address its messages to the host."
},
"height": {
"$ref": "common_types.json#/$defs/DynamicNumber",
"description": "The height of the iframe in pixels."
},
"config": {
"type": "object",
"description": "A dictionary of static key-value initialization properties passed to the embedded application once, in the `a2ui_app_frame_init` handshake, without reactive data model binding."
},
"data": {
"type": "object",
"description": "Data binding configuration for the component.",
"properties": {
"paths": {
"type": "object",
"description": "A dictionary mapping custom state keys to distinct JSON Pointer paths in the data model. The host sends the current value of every path in the handshake and pushes an `a2ui_data_model_update` message whenever one changes.",
"additionalProperties": {
"type": "string"
}
}
},
"required": ["paths"],
"additionalProperties": false
},
"allowedEvents": {
"type": "object",
"description": "A map of authorized action names to JSON Schemas describing the expected `data` payload. The host silently drops an `a2ui_action` message whose action is not listed or whose data fails validation.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"allowedFunctions": {
"type": "object",
"description": "A map of authorized host client function names to JSON Schemas describing their expected arguments. The host rejects an `a2ui_function_call` message whose function is not listed or whose arguments fail validation. The functions must exist in the surface's catalog.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"mutableData": {
"type": "object",
"description": "A map of state keys, as declared in `data.paths`, that the embedded application is authorized to mutate in the parent data model, each mapped to a JSON Schema describing the allowed values. The host drops an `a2ui_data_model_change` message whose key is not listed or whose value fails validation.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"disableSchemaValidation": {
"type": "boolean",
"description": "If true, the host skips the JSON Schema validation of `allowedEvents`, `allowedFunctions` and `mutableData` payloads and forwards them as they arrive. Source checks, payload limits and the allowlists still apply. Reserve it for trusted first-party applications; the agent backend must not set it for untrusted content.",
"default": false
}
},
"required": ["component", "url"]
},
"WebAppFrameSrcdoc": {
"type": "object",
"description": "Renders inline HTML, such as a model-generated application, in a sandboxed iframe with no network access. The host injects a strict Content Security Policy into the markup before rendering it.",
"properties": {
"component": {
"const": "WebAppFrameSrcdoc"
},
"htmlContent": {
"type": "string",
"description": "The raw HTML string to render via srcdoc. A value prefixed with `url_encoded:` is decoded with decodeURIComponent before rendering."
},
"height": {
"$ref": "common_types.json#/$defs/DynamicNumber",
"description": "The height of the iframe in pixels."
},
"config": {
"type": "object",
"description": "A dictionary of static key-value initialization properties passed to the embedded application once, in the `a2ui_app_frame_init` handshake, without reactive data model binding."
},
"data": {
"type": "object",
"description": "Data binding configuration for the component.",
"properties": {
"paths": {
"type": "object",
"description": "A dictionary mapping custom state keys to distinct JSON Pointer paths in the data model. The host sends the current value of every path in the handshake and pushes an `a2ui_data_model_update` message whenever one changes.",
"additionalProperties": {
"type": "string"
}
}
},
"required": ["paths"],
"additionalProperties": false
},
"allowedEvents": {
"type": "object",
"description": "A map of authorized action names to JSON Schemas describing the expected `data` payload. The host silently drops an `a2ui_action` message whose action is not listed or whose data fails validation.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"allowedFunctions": {
"type": "object",
"description": "A map of authorized host client function names to JSON Schemas describing their expected arguments. The host rejects an `a2ui_function_call` message whose function is not listed or whose arguments fail validation. The functions must exist in the surface's catalog.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"mutableData": {
"type": "object",
"description": "A map of state keys, as declared in `data.paths`, that the embedded application is authorized to mutate in the parent data model, each mapped to a JSON Schema describing the allowed values. The host drops an `a2ui_data_model_change` message whose key is not listed or whose value fails validation.",
"additionalProperties": {
"type": "object",
"description": "A JSON Schema. The host validates the matching payload against it before acting on the message; an empty object accepts any value."
}
},
"disableSchemaValidation": {
"type": "boolean",
"description": "If true, the host skips the JSON Schema validation of `allowedEvents`, `allowedFunctions` and `mutableData` payloads and forwards them as they arrive. Source checks, payload limits and the allowlists still apply. Reserve it for trusted first-party applications; the agent backend must not set it for untrusted content.",
"default": false
}
},
"required": ["component", "htmlContent"]
}
},
"functions": {},
"$defs": {
"anyComponent": {
"oneOf": [
{
"$ref": "#/components/WebAppFrameUrl"
},
{
"$ref": "#/components/WebAppFrameSrcdoc"
}
],
"discriminator": {
"propertyName": "component"
}
},
"anyFunction": {
"description": "This catalog declares no functions, so no function call validates against it.",
"not": {}
}
}
}
Loading
Loading