ChatGPT App Rejections - Why Broad Tool Descriptions Get You Rejected
ChatGPT App Rejections - Why Broad Tool Descriptions Get You Rejected
The ChatGPT app store opened to developers in early 2025, and the rejection queue filled up fast. The most consistent failure point is not broken functionality or privacy violations - it is tool descriptions that are too broad to be reviewable.
OpenAI's submission guidelines are explicit: descriptions must not recommend "overly-broad triggering beyond the explicit user intent and purpose the app fulfills." If a reviewer cannot tell from your description exactly when the model should call a tool and what it will return, your app gets sent back.
What "Too Broad" Actually Means
A description like "handles file operations" covers at least four different capabilities: reading, writing, deleting, and moving files. The model has to guess which operations are available and under what conditions to call the tool. This produces unpredictable behavior - and unpredictable behavior fails review.
The same applies to descriptions like:
- "manages user data" (does it read? write? delete? which data?)
- "processes documents" (PDF parsing? OCR? format conversion? summarization?)
- "interacts with the database" (reads? writes? which tables? with what safety boundaries?)
Reviewers check each tool by asking: does the model have enough information to call this correctly every time? If the answer requires the model to make assumptions, your description is too broad.
One Specific Thing Per Tool
The fix is decomposition. Split broad tools into specific ones. Instead of manage_files, you build four tools:
// Too broad - gets rejected
server.tool("manage_files", {
description: "Manages files and directories on the filesystem",
parameters: {
action: { type: "string", enum: ["read", "write", "delete", "list"] },
path: { type: "string" }
}
});
// Specific - passes review
server.tool("read_file_contents", {
description: "Reads and returns the text contents of a file at the given path. Returns a string. Use this when you need to examine what a file contains. Use list_directory to discover available files first.",
parameters: {
path: { type: "string", description: "Absolute or relative path to the file" }
}
});
server.tool("write_text_to_file", {
description: "Writes text content to a file, creating it if it does not exist. Overwrites existing content. Returns success confirmation with bytes written.",
parameters: {
path: { type: "string", description: "Path where the file will be written" },
content: { type: "string", description: "Text content to write" }
}
});
Each tool description now answers four questions: what does it do, what inputs does it take, what does it return, and when should the model use it instead of a related tool.
The Tool Annotations Requirement
Beyond descriptions, OpenAI's review process checks for tool annotations - metadata that signals the safety profile of each tool. The readOnlyHint annotation marks tools that do not modify state. The destructiveHint annotation flags tools that delete or overwrite data.
Missing annotations are a common rejection source that developers overlook:
server.tool("delete_file", {
description: "Permanently deletes a file at the given path. This action cannot be undone. Confirm with the user before calling this tool.",
parameters: {
path: { type: "string" }
},
annotations: {
destructiveHint: true,
readOnlyHint: false
}
});
server.tool("list_directory", {
description: "Lists all files and subdirectories in a directory. Returns an array of names. Does not read file contents - use read_file_contents for that.",
parameters: {
path: { type: "string" }
},
annotations: {
readOnlyHint: true,
destructiveHint: false
}
});
Privacy and Parameter Scoping
Another rejection trigger: parameters that collect more data than the tool needs. A search tool that accepts a user_profile object when it only needs a query string fails the "data minimization" check. Each parameter should be narrowly scoped to what the tool actually uses.
Avoid "just in case" fields. If your tool needs a user ID to look up a record, accept the ID - not the full user object. If it needs a date range, accept start and end dates - not a general context object with everything in it.
Testing Before Submission
The submission guidelines require test cases showing actual outputs matched against expected behavior. Before submitting, run your tool set through the review team's perspective: for each tool, write down what the model should receive when it calls the tool successfully, what it receives when parameters are wrong, and how it should distinguish between this tool and any similar tool.
If you cannot write that document clearly, your descriptions need more work.
Why This Improves the Tool, Not Just the Review
Specific tool descriptions do more than satisfy reviewers. They improve actual model behavior. The model calls the right tool more often, passes correctly-typed parameters, and handles edge cases predictably. Integration bugs at the boundary between tool description and model behavior account for a large fraction of the reliability problems in shipped integrations.
The same principle applies outside the ChatGPT app store: MCP servers, OpenAI function calling, Anthropic tool use - every tool-using AI system performs better when each tool does one thing with an explicit description of what that one thing is.
Fazm is an open source macOS AI agent. Open source on GitHub.