Overview
This guide covers common patterns for building MCP Apps with sunpeak. Each recipe shows both the tool file (server-side) and resource component (client-side) where applicable.App-only tools
Setvisibility: ["app"] in a tool’s _meta.ui to make it callable only from the UI — hidden from the LLM. Use this for polling, pagination, form submissions, and other UI-driven server actions.
useCallServerTool.
Polling for live data
For real-time dashboards or monitoring, poll an app-only tool at regular intervals.See the system-monitor example in the MCP Apps SDK for a full implementation.
Chunked data loading
Some hosts have size limits on tool call responses. Use an app-only tool with chunked responses to load large files (PDFs, images) without hitting limits. Server-side — return data in chunks with pagination:See the pdf-server example for a full implementation of chunked loading.
Binary resources
Serve binary content (video, PDF) via MCP resources and fetch it withuseReadServerResource.
See the video-resource example for a full implementation.
Progressive rendering
UseuseToolData’s inputPartial to show a preview while the LLM is still generating tool arguments. This lowers perceived latency for tools with large inputs like code or structured data.
Giving errors to the model
When a runtime error occurs in your resource (API failure, permission denied, resource unavailable), useuseUpdateModelContext to inform the model:
Entering and exiting fullscreen
UseuseRequestDisplayMode to toggle fullscreen. Always check availableModes first — not all hosts support all modes.
Passing state to the model
Two approaches depending on your needs:Automatic with useAppState
useAppState syncs React state to the model context automatically after each update. Best for simple state that the model should always see.
Manual with useUpdateModelContext
useUpdateModelContext gives you full control over what and when to send. Best for large or structured context, or when you want to batch updates.
updateModelContext is deferred — the model sees the updated context on its next turn, not immediately. It does not trigger a model response. Use useSendMessage to trigger a response.Large follow-up messages
When you need to send more data than fits in a message, set the context first, then trigger with a brief message:Persisting view state
For recoverable state (current page, camera position, scroll position), uselocalStorage with a server-provided viewUUID.
Server-side — include a viewUUID in the tool result _meta:
Pausing offscreen views
Views with animations, WebGL, or polling consume resources even when scrolled out of view. UseIntersectionObserver to pause when offscreen.
See also
MCP Apps SDK Examples
20+ example apps demonstrating these patterns (maps, video, PDF, 3D, monitoring, and more).
MCP Apps SDK Patterns
Framework-agnostic version of these patterns in the SDK documentation.