The vault_drop tool disappeared from ChatGPT the moment we labeled it accurately.

Nothing had failed at the transport layer. The client could reach the same MCP endpoint that claude.ai and Manus were using. The tool server was healthy and the tool description was present. But ChatGPT’s runtime saw a write annotation and hard-gated the tool out of chat and voice.

We had assumed the generic, technically accurate label was the responsible choice: the same annotation everywhere, no client-specific carve-outs. We never asked what a runtime we don’t control would do with that label. A real feature stopped working for anyone using it through ChatGPT, and we had to trace an absence back to metadata to see why.

What the annotation missed

vault_drop does one job. It creates a new Markdown file in a sandboxed inbox directory. It cannot overwrite an existing file. It cannot edit a file in place. It cannot choose an arbitrary destination. Its payload is capped at 256 KB.

That is a write in the literal sense, because a new file exists after the call. So the accurate MCP annotation is write-capable, and that is what claude.ai continues to receive.

The risk that matters is different. vault_drop cannot alter existing records, escape its directory, or hide an unrestricted operation behind a friendly name.

ChatGPT did not make that distinction. Its runtime treated the write annotation as a hard availability gate. The tool never turned into a confirmation step or a visibly restricted action. It just became unavailable.

The diagnostic path ran in that order. First we checked the endpoint and the tool registration, and both were fine. Then we traced the absence to the annotation gate. What looked like a connector problem was client policy working as designed.

One tool, two advertised contracts

The change landed in server/mcp.ts as commit commit-4C2A: 10 additions and 1 deletion.

server/mcp.ts | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)

We did not fork the tool or create a second MCP endpoint. We did not loosen the sandbox, raise the 256 KB cap, or grant overwrite access. We changed only the metadata advertised to the ChatGPT-facing client. It now receives vault_drop as read-only. claude.ai keeps the write annotation, because that is still the accurate generic classification for a tool that creates a file.

That is the lie in the title. The endpoint is not lying about the operation. It is lying about the risk category needed to get past one client’s coarse safety gate.

The split exists only at advertisement time. All three clients still invoke the same tool with the same two inputs:

vault_drop(content, filename)

After the call, the server applies the same new-file-only behavior no matter which client sent it. The divergent annotation changes discoverability and leaves authority where it was.

Why the label change and not another tool

Leaving the write annotation everywhere was the cleanest semantic choice, and it is the one we shipped first. It cost us the use case in ChatGPT chat and voice. A perfect label is no use when the client turns it into a permanent off switch.

A second tool with a more comforting name would duplicate the contract and leave two descriptions to maintain. The supposedly safe tool and the original could drift apart. Every later feature request would reopen the question of which of the two gets it and whether their constraints still match.

A description saying “new files only” would not have helped either. The runtime evaluates the annotation before a person or model can act on that detail. So the enforcement stays in the server behavior. The sandboxed directory, the no-overwrite rule and the size limit are real constraints there, which a line in a tool description can’t be.

The annotation is part of the product surface

The same tool implementation can be reachable, hidden, blocked or framed as safe depending on how a client interprets one field. That makes the annotation worth the same review as the implementation.

When we wire a tool into a new client, we now ask two separate questions. What can this tool actually do? And what will this client let the user do once it sees that label?

For claude.ai the answers matched. For ChatGPT they did not, and keeping the generic label would have made a constrained tool unusable.

So the constraint stays real, the endpoint stays shared, and the label changes in the one place where the runtime could not see the difference. The tool is still new-file-only and the safety boundary is still on the server. If you rely on a tool in several clients, test its availability in each of them, because one annotation was enough to hide this one entirely.