Sunpeak Framework

repository·main·Indexed 41 days ago

https://github.com/sunpeak-ai/sunpeak

A framework for building Model Context Protocol (MCP) applications that provide rich UI resources and functional tools to LLM hosts like ChatGPT and Claude. It includes a structured project organization for resources, tools, and simulations, as well as a dedicated inspector for visualizing MCP server behavior locally. Sunpeak provides a comprehensive testing suite featuring E2E tests, visual regression, and multi-model LLM evaluations.

Tokens
196.3K
Snippets
561
Records
802
Agent score
52%

What's inside Sunpeak

  1. Overview of the MCP Testing Framework levels

    main

    The sunpeak testing framework provides five levels of automated testing to replicate host environments (like ChatGPT and Claude) without requiring host accounts or API credits:

    1. Unit tests: Component and hook logic using Vitest and happy-dom.
    2. E2E tests: Playwright specs against replicated ChatGPT and Claude runtimes via the inspector.
    3. Visual regression tests: Playwright specs comparing screenshots against saved baselines.
    4. Live tests: Playwright specs against real ChatGPT (requires API keys/costs money).
    5. Evals: Multi-model tool calling reliability tests (requires API keys/costs money).

    Command Reference:

    CommandWhat it testsRuntime
    sunpeak testUnit + e2e testsVitest + Playwright
    sunpeak test --unitUnit tests onlyVitest + happy-dom
    sunpeak test --e2eE2E tests onlyPlaywright + inspector
    sunpeak test --visualE2E with visual regressionPlaywright + inspector
    sunpeak test --visual --updateUpdate visual baselinesPlaywright + inspector
    sunpeak test --liveLive tests against real ChatGPTPlaywright + real host
    sunpeak test --evalEvals against multiple modelsVitest + Vercel AI SDK
  2. Use the Albums resource for photo galleries

    main

    The Albums resource is a production-ready component for displaying photo albums in a carousel layout. It supports two display modes:

    1. Inline Mode (Default): Displays albums as a horizontal scrolling carousel of cards, each showing a cover image and photo count.
    2. Fullscreen Mode: Triggered when an album is selected. It provides a detailed photo viewer with large centered images and film strip navigation (on desktop).

    To use this resource, you must provide data via useToolData().output and manage selection state using useAppState().

    /* The Albums resource retrieves data from: */
    useToolData().output
    
    /* And manages selection state via: */
    useAppState()
  3. Map resource features and components

    main

    The Map resource includes several built-in capabilities for location-based discovery:

    • Interactive Map: Powered by Mapbox, supporting clickable markers and pan/zoom controls.
    • Multiple View Modes: Automatically switches between a bottom carousel (Inline) and a sidebar list with an inspector panel (Fullscreen).
    • Place Selection: Clicking a marker, carousel card, or list item updates the selection and triggers detailed views.
    • Safe Area Support: The resource uses the <SafeArea> component to ensure content respects device safe area padding and viewport height constraints.
  4. What is an MCP App and how does it work?

    main

    An MCP App is an interactive UI delivered by an MCP server and rendered by an AI chat host (like ChatGPT or Claude) inside a sandboxed iframe.

    How it works:

    1. A server declares UI resources as HTML templates using the ui:// URI scheme with the text/html;profile=mcp-app MIME type.
    2. A tool is linked to a UI resource via resource metadata (_meta.ui.resourceUri).
    3. When a tool runs, the host receives the tool's data and pairs it with the app's HTML to render an interface (e.g., a chart, map, or form).
    4. The app communicates with the host via JSON-RPC messages over postMessage.

    This architecture allows for graceful degradation: if a host does not support MCP Apps, it simply receives the tool's text and structured data as a regular MCP tool, ensuring compatibility across different AI platforms.

  5. What is the Model Context Protocol (MCP)?

    main

    The Model Context Protocol (MCP) is an open standard that enables AI hosts (such as ChatGPT or Claude) to connect to external data and capabilities. It provides a structured way for AI models to interact with external systems through a standardized communication layer between a Client (running within the Host) and a Server (the program exposing capabilities).

    Core Components

    • Host: The AI application (e.g., ChatGPT, Claude) that initiates connections.
    • Client: A protocol client within the host that manages the 1:1 connection, capability negotiation, and request routing to a specific server.
    • Server: A program that exposes specific capabilities like tools and resources over the MCP protocol.

    Supported Transports

    • stdio: Used for local servers running as subprocesses via standard input/output.
    • Streamable HTTP: Used for remote servers accessible over a network via HTTP with server-sent events.
  6. Understand the MCP Apps Security Model

    main

    MCP Apps operate under a strict security model where the View (the HTML/UI) is treated as untrusted web content, and every request from the View is treated as untrusted server input. The Host acts as the mediator between the View and the MCP server.

    Trust Boundaries

    BoundaryWhat crosses itWho enforces it
    Host to sandboxMCP Apps JSON-RPC messages and raw resource HTMLHost and sandbox proxy
    Sandbox to ViewLifecycle events, tool data, and View requestsSandbox proxy and Host
    Host to MCP serverTool calls and resource readsHost transport and server authorization
    View to external originsFetches, assets, media, and nested framesHost-generated CSP, browser CORS, and external server policy

    Key Principle: The iframe isolation prevents direct DOM access to the Host, but it does not make View requests trusted. You must still implement authorization on your MCP server.

  7. Handle MCP App host events with the App class

    main

    The App class provides two patterns for handling host notifications and requests.

    1. Setter properties (e.g., app.ontoolinput = ...): Follows DOM-model replace semantics. Assigning a new handler replaces the previous one; assigning undefined clears it.
    2. addEventListener (e.g., app.addEventListener("toolinput", ...)): Supports multiple listeners and cleanup via removeEventListener. This is preferred for composable handlers.

    CRITICAL: Register all handlers before calling connect() to ensure you don't miss notifications during the initialization handshake.

    import { App } from "@modelcontextprotocol/ext-apps";
    
    // Pattern 1: Setter (replaces previous)
    app.ontoolinput = (params) => { ... };
    
    // Pattern 2: Event Listener (composable)
    app.addEventListener("toolinput", (params) => { ... });
  8. AppProvider behavior: HMR and StrictMode

    main

    The AppProvider is designed with specific behaviors to support modern React development:

    • HMR (Hot Module Replacement) persistence: The App instance is stored at module scope. This means code changes during development (Fast Refresh) will not trigger a reconnection to the host. A full page reload is required to establish a fresh connection.
    • StrictMode compatibility: The provider handles React StrictMode's double-mount cycle by deduplicating connection attempts. If a connection is already in flight, the second mount will wait for the existing one rather than starting a new one.
    • Single instance: Only one App instance is created per page, even if multiple AppProvider mounts occur.
  9. How MCP Tools and Resources are served

    main

    The dev server automatically generates MCP components from your project files:

    1. Tools: Created from simulations using metadata from src/tools/ files (including tool config and schema). When a tool is called, it returns the simulation's toolResult.structuredContent as fixture data. Metadata like visibility is preserved.
    2. Resources: Created from simulations using the built HTML from distPath (or Vite HMR HTML for local connections). Metadata like permissions, csp, prefersBorder, and domain is preserved.

    To access the mock data provided by these simulations in your UI, use the useToolData hook from sunpeak.

    import { useToolData } from 'sunpeak';
    
    function MyApp() {
      // Accesses the mock data from the simulation
      const { output } = useToolData<unknown, { items: string[] }>();
    
      return <div>{output?.items.map(item => <p key={item}>{item}</p>)}</div>;
    }
  10. Compare useUpdateModelContext with useAppState

    main

    Choosing between useUpdateModelContext and useAppState depends on your synchronization and content requirements:

    FeatureuseAppStateuseUpdateModelContext
    Automatic syncYes — syncs on every state changeNo — you call it explicitly
    Content typesStructured data onlyText blocks + structured data
    State managementBuilt-in (like useState)Bring your own
    Use caseSimple persistent stateCustom sync logic, text content