render_artifact
Render structured specifications into interactive HTML artifacts for diagrams, timelines, code reviews, and more.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| input | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| artifact_id | Yes | ||
| delivery | Yes | ||
| title | Yes | ||
| html | No | ||
| resource_uri | No | ||
| byte_size | Yes | ||
| warnings | Yes |
Implementation Reference
- src/web_gui_mcp/mcp_tools.py:58-87 (handler)The render_artifact_handler function is the main MCP tool handler. It builds RenderOptions from the input, calls render_artifact_to_html, optionally stores the artifact, and returns a RenderArtifactOutput with html, resource_uri, warnings, etc.
def render_artifact_handler( input_data: RenderArtifactInput, store: MemoryArtifactStore, ) -> RenderArtifactOutput: options = RenderOptions( delivery=input_data.delivery, interactivity=input_data.interactivity, density=input_data.spec.density, theme=input_data.spec.theme, include_runtime=input_data.interactivity != "none", ) rendered = render_artifact_to_html(input_data.spec, options) should_store = input_data.persist or input_data.delivery in {"mcp_app", "resource_only"} stored = store.save(input_data.spec, rendered.html) if should_store else None artifact_id = stored.artifact_id if stored else rendered.artifact_id resource_uri = f"{RESOURCE_PREFIX}/{artifact_id}" if stored else None warnings = list(rendered.warnings) if input_data.delivery != "static_html" and not stored: warnings.append("No resource URI returned because persist=false.") if input_data.token_budget == "low" and input_data.delivery == "static_html": warnings.append("static_html can be token-heavy; use resource_only for low token budgets.") return RenderArtifactOutput( artifact_id=artifact_id, delivery=input_data.delivery, title=input_data.spec.title, html=rendered.html if input_data.delivery == "static_html" else None, resource_uri=resource_uri if input_data.delivery in {"mcp_app", "resource_only"} else None, byte_size=rendered.byte_size, warnings=warnings, ) - render_artifact_to_html is the core rendering helper. It takes an ArtifactSpec and RenderOptions, generates a complete HTML document with CSS, sections, header, actions, and runtime tag, and returns a RenderedArtifact.
def render_artifact_to_html(spec: ArtifactSpec, options: RenderOptions | None = None) -> RenderedArtifact: options = options or RenderOptions(density=spec.density, theme=spec.theme) include_runtime = options.include_runtime or options.interactivity != "none" or spec.v == "0.2" warnings: list[str] = [] if options.interactivity == "host_intents": warnings.append("host_intents interactivity is a v0.1 stub using postMessage.") if options.allow_trusted_html_preview: warnings.append("allow_trusted_html_preview bypasses escaped preview rendering.") sections_html = "\n".join(render_section(section, options) for section in spec.sections) if spec.sources and not any(section.kind == "source_list" for section in spec.sections): sections_html += "\n" + render_source_list(SourceListSection(kind="source_list", sources=spec.sources)) state = json.dumps( spec.model_dump(mode="json", by_alias=True), ensure_ascii=False, sort_keys=True, separators=(",", ":"), ) state_json = safe_json_script(state) artifact_id = artifact_id_for_spec(spec) html = f"""<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta http-equiv="Content-Security-Policy" content="{_csp(include_runtime)}"> <title>{h(spec.title)}</title> <style>{render_css(theme=options.theme, density=options.density)}</style> </head> <body data-gui2-artifact="{attr(spec.artifact)}" data-gui2-id="{attr(artifact_id)}" data-gui2-version="{attr(spec.v)}" data-gui2-density="{attr(spec.density)}" data-gui2-theme="{attr(spec.theme)}" > <script id="artifact-state" type="application/json">{state_json}</script> <main class="gui2-shell"> {render_header(spec)} {sections_html} {render_actions(spec.actions, options)} </main> {render_runtime_tag(include_runtime)} </body> </html>""" return RenderedArtifact( artifact_id=artifact_id, html=html, resource_uri=None, byte_size=byte_size(html), warnings=warnings, ) - RenderArtifactInput schema: defines the input fields - spec (ArtifactSpec), delivery, interactivity, persist, and token_budget.
class RenderArtifactInput(ToolBaseModel): spec: ArtifactSpec delivery: DeliveryMode = "resource_only" interactivity: InteractivityMode = "none" persist: bool = True token_budget: TokenBudget = "medium" - RenderArtifactOutput schema: defines the output fields - artifact_id, delivery, title, html, resource_uri, byte_size, warnings.
class RenderArtifactOutput(ToolBaseModel): artifact_id: str delivery: DeliveryMode title: str html: str | None = None resource_uri: str | None = None byte_size: int warnings: list[str] - src/web_gui_mcp/mcp_tools.py:180-182 (registration)Registration of the render_artifact MCP tool via the @mcp.tool() decorator, which delegates to render_artifact_handler.
@mcp.tool() def render_artifact(input: RenderArtifactInput) -> RenderArtifactOutput: return render_artifact_handler(input, store)