I stopped using MCP for most of my work
Through the MCP tool call
- Read the whole record
- Rewrite every field
- Send it back
The model writes the payload
Through a script on the API
- Edit the file locally
- Run the script
- Send it back
The script writes the payload
Both routes hit the same endpoint.
For a few months now I’ve avoided MCP whenever I have the choice, and used something else instead. I don’t have a problem with the protocol. I have a problem with what it costs me on the work I do every day, which is a lot of repetitive operations across a CRM, a CMS and a few analytics tools.
This is the written version of a video I published, with the same examples.
The setup never held across harnesses
I switch between Claude Code, Codex and Antigravity depending on what I’m doing. Each of them connects MCP servers its own way. Sometimes it’s a JSON config file. Sometimes there’s an official plugin to find, and when there isn’t, you add a custom server by hand.
So every time I opened a session in a different harness, I wasn’t sure I had everything connected. Some servers had dropped and needed re-authenticating. I’d start the work and find out halfway through.
On a team plan it gets worse. In Claude Code, only the admin can add custom connectors before they’re available to everyone, so a teammate who needs one waits.
That’s friction I can live with. The part that really costs me is further down.
Tool descriptions cost you before you ask anything
When an MCP server is connected, it exposes its tools to the client. For a CRM that’s things like list contacts, get a contact, create a contact, edit a contact. Each tool carries a description saying when to use it, plus the shape of the payload it expects.
All of that sits in the session. Connect ten servers with twenty tools each and you’re carrying two hundred tool descriptions and their schemas into every conversation, including the ones where you use two of them.
What is in the window before your first messageone session
- Tool descriptionsTen servers, twenty tools each, one description apiece
- Payload schemasThe shape each of those tools expects
- The two tools you will actually callAlready counted above. Drawn to scale.
- Left for your actual work
Clients are getting better here. Claude Code can reveal tools progressively instead of loading every description up front, and there are other approaches where the agent searches for the tool it needs. So I expect this one to mostly go away on its own, which is why it’s not my main complaint.
The agent retypes what you already have
Say you ask your agent to push two hundred contacts from a CSV into your CRM. The file is right there on your laptop, properly formatted.
The agent still has to write every tool call itself, character by character: the tool name, then the payload with the contact’s name, email and whatever else. Two hundred times. Usually not in parallel.
- Read the CSVThe file is already on diskcheap
- Write one tool call per rowThe model types out every field of every payload×200
- Wait for each call to returnOne after the other×200
Data that had to be typed by the modelall of it
What I’d want is for the agent to look at the CSV, work out how the headers map to the CRM’s fields, and then move the data without reading it into itself. That’s a transformation, and most clients can’t do it, so they rewrite instead.
It’s also unreliable. Past a couple of hundred records, an agent gets lazy and does half of them, or makes a small mistake in the middle that you find later.
Seven minutes to change one number
This is the one that made me stop using MCP for the work I repeat.
I manage a website in Webflow. Articles live in a CMS collection, one row per article, and the body is rich text, which Webflow stores as inline HTML. A typical article is two thousand words.
I asked the agent to find an article and change one number in it, 70 to 80.
Finding it was instant. Then Webflow’s MCP has one tool for this: edit a CMS item, where you pass the fields you want to change along with their new values. There’s no search and replace inside a field. So to change two characters, the agent read the whole body back, retyped all two thousand words with the new number in the middle, and sent the whole thing.
- Find the articleA search on the collectiona few tokens
- Read the CMS itemThe full rich text field comes back~2,000 words
- Rewrite the whole fieldEvery character, to change two of them~2,000 words
- Send the updateEdit item is the only tool there is1 call
What it took~7 min, 20% of my limit
One fix would be smarter tools: a search and replace endpoint on a CMS field. That would help, and it’s not something I can make happen on someone else’s server.
The other fix doesn’t need anyone’s permission. Pull the article once, write it to a local file, edit it there with the tools the harness is already good at, and push it back.
You can’t limit what comes back
An MCP call always returns something, and whatever it returns becomes part of your context window.
Ask for your twenty most recent articles because you want their publication dates, and unless the server happens to expose a fields parameter, you get twenty full articles. Bodies included. Two thousand words each, plus every other field in the collection.
What I asked forOne field, twenty rows
- Twenty publication dates
What entered the contextThe whole response
- Twenty article bodies
- Every other field in the collection
- All of it, on every later turn
The API was already there
A lot of MCP servers are a wrapper around an API the company already had.
Webflow, HubSpot and the rest have documented REST APIs that have been public for years. That’s what Zapier, Make, n8n and Softr built their connectors on. When those companies shipped an MCP server, most of them mapped their existing endpoints into the protocol. So it’s a second interface onto the same operations.
Interfaces
- An MCP server
- A CLI
- A script on your laptop
The platform's REST API
- Documented for years
- Usually an OpenAPI spec
- What the low-code connectors already use
The same operations
- List contacts
- Create a contact
- Update a CMS item
And your agent can call an API perfectly well. In a Codex or Claude Code session it writes the request and runs it from your machine. The difference is that an API call can sit inside a script.
That one difference is what fixes the retyping. The agent looks at your CSV, works out the mapping once, writes a script that loops over the rows and makes one call each, and then runs it. From that point there’s no model in the loop at all. The script runs until it’s done.
Write a skill, not a tool list
An API isn’t self-explanatory, and that’s what MCP actually gives you. Tell an agent to “use the HubSpot API” and it will guess from whatever it remembers. Usually close, but not exact.
But APIs are documented, usually with an OpenAPI spec you can point at or let the agent find. And for anything you do more than once, you write it down.
# Skill: CSV to CRM contacts
We never use the CRM MCP. Everything goes through the REST API.
## Endpoints we use
- `POST /crm/v3/objects/contacts` for one contact
- `POST /crm/v3/objects/contacts/batch/create` for up to 100 per call
- Full reference: https://developers.hubspot.com/docs/api/crm/contacts
## Auth
The key lives in `.env` at the repo root as `CRM_KEY`. Read it with
`source .env` inside the script. Never print it, never paste it into a
message.
## Mapping
Inspect the CSV headers first, then map to the CRM fields. Ask before
guessing on anything that isn't an obvious match.Once that file exists, the agent knows how you talk to your CRM, which endpoints you use and how to authenticate. It stops guessing, and you get the same reliability MCP was giving you.
CLIs work the same way and are often better. Agents are good at terminal commands, most CLIs document themselves through help output, and many handle OAuth for you: you log in once in the browser and the token sits on your machine. Under the hood it’s usually the same API again.
The key stays in the file
This is where APIs are genuinely more work than MCP. Most MCP servers now use OAuth, so you click through a login page and you’re done. With an API you’re usually holding a key.
I keep one .env file at the root of the folder the agent works in, and I tell the agent the key is there and how to use it: through a command that reads it into the script, never by printing it into the conversation. The agent knows the key exists and where it lives. It never sees the value.
Chain it like the terminal already does
Once calls live in scripts, you can put them end to end, and the model only sees what comes out.
Take something I do regularly: find the three articles I haven’t touched in the longest time, pull how they’re performing, and decide what to rewrite.
- 1Find candidatesSort the CMS by last edit, take three
- 2Fetch contentOnly those three
- 3Fetch performanceSearch Console for those URLs
- 4Hand over a reportThe only thing the model reads
The agent gets a short, structured report and does what it’s actually good at, which is reading it and telling me what to fix. It never saw the twenty articles it sorted through.
Nobody needs an API key on their laptop
The obvious objection: we’re ten people on a marketing team, does everyone now keep API keys on their machine?
No. What we built at Softr is a proxy. Each person has one key of their own. They call the proxy with it, the proxy knows who they are, and it routes the request to the right service using the key it holds for that service.
The team
- One personal key each
- No service keys locally
- Nothing to set up per harness
The proxy
- Identifies the teammate by their key
- Holds the service keys in one place
- Allows only whitelisted operations
- Different permissions per person
The services
- The CRM
- Analytics
- The website CMS
Permissions are the part I care about most. An API key is scoped when you create it, and after that everyone holding it can do the same things. Through the proxy we whitelist operations, so our Webflow key can be read-only for most of the team and let a content manager create and edit. Nobody can delete an article by accident, and there was nothing for anyone to install.
When MCP is still the right tool
I’m not arguing against MCP. For one-off work it’s the fastest thing there is, and I still use it.
Reach for MCPOne-off
- Find one thing and change it
- Explore a tool you rarely touch
- Anything where setup time is the cost
Reach for a script on the APIRepeated or in volume
- Hundreds of records at once
- A task you run every week
- Anything that would retype a payload
The moment to look at this is when a real part of your work runs through an agent talking to your tools. Before that, setting things up is most of the work, and MCP wins on that.
After that, it’s worth an afternoon. Ask your agent what endpoints your tools expose, have it write the skill with you, and run one of your recurring tasks both ways. The difference shows up immediately on anything with volume in it.
