# How to pass Claude and ChatGPT MCP directory review

Most rejections from the MCP directories trace back to a short list of published rules, and you can check nearly all of them before you submit. This guide covers three directories: the Claude connector directory, the OpenAI plugin directory that ChatGPT and Codex share, and Meta's Muse connector directory.

You can't make a review faster, but you can avoid going through it twice. OpenAI allows [only one active review per plugin](https://developers.openai.com/plugins/deploy/submission), and none of the three directories promises a turnaround. On the OpenAI forum, one developer said each resubmission [takes about 20 days](https://community.openai.com/t/submissions-take-so-long-that-requirements-change-which-leads-to-app-rejections/1392493), so it pays to fix everything before the first one.

We checked each rule below against the linked directory page on November 8, 2026. These pages change often, so follow the link before you rely on a detail.

## How each directory reviews

|  | Claude connectors | OpenAI (ChatGPT and Codex) | Muse (Meta) |
| --- | --- | --- | --- |
| Who reviews | An automated policy scan. Some listings are escalated to a slower Verified review, where people test each tool. | "Automated scans or manual reviews". | Three stages: risk assessment, tool review, and end-to-end QA "including manual review". |
| Default outcome | Listed as a Community connector. | Approval or feedback by email. | Approved connectors become discoverable in Muse. |
| Stated timeline | "Review time isn't fixed." | "Review timelines may vary"; no expedited review. | None. Meta doesn't answer individual status emails. |
| What you supply | HTTPS URL, a fully populated test account, docs and privacy URLs, use cases. | 5 positive and 3 negative test cases, a video walkthrough, a test account without MFA, a domain challenge token. | Overview, business verification, a data questionnaire, tool docs, a dedicated test account. |
| Annotations | A `title` and the applicable `readOnlyHint` or `destructiveHint` on every tool. | `readOnlyHint`, `destructiveHint` and `openWorldHint` as explicit booleans. | Meta classifies each tool as Read, Write or Sensitive write from your docs. |

Sources: Claude [submission](https://claude.com/docs/connectors/building/submission) and [review criteria](https://claude.com/docs/connectors/building/review-criteria); OpenAI [app review](https://developers.openai.com/plugins/deploy/app-review) and [submission](https://developers.openai.com/plugins/deploy/submission); [Muse connector guidelines](https://platform.muse.ai/docs). Claude [plugins](https://claude.com/docs/plugins/pre-submission-checklist) have their own file-level checklist, which this guide doesn't cover.

## Eight reasons submissions get rejected

OpenAI publishes four [rejection reasons](https://developers.openai.com/plugins/deploy/app-review): connectivity, test cases, an incomplete privacy policy, and annotations. Claude and Muse publish rules rather than reasons, but they point at the same problems, plus a few more.

### 1. Annotations that don't match what the tool does

OpenAI's wording is "Tool hint annotations do not appear to match the tool's behavior." The typical case is a tool marked `readOnlyHint: true` that also sends an email, increments a counter or writes something the user can see.

- Decide each tool's class from its code, not its name. Anything that changes state outside the call is a write.
- On Claude, "Every tool must include a title and the applicable hint." On OpenAI, set all three hints to an explicit `true` or `false` instead of relying on defaults.
- On Muse, "A tool that combines reads and writes must be classified as a write." The guidelines go on: "Never hide a send, share, publish, or payment action in a tool described as a read or routine edit."
- If one tool both reads and writes, split it.

### 2. Descriptions that steer the model

All three directories reject text that tells the model how to behave instead of saying what the tool does. Claude [rejects descriptions](https://claude.com/docs/connectors/building/review-criteria#avoid-prompt-injection-patterns) that tell it to call tools the user didn't ask for, or that interfere with its other tools. OpenAI's [guidelines](https://developers.openai.com/plugins/plugin-guidelines) rule out "instructing the model to prefer one plugin over others". Muse says "Tool descriptions must be factual."

Claude's review flagged three descriptions in [Mapbox's MCP server](https://github.com/mapbox/mcp-server/pull/273), including "ALWAYS use this tool to display maps", "Use this as the FIRST and ONLY tool when given coordinates" and "Invoke this as the FINAL step". One team found that [34 of its 50 tools](https://dev.to/tp1111/we-rewrote-all-50-of-our-mcp-tool-descriptions-to-get-into-claudes-connectors-directory-11ji) carried text like "CALL get_monitor FIRST". Check the server's `instructions` field and the text your tools return as well. In the Mapbox PR, a reviewer caught a hint in the tool results that was "basically the old FINAL step instruction coming back".

### 3. The reviewer can't connect or sign in

OpenAI lists this first: "We're unable to connect to your MCP server using the MCP URL and/or test credentials we were given." Common causes:

- The URL is local, behind a VPN, or blocked by a firewall. Claude's traffic comes from [`160.79.104.0/21`](https://claude.com/docs/connectors/building/authentication#network-reference) if you need to allowlist it.
- The server answers an unauthenticated request with `200` instead of `401`. Claude [needs the 401](https://claude.com/docs/connectors/building/authentication) to start sign-in and "ignores a WWW-Authenticate header on a 200 response", so the user is never asked to log in and sees no tools.
- Sign-in discovery is broken. Either the 401 has no `resource_metadata` pointer and the well-known paths return 404, or the metadata's `resource` field doesn't exactly match the URL the user enters.
- The test account needs MFA, an email or SMS code, a magic link or a new sign-up, or its credentials expired. OpenAI asks for an account that "should work immediately".
- On OpenAI, the domain challenge token is missing, or isn't served as plain text. OpenAI wants the exact token alone, not JSON or a list of tokens.

### 4. Test cases that don't produce the right result

OpenAI asks for five positive test cases, each with "the scenario, user prompt, expected tools, and expected result", and three negative ones where the plugin should not act. Claude's [directory policy](https://support.claude.com/en/articles/13145358-anthropic-software-directory-policy) asks for "at least three working examples of prompts or use cases". A failure here usually means a tool errored, or returned empty data on the test account.

Write prompts the way a user would, without naming tools. Make the negatives near-misses the server should decline, not obviously unrelated requests. Then run every case against the exact account you give the reviewer.

### 5. Catch-all tools

Claude [rejects](https://claude.com/docs/connectors/building/review-criteria#separate-read-and-write-tools) a tool that accepts both safe and unsafe HTTP methods: "Don't ship a catch-all api_request tool with a method parameter." It asks you to split such a tool into reads and writes, and ideally to split the writes into create, update and delete. OpenAI goes further: "Expose each model-callable operation as a separate tool." That rules out a `manage_customers` tool with an `action` enum. If a tool takes free-form queries or request bodies, Claude also requires its description to name or link the target API.

### 6. Data you ask for or return

Don't ask for more than the tool needs. Claude's criteria say "Don't query Claude's memory, chat history, conversation summaries, or user files." OpenAI's guidelines rule out requesting "the full conversation history, raw chat transcripts", or precise location, and restrict access credentials such as API keys and passwords.

On the way out, return only what the request needs. Session tokens, internal IDs and telemetry in responses are common findings. OpenAI's fourth rejection reason is "Your plugin returns user-related data types that are not disclosed in your privacy policy", so every data type you return needs to appear in that policy.

### 7. Use cases the directory doesn't accept

Claude's review criteria don't accept connectors that "Transfer money, cryptocurrency, or other financial assets" or "Generate images, video, or audio through AI models". Diagram and chart tools are allowed. OpenAI doesn't allow "money transfers, crypto transfers, or investment trades", or selling digital products such as subscriptions and credits inside the plugin. Muse requires that the task finishes inside Muse: "Sending the user to finish the entire checkout does not meet the completion requirement."

### 8. Listing details

On OpenAI, `displayName` and `shortDescription` are at most 30 characters each. Icons must be square, and all four listing URLs (website, support, privacy policy and terms of service) are required over HTTPS. Don't append "MCP", "MCP Server" or "Plugin" to the name, and don't advertise pricing. Claude allows up to 100 characters for the server name, 200 for the one-liner and 2,000 for the description.

## Check your server before you submit, with M3

[M3](https://github.com/sineframe/m3) is our open-source tool for [testing MCP servers](/mcp-testing). Two parts of it cover directory review. `m3 lint --directory` checks tool metadata, and the `preparing-directory-submissions` agent skill covers the checks that require reading the code.

Both are free and Apache-2.0 licensed. They run on your machine and need no account or API key, and M3 doesn't send anything about your server anywhere. The skill runs inside the coding agent you already use.

### Lint the metadata

Install M3 0.3.2 or later, then point lint at your server's start command or URL:

```sh
uv tool install sf-m3-cli
m3 lint --directory all -- python -m my_server
m3 lint https://mcp.example.com/mcp --directory openai
```

Lint reads the tool list and never calls a tool. It reports what metadata alone can decide: missing titles and safety hints, OpenAI hints that aren't explicit booleans, contradictory hints, names over 64 characters, missing descriptions, duplicate names, tools whose `method` input mixes GET with POST, and hidden characters. Each finding names the directory, quotes the policy and gives a fix. Here is part of a run against a small server with one unannotated tool:

```
ERROR   directory-claude-safety-hints  tool 'create_issue' annotations
  detail: readOnlyHint absent, destructiveHint absent
  claude [error]: missing the applicable safety hint. https://claude.com/docs/connectors/building/review-criteria#provide-tool-annotations (policy checked 2026-10-18)
  fix: Set "readOnlyHint": true if this tool only reads; otherwise set "destructiveHint" (true if it modifies or deletes data). Claude's MCP page asks for both hints on every tool.

3 errors, 0 warnings, 0 notes
directory readiness: claude 2 errors, 0 warnings · openai 1 errors, 0 warnings · muse not checked (no rule checks metadata yet)
```

Lint exits with status 1 when it finds an error, so you can run it in CI. Muse shows as "not checked", because Meta classifies tools from your documentation rather than from annotations. The [directory readiness reference](/docs/reference/directory-readiness) lists every rule.

### Run the readiness skill

Lint can't tell whether a "read-only" tool sends email, or whether a description steers the model. That takes reading the code, and the skill gives your coding agent a procedure for it. Install it in the project:

```sh
npx --yes skills@1.7.0 add sineframe/m3#v0.3.2 --skill preparing-directory-submissions --agent universal claude-code -y
```

Then ask your agent something like "get this server ready for the OpenAI directory". The agent:

- runs `m3 lint --directory` and copies its findings into the report unchanged;
- checks steering language, hints against what the code does, catch-all tools, data requests, use case, privacy, listing limits, reviewer access and the Muse tool classes, with a `file:line` and a policy quote behind each failure;
- probes the public URL for the 401 and sign-in metadata, and for the OpenAI domain challenge;
- drafts the review test cases and writes an M3 test for each positive case, running only read-only tools unless you confirm a test account;
- writes `directory-readiness-report.md`, with a section per directory and proposed fixes as diffs.

It doesn't edit your server without asking, submit anything, or ask for credentials. The report lists what was checked and what was found; it won't predict whether a reviewer approves the server.

## If your ChatGPT app or Claude connector was rejected

Rejection emails are short and often name a single example of a problem. Find and fix every other instance of it before you resubmit. One builder on the OpenAI forum wrote about their [fifth rejection](https://community.openai.com/t/fifth-chatgpt-app-rejection-still-no-clear-actionable-reason/1391434), each one after another wait.

Map the feedback to the checks it implies:

| Feedback you received | Check again |
| --- | --- |
| "Tool hint annotations do not appear to match the tool's behavior" | Every tool's class from its code, and all three hints |
| "We're unable to connect to your MCP server using the MCP URL and/or test credentials we were given" | Public HTTPS, the 401 and discovery chain, firewall rules, a test account without MFA |
| "One or more of your test cases did not produce correct results" | Each case against the test account, and extra fields in responses |
| "Your plugin returns user-related data types that are not disclosed in your privacy policy" | Every field you return against the policy text |
| Steering, preferring itself, interfering with other tools | Every description, the server `instructions` and text in tool results |
| Sends the user to a website to finish (Muse) | Whether the task finishes inside the agent |

If you use the readiness skill, paste the rejection into the chat. The agent maps each point to checks, runs those first for every tool, and puts them at the top of the report.

On OpenAI, make sure everything is fixed before you resubmit, because only one review can be active at a time. If you think the rejection is wrong, OpenAI says to reply to the email you received and explain why.

## Pre-submission checklist

- Every tool has a `title`, and its hints match what the code does (all three as explicit booleans for OpenAI).
- Tools that read and write are split, with no `method` catch-alls, and no `action` catch-alls for OpenAI.
- No description, `instructions` text or tool result tells the model what to prefer, avoid or call.
- Tool inputs don't ask for chat history, credentials or precise location.
- Responses carry no tokens, internal IDs or telemetry, and the privacy policy covers every data type returned.
- The use case is allowed: no money movement, no AI media generation, and on Muse the task finishes inside the agent.
- The URL is public HTTPS, and an unauthenticated request gets a `401` with sign-in metadata, unless the server has no sign-in or signs in lazily per tool.
- The OpenAI domain challenge token is served as plain text.
- A populated test account with no MFA and no expiry is ready for the reviewer.
- The test cases are written and pass against that account: 5 positive and 3 negative for OpenAI, at least 3 for Claude.
- Listing text fits each directory's limits, and every listing URL is live.
- `m3 lint --directory` reports no errors.
