DEV Community

Cover image for Advent of AI 2025 - Day 17: Building a Wishlist App with Goose and MCP-UI
Nick Taylor
Nick Taylor Subscriber

Posted on • Edited on • Originally published at nickyt.co

Advent of AI 2025 - Day 17: Building a Wishlist App with Goose and MCP-UI

I've edited this post, but AI helped. These are meant to be quick posts related to the Advent of AI. I don't have time if I'm doing one of these each day to spend a couple hours on a post. πŸ˜…

The advent of AI series leverages Goose, an open source AI agent. If you've never heard of it, check it out!

GitHub logo aaif-goose / goose

an open source, extensible AI agent that goes beyond code suggestions - install, execute, edit, and test with any LLM

πŸ¦† goose has moved! This project has moved from block/goose to the Agentic AI Foundation (AAIF) at the Linux Foundation. Some links and references are still being updated β€” please bear with us during the transition.

goose

your native open source AI agent β€” desktop app, CLI, and API β€” for code, workflows, and everything in between

Discord CI Packaging status

goose is a general-purpose AI agent that runs on your machine. Not just for code β€” use it for research, writing, automation, data analysis, or anything you need to get done.

A native desktop app for macOS, Linux, and Windows. A full CLI for terminal workflows. An API to embed it anywhere. Built in Rust for performance and portability.

goose works with 15+ providers β€” Anthropic, OpenAI, Google, Ollama, OpenRouter, Azure, Bedrock, and more. Use API keys or your existing Claude, ChatGPT, or Gemini subscriptions via ACP. Connect to 70+ extensions via…




For Day 17 of the Advent of AI challenge, I built a Winter Wishlist app using MCP-UI.

What I Built

A wishlist MCP server that renders a visual UI directly in Goose. Users can:

  • Add wishes with a quick message to Goose
  • View all their wishes in a nicely formatted UI
  • Grant wishes when they come true
  • Delete wishes they no longer want

Asking the wishlist MCP server for a wish

Check out the repo:

GitHub logo nickytonline / wishlist-mcp

Advent of AI Day 17: Wishlist MCP App

πŸŽ„ Winter Fairy's Wishbox

A magical MCP-UI application that brings the Winter Festival's enchanted wishbox to life! Built for Advent of AI 2025 - Day 17, this app lets you make wishes, view them in a beautiful UI, grant them when they come true, and release them when needed - all within your MCP client like goose or ChatGPT.

πŸ“– The Story

In the center of the Winter Festival stands an ancient, frost-covered mailbox known as the Winter Fairy's Wishbox. For generations, children (and adults too!) have written their wishes on paper and dropped them in, hoping the Winter Fairy would see them. This year, the magic has gone digital! Make wishes, watch them appear in a beautiful enchanted interface, and track them as the Winter Fairy grants them!

✨ Features

  • 🌟 Make Wishes - Tell goose your wishes with categories (toy/experience/kindness/magic) and priorities (dream wish/hopeful wish/small wish)
  • πŸ“‹β€¦

The implementation stores wishes in memory based on MCP session ID. Obviously something more robust would make sense for production, but for this challenge it works great.

The ChatGPT App Template Foundation

I based this on a ChatGPT app TypeScript template I had created for work just before the holiday. Having that foundation made spinning up the wishlist server much faster.

GitHub logo pomerium / chatgpt-app-typescript-template

ChatGPT app template using Pomerium, OpenAI Apps SDK and Model Context Protocol (MCP), with a Node.js server and React widgets.

MCP Apps Template

A well-architected starter template demonstrating best practices for building MCP Apps using the Model Context Protocol (MCP) with React widgets. It leverages TypeScript, Tailwind CSS v4, Pino logging, Storybook, and Vitest for a robust development experience.

Features

  • MCP Server - Node.js server with McpServer and MCP Apps helpers
  • Echo Tool - Example tool with Zod validation and UI binding
  • React Widgets - Interactive Echo component with MCP Apps App API demo
  • Display Modes - Inline, picture-in-picture, and fullscreen with runtime toggling via requestDisplayMode()
  • App API Demo - callServerTool, openLink, sendMessage, updateModelContext showcased in the Echo widget
  • UI Capability Negotiation - Server detects host capabilities and falls back to text-only for non-UI clients
  • Inline Widget Assets - Self-contained HTML mode for hosts that sandbox iframes (e.g. Claude.ai)
  • Container Dimensions - Responsive widget sizing using host-provided containerDimensions
  • Mock App - Drop-in createMockApp() helper for testing and…

One of the best parts of this setup is the development workflow. You can build out your components in Storybook, make live edits to widgets, and see them update in Goose in real-time. This makes iterating on the UI super fast.

components in Storybook

live edits in Goose

The iframe Sizing Battle

The main issue I ran into was iframe sizing. In ChatGPT apps, the iframe sizing seems to handle itself based on content. But in Goose? Not so much. I had to add some JavaScript to handle the sizing properly.

Initially I thought I was doing something silly because all my iframes weren't sizing to my content. There's additional metadata you can add to the UI resource, but that didn't change anything. I even noticed while debugging that my iframe was inside another iframe, which seemed odd.

Then Rizel in a GitHub discussion (@blackgirlbytes) came through with the solution. You need to use a ResizeObserver on your content container and post messages to the parent frame for Goose:

// Auto-resize the iframe to fit content - observe only the container
const container = document.querySelector('.container');
if (container) {
  // Send initial size
  window.parent.postMessage({
    type: "ui-size-change",
    payload: { height: container.offsetHeight + 100 }
  }, "*");

  // Observe container only (not document which snowflakes affect)
  new ResizeObserver(entries => {
    entries.forEach(entry => {
      window.parent.postMessage({
        type: "ui-size-change",
        payload: { height: entry.contentRect.height + 100 }
      }, "*");
    });
  }).observe(container);
}
Enter fullscreen mode Exit fullscreen mode

That fixed it completely.

Key Learnings

MCP-UI is powerful for creating visual interfaces right in your AI chat. Having a solid template to start from made a huge difference. If you're building MCP servers, especially UI-based ones, starting with a good foundation saves a ton of time.

Even if you missed the Advent of AI this year I encourage you to head over to AdventOfAI.dev and jump in.

If you want to stay in touch, all my socials are on nickyt.online.

Until the next one!

Photo by Phil Stanier on Unsplash

Top comments (0)