Image: Macbook Laptop by Wilfred Iven, licensed under CC0 1.0.
Your transport manager wants to know which lanes billed above contract rate last week, and the answer sits four screens deep in the TMS. They would rather type the question into ChatGPT, where they already work. Sam Altman put the product past 800 million weekly users at OpenAI's DevDay on 6 October 2025, per TechCrunch, and your operations team is somewhere in that number.
So you build the connector. The read side goes well for about a week. Then somebody types "fine, approve those three invoices" and the question you postponed arrives in full: what exactly is this thing allowed to change?
A connector is an API surface, not a read-only window
The Model Context Protocol is how a chat client reaches into your systems. OpenAI's developer account announced in September 2025 that ChatGPT's developer mode supports MCP tools in full, which took connectors past search and retrieval into actions that modify data.
OpenAI's guidance for the people building those servers stays narrow on purpose. Its MCP documentation tells builders to implement two read-only tools, search and fetch, and in its worked example approval is skipped only for that pair, alongside the instruction to "keep approval enabled for tools that can modify data or take other consequential actions."
That split carries the entire design. A tool answering "which loads on Atlanta to Dallas billed detention in September" runs a query. A tool that approves an invoice moves money out of your account. Both reach the model through the same protocol and look alike in a tool list, so the boundary between them has to be built rather than assumed.
Two gates, and neither one works alone
Permission on a TMS connector is the product of two independent checks, set by different people at different moments.
The connector scope is the ceiling. An administrator installs it and fixes which tool families exist at all: invoices, shipments, rate tables, documents. Nothing outside that set can be called by anyone, no matter how the question is phrased.
Underneath sits the person asking. Every call carries their identity, resolved server side against the same role model that governs what they see in the application. A dispatcher who cannot open the quarterly spend report in the UI does not get it back as a paragraph in chat.
| Gate | Who sets it | What it governs | What breaks without it |
|---|---|---|---|
| Connector scope | The administrator who installs the connector | Which tools exist, and whether any of them write | One prompt reaches every object in the TMS |
| User role | Your existing RBAC, unchanged | Which records come back, and which actions this person may take | Chat becomes a privilege escalation route around the UI |
The effective permission is the intersection of the two, and the order matters: a connector cannot grant what a role withholds. The MCP security guidance states the rule underneath this plainly. A server must not accept tokens that were not issued for it, because a passed-through credential breaks the audit trail and obscures which client did what. The same document warns against publishing wildcard or omnibus scopes such as full-access, since one stolen token then opens the lot.
Read-only by default, because the hint is not a control
MCP lets a server annotate a tool as read-only. The specification is blunt about what that annotation is worth: clients "MUST consider tool annotations to be untrusted unless they come from trusted servers." OpenAI says the same thing from the client side, warning that "it is possible for write actions to occur even if the MCP server has tagged the action as read only."
Treat the label as documentation and put enforcement in the server. Read tools and write tools are separate definitions behind separate scopes, and a connector provisioned for questions does not contain the write tools at all. A tool that never appears in the list cannot be called by a confused model, or by a well-directed one.
The reason writes need their own gate
Freight operations run on text that other people wrote. A carrier's remittance advice, the comment field on a load, the notes page of a scanned invoice, an email from a broker you have never dealt with. Each one is untrusted input that a model will read while answering a perfectly reasonable question.
Invariant Labs showed on 26 May 2025 what follows. Using the official GitHub MCP server, the researchers planted instructions inside an issue on a public repository. When the account owner asked their agent to look at open issues, it followed the planted text and pulled content out of private repositories into a public pull request. Simon Willison named the shape of it the lethal trifecta: access to private data, exposure to malicious instructions, and a way to send information out.
A TMS connector with write access assembles all three. The private data is your contract rate table. The hostile instruction arrives inside a document you were always going to process. The exit is any field the agent can write. Invariant noted both that reviewing and approving agent actions mitigates the attack and that users gravitate toward an always-allow setting. Those two observations together are why the gate cannot be a confirmation prompt on its own.
The one approval we kept in the UI
Reading from chat earns its place quickly. Which invoices Penny parked this week and why, what Chase logged against a late container, which carrier has three open disputes on one lane. Those are questions, and answering them changes nothing.
Releasing a payment or sending a dispute to a carrier stays out of chat by choice. ChatGPT does require manual confirmation before a write action runs, in its documentation's words in any conversation, and what that dialog puts in front of the approver is the JSON payload of a tool call. Wrong evidence. Approving a short pay is a judgment about a contract clause, a charge code and a signed delivery receipt, and those belong on one screen together, which is the argument in "the AI decided" is not a dispute position.
Hence a checkbox of its own, off until somebody turns it on, scoped per connector and per role. Which workflows ever earn it is decided workflow by workflow rather than once for the product, the subject of full autonomy is a setting, not a product. Chat is a question interface. The places where money leaves keep their own front door.
What to do next
- List every tool your connector exposes and mark each one read or write. If the tool definitions do not let you do that, you have one gate rather than two.
- Test the lower gate directly. Have someone without spend visibility ask the connector for spend, and confirm they meet the same refusal the UI gives them.
- Name the writes you genuinely want available in chat. Most teams settle on a short list: a note on a load, a flag on an invoice, nothing that settles money.
- Look at what your approval dialog actually displays. If the answer is a payload rather than evidence, move that approval back into the application.
Book a walkthrough if you want to see the read side running against your own lanes, with the write checkbox sitting where it belongs.
