Skip to content
Draft
Show file tree
Hide file tree
Changes from 10 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
62 changes: 62 additions & 0 deletions examples/html-widgets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# HTML Widgets Example

This example bot demonstrates the HTML widget contract for Teams bots using the Teams SDK.

## What it tests

| Command | Purpose | Widget callbacks |
|---------|---------|-----------------|
| `/simple` | Static widget rendering | None |
| `/calltool` | Widget calling bot tools | `htmlwidget/calltool` invoke |
| `/messageback` | Widget sending messageBack | `onMessage` |
| `/fullscreen` | Widget requesting display mode change | `onRequestDisplayMode` (client-side) |
| `/multi` | Multiple tool dispatch | `htmlwidget/calltool` with different tool names |
| `/raw` | Direct markdown helper usage | None |
| `/permissions` | Widget requesting permissions | None (host-enforced) |

## Architecture

```
Bot sends message:
textFormat: 'extendedmarkdown'
text: "...\n```html-widget\n{JSON payload}\n```"

Teams client:
McpWidgetRenderer loads widget HTML in sandboxed iframe
@modelcontextprotocol/ext-apps SDK provides callServerTool API

Widget calls tool:
ext-apps SDK -> postMessage -> McpWidgetRenderer -> htmlwidget/calltool invoke -> Bot

Bot returns:
{ status: 200, body: { content: [...], structuredContent: {...}, isError: false } }
Comment on lines +31 to +32
```

## Running

1. Copy credentials:
```
cp ../../../bots/.env .env
```

2. Start a devtunnel and update the Azure Bot endpoint

3. Run the bot:
```
npm run dev
```

4. In Teams, message the bot with `/help` to see available commands

## Note on widget HTML

The widget HTML in `src/widgets/` is static HTML for rendering verification.
Interactive behavior (callTool, messageBack, displayMode) requires the
`@modelcontextprotocol/ext-apps` SDK which is provided by the Teams widget host
page (`mcpwidget.html` on `widget-renderer.usercontent.microsoft`).

The bot-side code (`widget.callTool` handler in `src/index.ts`) is the primary
test target. It verifies that:
- The SDK's invoke route alias correctly matches `htmlwidget/calltool`
- The typed handler receives `{ name, arguments }` in `activity.value`
- The response body format (`McpUiCallToolResult`) is accepted by the client
1 change: 1 addition & 0 deletions examples/html-widgets/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@microsoft/teams.config/eslint.config').default;
31 changes: 31 additions & 0 deletions examples/html-widgets/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"name": "@examples/html-widgets",
"version": "0.0.1",
"private": true,
"license": "MIT",
"main": "dist/index",
"types": "dist/index",
"files": [
"dist",
"README.md"
],
"scripts": {
"clean": "npx rimraf ./dist",
"lint": "npx eslint",
"lint:fix": "npx eslint --fix",
"build": "npx tsc",
"start": "node .",
"dev": "tsx watch -r dotenv/config src/index.ts"
},
"dependencies": {
"@microsoft/teams.apps": "*"
},
"devDependencies": {
"@microsoft/teams.config": "*",
"@types/node": "^22.5.4",
"dotenv": "^16.4.5",
"rimraf": "^6.0.1",
"tsx": "^4.20.6",
"typescript": "^5.4.5"
}
}
Loading
Loading