Template

Kanban board widget for MCP Apps

Show work grouped by status right inside the conversation. The model sorts your tasks into columns and the board draws them as cards with labels, dates and people.

Add a UI to your MCP server

Where are we with the beta launch? Show me the board before the stand-up.

Used show_kanban

The house design: black outline, butter yellow and a marker swipe under the title.

When to use a kanban widget

A board answers "where are we?" faster than any paragraph. Use it when your MCP server already knows about work items and their status, and the person asking wants the whole picture at once:

  • Sprint or release status pulled from your issue tracker: to do, in progress, in review, done.
  • Support tickets grouped by state, so a lead sees what is waiting on whom.
  • Hiring pipelines: candidates as cards, stages as columns, interview dates as due dates.
  • Content calendars and launch checklists, where labels such as "Web" or "Sales" tell teams apart.

If your data is a flat list with many attributes per row, a table reads better. If the question is how much is done rather than what, progress rings answer it in one look.

How the model fills the board

The widget's data schema is the input schema of its tool (show_<slug>), so the model sees exactly what a board needs: a title, an optional subtitle and a list of columns, each with a name and its cards. Only the card title is required. Everything else is optional and the board adapts:

  • due is an ISO 8601 date and shows as day and short month.
  • members takes full names. The board turns them into initials in small avatars and keeps the full name as a tooltip, so ask your tool for names, not ids.
  • labels have a name and an optional color. Leave the color out and the board picks one from the design palette, always the same one for the same name, so "Backend" keeps its color across every card without the model having to choose.

The tool description tells the model to use it for "tasks, tickets or any work grouped by status". If your columns have fixed names in your system, write them into the schema (an enum on the column name) and the model will stop inventing new ones.

What it does in the chat

Each column shows its card count, and an empty column says so instead of collapsing. With many columns the board scrolls sideways rather than squeezing the cards.

Every card is a host action: it carries a data-wg-message, so clicking it posts a follow-up message to the chat asking about that card. The model then answers with the detail, or calls another of your tools to fetch it. The board needs no script and no library, so its document loads nothing from outside and needs no extra CSP domains.

Make it yours

The board works in all twenty built-in designs and in any design your organization creates in the designer: glass lanes in Aurora, boxed lanes with hard shadows in Brutalist, ruled columns with serif headlines in Editorial. The markup is a Liquid template you can edit, together with the styles and the schema. The follow-up message and the empty-column text come in English and Spanish and follow the language the host reports; both are strings in the markup, so change the wording there. Add fields to the schema (a priority, an estimate) and render them on the card.

Take it to your server

Publish the widget and link it from your MCP server with a read-only key, so every change you publish reaches the server without a deploy, or download the HTML and the manifest and register them yourself. Add UI to your MCP server walks through both. If you would rather have your agent build the board for you, see create MCP App widgets with your AI agent.

The data it takes

FieldTypeWhat it is
titlerequiredstringBoard name
subtitlestring
columnsrequiredobject[]
└ namerequiredstring
└ cardsrequiredobject[]
└ titlerequiredstring
└ duestringISO 8601 date
└ membersstring[]Full names
└ labelsobject[]
└ namerequiredstring
└ colorstringAny CSS color. Optional: without it the label takes a color of the design palette

Sample data

{
  "title": "Beta launch",
  "subtitle": "Product team",
  "columns": [
    {
      "name": "To do",
      "cards": [
        {
          "title": "Write the pricing page",
          "labels": [
            {
              "name": "Web"
            }
          ],
          "members": [
            "Anna Reed"
          ]
        },
        {
          "title": "Prepare the investor demo",
          "due": "2026-10-09",
          "labels": [
            {
              "name": "Sales"
            }
          ]
        }
      ]
    },
    {
      "name": "In progress",
      "cards": [
        {
          "title": "MCP endpoint per organization",
          "due": "2026-10-05",
          "labels": [
            {
              "name": "Backend"
            }
          ],
          "members": [
            "Luke Grant",
            "Martha Sands"
          ]
        },
        {
          "title": "Launch video",
          "labels": [
            {
              "name": "Marketing"
            },
            {
              "name": "Sales"
            }
          ],
          "members": [
            "Martha Sands"
          ]
        }
      ]
    },
    {
      "name": "Done",
      "cards": [
        {
          "title": "Template gallery",
          "labels": [
            {
              "name": "Web"
            }
          ],
          "members": [
            "Anna Reed",
            "Luke Grant"
          ]
        }
      ]
    }
  ]
}

The tool that shows it

A widget made from this template is shown by one tool. The model reads its description to decide when to call it and fills the input schema with the data. This is the definition Widgetry exports:

{
  "name": "show_kanban",
  "title": "Board",
  "description": "Shows a kanban board: columns with cards, each card with optional labels, due date and assignees. Use it to display tasks, tickets or any work grouped by status.",
  "inputSchema": {
    "type": "object",
    "required": [
      "title",
      "columns"
    ],
    "properties": {
      "title": {
        "type": "string",
        "description": "Board name"
      },
      "subtitle": {
        "type": "string"
      },
      "columns": {
        "type": "array",
        "items": {
          "type": "object",
          "required": [
            "name",
            "cards"
          ],
          "properties": {
            "name": {
              "type": "string"
            },
            "cards": {
              "type": "array",
              "items": {
                "type": "object",
                "required": [
                  "title"
                ],
                "properties": {
                  "title": {
                    "type": "string"
                  },
                  "due": {
                    "type": "string",
                    "description": "ISO 8601 date"
                  },
                  "members": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Full names"
                  },
                  "labels": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "name"
                      ],
                      "properties": {
                        "name": {
                          "type": "string"
                        },
                        "color": {
                          "type": "string",
                          "description": "Any CSS color. Optional: without it the label takes a color of the design palette"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}

Your first widget, in the chat in minutes

Pick a template, drop in your data and see it as ChatGPT or Claude will show it. Then link it from your MCP server, or let your agent build the next one.