Skip to main content
Definitions: An MCP App is an interactive UI embedded in an agent conversation.A ChatGPT App is an MCP App with optional ChatGPT-specific features.The UI of an MCP App is an MCP Resource.The API of an MCP App is an MCP Tool.More on MCP and the MCP Apps protocol.
This documentation is available via MCP at https://sunpeak.ai/docs/mcp, use it in your coding agent!
Install the sunpeak coding agent skills for built-in knowledge of patterns, hooks, simulations, and testing:
pnpm dlx skills add Sunpeak-AI/sunpeak@create-sunpeak-app Sunpeak-AI/sunpeak@test-mcp-server

sunpeak is three things

1. Inspector

Inspector

Test any MCP server in replicated ChatGPT and Claude runtimes.
Test any MCP server — no sunpeak project required:
sunpeak inspect --server http://localhost:8000/mcp
sunpeak inspect --server "python my_server.py"
  • Multi-host inspector replicating ChatGPT and Claude runtimes
  • Toggle themes, display modes, device types from the sidebar or URL params
  • Call real tool handlers or use simulation fixtures for mock data
  • Built into sunpeak dev for framework users

2. Testing Framework

Testing

Automated tests powered by the inspector and simulations.
Four levels of automated testing for MCP Apps (Unit, E2E, Live, Evals): E2E tests — the inspector as a test runtime. Define simulation fixtures (JSON), write Playwright tests that load them in the inspector across hosts, themes, and display modes:
import { createInspectorUrl } from 'sunpeak/inspector';

test('album cards render in dark mode', async ({ page }) => {
  await page.goto(createInspectorUrl({
    simulation: 'show-albums',
    theme: 'dark',
    host: 'claude',
  }));
  // assert against the rendered resource
});
Live tests — automated browser tests against real ChatGPT (and future hosts). Import sunpeak/test, get a live fixture that handles auth, message sending, and iframe access:
import { test, expect } from 'sunpeak/test';

test('albums render in ChatGPT', async ({ live }) => {
  const app = await live.invoke('show me albums');
  await expect(app.locator('h1')).toBeVisible();
});

3. App Framework

Next.js for MCP Apps. Convention-over-configuration with the inspector and testing built in.
sunpeak-app/
├── src/
   ├── resources/
   └── review/
       └── review.tsx                   # Review UI component + resource metadata.
   ├── tools/
   ├── review-diff.ts                   # Tool with handler, schema, and optional resource link.
   ├── review-post.ts                   # Multiple tools can share one resource.
   └── review.ts                        # Backend-only tool (no resource, no UI).
   └── server.ts                            # Optional: auth, server config.
├── tests/
   ├── unit/
   └── review.test.ts                   # Unit tests for component and hook logic.
   ├── simulations/
   ├── review-diff.json                 # Mock state for testing (includes serverTools).
   ├── review-post.json                 # Mock state for testing (includes serverTools).
   └── review-purchase.json             # Mock state for testing (includes serverTools).
   ├── e2e/
   └── review.spec.ts                   # Playwright tests against the inspector.
   ├── live/
   └── review.spec.ts                   # Live tests against real ChatGPT (one per resource).
   └── evals/
       └── review.eval.ts                   # Multi-model tool calling evals.
└── package.json
  • Runtime APIs: Multi-platform React hooks for the MCP Apps runtime
  • Project Scaffold: Complete dev setup with pre-configured tooling
  • UI Components: Production-ready components following MCP App design guidelines
  • Convention over configuration: resources, tools, and simulations are auto-discovered from src/ and tests/

The sunpeak CLI

Examples

Example sunpeak resource, tool, & simulation files for an MCP App called “Review”.

Resource

Each resource .tsx file exports both a ResourceConfig metadata object and the React component:
// src/resources/review/review.tsx

import { useToolData } from 'sunpeak';
import type { ResourceConfig } from 'sunpeak';

export const resource: ResourceConfig = {
  description: 'Visualize and review a code change',
  _meta: { ui: { csp: { resourceDomains: ['https://cdn.example.com'] } } },
};

export function ReviewResource() {
  const { output: data } = useToolData<unknown, { title: string }>();

  return <h1>Review: {data?.title}</h1>;
}

Tool

Each tool .ts file exports metadata (with a resource name), a Zod schema, and a handler:
// src/tools/review-diff.ts

import { z } from 'zod';
import type { AppToolConfig, ToolHandlerExtra } from 'sunpeak/mcp';

export const tool: AppToolConfig = {
  resource: 'review',
  title: 'Diff Review',
  description: 'Show a review dialog for a proposed code diff',
  annotations: { readOnlyHint: false },
  _meta: { ui: { visibility: ['model', 'app'] } },
};

export const schema = {
  changesetId: z.string().describe('Unique identifier for the changeset'),
  title: z.string().describe('Title describing the changes'),
};

type Args = z.infer<z.ZodObject<typeof schema>>;

export default async function (args: Args, extra: ToolHandlerExtra) {
  return { structuredContent: { title: args.title, sections: [] } };
}

Simulation

Simulation files provide fixture data for testing. Each references a tool by filename and contains the mock input/output:
// tests/simulations/review-diff.json

{
  "tool": "review-diff",                      // References src/tools/review-diff.ts
  "userMessage": "Refactor the auth module to use JWT tokens.",
  "toolInput": {
    "changesetId": "cs_789",
    "title": "Refactor Authentication Module"
  },
  "toolResult": {
    "structuredContent": {
      "title": "Refactor Authentication Module"
      // ...
    }
  }
}