Template

Bar chart widget for MCP Apps

Horizontal bars that compare one number across categories, each with its value at the end. Pure HTML and CSS, so it renders the instant the data arrives.

Add a UI to your MCP server

Where did our website visitors come from this month?

Used show_bar_chart

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

When to use a bar chart widget

Bars are the honest way to compare quantities. Lengths are easy to rank by eye, labels sit next to their bars, and every value is printed, so nobody has to estimate.

Reach for it when someone asks "which is biggest?" or "how do these compare?":

  • Visits by channel or signups by source.
  • Sales by product or by region.
  • Tickets by team, bugs by component.
  • Hours by client in a time-tracking summary.
  • Votes per option in a quick poll.

The bars are horizontal on purpose. Category names are often long (a full product name, a campaign, a team), and horizontal bars give them room even in a narrow chat column on a phone. When the total and its shares matter more than the ranking, the donut chart says it better.

How the model fills it

The schema needs a title and a list of bars, each a label and a value of zero or more. subtitle usually holds the period, and unit is printed after every value.

Bars keep the order they arrive in. That is deliberate (sometimes the order is meaningful: months, steps, a fixed list of regions), but it means the model decides the ranking. If you always want the largest bar first, say so in the widget's description, which the model reads as the tool description, or sort in the markup with Liquid's sort and reverse filters.

Everything else is computed by the template. Each bar's width is its share of the largest value, so the leader always fills the track, and the leader is marked so designs can highlight it. The model passes raw numbers; formatting for the host's language happens in the widget.

What it does in the chat

When the widget renders, each bar grows from the left, one after another with a short stagger. The animation is plain CSS: there is no script and no library, so the widget runs under the default MCP Apps CSP with nothing to declare and nothing to download. With reduced motion on, the bars appear at full length.

Long labels are cut with an ellipsis rather than pushing the bars out of line, and values use tabular figures so they line up.

No host actions are declared.

Make it yours

Each of the five classic designs draws the bars its own way: thin ink bars on a hairline card in Nordic, luminous gradient bars on glass in Aurora, fat boxed bars with hard shadows in Brutalist, a ruled list where only the leader takes the accent in Editorial, and dashed glowing tubes in Neon. The brand-inspired designs and your own ones apply their colors and type on top.

Since the markup is a short Liquid loop, extending it is easy. Add a second value for a target and draw it as a marker on the track, or add a data-wg-message to each row so a click asks the model to dig into that category. Change the schema to match and the model will follow it.

Take it to your server

Link the published widget from your MCP server so updates arrive without a deploy, or download the HTML and the manifest. The guide to adding a UI to your MCP server has both. For trends over time, look at the area chart template; to let your agent build either one, see creating widgets with an AI agent.

The data it takes

FieldTypeWhat it is
titlerequiredstring
subtitlestring
unitstringUnit shown after each value
barsrequiredobject[]
└ labelrequiredstring
└ valuerequirednumber

Sample data

{
  "title": "Visits by channel",
  "subtitle": "Last 30 days",
  "bars": [
    {
      "label": "Organic search",
      "value": 12840
    },
    {
      "label": "LinkedIn",
      "value": 7310
    },
    {
      "label": "Newsletter",
      "value": 4105
    },
    {
      "label": "Direct",
      "value": 3620
    },
    {
      "label": "Referrals",
      "value": 1190
    }
  ]
}

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_bar_chart",
  "title": "Bar chart",
  "description": "Shows a horizontal bar chart comparing a numeric value across categories. Use it to compare quantities such as sales by product or visits by channel.",
  "inputSchema": {
    "type": "object",
    "required": [
      "title",
      "bars"
    ],
    "properties": {
      "title": {
        "type": "string"
      },
      "subtitle": {
        "type": "string"
      },
      "unit": {
        "type": "string",
        "description": "Unit shown after each value"
      },
      "bars": {
        "type": "array",
        "items": {
          "type": "object",
          "required": [
            "label",
            "value"
          ],
          "properties": {
            "label": {
              "type": "string"
            },
            "value": {
              "type": "number",
              "minimum": 0
            }
          }
        }
      }
    }
  }
}

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.