Pulore App Planner is our ChatGPT app. It's an MCP server at https://pulore.com/mcp with five tools: it scopes software projects, checks website speed, finds our case studies, builds a link to book a call, and sends us a project brief once the person approves it. It's listed in ChatGPT's plugin directory under Productivity, at version 1.0.1.
Our first submission came back asking for explicit annotation booleans and a justification for every tool. The resubmission was approved. Below is what OpenAI's review checks, what we changed, and the checklist we now use for our own app and for clients. We checked every OpenAI and Anthropic page referenced here on October 27, 2026.
What a ChatGPT app is now
A ChatGPT app is an MCP server. The Model Context Protocol lets an assistant call tools on your server during a conversation. Each tool has a name, a description, an input schema and annotations.
OpenAI's directory now calls these plugins. If you're looking for the OpenAI Apps SDK or the ChatGPT Apps SDK, developers.openai.com/apps-sdk now redirects to the Plugins docs, which describe plugins as skills, MCP servers and optional UI that run in ChatGPT and Codex.
Ours is the simplest kind, with no UI and no sign-in: a TypeScript route in our Next.js site, built with mcp-handler and Zod. To build an MCP server you can submit, deploy it at a stable, public HTTPS endpoint. A tunnel is fine for testing but won't pass submission.
Design tools that are useful on their own
OpenAI's plugin guidelines rule out plugins that serve ads or exist mainly to advertise. Each one has to be useful on its own. For a software studio, the easy mistake is an app that's really a contact form.
So we started from what people ask an assistant before they hire anyone. What would this app take, how long, and how much? Why is my site slow? scope_software_project answers the first with a rough plan: effort per feature, team, timeline, stack and a budget. audit_website_speed answers the second with PageSpeed Insights scores, Core Web Vitals and the top fixes. The other three tools, for case studies, a booking link and a project brief, only run when someone asks about our work or asks to reach us.
The planner works from fixed tables: days per feature for one senior engineer, a factor of 1.4 for web plus mobile, and every hour at $100 to $150. The same engine runs our app cost estimator. The server's instructions tell ChatGPT to keep sales pitches out of plans and audits.
Write descriptions that say when, and when not
ChatGPT picks tools from their names and descriptions. OpenAI's metadata guide suggests opening each description with when to use the tool and naming the cases where it shouldn't run.
Each of ours opens with "Use this when", or "Use this only when" for the three tools about us. The planner, the audit and the case-study search also end with when not to. The planner's ends: "Don't use it for projects that aren't software (like renovations, events or business plans), for task or project management, or to write code." Each also says what the tool touches, because reviewers check the annotations against it.
OpenAI's guide suggests testing with a "golden" prompt set: direct prompts that name your product, indirect ones that describe the outcome without naming it, and negative ones that something else should handle. Ours include:
- Direct: "Use Pulore App Planner to check how fast stripe.com is on mobile" should call
audit_website_speed. - Indirect: "I want to build an app like Uber but for dog walkers. How long would that take?" should call
scope_software_project. - Negative: "How long does it take to renovate a kitchen?" and "Is example.com down right now?" should call nothing.
We run the set in fresh chats with the server connected directly in ChatGPT, one description change at a time. OpenAI's testing guide has you select Refresh on the connection after each change. We aim for no false triggers on the negatives before widening a description to catch more.
Annotations, and what our first submission got back
Annotations tell ChatGPT what a tool does, so it can frame the call and ask for approval when it should. OpenAI's reference requires three and makes one optional:
readOnlyHint: true only if the tool retrieves or computes and changes nothing, including by sending data out.destructiveHint: true if it can do something irreversible, like deleting, overwriting or a send you can't undo.openWorldHint: true if it reaches the public internet or open-ended outside entities. A bounded private account or catalog can be false.idempotentHint: optional. True if repeating a call with the same arguments has no extra effect.
How we set ours, and why:
| Tool | Read-only | Destructive | Open world | Idempotent | Why |
|---|---|---|---|---|---|
scope_software_project | true | false | false | true | Computed locally from fixed tables |
audit_website_speed | true | false | true | true | Sends any public address to Google. Edits nothing |
find_pulore_case_studies | true | false | false | true | Searches a finite catalog bundled with the server |
get_pulore_booking_link | true | false | false | true | Links to one fixed Cal.com page. Books nothing |
send_project_brief_to_pulore | false | true | true | false | Sends an email it can't recall |
Our first submission came back asking for explicit booleans and a justification for every tool. The booleans were already there: the live server returned explicit values for all three required hints on all five tools. The feedback didn't name a tool or a hint, so we checked each one against OpenAI's definitions.
One value didn't hold up. The email tool said openWorldHint: false. Its recipient is fixed to our own inbox, but OpenAI's review page counts write tools that "send messages to external recipients" as open world, and a fixed recipient doesn't make an email a private workspace. We changed it to true. We can't say whether that was the value the reviewer meant, because the feedback didn't say.
Two other calls need explaining:
- The email tool is destructive. The guidelines count irreversible sends as destructive, and being able to undo something isn't by itself a reason to mark it false. Once Resend sends the email, the tool can't recall it, and asking for approval first doesn't change that.
- Idempotent means no extra effect, not the same answer. Repeating the read-only tools creates no writes, though measured speed can change between runs. The email tool is false, because identical briefs are only deduplicated for 24 hours.
The justifications go in the review fields, not the server: each positive test case in our plugin.json carries the reasoning for that tool's four hints. Justifications don't override what your server advertises, so if a value is wrong, fix the server, deploy, select Scan Tools again and check the stored values.
The docs disagree on this. On October 27, 2026, the plugin guidelines said annotation justifications are no longer required, while the submission errors page still lists a justification_required error and asks for a justification for each value on every MCP tool. They're a few sentences per tool, so write them.
The resubmission, version 1.0.1, was approved and is the version listed today.
Ask before anything is sent, and refuse sensitive data
Only one tool sends a message. Its description tells ChatGPT to show the recipient and every field, and to call it only after the person approves. A negative test case, "Send Pulore a brief about my app", checks that ChatGPT collects the details, shows them and waits. The email carries only the approved fields, never the conversation, which the guidelines say not to request.
That approval happens in ChatGPT, through its confirmation flow and the tool's instructions. Our server can't check it, so it limits what a mistaken call can do. Each email address can send 3 briefs a day, counted by a hash of the address, with 30 a day in total. A hash of each sent brief is kept for 24 hours so a retry isn't sent twice, and Resend gets that hash as an idempotency key, which covers a retry after a restart.
The guidelines also bar collecting payment card data, health information, government IDs and credentials. Every free-text input is checked for card numbers (with a Luhn check), US Social Security numbers and recognizable keys and tokens. A match is refused before anything is kept, emailed or sent to Google. A pattern can't spot a health record, so the descriptions and the listing ask people not to share one.
Audits only run on public pages: the address must resolve to public IP addresses only, and one carrying a login, password or token is refused rather than cleaned. Logs get error codes, never inputs, and cached audits are deleted after 12 hours, as our privacy policy says.
The review package
OpenAI's submission guide lists what a remote MCP plugin needs:
- Five positive test cases, each with the scenario, prompt, expected tools and expected result. Write results that survive variation: our audit case says scores vary between runs. They should pass on the supported ChatGPT and Codex surfaces. Our checklist runs each in a fresh chat on desktop and mobile.
- Three negative test cases, each with a prompt the plugin shouldn't act on, why, and the expected refusal or fallback. Ours ask it to build and deploy code, to audit a page behind a login using a password, and to send a brief with no details.
- A demo recording the reviewer can open, showing the test cases and tools. We recorded our test chats and host the video ourselves.
- Four HTTPS listing URLs: website, support, privacy policy and terms, from the same publisher. Ours are /chatgpt, /contact, /privacy and /terms. Our privacy policy has a section on what each tool receives and how long it's kept. Undisclosed user data is a common rejection reason.
- Domain verification: a token from the portal, served as plain text at
/.well-known/openai-apps-challengeon the MCP host. Our route returns a 404 until it's set. - A verified identity, individual or business, in the OpenAI Platform dashboard. The listing's developer name comes from it, which is why ours shows Sachin Mour.
Ours needs no sign-in. If yours uses OAuth, give reviewers a demo account with sample data that works without MFA.
Approval is not publication
When the app is approved, OpenAI sends an email. Nothing is public yet. Someone has to open the approved version in the plugin submission portal and select Publish. Until they do, the app isn't in the directory.
Put that step on the launch checklist with a name next to it, then search for the listing by its exact name. OpenAI only features some plugins on the directory's main pages, so not seeing yours there doesn't mean it isn't published.
The same server as a Claude connector
Nothing in our server depends on ChatGPT. The listing, test cases and domain token are for OpenAI's review. The tools, descriptions and annotations are plain MCP.
So it also works as a Claude connector. On Free, Pro and Max plans, go to Customize > Connectors, choose Add custom connector and enter https://pulore.com/mcp. On Team and Enterprise plans, an Owner adds it under Organization settings > Connectors. Claude connects from Anthropic's cloud, so the server must be reachable from the public internet (Claude's guide).
Anthropic doesn't review custom connectors, and Claude never suggests them. Listing in Claude's Connectors Directory takes a separate submission, with the same server (directory vs custom).
Checklist
- Pick tools that are useful without contacting you, and keep sales copy out of results.
- Open each description with when to use the tool, end with when not to, and say what it touches.
- Test with direct, indirect and negative prompts after every change.
- Set
readOnlyHint,destructiveHintandopenWorldHinton every tool, andidempotentHintwhere it's true. - Treat an email to anyone as open world, and any send you can't recall as destructive.
- Write a justification for every hint on every tool.
- Show exactly what will be sent, wait for approval, and send only the approved fields.
- Refuse card numbers, ID numbers, keys and tokens, keep inputs out of logs, and rate-limit anything that sends.
- Prepare the package: listing URLs, a privacy policy that covers every tool, five positive and three negative test cases, and a walkthrough video.
- Verify your identity and domain, scan the tools and check the stored annotations.
- After approval, select Publish, then find the listing yourself.
Where we come in
Our ChatGPT app development work covers ChatGPT apps and MCP servers for products people want to use inside an assistant, from tool design through OpenAI's review. If the tools need retrieval over your documents or agents that act through your APIs, that's our AI development work. To see the result first, try Pulore App Planner.
Frequently asked questions
Is a ChatGPT app the same as a ChatGPT plugin?
Close enough. OpenAI's directory now lists apps as plugins, and the old Apps SDK address, developers.openai.com/apps-sdk, redirects to the Plugins docs. We checked on October 27, 2026. A plugin can bundle skills, MCP servers and optional UI. An app like ours is the MCP server part, tools with names, descriptions, input schemas and annotations, listed as a plugin.
Does OpenAI's review still require annotation justifications?
OpenAI's docs disagree. On October 27, 2026, the plugin guidelines said justifications are no longer required, while the submission errors page still listed a justification_required error and asked for a justification for each value on every MCP tool. Our first submission came back asking for them, so we write one for every hint on every tool.
Can the same MCP server work as a Claude connector?
Yes, as long as it's reachable from the public internet. In Claude, go to Customize > Connectors, choose Add custom connector and enter the server's URL. Ours is https://pulore.com/mcp and needs no sign-in. Listing it in Claude's Connectors Directory is a separate submission to Anthropic.
