mcp-create-adaptive-cards

mcp-create-adaptive-cards

熱門

由 mcp-create-adaptive-cards.prompt.md 轉換而成的 Skill

3.7萬星標
4569分支
更新於 2026/7/14
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 -->