← Files ChooseCruiseARCHIVED FILE

skills/choosecruise-chatgpt-app/references/app-contract.md

3.41 KB · Oct 5, 2026 · 18:22 UTC

↓ Download file

# ChooseCruise ChatGPT app contract

Read this reference when changing public tools, widget metadata, ownership verification, analytics, or submission files.

## Architecture

- Primary archetype: submission-ready React widget.
- MCP endpoint: stateless `POST /mcp` in `mcp-gateway/src/httpServer.ts`.
- Public tools are registered centrally by `MCPGatewayServer` through `ToolRegistry`.
- `search_cruises` renders `ui://widget/cruise-carousel-<content-hash>.html`.
- `get_cruise_details` returns compact structured details without a separate widget.
- The carousel receives results through the ChatGPT host bridge and can call `get_cruise_details` or open a ChooseCruise web URL.

## Public tools

### `search_cruises`

- Searches ocean or river cruise inventory using natural-language ports, regions, lines, date ranges, price, sorting, and pagination.
- Maps names to internal IDs, queries the internal ChooseCruise API, inlines visible card images when possible, and returns a compact result set.
- Records filters, result summary, request origin, and timing in RudderStack.
- Required annotations: `readOnlyHint: false`, `openWorldHint: true`, `destructiveHint: false` while that analytics behavior remains.

### `get_cruise_details`

- Accepts a master cruise ID from a search result and retrieves itinerary, ship, cabins, price, and booking URL.
- Records a cruise-view analytics event, including failed views.
- Must not expose `userId` on the public unauthenticated schema.
- Required annotations: `readOnlyHint: false`, `openWorldHint: true`, `destructiveHint: false` while that analytics behavior remains.

### `ping`

- Internal diagnostic implementation only.
- Do not register it in the public MCP server and do not include it in submission JSON.

## Widget and security invariants

- Tool descriptors publish both `_meta.ui.resourceUri` and the `openai/outputTemplate` compatibility alias.
- Resource descriptors publish both MCP Apps `ui` metadata and required OpenAI compatibility aliases.
- Widget bundle URIs include a content hash; the unversioned alias remains readable for existing connectors.
- Resource domains are derived from the configured ChooseCruise webapp image origin plus the supplier fallback `https://images.cruisec.net`.
- The current widget makes no direct network connections, so it should not declare `connectDomains`/`connect_domains` without a corresponding code change.
- Avoid `frameDomains` unless embedding becomes a product requirement.
- The repository currently retains `text/html+skybridge` for verified ChatGPT compatibility. Treat migration to `text/html;profile=mcp-app` as a tested compatibility change, not a mechanical cleanup.

## Ownership verification

`GET /.well-known/openai-apps-challenge` must return the configured OpenAI ownership token as `text/plain` with status 200. The current token is:

```text
VwfWPAkSOvfg-pDqOu5-29kL6Gz5zRxhlqMUZktweZE
```

If OpenAI issues a replacement, update the route and its regression test together.

## Submission invariants

- Production `tools/list` is the source of truth for imported annotations and schemas.
- Every exposed tool has an `outputSchema` matching its actual `structuredContent`.
- Submission JSON contains exactly five positive and three negative test cases when generated through the repository's submission workflow.
- Tool descriptions and privacy policy explain analytics data use.
- Deploy before rescanning in the submission portal; local edits do not affect scan results.

SHA-256: 178efb21c8d5dd2618e0c889d3988db50c16668983d3afc338001d13b3290beb