Skip to content

feat: HTML widget support (MCP Apps UI)#586

Draft
corinagum wants to merge 5 commits into
mainfrom
cg/widgets
Draft

feat: HTML widget support (MCP Apps UI)#586
corinagum wants to merge 5 commits into
mainfrom
cg/widgets

Conversation

@corinagum

@corinagum corinagum commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator
image

Summary

Adds HTML widget support to the Teams .NET SDK (core), enabling bots to send rich interactive MCP Apps UI widgets in Teams messages.

What's included

Models (Microsoft.Teams.Apps.HtmlWidget)

  • HtmlWidgetPayload, HtmlWidgetSecurityPolicy, HtmlWidgetPermissions
  • McpUiCallToolResult, HtmlWidgetCallToolResponse (wire-format wrapper with FromText() / FromError() helpers)
  • HtmlWidgetCallToolRequest (incoming invoke deserialization)
  • extendedmarkdown added to TextFormats

App helpers (HtmlWidgetHelpers)

  • BuildHtmlWidgetMarkdown - wraps payload in ```html-widget code fence
  • BuildHtmlWidgetMessage - builds a ready-to-send MessageActivity
  • InjectWidgetProtocol - optional convenience helper that injects the MCP Apps protocol (ui/initialize handshake, size reporting, notification hooks)
  • ValidateSecurityPolicy - static analysis of widget HTML against declared security policy

Handler (HtmlWidgetCallToolHandler)

  • OnWidgetCallTool extension method on TeamsBotApplication
  • Routes htmlwidget/calltool invoke activities to typed delegate

Internal (not exported):

  • ValidatePayload - runtime validation (name, html, domain) called automatically by builders

Sample bot (core/samples/HtmlWidgetBot/)

  • 9 commands demonstrating the full widget contract
  • Typed OnWidgetCallTool handler with multi-tool dispatch

Tests

  • 60 unit tests covering all helpers, protocol injection, validation, security policy, and immutability
  • 4 integration tests (send, send with tool data, update, delete)

Preview markers

  • All public APIs marked [Experimental("ExperimentalTeamsHtmlWidget")]

Design decisions

  • Protocol injection is opt-in: InjectWidgetProtocol is called internally by the builders, but widgets that implement the MCP Apps protocol themselves are returned unchanged (detected by presence of ui/initialize)
  • Notification hooks are explicit: only mapped notification names are injected; unknown names are silently ignored
  • Payload validation throws early: prevents silent client-side "Couldn't load widget" failures
  • Default security policy: restrictive defaults per MCP Apps spec (no external network, self+data resources only)
  • Security validation is advisory: ValidateSecurityPolicy is a static linter; CSP enforcement in the iframe is the actual security boundary
  • Options immutability: BuildHtmlWidgetMarkdown copies protocol options rather than mutating the caller's instance

Related

Status

Draft - pending:

  • .NET Libraries port
  • Documentation in teams-sdk/teams.md

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant