|
| 1 | +# ChatGPT MCP Apps Submission |
| 2 | + |
| 3 | +Status: **In Progress** |
| 4 | +Last updated: 2026-03-12 |
| 5 | + |
| 6 | +## Prerequisites |
| 7 | + |
| 8 | +- [ ] Organization verification (individual or business) on [OpenAI Platform Dashboard](https://platform.openai.com/settings/organization/general) |
| 9 | +- [ ] Owner role confirmed for submitting org member |
| 10 | +- [x] MCP server publicly accessible at `https://mcp.apify.com/` |
| 11 | +- [x] Not using local/testing endpoint |
| 12 | +- [x] Content Security Policy (CSP) defined (`src/resources/widgets.ts:15-26`) |
| 13 | +- [x] Authentication configured — Bearer token + OAuth2 (`src/server_card.ts:30-33`) |
| 14 | + |
| 15 | +## Submission Form Fields |
| 16 | + |
| 17 | +| Field | Status | Value | |
| 18 | +|---|---|---| |
| 19 | +| App name | Done | `Apify MCP server` | |
| 20 | +| Logo | Done | `docs/apify-logo.png` | |
| 21 | +| Short description | Done | "Extract data from any website with thousands of scrapers, crawlers, and automations on Apify Store" | |
| 22 | +| Long description | Done | "Extract data from any website using thousands of tools from the Apify Store. Apify is the world's largest marketplace of tools for web scraping, data extraction, and web automation." | |
| 23 | +| Privacy policy URL | Done | https://docs.apify.com/legal/privacy-policy | |
| 24 | +| Company URL | Done | https://apify.com | |
| 25 | +| MCP URL | Done | https://mcp.apify.com/ | |
| 26 | +| Screenshots | TODO | Need ChatGPT-specific screenshots showing widgets in action | |
| 27 | +| Test prompts & responses | TODO | Need 3-5 test cases (see below) | |
| 28 | +| Localization / countries | TODO | Define target countries | |
| 29 | + |
| 30 | +## Code Changes Needed |
| 31 | + |
| 32 | +- [ ] Add explicit `destructiveHint: false` to ~19 read-only tools that currently omit it (should be explicit per OpenAI guidelines). Affected tools: all `get_*`, `search_*`, `fetch_*` in `src/tools/common/` and `src/tools/core/`. |
| 33 | + |
| 34 | +## Tool Hint Annotations Audit |
| 35 | + |
| 36 | +Per [OpenAI guidelines](https://developers.openai.com/apps-sdk/deploy/submission), tool annotations must match actual behavior. |
| 37 | + |
| 38 | +### Correctly annotated (no changes needed) |
| 39 | + |
| 40 | +| Tool | readOnlyHint | destructiveHint | openWorldHint | Rationale | |
| 41 | +|---|---|---|---|---| |
| 42 | +| `call-actor` (both modes) | false | true | true | Runs Actors that can modify external state | |
| 43 | +| Dynamic Actor tools | false | true | true | Same as call-actor | |
| 44 | +| `abort-actor-run` | false | true | false | Irreversible abort within Apify platform | |
| 45 | +| `add-actor` | false | false | true | Reads from public Apify Store, modifies local tool list | |
| 46 | +| `get-html-skeleton` | true | — | true | Reads from arbitrary external URLs via Actor | |
| 47 | +| `search-actors` | true | — | false | Searches Apify Store (read-only) | |
| 48 | +| `fetch-actor-details` | true | — | false | Reads Actor metadata | |
| 49 | +| `get-actor-run` | true | — | false | Reads run status | |
| 50 | +| `get-actor-output` | true | — | false | Reads dataset items | |
| 51 | +| `get-dataset-items` | true | — | false | Reads dataset items | |
| 52 | +| `get-dataset` | true | — | false | Reads dataset metadata | |
| 53 | +| `get-dataset-schema` | true | — | false | Reads items for schema | |
| 54 | +| `get-actor-run-log` | true | — | false | Reads run logs | |
| 55 | +| `get-key-value-store-record` | true | — | false | Reads stored records | |
| 56 | +| `get-key-value-store` | true | — | false | Reads store metadata | |
| 57 | +| `get-key-value-store-keys` | true | — | false | Lists keys | |
| 58 | +| `get-user-runs-list` | true | — | false | Lists runs | |
| 59 | +| `get-user-datasets-list` | true | — | false | Lists datasets | |
| 60 | +| `get-user-key-value-stores-list` | true | — | false | Lists stores | |
| 61 | +| `search-apify-docs` | true | — | false | Searches documentation | |
| 62 | +| `fetch-apify-docs` | true | — | false | Fetches documentation | |
| 63 | + |
| 64 | +> **Note:** "—" in destructiveHint means the field is currently omitted and needs to be explicitly set to `false`. |
| 65 | +
|
| 66 | +## Privacy / PII Audit |
| 67 | + |
| 68 | +- [x] No unnecessary PII in tool responses — tools return public resource IDs (runId, datasetId), not internal/private data |
| 69 | +- [x] No session/trace/request IDs leaked — `mcpSessionId` is logging-only, never in tool responses |
| 70 | +- [x] API tokens never exposed in responses — used internally only |
| 71 | +- [x] Skyfire tokens redacted in logs (`src/utils/logging.ts:56-80`) |
| 72 | +- [ ] Verify privacy policy explicitly covers all data categories returned by tools (run metadata, dataset items, Actor details) |
| 73 | + |
| 74 | +## Widgets |
| 75 | + |
| 76 | +| Widget | URI | ChatGPT Status | Mobile Status | |
| 77 | +|---|---|---|---| |
| 78 | +| Search Actors | `ui://widget/search-actors.html` | Confirmed working | TODO | |
| 79 | +| Actor Run | `ui://widget/actor-run.html` | TODO | TODO | |
| 80 | + |
| 81 | +- [x] CSP configured for all widgets (`api.apify.com`, `mcp.apify.com`, image CDNs, Google Fonts) |
| 82 | +- [x] Pure MCP Apps SDK — no legacy `window.openai` fallbacks |
| 83 | +- [x] `openai/toolInvocation/*` UX hints configured (invoking/invoked messages) |
| 84 | +- [x] `openai/outputTemplate` intentionally NOT included (breaks MCP Apps renderer detection in MCP Jam) |
| 85 | + |
| 86 | +## Test Cases (TODO) |
| 87 | + |
| 88 | +Need to prepare test prompts with expected responses. Suggested cases: |
| 89 | + |
| 90 | +### Test 1: Search for Actors |
| 91 | +- **Prompt:** "Find web scraping tools on Apify" |
| 92 | +- **Expected:** Search widget renders with list of relevant Actors (web scraping category) |
| 93 | +- **Tools invoked:** `search-actors` |
| 94 | + |
| 95 | +### Test 2: Get Actor details |
| 96 | +- **Prompt:** "Tell me about the apify/web-scraper Actor" |
| 97 | +- **Expected:** Actor name, description, pricing, input schema summary |
| 98 | +- **Tools invoked:** `fetch-actor-details` |
| 99 | + |
| 100 | +### Test 3: Run an Actor |
| 101 | +- **Prompt:** "Scrape the homepage of https://example.com using apify/web-scraper" |
| 102 | +- **Expected:** Actor Run widget shows run progress, completes with results |
| 103 | +- **Tools invoked:** `call-actor` (or dynamic Actor tool) |
| 104 | + |
| 105 | +### Test 4: Get run results |
| 106 | +- **Prompt:** "Show me the results from my last run" |
| 107 | +- **Expected:** Dataset items displayed |
| 108 | +- **Tools invoked:** `get-user-runs-list`, `get-actor-output` |
| 109 | + |
| 110 | +### Test 5: Abort a run |
| 111 | +- **Prompt:** "Stop the currently running Actor" |
| 112 | +- **Expected:** Run aborted, confirmation message |
| 113 | +- **Tools invoked:** `abort-actor-run` |
| 114 | + |
| 115 | +## Common Rejection Reasons (from OpenAI docs) |
| 116 | + |
| 117 | +Watch out for these during testing: |
| 118 | + |
| 119 | +1. **MCP server unreachable** — Ensure `https://mcp.apify.com/` is stable and reachable |
| 120 | +2. **Test credentials don't work** — If OAuth is used, provide demo account without MFA |
| 121 | +3. **Test cases produce wrong results** — Verify all test cases pass on both web AND mobile |
| 122 | +4. **Undisclosed data types in privacy policy** — Audit all tool responses for user-related fields |
| 123 | +5. **Tool annotations don't match behavior** — Already audited above, need to add missing `destructiveHint: false` |
| 124 | + |
| 125 | +## Architecture Notes |
| 126 | + |
| 127 | +- Server runs as Apify Actor with Streamable HTTP transport |
| 128 | +- Public URL: `https://mcp.apify.com/` |
| 129 | +- Package: `@apify/actors-mcp-server` (v0.9.8) |
| 130 | +- Server card: SEP-1649 compliant |
| 131 | +- Widget metadata: MCP Apps standard (SEP-1865) |
| 132 | +- ChatGPT connects with `ui=openai` server mode |
| 133 | +- `stripWidgetMeta()` removes `openai/*` and `ui` keys in non-OpenAI mode |
0 commit comments