sunpeak is an open-source (MIT) MCP App framework and MCP testing framework. MCP Apps are cross-platform, so sunpeak is also a ChatGPT App framework and a Claude Connector framework.
https://t.co/HqQuV4JZI2
$SUNPEAK × @ponsdotfamily
CA: 0x5e09f8fb59a1c336959abc6d74e227806d710ffe
It ships a local inspector with replicated ChatGPT and Claude runtimes, an MCP dev server, UI components, 20+ typed React hooks and a testing framework for E2E, visual regression and multi-model evals.
Make your MCP App look native in every host.
applyHostStyleVariables() sets the host's CSS variables on your document. Then use var(--color-background-primary), var(--color-text-primary) and the rest in your CSS.
Hosts may send any subset.
Tool annotations tell the host what a tool does. _meta.ui says who can call it. Visibility does not describe safety, so MCP App tools need both.
readOnlyHint
True for search, preview, list, load and filter tools. Never on a tool that writes state, even a small write.
destructiveHint
True when a tool can delete, overwrite, cancel, charge or send. Hosts may add confirmation or stronger review UI.
idempotentHint
True only when retries are safe, like saveDraft with a stable draft id.
openWorldHint
False for local reads or your own database. True for email, payment, web, SaaS or third-party APIs.
App-only tools count too. If a button in the View writes data, annotate that tool honestly.
Annotations are hints, not authorization. Your server still needs authentication, permission checks and input validation.
The host owns the container. Your View owns the layout.
A fixed height or width: fill it. A maxHeight: let content size the iframe up to the limit, then scroll. Auto-resize reports every change to the host for you.
Not every tool is for the model.
Set _meta.ui.visibility to ["app"] and your View can call it while the model never sees it. Use it for refreshing data, loading the next page, saving form edits, polling, and bulky data that should stay out of model context.
MCP 2026-07-28 is the current core protocol revision. Does your MCP App need to change?
Host ↔ server: changes
No more initialize or Mcp-Session-Id. Each request carries its protocol version and client capabilities in _meta, and servers implement server/discover. HTTP requests add MCP-Protocol-Version, Mcp-Method and Mcp-Name headers.
View ↔ Host: stays
The MCP Apps View protocol is still 2026-01-26. app.connect() still sends ui/initialize over postMessage. No View code changes.
Caching: new
List and resources/read results carry ttlMs and cacheScope. A host may cache your ui:// HTML, so keep user data out of the View template.
In sunpeak today
--stateless creates a fresh MCP server per request, but it does not enable the 2026-07-28 wire protocol. The inspector and test client negotiate the version automatically, with a fallback for legacy servers.
Which API should your MCP App View call?
Fresh server data or an action: callServerTool(). State the model should see next turn: updateModelContext(). Continue the chat now: sendMessage(). Save a file: downloadFile().
The full map is in the picture.
Every inspector state is a URL.
?simulation=show-albums&theme=dark renders mock data right away. ?tool=show-albums waits for Run and calls the real handler. Add &sidebar=false for the app viewer only.
Handy for programmatic testing.
The sunpeak Inspector also ships as a standalone React component.
Drop it into any React app and render any MCP App, without the CLI dev server or the simulation file layout.
MCP App HTML comes from your MCP server and runs inside an AI host. Before you ship one:
✓ The UI resource uses ui:// and text/html;profile=mcp-app.
✓ CSP lists only the external origins the built View loads.
✓ The View works when optional browser permissions are denied.
✓ Every View-callable tool includes "app" visibility.
✓ Every tool validates input and enforces server-side authorization.
✓ Destructive calls are honestly annotated and safe against retries.
✓ Model-safe data goes in content or structuredContent. View-only data goes in _meta.
✓ Result strings render through escaped text APIs.
✓ Partial tool input cannot trigger tool calls, writes, or other side effects.
✓ The app works in a real separate-origin sandbox, not only a same-origin development iframe.
One line to remember: visibility is not authorization. A button click is still an untrusted tools/call request.
Tool handlers are plain async functions, so you can unit test them directly.
pnpm test:unit runs them with Vitest and happy-dom. No inspector, no browser.
npx sunpeak new sunpeak-app review,map
Your project starts with working resources in src/resources/. Review handles confirmations for code changes, purchases, posts and bookings. Map shows points of interest.
Both adapt to light and dark themes, and both are yours to edit.
Your MCP server needs login? sunpeak implements the resource-server side of MCP OAuth.
What sunpeak does
+ Publishes OAuth 2.0 Protected Resource Metadata at /.well-known/oauth-protected-resource
+ Returns RFC 6750 bearer challenges to unauthenticated requests
+ Returns a 403 challenge for a scope upgrade when your auth function reports insufficient_scope
+ Passes verified token data to your tool handlers
What your authorization server still owns
+ Login and consent
+ Client registration
+ Token issuance and refresh tokens
You export two things from src/server.ts: oauth (resource, authorization servers, scopes) and auth (your token check).
The inspector follows the same MCP OAuth discovery flow, with PKCE and state validation.
content, structuredContent or _meta?
The model reads the first two. _meta goes only to the Host and your View, which makes it the place for component-only IDs and lookup data.
useAppState works like React's useState, but every update is pushed to the host, so the AI model can see it on the next message.
Use it for user decisions, selections, or any state the model should be aware of.
pnpm build turns every resource into a self-contained HTML file. pnpm start launches a production MCP server.
Or mount it yourself: createMcpHandler for Express, Fastify or a plain http server, createHandler for Cloudflare Workers, Deno, Bun and Vercel Edge.