Template

Donut chart widget for MCP Apps

How a total splits into parts, drawn as an animated donut with Chart.js. The model sends labels and values; the widget adds up the total and works out every share.

Uses Chart.js

Add a UI to your MCP server

Can you break down last month's team spending by category?

Used show_donut_chart

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

When to use a donut chart widget

A donut answers "where did it go?" at a glance. It works when there is one total, a handful of parts, and the reader cares about proportions more than exact gaps between values.

Typical questions:

  • Spending by category, from an expenses or accounting tool.
  • Traffic by source, from an analytics API.
  • Time by project or client, from a time tracker.
  • Answers to one survey question, or tickets by status.

Keep it to roughly six segments. With more, or when the reader needs to rank similar values, the bar chart template reads better. For change over time, use the area chart.

How the model fills it

The schema requires a title and a list of segments, each with a label and a value of zero or more. Optional fields:

  • subtitle, usually the period the data covers.
  • unit, the short text under the total in the middle of the ring, such as a currency or "hours in total".
  • color on a segment, any CSS color. Leave it out and the segment takes the next color of the design's palette.

The model never does the arithmetic. The template sums the values for the total and computes each segment's percentage itself, so the total and the shares always agree with the values, and the model has no percentages to get wrong.

The tool description says what the widget is for: shares such as spending by category, traffic by source or time by project. That is what lets the model pick it over the bar chart when someone asks "how is it split?" rather than "which is biggest?".

What it does in the chat

The ring sweeps in when the widget renders. Hovering a segment pushes it out a little and shows a tooltip with its label and value. Next to the ring, an HTML legend lists every part with its value and percentage, readable even where the chart is small.

The chart is drawn by Chart.js 4.5.1, pinned and loaded as an ES module from jsDelivr. The widget's resource declares that origin in its CSP, so ChatGPT, Claude and other MCP Apps hosts let it load. Colors, fonts and the tooltip are read from the design tokens at render time, so the chart follows the design and switches with the host's light or dark theme. With reduced motion on, the sweep is off. Each new render destroys the previous chart before drawing the next.

No host actions are declared.

Make it yours

The ring's shape is set in CSS, not in the script: --donut-cutout, --donut-border, --donut-spacing, --donut-radius and --donut-seam are custom properties the script reads. That is how one template looks so different across designs: a thin monochrome ring with hairline gaps in Nordic, rounded glowing arcs floating apart in Aurora, a fat pie with black seams in Brutalist, a fine ring with a Didot total in Editorial, separated neon arcs in Neon. Change those five values in the styles and you have your own ring without touching JavaScript.

To make the legend interactive, add data-wg-message to each row so a click asks the model to break that category down further.

Take it to your server

Link the published widget from your MCP server, or download its HTML and manifest; both are explained in the guide to adding a UI to your MCP server. If your agent should create it for you, see creating widgets with an AI agent.

The data it takes

FieldTypeWhat it is
titlerequiredstring
subtitlestring
unitstringShown under the total
segmentsrequiredobject[]
└ labelrequiredstring
└ valuerequirednumber
└ colorstringAny CSS color. Leave it out to use the design palette.

Sample data

{
  "title": "Spending by category",
  "subtitle": "September 2026",
  "unit": "€ in total",
  "segments": [
    {
      "label": "Software",
      "value": 1840
    },
    {
      "label": "Training",
      "value": 960
    },
    {
      "label": "Travel",
      "value": 720
    },
    {
      "label": "Equipment",
      "value": 410
    }
  ]
}

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_donut_chart",
  "title": "Donut",
  "description": "Shows how a total splits into parts as a donut chart with a legend and the total in the middle. Use it for shares such as spending by category, traffic by source or time by project.",
  "inputSchema": {
    "type": "object",
    "required": [
      "title",
      "segments"
    ],
    "properties": {
      "title": {
        "type": "string"
      },
      "subtitle": {
        "type": "string"
      },
      "unit": {
        "type": "string",
        "description": "Shown under the total"
      },
      "segments": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "required": [
            "label",
            "value"
          ],
          "properties": {
            "label": {
              "type": "string"
            },
            "value": {
              "type": "number",
              "minimum": 0
            },
            "color": {
              "type": "string",
              "description": "Any CSS color. Leave it out to use 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.