Two weeks ago I published a post on this blog called "The One MCP Tool We Refused to Build."

I was proud of it. It argued that ClearList would never let an AI agent share a seller's home address, that a confirmation prompt was the wrong answer, and that some capabilities should be absent rather than restricted. It ended with a line about how the interesting question is not how many tools you shipped, but which one you decided not to.

Then I ran a moving sale with my own product.

The wall

Here is what a real sale actually looks like on day three.

Someone reserves a chest of drawers. They want to pick it up tomorrow at two. They need to know where to come. So I open Claude, where I have been running the entire sale, and I type "share my address with Sarah."

Claude tells me it cannot do that.

Fine. That was my rule. So I open ClearList in a browser. It asks me to sign in. It emails me a six-digit code. I switch to my email, find the code, switch back, paste it in, find the conversation, tap Share.

That is four surfaces to send one sentence I have already typed.

Then it happened again two hours later. Then twice more the next day.

The part I got wrong

The friction was annoying. That alone would not have changed my mind, because friction is a perfectly good price for safety and I would have paid it.

What changed my mind was noticing who my rule was actually protecting.

The whole reason ClearList has an MCP server is so somebody can run a sale without ever opening the app. That seller signs up through their assistant. They never see the settings page. They have no address saved in ClearList at all, because nothing ever asked them for one.

So for that seller, my careful rule was not a wall standing between an attacker and their door. It was a dead end. They could not share through the assistant, because I had refused to build it. And they could not share through the app either, because there was nothing in there to share. They would have to go and enter their address into a product they had never opened, purely to satisfy a rule I wrote to protect them.

I had built a safety mechanism that stranded the exact person it existed for.

The argument I was actually making

Reading my own post back, the reasoning has a hole in it that I did not see while writing.

I said a confirmation prompt is not enough. But ClearList already shipped one. A signed-in seller taps a button and the address goes out. One human confirmation, exactly the mechanism I had spent a thousand words calling insufficient.

So I was never really arguing that a confirmation is insufficient. I was arguing that a confirmation is insufficient when a model is the one clicking it. Those are different claims, and only the second one is defensible.

Once I saw it that way, the question stopped being "should this capability exist" and became "what would make a model-driven confirmation trustworthy enough."

What I was actually protecting

The threat model has not changed and I want to be clear about that, because this is the part where a founder usually starts quietly redefining the risk to make the feature easier to ship.

Picture someone leaving a bad relationship. They have moved, they have not told the person they left, and they are selling furniture because they are starting over and need the money. They photograph a couch and put it online.

The person they left recognizes the couch.

That is still the situation. What I got wrong was the conclusion I drew from it. I concluded that the capability must not exist. The better conclusion is that a human has to be demonstrably the one who shared it, and that the seller has to find out every single time one goes out.

That is a lower bar than "the tool cannot exist." It is also an honest one, and unlike the original it does not fall apart the moment you meet a seller with no address on file.

Craigslist has run since 1995 on the principle that an adult may give out their own address. My product should not be more paternalistic than the person using it.

What we built instead

Two tools, and the first one discloses nothing.

share_address looks up who would receive the address. Nothing reaches the buyer when it runs. No message is written, and they have no way of knowing it happened at all. Everything it returns comes back to my side of the conversation: the recipient's name and email, the exact address that would go out, and a confirmation token.

The assistant shows the seller that card. Sarah M. Her email. The address underneath. One button.

confirm_address_share takes the token and sends it.

The reason the address is frozen at step one is the whole design. If the second call could carry its own address, then the seller approves one thing and the system sends another, and the confirmation confirms nothing at all. What you saw is what goes.

What I kept

An API key that turns up without a valid token is still refused, exactly as before. An address still cannot be sent as an ordinary message. An agent still cannot read an old address out of a conversation it was pointed at and retype it.

And the seller gets an email, every single time, sent by the server after the fact, naming the buyer and containing the exact address that went out. It cannot be switched off.

That email is doing more work than anything else here.

The thing I have to be honest about

The confirmation button is not a security boundary.

When the seller taps Approve, that click travels to my server carrying the same API key the assistant uses. My server genuinely cannot tell the difference between a human tapping and a model calling the tool directly. Anyone who tells you their agent confirmation dialog is a boundary is describing a feeling, not a mechanism.

So I wrote that limitation into the code, in three separate places, because the danger is not that it is imperfect. The danger is that someone later reads the button as a guarantee and builds on it.

What actually holds is the boring stuff. An address can only ever reach the buyer in the one conversation it was prepared for, and the token that carries it works exactly once before expiring ten minutes later. Then the seller gets told, whatever happened. None of that depends on a model behaving well.

And then the security review found the door I had left open

I ran an adversarial review before shipping, with instructions to try to break it rather than to approve it.

It found something I had missed completely, and it was my original nightmare wearing a different hat.

Every ClearList sale page has to expose the seller's ID, because a buyer's browser needs it to reserve anything. And ClearList has an enquiry route, so a buyer can message a seller without reserving. That route has no login, no email verification, and no rate limit. Whatever name and email you type, it copies straight into the seller's inbox.

So somebody could invent a thread that looks like a buyer, put an instruction in the name field, and wait for the seller's assistant to read it while doing something ordinary like checking reservations.

I had a defence for this and it did not work. I had been saying the address can only go to the buyer in that conversation. Perfectly true. Completely useless here, because the attacker is the buyer in that conversation. I had protected against sending it to the wrong person, when the risk was sending it to exactly the person who asked.

The fix is that an assistant can now only share with a buyer who actually reserved something, which means they proved they control their email with a six-digit code. An enquiry on its own is not enough. It costs almost nothing, because a pickup address is only useful to somebody who is coming to collect a thing. And if you are in the app yourself, you can still share with anyone, because you can see who you are talking to.

What I would tell myself two weeks ago

Absence is still a real design tool and I stand by that half of the original post. There are capabilities that should not exist, and "just add a confirmation" is still usually a lazy answer.

What I would add is this: when you decide a capability must be absent, go and look at who is standing on the other side of the wall you just built. I never did. I wrote the rule, then the tests, then a whole essay about it, and it took running my own sale to notice that the person I had locked out was the one I meant to protect.

The interesting question is still which tool you decided not to build. It just has a second half I did not know about at the time…

Which of your rules have you never actually used?


More on how the rest of it works: every tool in the ClearList MCP server, explained and what happens when you let ChatGPT run your sale.

Frequently Asked Questions

Can an AI agent share a ClearList seller's address?

Yes, in two steps, and never on its own. The first tool discloses nothing. It looks up who would receive the address and hands back a confirmation token, so the assistant can tell the seller "this is going to Sarah M. at sarah@example.com" before anything happens. Only after the seller says yes does a second tool send it. The recipient and the exact address are frozen at step one, so nothing in the second call can redirect it.

Why did ClearList reverse its own rule?

Because the rule was protecting the wrong person. A seller who sets up their whole sale through Claude or ChatGPT never opens the web app, so they have no address stored in it. The old rule meant they could not share through the assistant, and had nothing to share through the app either. Their first pickup was a dead end. Meanwhile the app itself had always sent the address on a single button tap, so the real position was never "a confirmation is not enough". It was "a confirmation is not enough when a model is the one clicking it".

What stops an agent sharing an address with a stranger?

Only a buyer who verified their email by reserving something can receive one. An enquiry alone is refused. This matters because anyone can send a ClearList seller an enquiry without proving who they are, which a security review pointed out before launch and which is exactly the door the original threat model was worried about.

How does a seller find out their address was shared?

By email, every single time, sent by the server after the fact. It names the buyer, includes the exact address that went out, and cannot be switched off. That email is the real control here, more than any confirmation prompt, because a prompt can be clicked and an email cannot be un-received.

Is the confirmation button a security boundary?

No, and saying so plainly is the point. The server cannot tell a human tapping Approve from a model calling the same tool, because both arrive with the same API key. The controls that actually hold are the ones a model cannot touch: the address can only reach one conversation's verified buyer, the token works once and expires in ten minutes, and the seller is emailed every time.