SKILL.md
唯讀
名稱
mcp-create-adaptive-cards
描述
由 mcp-create-adaptive-cards.prompt.md 轉換而成的 Skill
---
mode: 'agent'
tools: ['changes', 'search/codebase', 'edit/editFiles', 'problems']
description: '為基於 MCP 的 API 外掛新增 Adaptive Card 回應範本,優化 Microsoft 365 Copilot 中的資料視覺化呈現'
model: 'gpt-4.1'
tags: [mcp, adaptive-cards, m365-copilot, api-plugin, response-templates]
---
# 為 MCP 外掛建立 Adaptive Card
為基於 MCP 的 API 外掛新增 Adaptive Card 回應範本,以提升資料在 Microsoft 365 Copilot 中的視覺化呈現效果。
## Adaptive Card 類型
### 靜態回應範本
當 API 總是傳回相同類型的項目,且格式不常變動時使用。
在 ai-plugin.json 的 `response_semantics.static_template` 中定義:
```json
{
"functions": [
{
"name": "GetBudgets",
"description": "Returns budget details including name and available funds",
"capabilities": {
"response_semantics": {
"data_path": "$",
"properties": {
"title": "$.name",
"subtitle": "$.availableFunds"
},
"static_template": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5",
"body": [
{
"type": "Container",
"$data": "${$root}",
"items": [
{
"type": "TextBlock",
"text": "Name: ${if(name, name, 'N/A')}",
"wrap": true
},
{
"type": "TextBlock",
"text": "Available funds: ${if(availableFunds, formatNumber(availableFunds, 2), 'N/A')}",
"wrap": true
}
]
}
]
}
}
}
}
]
}
```
### 動態回應範本
當 API 傳回多種類型,且每個項目需要不同的範本時使用。
**ai-plugin.json 設定:**
```json
{
"name": "GetTransactions",
"description": "Returns transaction details with dynamic templates",
"capabilities": {
"response_semantics": {
"data_path": "$.transactions",
"properties": {
"template_selector": "$.displayTemplate"
}
}
}
}
```
**內嵌範本的 API 回應:**
```json
{
"transactions": [
{
"budgetName": "Fourth Coffee lobby renovation",
"amount": -2000,
"description": "Property survey for permit application",
"expenseCategory": "permits",
"displayTemplate": "$.templates.debit"
},
{
"budgetName": "Fourth Coffee lobby renovation",
"amount": 5000,
"description": "Additional funds to cover cost overruns",
"expenseCategory": null,
"displayTemplate": "$.templates.credit"
}
],
"templates": {
"debit": {
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"color": "attention",
"text": "Debit"
},
{
"type": "FactSet",
"facts": [
{
"title": "Budget",
"value": "${budgetName}"
},
{
"title": "Amount",
"value": "${formatNumber(amount, 2)}"
},
{
"title": "Category",
"value": "${if(expenseCategory, expenseCategory, 'N/A')}"
},
{
"title": "Description",
"value": "${if(description, description, 'N/A')}"
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
},
"credit": {
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"color": "good",
"text": "Credit"
},
{
"type": "FactSet",
"facts": [
{
"title": "Budget",
"value": "${budgetName}"
},
{
"title": "Amount",
"value": "${formatNumber(amount, 2)}"
},
{
"title": "Description",
"value": "${if(description, description, 'N/A')}"
}
]
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json"
}
}
}
```
### 結合靜態與動態範本
當項目沒有 `template_selector` 或其值無法解析時,將靜態範本作為預設範本使用。
```json
{
"capabilities": {
"response_semantics": {
"data_path": "$.items",
"properties": {
"title": "$.name",
"template_selector": "$.templateId"
},
"static_template": {
"type": "AdaptiveCard",
"version": "1.5",
"body": [
{
"type": "TextBlock",
"text": "Default: ${name}",
"wrap": true
}
]
}
}
}
}
```
## Response Semantics 屬性
### data_path
指出資料位於 API 回應中何處的 JSONPath 查詢:
```json
"data_path": "$" // 回應根目錄
"data_path": "$.results" // 位於 results 屬性中
"data_path": "$.data.items"// 巢狀路徑
```
### properties
為 Copilot 引用資料對應回應欄位:
```json
"properties": {
"title": "$.name", // 引用標題
"subtitle": "$.description", // 引用副標題
"url": "$.link" // 引用連結
}
```
### template_selector
每個項目上記錄要使用哪個範本的屬性:
```json
"template_selector": "$.displayTemplate"
```
## Adaptive Card 範本語言
### 條件式渲染
```json
{
"type": "TextBlock",
"text": "${if(field, field, 'N/A')}" // 顯示欄位內容,若無則顯示 'N/A'
}
```
### 數字格式化
```json
{
"type": "TextBlock",
"text": "${formatNumber(amount, 2)}" // 保留兩位小數
}
```
### 資料繫結
```json
{
"type": "Container",
"$data": "${$root}", // 切換至根情境 Context
"items": [ ... ]
}
```
### 條件式顯示
```json
{
"type": "Image",
"url": "${imageUrl}",
"$when": "${imageUrl != null}" // 僅在 imageUrl 存在時顯示
}
```
## 卡片元件
### TextBlock
```json
{
"type": "TextBlock",
"text": "Text content",
"size": "medium", // small, default, medium, large, extraLarge
"weight": "bolder", // lighter, default, bolder
"color": "attention", // default, dark, light, accent, good, warning, attention
"wrap": true
}
```
### FactSet
```json
{
"type": "FactSet",
"facts": [
{
"title": "Label",
"value": "Value"
}
]
}
```
### Image
```json
{
"type": "Image",
"url": "https://example.com/image.png",
"size": "medium", // auto, stretch, small, medium, large
"style": "default" // default, person
}
```
### Container
```json
{
"type": "Container",
"$data": "${items}", // 迭代陣列
"items": [
{
"type": "TextBlock",
"text": "${name}"
}
]
}
```
### ColumnSet
```json
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [ ... ]
},
{
"type": "Column",
"width": "stretch",
"items": [ ... ]
}
]
}
```
### Actions
```json
{
"type": "Action.OpenUrl",
"title": "View Details",
"url": "https://example.com/item/${id}"
}
```
## 響應式設計最佳實踐
### 單欄版面配置
- 針對較窄的視埠使用單欄配置
- 盡量避免使用多欄配置
- 確保卡片在最小視埠寬度下能正常運作
### 彈性寬度
- 切勿為元件指定固定寬度
- 寬度屬性請使用 "auto" 或 "stretch"
- 允許元件隨視埠大小彈性調整
- 僅有圖示/頭像可使用固定寬度
### 文字與圖片
- 避免將文字與圖片放在同一列
- 例外情況:小型圖示或頭像
- 文字內容請設定 `"wrap": true`
- 在各種不同的視埠寬度下進行測試
### 跨平台驗證
在以下環境中驗證卡片:
- Teams(桌面版與行動版)
- Word
- PowerPoint
- 各種視埠寬度(收合/展開 UI)
## 完整範例
**ai-plugin.json:**
```json
{
"functions": [
{
"name": "SearchProjects",
"description": "Search for projects with status and details",
"capabilities": {
"response_semantics": {
"data_path": "$.projects",
"properties": {
"title": "$.name",
"subtitle": "$.status",
"url": "$.projectUrl"
},
"static_template": {
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5",
"body": [
{
"type": "Container",
"$data": "${$root}",
"items": [
{
"type": "TextBlock",
"size": "medium",
"weight": "bolder",
"text": "${if(name, name, 'Untitled Project')}",
"wrap": true
},
{
"type": "FactSet",
"facts": [
{
"title": "Status",
"value": "${status}"
},
{
"title": "Owner",
"value": "${if(owner, owner, 'Unassigned')}"
},
{
"title": "Due Date",
"value": "${if(dueDate, dueDate, 'Not set')}"
},
{
"title": "Budget",
"value": "${if(budget, formatNumber(budget, 2), 'N/A')}"
}
]
},
{
"type": "TextBlock",
"text": "${if(description, description, 'No description')}",
"wrap": true,
"separator": true
}
]
}
],
"actions": [
{
"type": "Action.OpenUrl",
"title": "View Project",
"url": "${projectUrl}"
}
]
}
}
}
}
]
}
```
## 工作流程
詢問使用者:
1. API 傳回哪種類型的資料?
2. 所有項目都是相同類型(靜態),還是包含不同類型(動態)?
3. 卡片中應該顯示哪些欄位?
4. 是否需要加入動作(例如「檢視詳細資訊」)?
5. 是否有多種狀態或分類需要使用不同的範本?
接著產生:
- 適當的 response_semantics 設定
- 靜態範本、動態範本或兩者兼具
- 搭配條件式渲染的正確資料繫結
- 響應式單欄版面配置
- 用於驗證的測試情境
## 參考資源
- [Adaptive Card Designer](https://adaptivecards.microsoft.com/designer) - 視覺化設計工具
- [Adaptive Card Schema](https://adaptivecards.io/schemas/adaptive-card.json) - 完整 Schema 參考說明
- [Template Language](https://learn.microsoft.com/en-us/adaptive-cards/templating/language) - 資料繫結語法指南
- [JSONPath](https://www.rfc-editor.org/rfc/rfc9535) - 路徑查詢語法
## 常見模式
### 帶有圖片的清單
```json
{
"type": "Container",
"$data": "${items}",
"items": [
{
"type": "ColumnSet",
"columns": [
{
"type": "Column",
"width": "auto",
"items": [
{
"type": "Image",
"url": "${thumbnailUrl}",
"size": "small",
"$when": "${thumbnailUrl != null}"
}
]
},
{
"type": "Column",
"w
<!-- truncated for translation batch; full body continues in source -->






