Template

Weather widget for MCP Apps

Answer "what's the weather like?" with a card instead of a sentence. Animated SVG icons, the temperature in large type and the next hours in a row, in whatever design you choose.

Add a UI to your MCP server

Will I need a jacket this afternoon? I'm walking to the office around five.

Used show_weather

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

When to use a weather widget

Weather is the classic case for a widget: the answer is a handful of numbers and an icon, and a sentence that lists them all is harder to read than a glance at a card. Use it when your MCP server can get a forecast and people ask about it:

  • A weather tool wrapped around the forecast API you already use.
  • Travel and trip planning, showing the destination's weather next to the itinerary.
  • Event and outdoor work planning: a wedding venue, a building site, a delivery route.
  • Morning briefings, where an agent puts the day's weather next to the calendar.

For several days side by side, a bar chart of highs per day works with no changes. To pair the weather with other figures, combine it with metrics.

How the model fills it

Your tool fetches the forecast; the widget never calls a weather API itself. The model takes what your tool returned and calls the widget's tool with it. The schema keeps that mapping simple:

  • place, temperature, high and low are required. Temperatures are in Celsius according to the schema; if your audience reads Fahrenheit, change the field description and the model will send Fahrenheit.
  • condition is an enum of five values: sunny, partly-cloudy, cloudy, rain and night. The enum forces the model to map whatever your API says ("light drizzle", code 61) onto one of the icons the card can draw. Add more values only if you also add their icon to the markup.
  • summary is the free text under the temperature, and its description asks for the user's language, so a Spanish speaker gets "Soleado" and an English speaker "Sunny" from the same tool.
  • hours is an optional list of times and temperatures for the row at the bottom.

What it does in the chat

The icon is inline SVG drawn by the Liquid template from condition: the sun turns slowly, the cloud drifts, rain falls in staggered drops, and the moon appears at night. Each condition also tints the card with its own hue, and each design decides how much sky to paint, from a white card with an ink line icon in Nordic to a glowing terminal sky in Neon. Animations stop for people who prefer reduced motion.

There is no script and no library, so the document is self-contained and needs nothing in its CSP beyond the defaults. The card declares no host actions; it is a pure answer.

Make it yours

It works in all twenty built-in designs and in your organization's own. The "high" and "low" labels come in English and Spanish and follow the language the host reports; they live in the markup with the degree format, so reword them there. You can add a field (wind, rain probability, a "feels like" temperature) to the schema and show it under the range, or add conditions such as snow or fog with their own SVG.

Take it to your server

Link the published card from the MCP server that already has your forecast tool, so both live side by side, or download its HTML and manifest. Add UI to your MCP server explains both, and which clients render MCP Apps covers what text-only hosts see instead.

The data it takes

FieldTypeWhat it is
placerequiredstring
conditionrequiredsunny | partly-cloudy | cloudy | rain | night
summarystringShort description in the user language, e.g. "Sunny"
temperaturerequirednumberCelsius
highrequirednumber
lowrequirednumber
hoursobject[]
└ timerequiredstringe.g. "14:00"
└ temperaturerequirednumber

Sample data

{
  "place": "Madrid",
  "condition": "partly-cloudy",
  "summary": "Partly cloudy",
  "temperature": 21,
  "high": 24,
  "low": 13,
  "hours": [
    {
      "time": "12:00",
      "temperature": 21
    },
    {
      "time": "13:00",
      "temperature": 22
    },
    {
      "time": "14:00",
      "temperature": 24
    },
    {
      "time": "15:00",
      "temperature": 24
    },
    {
      "time": "16:00",
      "temperature": 23
    },
    {
      "time": "17:00",
      "temperature": 21
    }
  ]
}

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_weather",
  "title": "Weather",
  "description": "Shows the weather for one place: the current condition and temperature, the high and low, and the next hours. Use it whenever the user asks about the weather or the forecast.",
  "inputSchema": {
    "type": "object",
    "required": [
      "place",
      "condition",
      "temperature",
      "high",
      "low"
    ],
    "properties": {
      "place": {
        "type": "string"
      },
      "condition": {
        "type": "string",
        "enum": [
          "sunny",
          "partly-cloudy",
          "cloudy",
          "rain",
          "night"
        ]
      },
      "summary": {
        "type": "string",
        "description": "Short description in the user language, e.g. \"Sunny\""
      },
      "temperature": {
        "type": "number",
        "description": "Celsius"
      },
      "high": {
        "type": "number"
      },
      "low": {
        "type": "number"
      },
      "hours": {
        "type": "array",
        "items": {
          "type": "object",
          "required": [
            "time",
            "temperature"
          ],
          "properties": {
            "time": {
              "type": "string",
              "description": "e.g. \"14:00\""
            },
            "temperature": {
              "type": "number"
            }
          }
        }
      }
    }
  }
}

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.