> ## Documentation Index
> Fetch the complete documentation index at: https://sunpeak.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Common issues when testing MCP Apps with the inspector, E2E tests, and live tests.

## Blank page in the inspector

If the inspector loads but the resource iframe is blank:

1. Check the browser console for errors (especially CSP or CORS issues)
2. Make sure your resource component is the default export from `src/resources/{name}/{name}.tsx`
3. Verify you have at least one simulation in `tests/simulations/` that references your tool

For standalone usage (`sunpeak inspect --server`), verify your MCP server is running and reachable at the URL you provided.

## Stdio server fails to start

When a stdio MCP server fails to start, sunpeak captures and displays the server's stderr output. This includes Python tracebacks, import errors, missing dependencies, and other startup failures. Check the error message for the specific cause.

Common fixes:

* **Python `ModuleNotFoundError`**: Install missing dependencies or set `PYTHONPATH` via the `env` option in your config or `--env` on the CLI.
* **Wrong working directory**: Set `cwd` in your config or `--cwd` on the CLI so the server resolves relative imports correctly.
* **Missing environment variables**: Pass them with `server.env` in `defineConfig()` or `--env KEY=VALUE` on the CLI.

```typescript theme={null}
// Example: fixing a Python server that needs a specific working directory and env
export default defineConfig({
  server: {
    command: 'python', args: ['server.py'],
    cwd: './backend',
    env: { PYTHONPATH: './src' },
  },
});
```

## Tests failing with iframe errors

E2E tests must use the double-iframe locator pattern because resource content renders inside a nested sandbox:

```typescript theme={null}
// Wrong - this looks at the inspector chrome, not the app
page.locator('.my-element')

// Correct - drill through both iframe layers
page.frameLocator('iframe').frameLocator('iframe').locator('.my-element')
```

When using the `inspector` fixture from `sunpeak/test`, `result.app()` returns a locator already scoped to the inner iframe, so you don't need to chain `frameLocator` manually:

```typescript theme={null}
const result = await inspector.renderTool('show-albums');
const app = result.app();
await expect(app.locator('.my-element')).toBeVisible();
```

See the [Inspector architecture](/testing/inspector) for details on the double-iframe sandbox.

## MCP server requires authentication (OAuth)

sunpeak auto-negotiates OAuth when connecting to MCP servers that require it. If your server returns a 401 response, sunpeak will:

1. Discover the server's OAuth metadata
2. Register a client dynamically
3. Complete the authorization flow

For servers with auto-approved (anonymous) OAuth, this happens automatically with no user interaction. For servers that require interactive login, sunpeak opens the authorization URL in your browser and waits for the callback.

If OAuth negotiation fails, check that your server's OAuth endpoints are accessible and return standard MCP OAuth responses (`/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`).

## Server startup timeout

If your MCP server takes a long time to start (compiling, loading large models, etc.), you may see a timeout error. Increase the startup timeout in your config:

```typescript theme={null}
export default defineConfig({
  server: { command: 'python', args: ['server.py'] },
  timeout: 120_000, // 120 seconds (default: 60000)
});
```

## Flaky E2E tests

The double-iframe sandbox proxy can be overwhelmed by too many concurrent Playwright workers. If you see PostMessage relay timeouts or intermittent failures:

* Limit workers to 2 locally (`workers: 2` in your Playwright config)
* In CI, use 1 worker (`workers: process.env.CI ? 1 : 2`)

The `defineConfig()` from `sunpeak/test/config` sets these defaults automatically.

## Live test authentication

<AccordionGroup>
  <Accordion title="'Not logged into ChatGPT' error">
    On first run, a browser window opens for you to log in to ChatGPT. The session is saved to `.auth/chatgpt.json` but typically only lasts a few hours because Cloudflare's `cf_clearance` cookie is HttpOnly and cannot be persisted across runs. When you see this error, just re-authenticate in the browser window that opens. If it keeps failing, delete the `.auth/` directory and run `pnpm test:live` again.
  </Accordion>

  <Accordion title="Tunnel not reachable">
    Verify your tunnel is running and the URL is correct. The test checks the tunnel's `/health` endpoint before proceeding.
  </Accordion>

  <Accordion title="'ChatGPT DOM may have changed' warning">
    ChatGPT occasionally updates their UI. The `ChatGPTPage` class checks selector health at startup. If selectors are stale, update the `SELECTORS` constant in `chatgpt-page.mjs`.
  </Accordion>

  <Accordion title="Tool not called by ChatGPT">
    Live tests use specific prompts like "Use the show-albums tool to..." to reliably trigger tool calls. If a tool isn't called, the test retries once. Persistent failures may indicate the tool isn't properly connected. Check the developer-mode app under ChatGPT Plugins.
  </Accordion>
</AccordionGroup>

<Note>
  For dev server, tunnel, and build-related troubleshooting, see [App Framework Troubleshooting](/app-framework/guides/troubleshooting).
</Note>
