SineFrameM3CI gate for MCPs Back to home
Blog

November 8, 20269 min read

How to pass Claude and ChatGPT MCP directory review

Why the Claude connector directory, ChatGPT and Codex plugins, and Muse reject MCP servers, the rule behind each one, and how to check before you submit.

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, and none of the three directories promises a turnaround. On the OpenAI forum, one developer said each resubmission takes about 20 days, 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 connectorsOpenAI (ChatGPT and Codex)Muse (Meta)
Who reviewsAn 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 outcomeListed 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 supplyHTTPS 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.
AnnotationsA 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 and review criteria; OpenAI app review and submission; Muse connector guidelines. Claude plugins have their own file-level checklist, which this guide doesn't cover.

Eight reasons submissions get rejected

OpenAI publishes four rejection reasons: 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 that tell it to call tools the user didn't ask for, or that interfere with its other tools. OpenAI's 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, 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 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 if you need to allowlist it.
  • The server answers an unauthenticated request with 200 instead of 401. Claude needs the 401 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 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 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 is our open-source tool for testing MCP servers. 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:

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 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:

npx --yes [email protected] 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, each one after another wait.

Map the feedback to the checks it implies:

Feedback you receivedCheck 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 toolsEvery 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.
UP

Written byUtkarsh PandeyCo-founder, SineFrame

Read this post as MarkdownAll posts
© 2026 SineFrame M3
HomeMCP testingMCP CI gateM3 vs MCPJamBlogDocumentationPrivacy policyTerms of use