scanned Jun 2, 2026

sunpeak

sunpeak.ai

Sunpeak is an open-source framework for building interactive applications that run inside AI hosts like ChatGPT and Claude.

59/100

Tier 3 · Agent-Accessible

Content answers65/100
Protocol plumbing44/1007 of 16 checks pass

Scored by asking 15 questions a buyer of a ai-ml product asks, then grading this site’s own pages: answered, hedged (partial or vague), or silent (no page answers it). How scoring works

This report is public. Own sunpeak.ai? Claiming is free: crawl every page, re-audit as you fix, and track your score over time.

Sign in to claim

The fix queue

41 points sit between sunpeak.ai and 100: 9 open questions and 9 missing protocol checks, ordered by estimated payoff.

Point estimates are per fix under scoring v2. They are not additive to a promised total.

01operations · importance highGoes silent+7 content pts est.

When deploying to ChatGPT as a GPT Action, does Sunpeak generate the required `ai-plugin.json` or `openapi.yaml` automatically during build, or do I need to maintain that separately?

What the pages say

No page on the site addresses this.

The fix

Add a FAQ or docs page that clarifies whether Sunpeak supports GPT Actions (which require ai-plugin.json/openapi.yaml) or only MCP Apps, and what configuration files are auto-generated during build.

confidence high · grounding world-knowledge · weight 0.00 · Absent

02technical · importance lowGoes silent+7 content pts est.

If the user's host locale isn't in my supported languages, what's the exact fallback chain `useLocale` uses—does it try language-only match before default, or jump straight to default?

What the pages say

No page on the site addresses this.

The fix

Add documentation for a `useLocale` hook that explicitly defines the fallback chain when a host locale is not in the supported languages list (e.g., whether it tries a language-only match before falling back to the default locale).

confidence high · grounding world-knowledge · weight 0.00 · Absent

Hedged · 7 of 15 questions

A buyer gets something, then has to guess the rest. Expand any row for the evidence and the fix.

03For OAuth flows in Sunpeak apps, what's the default access token lifetime before refresh, and can I configure a shorter maximum for security compliance?securityHedges+7 pts est.

For OAuth flows in Sunpeak apps, what's the default access token lifetime before refresh, and can I configure a shorter maximum for security compliance?

What the pages say

The retrieved documentation does not specify a default access token lifetime for OAuth flows in Sunpeak apps, nor does it mention whether developers can configure a shorter maximum token lifetime for security compliance.

The fix

Document the default access token lifetime (e.g., in minutes or hours) and clarify whether developers can configure a shorter maximum expiration via app settings, the auth() export, or their identity provider.

Where we looked: /docs/app-framework/guides/authorization, /docs/app-framework/guides/authorization.md, /docs/app-framework/tools/server-entry.md, /blogs/mcp-app-authentication-oauth, /blogs/mcp-app-authentication-oauth

confidence high · grounding synthesized · weight 0.00 · Vague

04Does `useAppState` persist across sessions if the user closes and reopens the AI host, or is it strictly in-memory for that conversation?technicalHedges+2 pts est.

Does `useAppState` persist across sessions if the user closes and reopens the AI host, or is it strictly in-memory for that conversation?

What the pages say

The chunks do not explicitly state whether `useAppState` persists when the user closes and reopens the AI host. The hook is described as providing “Automatic state persistence and sync” (chunk [4]) and is said to persist selections “across sessions” within individual resources like Albums (chunk [1]). However, the Patterns guide explicitly recommends using `localStorage` with a server-provided `viewUUID` for “recoverable state” (e.g., scroll position, current page) that should survive reloads (chunk [13]), which implies `useAppState` alone may not be intended for state that must survive host restarts or page reloads. The documentation characterizes it as “Simple persistent state” (chunk [16]) but does not define the exact session boundary.

The fix

Clarify on the useAppState reference page whether state survives page reloads, host restarts, or new conversations, and explicitly define the persistence boundary.

Where we looked: /docs/app-framework/resources/albums.md, /docs/app-framework/hooks/use-update-model-context.md, /docs/app-framework/guides/patterns.md, /docs/app-framework/hooks/use-update-model-context.md

confidence medium · grounding synthesized · weight 0.65 · Vague

05I'm getting CORS errors when my Sunpeak app runs in Claude but not ChatGPT. Are there specific Claude origin headers I need to whitelist that differ from OpenAI's?troubleshootingHedges+2 pts est.

I'm getting CORS errors when my Sunpeak app runs in Claude but not ChatGPT. Are there specific Claude origin headers I need to whitelist that differ from OpenAI's?

What the pages say

Sunpeak's documentation mentions that CORS preflight errors can surface when debugging apps and recommends checking CSP configuration during pre-submission testing, but it does not specify which Claude origin headers (if any) differ from OpenAI's or need to be whitelisted separately.

The fix

Add a troubleshooting entry or FAQ that documents the specific origin headers (or iframe sandbox origins) used by Claude and ChatGPT, and clarifies any server-side CORS whitelist differences developers must handle.

Where we looked: /blogs/debugging-chatgpt-apps-guide, /blogs/pre-submission-testing-mcp-apps

confidence medium · grounding synthesized · weight 0.65 · Vague

06When I run `sunpeak build`, where does the production bundle actually get written? Is it configurable or hardcoded to a specific folder?technicalHedges+2 pts est.

When I run `sunpeak build`, where does the production bundle actually get written? Is it configurable or hardcoded to a specific folder?

What the pages say

The `sunpeak build` command writes production bundles to a top-level `dist/` directory. Each resource folder from `src/resources/{name}/` is built to `dist/{name}/` (containing `{name}.html` and `{name}.json`), tool handlers are compiled to `dist/tools/{name}.js`, and an optional `src/server.ts` becomes `dist/server.js`. The documentation does not state whether this output directory is configurable or hardcoded.

The fix

Add a note or CLI reference on the `sunpeak build` page clarifying whether the output directory is hardcoded to `dist/` or can be configured via a flag or config file.

Where we looked: /docs/app-framework/cli/build, /docs/app-framework/cli/build.md, /docs/app-framework/guides/deployment.md

confidence high · grounding synthesized · weight 0.70 · Vague

07The SafeArea component mentions handling notches and home indicators. What are the exact pixel values or CSS env() variables it injects for iPhone Dynamic Island vs standard notches?technicalHedges+2 pts est.

The SafeArea component mentions handling notches and home indicators. What are the exact pixel values or CSS env() variables it injects for iPhone Dynamic Island vs standard notches?

What the pages say

The documentation does not specify exact pixel values for iPhone Dynamic Island versus standard notches, nor does it mention CSS env() variables. The SafeArea component dynamically applies `paddingTop`, `paddingBottom`, `paddingLeft`, and `paddingRight` from the host's safe area insets in pixels (sourced from `McpUiHostContext.safeAreaInsets`) rather than injecting fixed device-specific values. The testing inspector docs show example notch-simulation values of `safeAreaTop: 44` and `safeAreaBottom: 34`, but do not map these to specific iPhone models.

The fix

Add a reference table showing typical safe area inset values (e.g., Dynamic Island vs standard notch) and clarify whether the component uses CSS env() variables or only host-provided pixel insets.

Where we looked: /docs/app-framework/components/safe-area, /docs/app-framework/hooks/use-safe-area.md, /docs/testing/inspector.md, /docs/testing/inspector.md

confidence medium · grounding synthesized · weight 0.65 · Vague

08What's the maximum file size I can push through `useDownloadFile` before the AI host blocks it, and does that limit differ between ChatGPT and Claude?limitsHedges+2 pts est.

What's the maximum file size I can push through `useDownloadFile` before the AI host blocks it, and does that limit differ between ChatGPT and Claude?

What the pages say

The sunpeak documentation for `useDownloadFile` does not specify a maximum file size limit, and the site does not indicate whether ChatGPT and Claude enforce different caps on downloads through this hook. The API docs describe support for embedded text, embedded base64 binary, and resource links that the host fetches on behalf of the app, but they omit any size thresholds. Related host limits are documented elsewhere—Claude caps tool results at 25,000 tokens (and roughly 150,000 characters on Claude.ai/Desktop), both hosts require tool handlers to complete within about five minutes, and timeouts vary by plan and context—but these apply to tool outputs, not to `useDownloadFile` transfers.

The fix

Add a 'Limits' or 'Host-specific behavior' section to the `useDownloadFile` docs that states any maximum file size (per file or total payload) and notes whether ChatGPT and Claude enforce different caps.

Where we looked: /docs/app-framework/hooks/use-download-file, /blogs/performance-testing-mcp-apps, /blogs/pre-submission-testing-mcp-apps, /blogs/debugging-chatgpt-apps-guide, /blogs/debugging-claude-connectors

confidence high · grounding synthesized · weight 0.70 · Vague

09Does `usePlatform` distinguish between the ChatGPT iOS app and ChatGPT running in Safari on iOS, or does it just return 'mobile' for both?technicalHedges+2 pts est.

Does `usePlatform` distinguish between the ChatGPT iOS app and ChatGPT running in Safari on iOS, or does it just return 'mobile' for both?

What the pages say

`usePlatform` returns the host-reported platform type with possible values `'web'`, `'desktop'`, `'mobile'`, or `undefined`, sourced from `McpUiHostContext.platform`. However, none of the retrieved chunks specify what value ChatGPT reports for its native iOS app versus Safari on iOS, so it is unclear whether the hook distinguishes the two or returns `'mobile'` for both.

The fix

Clarify in the `usePlatform` documentation what platform values ChatGPT reports for its native iOS app versus mobile Safari, or add a host-specific platform mapping table.

Where we looked: /docs/app-framework/hooks/use-platform.md, /docs/app-framework/hooks/use-platform, /docs/app-framework/hooks/use-platform.md

confidence high · grounding synthesized · weight 0.70 · Vague

What the pages already answer cleanly

6 of 15. Answered with enough specificity for a buyer to act on. This is the bar the queue above is chasing.

technicalAnswered

I'm trying to conditionally render based on whether the user is in ChatGPT vs Claude. What exact fields does `useHostInfo()` return, and are they typed differently for each host?

What the pages say

`useHostInfo()` returns an object with two top-level fields: `hostVersion` (`HostVersion | undefined`) and `hostCapabilities` (`HostCapabilities | undefined`). `hostVersion` contains `name` (string) and `version` (string). `hostCapabilities` contains the boolean flags `serverTools`, `openLinks`, `logging`, `messages`, and `displayModes`. The TypeScript return type is consistent across hosts; the same fields are present in ChatGPT and Claude, though the values (e.g., which capabilities are `true`) vary by host.

Source: /docs/app-framework/hooks/use-host-info.md, /docs/app-framework/hooks/use-host-info.md, /blogs/snapshot-testing-mcp-apps

confidence high · grounding synthesized · weight 0.95 · Answered

getting-startedAnswered

What port does `sunpeak dev` start the local development server on by default, and can I override it if that port's already taken?

What the pages say

`sunpeak dev` starts the inspector UI on port `3000` by default and also runs an MCP server on port `8000`. You can override the inspector port with the `--port` flag (e.g., `sunpeak dev --port 3001`) or the `PORT` environment variable. If a port is already taken, sunpeak automatically finds a free one and prints the actual port used in the console.

Source: /docs/app-framework/cli/dev, /docs/app-framework/cli/dev.md, /docs/app-framework/cli/dev, /docs/app-framework/guides/troubleshooting.md, /docs/app-framework/guides/troubleshooting

confidence high · grounding synthesized · weight 0.95 · Answered

technicalAnswered

What specific device capabilities can I actually detect with `useDeviceCapabilities`? Does it expose camera permission status, or just screen dimensions and touch support?

What the pages say

The docs show that `useDeviceCapabilities` exposes `touch` and `hover` booleans from the host context. It does not expose camera permission status; camera permissions are part of the separate `McpUiResourcePermissions` interface used for iframe sandboxing. Screen dimensions are also handled separately via `getHostContext().containerDimensions`, not through `useDeviceCapabilities`.

Source: /docs/app-framework/functions/utilities.md, /docs/mcp-apps/app/accessors/get-host-context.md, /docs/testing/simulations, /docs/mcp-apps/types/core-types.md

confidence high · grounding synthesized · weight 0.95 · Answered

limitsAnswered

Is there a rate limit on how frequently I can call `useSendMessage` to stream updates back to the conversation, or can I spam it as fast as my server responds?

What the pages say

Yes, rate-limiting can occur. The `sendMessage` API documentation states that the host may reject the message if sending is rate-limited or disabled, in which case `isError` will be `true` in the response. You should not assume you can call it as fast as your server responds; design your app to handle rejected messages gracefully.

Source: /docs/app-framework/guides/patterns, /docs/mcp-apps/app/requests/send-message.md

confidence high · grounding synthesized · weight 0.95 · Answered

technicalAnswered

If my server tool called via `useCallServerTool` hangs, is there a default timeout before the host kills it, and can I set a custom timeout per call?

What the pages say

Yes. Because `useCallServerTool` proxies calls through the host bridge, the host’s limit applies: Claude.ai and Claude Desktop enforce a 300-second (5-minute) timeout before killing a hanging tool handler. No, you cannot set a custom timeout per call via a dedicated option on `useCallServerTool` or its underlying `callServerTool`. The API reference only documents an `AbortSignal` in `RequestOptions`; you must wire your own timeout with an `AbortController` if you need shorter cancellation.

Source: /docs/app-framework/hooks/use-call-server-tool, /docs/mcp-apps/app/requests/call-server-tool.md, /docs/mcp-apps/app/requests/call-server-tool, /blogs/how-claude-connectors-work, /blogs/debugging-claude-connectors, /blogs/mcp-app-lifecycle-host-bridge

confidence high · grounding synthesized · weight 0.95 · Answered

getting-startedAnswered

When I run `sunpeak new`, what starter templates are actually available beyond the default? Is there one preconfigured for just a simple tool-calling backend without UI?

What the pages say

The retrieved chunks only document a single default project scaffold created by `sunpeak new`; no alternative starter templates are mentioned. While the default scaffold includes an example of a backend-only tool (`review.ts` — described as a “Backend-only tool (no resource, no UI)”), there is no dedicated template preconfigured for only a simple tool-calling backend without UI.

Source: /docs/app-framework/project-scaffold, /docs/app-framework/cli/new, /docs/app-framework/cli/new.md

confidence high · grounding synthesized · weight 0.95 · Answered

Protocol plumbing · 44/1007 of 16 checks pass · each fix +6 protocol pts est.

The other half of the score: 16 checks for the files and headers agents look for. The 9 below are installs, not judgment calls, and most are an afternoon. Expand any for the snippet and the standard it follows. They sit after the queue because none of them changes what your pages say.

llms.txtDiscoverability+6 pts est.

Sitedex generates this file from your crawl. Grab it in Files from this audit below.

Standardllmstxt.orgCommunity spec

Content signalAccess+6 pts est.
Install snippet
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /

StandardCloudflare proposalVendor proposal

Clean crawlAccess+6 pts est.

StandardSitedex metricSitedex metric

Markdown negotiationRendering+6 pts est.

StandardRFC 9110 + 7763IETF RFC

MCP cardInteraction+6 pts est.

Sitedex generates this file from your crawl. Grab it in Files from this audit below.

StandardModel Context ProtocolCommunity spec

OpenAPI specInteraction+6 pts est.

StandardOpenAPI SpecIndustry standard

WebMCP widgetInteraction+6 pts est.

Sitedex generates this file from your crawl. Grab it in Files from this audit below.

StandardW3C WebMCP draftW3C / WHATWG

Meta descriptionsHygiene+6 pts est.
Install snippet
<meta name="description" content="sunpeak.ai: [outcome you deliver] for [who you help]. One sentence, 50-160 characters." />

StandardHTML Living StandardW3C / WHATWG

Sitemap lastmodDiscoverability+6 pts est.

Standardsitemaps.orgIndustry standard

Already passing 7 of 16: robots.txt, sitemap.xml, AI crawler access, Server-rendered content, Canonical URLs, HTML lang attribute, Organization schema.

Ask this site’s index

Sitedex already serves sunpeak.ai as an MCP endpoint. Ask sunpeak.ai anything an AI agent might ask, and see what its index returns. (To score your own site, use the form below.)

Snippets & configs

For developers and the engineer-on-call: copy these into your tools or your site.

Files from this audit

Built from this crawl. Download or copy each, then install it at the path noted.

llms.txt

Built from this crawl. Install at /llms.txt so agents start here.

organization.json

Organization JSON-LD, pre-filled from this crawl. Wrap in a ld+json script.

server-card.json

MCP server card built from this crawl. Host at /.well-known/mcp/server-card.json.

webmcp.json

WebMCP discovery manifest built from this crawl. Host at /.well-known/webmcp.json.

MCP endpoint

https://mcp.sitedex.dev/s/sunpeak-ai/mcp

The URL anyone's agent points at. Read-only; safe to share.

Claude Code

claude mcp add sunpeak --transport http https://mcp.sitedex.dev/s/sunpeak-ai/mcp

One command, then the agent has it.

Cursor / Continue

{
  "mcpServers": {
    "sunpeak": {
      "url": "https://mcp.sitedex.dev/s/sunpeak-ai/mcp"
    }
  }
}

Drop into mcp.json.

WebMCP: two parts

WebMCP-capable browsers run the widget at runtime. Crawlers without JS rendering need the discovery manifest to find your tool surface. Install both.

1 · Widget script

<script async src="https://sitedex.dev/widget.js"></script>

Drop in <head>. WebMCP-capable browsers (Chrome 146+ Origin Trial) call navigator.modelContext.provideContext() via this script.

2 · Discovery manifest

{
  "$schema": "https://wellknownmcp.org/schemas/webmcp.json",
  "name": "sunpeak.ai",
  "tools": [
    { "name": "search", "description": "Search sunpeak.ai's indexed content." },
    { "name": "get_page", "description": "Fetch a page from sunpeak.ai as markdown." }
  ]
}

Host alongside the script at /.well-known/webmcp.json. Crawlers that don't render JS rely on this.

Your turn

See which of these questions your site goes silent on.

Free, about 5 minutes. We crawl your site, test it against the buyer questions your category asks, and name what’s vague, contradictory, or missing, plus the files AI agents look for.

ComingEmbeddable grade badgeScore history and deltasOpt-in public board