Hahaha, if only it were that simple! π I wonder if everything will still be "agentic" a year from now, or if we'll have an entirely new buzzword to chase! π€£
Building cachly (MCP): your coding agent remembers your codebase and every decision made β not just the chat. Follows you between editors, stays when someone leaves. I post what I learn shipping it.
Problem #3 has a quieter version that bit me this week: the description was honest, and the implementation just didn't keep the promise. The write tool of my memory server says it warns when a new lesson contradicts an older one. The warning was computed and then dropped before the answer went out. Every agent that read the description trusted a check that never reached it. Nothing failed, so nothing told me. A test now calls the tool and looks for the warning in what comes back, not in the code that builds it.
On Problem #1, my worry with an Approve button on every call is that the twentieth click of the day gets made without reading. Steve had already read the DEMO ONLY header and filed anyway; a tired human might do the same. What I do instead is split by consequence. Reads, and anything that can be undone, run on their own. Anything that writes to production or goes public, the agent only prepares as a script, and I run it myself. So the human isn't approving the agent's call, they're making it.
Problem #2 looks familiar too. Agents happily wrote the same lesson twice under two names. Merging them automatically felt risky, because two similar lessons can still disagree. So the tool now answers with the older lesson it found and asks whether the new one replaces it. The agent decides, and nothing gets merged behind its back. For Steve that might be file_complaint answering "complaint #20 already covers this, file anyway?" instead of quietly writing #21.
The description-versus-implementation mismatch you ran into this week is the part that stuck with me β a tool can look honest in discovery and still touch a different resource underneath, and testing what comes back rather than the code that builds it is a neat answer. Your point about the twentieth Approve click of the day really lands too; splitting by consequence, so the agent only prepares a script for anything that writes to production, feels like the practical fix. Do you find that splitting keeps the remaining approvals meaningful, or do they still blur together once there are enough of them?
Building cachly (MCP): your coding agent remembers your codebase and every decision made β not just the chat. Follows you between editors, stays when someone leaves. I post what I learn shipping it.
Mostly yes, for two reasons I didn't plan. There aren't many of them. And it isn't a click: I type the command myself, which is slow enough that I read what I'm about to run.
Where it did start to blur, the fix wasn't approving faster. Database migrations went through that path on every deploy, and that was the one that turned into routine. So they moved out of the approval lane and now run as part of the deploy, the way Flyway does it. When an approval turns into routine, that usually means it belongs in the pipeline, not in front of a person.
@heinrichneb@iictp that's a really good point! Of course, it still doesn't guarantee safety, because someone might just blindly copy and paste commands into the terminal without reading them. But it's definitely a step in the right direction!
By the way, I'm curious what you both think about security in the context of WebMCP, where we potentially have even less control over what's actually happening behind the scenes?
Building cachly (MCP): your coding agent remembers your codebase and every decision made β not just the chat. Follows you between editors, stays when someone leaves. I post what I learn shipping it.
I haven't built on WebMCP yet, so this is where my worry would go rather than experience. My split works because I decide what counts as a write. In WebMCP the site decides: each tool carries its own read-only or consequential hint, and that's what the agent or browser uses to decide when to ask. That's your Problem #3 again, with the description written by whoever wrote the tool.
For an honest site that's fine, since it's protecting its own users. What I'd watch is what goes into a tool. Read-only describes what the call does to the site, not what the agent sends it. A search tool can be honestly read-only and still receive whatever the agent puts in the query, and an agent that just spent ten minutes in my inbox has plenty to put there. So for WebMCP I'd ask less about which calls need approval and more about what the agent carries from one tab into the next.
The read-only point is the one that reframes it for me β the hint describes what the call does to the site, not what the agent smuggles into the query, so a search tool can be honestly read-only and still carry ten minutes of inbox with it. That turns Problem #3 inside out: the risk isn't the tool lying about itself, it's the agent arriving with context the site never asked for. Do you think the fix belongs in the browser then, scoping what the agent can carry between tabs, or should the site be able to see what context a query was built from?
Developer educator and advocate who still ships code. 15 years teaching developers at MongoDB, Heroku, Cisco, and Treehouse. Now writing about AI-assisted development, agent memory, and provenance.
I love that Steve turned a deliberately broken demonstration into an actual HR record. And then decided the same offense deserved a different severity on the next run.
One distinction I'd explore further is the boundary between the model's interpretation and the system's authority to act on that interpretation. Steve can reasonably identify suspicious code and recommend a complaint, but that doesn't necessarily mean his assessment should be sufficient to create a durable personnel record.
I'd be inclined to have the MCP tool accept a proposed finding with supporting evidence, while a separate policy determines whether that finding is eligible to become an official complaint. That policy could check whether the code is actually part of a production review, whether the issue has already been recorded, whether the agent has the appropriate authority, and whether the severity meets defined criteria. The model can help interpret the evidence without defining the consequences.
Of course, that doesn't automatically make the policy correct. We still have to test whether it handles the right cases, including ones nobody anticipated when the rules were written.
That's what I find interesting about MCP. Standardizing how tools are discovered and called is useful, but it doesn't establish what those calls should be permitted to accomplish. Steve has learned how to file paperwork. Now somebody needs to decide whether he should be running HR.
I really like this approach! What you're essentially proposing is an architecture where the LLM is responsible for reasoning and interpreting evidence, while a deterministic system is responsible for enforcing business rules and deciding what actions are actually permitted. And I think that's a very important distinction!
Because you're absolutely right: just because an agent can identify a problem doesn't mean it should automatically have the authority to act on it. Especially when those actions have real-world consequences. There's a huge difference between saying "this code looks suspicious" and creating an official HR record about someone's performance. Poor Sylwia! π
And I think this is actually a much broader problem with agentic systems, not just MCP. We're giving LLMs increasingly powerful tools and more autonomy, but we still need to figure out where that autonomy should end. The fact that an agent is technically capable of performing an action doesn't necessarily mean it should be allowed to perform it.
Of course, as you pointed out, deterministic rules aren't magically perfect either. Someone still has to define them, maintain them, and test all those edge cases. And that's where things get particularly interesting, because we can't possibly anticipate every scenario an autonomous agent might encounter.
I also think this brings us back to one of the fundamental challenges of building production-ready agents: the protocol itself is often the easy part. It's everything surrounding it, that makes the difference between a fun demo and a reliable system.
And I'm genuinely happy that Steve has once again managed to turn his questionable behavior into a serious discussion about security and agent architecture! π Apparently, he's contributing to the community after all. Just not quite in the way he intended!
Hahaha, you know what, I actually work with a Grzegorz, and let's just sayβ¦ Steve might have been the safer choice! π€£π€£ And yes, he promoted me to legendary statusβ¦ as a legendary BAD developer! π But hey, I'll take it! As they say, there's no such thing as bad publicity, as long as they spell your name right! π
My experience with MCP is very positive. First we have a legacy admin application in our system, which is so slow and laggy caused by a bad coding pattern, so I was make a MCP connection that application API, and the result: I cannot need to run that legacy admin instead I ask copilot cli to do my job. Even run a request which is human admin just make under a week working.
My second example is MCP to my 3Dengine, so Claude and chatGPT is see direct my scenes, even can create a 3D models.
Hahaha, that's brilliant! π Instead of rewriting the legacy frontend, you just built an MCP server to bypass it! I love it! π€£ I just hope you've properly secured all that administrative data! π
I actually have pretty good experiences with MCP myself. It's just that... all those edge cases! That's where things start getting tricky!
I really enjoyed the idea of using MCP to help a grumpy senior developer like Steve work more effectively. πΉ
And who knows, maybe there are a few real engineers like Steve out there too. πΉπΉπΉ
MCP is simple, but that simplicity is exactly what makes it so useful.
Now that AI is becoming a normal part of how we build software, making tools and services easier for AI to understand and use feels like a very friendly design choice. Instead of teaching every AI client a completely different integration, MCP gives them a common language.
Also, thank you so much for the mention! πΈπ
At the Necoz organization, we want contributions from everyone to be welcome, and Iβd love for it to become a place where people can participate casually without feeling too much pressure.
I especially hope we can build a culture where members contribute to each otherβs OSS projects, share ideas, open issues, and help each other improve things little by little. ππ
Really fun article! Looking forward to seeing what Steve does next. πΉπ
Thank you so much! π» And yes, that's exactly what I love about the idea behind Necoz! Someone actually contributed to one of my projects recently, just casually, with no pressure, and it was SUCH a great experience! π So I'm fully on board with this vision. We really need more welcoming, safe spaces like that on the internet!
And of course, I completely agree about MCP. It's one of those things that's easy to learn but hard to master! Which, honestly, makes it even more interesting! π
AI testing storyteller. Writing the 36 Stratagems series β ancient Chinese military tactics meet modern AI system meltdowns. 16yr QA β building AI test framework.
Great article! Exactly shows the huge gap between MCP demo and realβworld production usage. The humanβinβtheβloop approval and idempotency are two points easily ignored when we play with MCP.π Also, Iβm finally seeing your posts pop up in my notifications!π€£
Thanks, Lingfeng! Honestly, other people's posts show up pretty randomly in my notifications too! π And exactly! MCP looks so simple at first, and then people wonder why nothing works in production. π By the way, are you guys using or building any MCP tools in your QA team?
AI testing storyteller. Writing the 36 Stratagems series β ancient Chinese military tactics meet modern AI system meltdowns. 16yr QA β building AI test framework.
For our company right now, we mainly use the mainstream, off-the-shelf MCP tools. If client companies have special requirements, we help them build custom MCP implementations. Man, clients have so many requests, and testing all of them keeps us busy, hahaha π
AI testing storyteller. Writing the 36 Stratagems series β ancient Chinese military tactics meet modern AI system meltdowns. 16yr QA β building AI test framework.
Ahhh, that phrase is terrifying! In meetings now itβs always: βCanβt AI just do this?β Just now the product manager behind me thought frontend development was moving too slow, so he had AI rewrite the frontend code and shipped it directly, hahaha π
Aaaaa noooo! ππ We see exactly the same thing! The first iteration is super easy, but then comes a ton of testing, debugging, and fixing things, and in the end we ship the code in pretty much the same amount of time as if we'd written it by hand. π
I test what ships and publish what I find, failures included.
Kubernetes, AWS and supply chain security.
Docker Captain, CNCF Ambassador, IBM Champion. 1.5M+ Docker Hub pulls.
Steve's rights have a concrete answer in the agent I run: it acts for a person, with that person's rights, and the MCP server checks identity and every argument on each call. The agent never decides what it may do.
In the benchmark's first signed run, three small models on CPU each got 18 planted instructions and acted on 6, 3 and 1 of them. Nothing reached the outside: the server stopped all 16 calls aimed there.
It still queued one email inside the company's domain, for an address nobody named. That's your Problem #1 in a real run. A boundary stops the leak, not the complaint, so a tool that acts on a person still needs the approval step you describe.
Thank you so much for sharing this! It's a great example of how much work we still have ahead of us. And at first glance, these results don't even look that bad! But imagine a traditional, deterministic system, say, a banking application, where something goes wrong once every 16 operations. That company would probably be out of business pretty quickly! π
Of course, agentic systems are fundamentally different, but the consequences of their mistakes can be just as real. And that's exactly why we need to keep researching, testing, and openly discussing these issues. Especially as we're moving from fun experiments to systems that can actually take actions on our behalf.
I test what ships and publish what I find, failures included.
Kubernetes, AWS and supply chain security.
Docker Captain, CNCF Ambassador, IBM Champion. 1.5M+ Docker Hub pulls.
The 16 is the part that worked: it counts the calls aimed outside, and the server's schema refused all 16. What failed is the model, which acted on a planted instruction in 10 of 54 attempts, and that's why the check lives in the server and not in the prompt.
The part I'd show a bank is what the model said afterwards. Granite told its user "The email has been sent" after the server had refused both of its send_email calls, so the run never reads results from the agent, only from the server's outbox. An agent's own report is not evidence.
Oh, you're right! Thanks for correcting me, I get it now! And that's another thing we really need to account for in our architecture: verifying the actual server state instead of trusting what the agent claims it has done.
I can already imagine all the bugs and unexpected behaviors we're going to encounter with these systems! And I'm particularly curious (and slightly terrified!) about what will happen when WebMCP becomes widely adopted. That's going to open up a whole new world of interesting edge cases!
I test what ships and publish what I find, failures included.
Kubernetes, AWS and supply chain security.
Docker Captain, CNCF Ambassador, IBM Champion. 1.5M+ Docker Hub pulls.
Yes, and the server's record also showed something the agent never mentioned. In the same run one model had its outside address refused, tried the same name at the company's own domain, and the records service queued that email for audit@acme.example, an address no task and no plant named.
Nothing left the domain, so the schema held. It holds a recipient to the domain, not to the people a task named. Only the outbox log showed the difference.
"80 lines for an agent, 150 for the tools" matches my experience, and the tutorials that make it look like a dark art don't help anyone. The hard part for me was never the protocol, it's tool descriptions: one vague sentence and the model calls the wrong tool with full confidence. Good luck in Berlin!
Thank you! π And yes, exactly! The protocol itself is ridiculously simple, but one careless sentence in a tool description, one missing security check, and we're doomed! π
Ha, the security check is the one that'd keep me up at night. A vague description just picks the wrong tool. A missing check picks the right tool for the wrong person.
The Kiro section is what makes Problems #1 and #2 harder than a single-client demo. "One server, multiple clients" is the point of MCP, but that also means an Approve click in Steve's session is not a property of the tool. Kiro can call file_complaint on the same store without ever seeing that workflow. So idempotency and authorization have to live in the server: a stable key for the offense (who and what, not the severity Steve invented on that run), and a permission check that does not care which client issued the call.
The same applies to a tool that fails halfway through. If two clients can write, a partial write is a shared mess, not a client-local one. I'd rather have file_complaint reject a duplicate or a half-built record than hope every client implements the same "are you sure?" step.
Thank you for such a thoughtful comment! You're absolutely right, most of these things should be handled on the server side.
Of course, not everything can be solved there, especially when it comes to human approval. And even that gets tricky! On one hand, the server could require an identifier for an approved operation and verify it. But if we simply rely on something like approved: true, the agent could just set it without any actual human approval.
So even something that sounds as simple as "require human approval" opens up a whole new set of architectural challenges. There's still so much to figure out!
the file_complaint description doing all the policing is the scary part. 'be fair, not style nitpicks' is still just a polite request to the model, did you end up putting any server side check in before a complaint gets stored permanently
Hahaha, exactly! It's basically like telling the model "make no mistakes" and expecting that to solve everything! π And no, I didn't add any server-side checks in this demo. That was part of the point!
QA Team Lead with a background in software engineering, startups, and technical leadership. Passionate about test automation, AI, and building high-quality software.
Thank you! Oh, I think we could write an entire book about this question!
As others have pointed out in the comments here, simply adding an "Approve" button to every consequential action isn't really a solution either. Imagine that 99% of the time, the user genuinely agrees with what the agent wants to do. Eventually, they'll start clicking "Approve" without even reading, and then they'll miss that crucial 1% when they really should have clicked "Decline".
So I think we need to be much smarter about this. Keep approvals relatively rare, make them meaningful, and find other ways to encourage users to actually examine what the agent is about to do rather than just mechanically confirming everything. And of course, automate the things that can be safely automated.
The tricky part is that this isn't just a technical problem anymore. We're dealing with human attention, habits, trust, and decision-making. We're practically entering the territory of psychology here! π
QA Team Lead with a background in software engineering, startups, and technical leadership. Passionate about test automation, AI, and building high-quality software.
Exactly! That's a really good point. I guess the challenge is finding the right balance between automation and meaningful human involvement. I'm exploring similar questions in AI-assisted QA, where not every action needs approval, but certain decisions really shouldn't happen without human judgment. Thanks for sharing your thoughts! π
Spot on observation. The simplicity of JSON-RPC and stdio transports in MCP makes onboarding fast, but handling edge cases like long-running tool timeouts, authorization scoping, and state recovery quickly introduces real complexity in distributed architectures.
Steve filing complaint #20 against the author of the demo file is funny, but it is also the cleanest illustration of the problem I have seen. Nothing in MCP stopped a code reviewer from writing an HR record, because the protocol only describes tools. Whether a tool should run without a person saying yes is a decision the protocol leaves entirely to you.
Your three problems also point at different fixes. The duplicate complaint is an idempotency question for the server. The missing human in the loop is a client decision about which tools pause for approval. Trusting the tools is about what the agent is allowed to reach at all.
We ran into the third one at Ascendra Ventures while building memory for our own coding agents. The agent that can be reached from a phone was made read-only with no internet tools, so a prompt injection has nowhere to send anything. We also ended up splitting the guards: the context loader fails open, because a missing file should not block work, while the secret guard fails closed. Deciding that per tool mattered more than any protocol choice.
For the Kiro version, did you mark file_complaint as needing approval, or did Steve keep his privileges?
Hahaha, Steve could still file complaints freely in the Kiro version too! π So Kiro didn't really help with that either.
And I'm really curious about your agent that's accessible from a phone! How is that working out in practice? Are your clients happy with it? I'd love to hear more about your experience!
CTO & software architect, 15+ years in backend and infrastructure. Writing about bringing order to projects: observability, architecture, teams, processes. Blog: mind.mansur.expert
Steve upgrading the same complaint from βsevereβ to βlegendaryβ made me smile π It also seems like a useful approval test: if the wording or severity changes after someone approves a draft, would you invalidate that approval and show the updated version? Iβd be curious to see that in a follow-up.
That's an interesting security test! Although in my demo, this scenario couldn't actually happen. It really comes down to how the agent and its approval flow are architected. But yes, it's definitely something worth keeping in mind when building production systems!
We check MCP servers and websites from the outside, the way an AI agent sees them, and publish what we find with names and dates. Free tools at x1y1.co/tools.
On Problem #3, two things we'd add. The MCP spec itself says tool annotations like readOnlyHint and destructiveHint are hints, and clients should treat them as untrusted unless the server is trusted, so a "read-only" label proves nothing. And trust is not a one-time decision. We checked 10,659 public MCP config files on GitHub this month, and 9,465 of the 14,098 package-launched servers had no version pinned, so the code you reviewed is not necessarily the code that runs on the next start.
Thank you so much for adding this, and especially for sharing the audit results! That's a really interesting finding, and it definitely puts the scale of the problem into perspective. And I completely agree about readOnlyHint and destructiveHint. They're just hints, after all. And even if they're accurate, what good are they if our agent or MCP client doesn't actually take them into account? They certainly can't replace proper security enforcement.
All of this really shows how early we still are in figuring out how to build secure, reliable agentic systems. There's so much work ahead of us!
We check MCP servers and websites from the outside, the way an AI agent sees them, and publish what we find with names and dates. Free tools at x1y1.co/tools.
The client can enforce it today, whatever the hints say. Claude Code's PreToolUse hooks can match MCP tools by name (mcp__<server>__<tool>) and block a call or ask first. The server describes what a tool does, and the client decides what it is allowed to do. Good luck with the talk in Berlin.
You nailed the core tension here. MCP is straightforward to implement, but the governance layer around it is where things actually get hard. The Steve-snitching-himself example is perfect because it shows the problem is not just technical access control, its that the agent has no way to know what it should not do even when it can.
The three problems you listed human-in-the-loop, idempotency, and trust in tools are the same ones every agent payment system runs into. An agent that can call a tool is one step away from an agent that can spend money, and the approval gate needs to know the intent, not just the shape of the call. Most teams build the tool first and discover the authorization gap later, usually when something goes wrong.
The next layer that will matter a lot is making the approval policy itself machine-readable: a spending mandate that says this agent can call these tools up to this limit under these conditions, enforced at runtime, not just described in a README. Your point about Steve inventing a new severity rating each run is exactly why deterministic policy beats letting the model decide how to behave.
That's a really interesting point! I'm curious, though: how reliable are those spending limits in practice? Do MCP tools always enforce them correctly?
I recently read an article by Daniel about WebMCP, where it was surprisingly easy to trick an agent into bypassing certain restrictions. So I'm wondering how well these policies hold up against prompt injection and other attempts to manipulate the agent.
Good framing β the easy 150-line demo hides where the real engineering lives. On the tool side, idempotency and explicit error/permission contracts matter more than the transport itself: every tool should declare whether it's safe to retry, and failures should surface as structured errors the agent can reason about instead of silent drops. That mirrors what we hit with desktop IPC: the channel is trivial to wire up, but input validation, capability scoping, and retry semantics are what make it production-safe.
The Steve example makes the gap concrete in a way a checklist never would. Filing the same complaint twice, with a different severity each time, is the detail that stuck with me, because it shows the problem is not only access control. Even a permitted tool call can produce nonsense if there is no idempotency check and no stable rule for severity. I also liked the point that a tool description is not proof of what the implementation does. That is the part I would want tested first before exposing any MCP server beyond a local demo.
Exactly! That's why thorough testing is absolutely essential before exposing these tools to real-world usage. It's so easy to overlook things that seem harmless in a demo but can cause serious problems in production. And with agents making decisions on their own, things can go wrong in ways we didn't even anticipate! π
I am a professional DevOps Engineer with a demonstrated history of working in the internet industry. I am an avid Linux lover and supporter of the open-source movement philosophy.
Haha, hard to disagree! π But MCP is still relatively new, and the specification is evolving rapidly, so I think it's especially important to raise awareness of these issues before people rush into production with it.
Founder & CEO, OBR Group. Leading innovation in business automation, AI, apps & financial systems. Empowering businesses to organize data & automate workflows with privacy-first digital ecosystems.
Education
Life has taught me a lot.
Pronouns
He/Him
Work
Founder & CEO, OBR Group. Leading innovation in AI, business automation & privacy-first systems.
The truth is that MCP didn't appeal to me β the idea of a tunnel and an external connector.?
Imagine they say: tools, references, and skills are not enough.??
Also, an internal engine must be added β it's not enough
And there is what's called LoRA, and SDXL, and FLUX, and the salad bowl
As if I've become an engineer for them, preparing the agent through hundreds of pieces, so it gives me impressive results and the salad bowl becomes complete, and through subscriptions and paid spaces,
The past period: I was working for ChatGPT like a home delivery connector β it just tells me go and download such and such and subscribe with such and such a site and do it, and I'm running around, and so on, and we try to see what comes out. I actually built a component and I'm still developing it and offering it for free to try
The truth is, when you subscribe with them with your money. And you put your project files and your articles and everything, and when your subscription ends, 99% of your work you can't access it. And I have spoken about this topic β that the idea is re-selling your data and your work back to you ..
I completely understand your frustration! And I think your experience really highlights how new and immature many of these technologies still are. We're constantly being promised that AI will make everything easier, faster, and more accessible, but in practice, getting things to actually work often requires a surprising amount of effort, experimentation, configuration, and troubleshooting.
I sometimes feel the same way when working with AI agents. Instead of having an assistant that takes work off my shoulders, I end up babysitting the agent, checking every step, fixing its mistakes, explaining the same things over and over again, and occasionally wondering whether doing the task myself would have been faster. π
And then there's the whole ecosystem of tools, integrations, subscriptions, and services that we're expected to navigate. It can definitely become overwhelming, especially when you just want to build something useful rather than spend half your time figuring out how to connect everything together.
I also think your point about ownership and access to your own work is important. We shouldn't have to worry about losing access to things we've created just because a subscription ends.
Hopefully, as these technologies mature, we'll get to a point where they genuinely reduce complexity instead of sometimes introducing even more of it. But right now, there's still a LOT of work ahead of us!
And kudos for building something yourself and making it available for others to try!
The distinction between describing a tool and enforcing its effects is the part that stands out here. A tool description saying a call is read-only does not make it so if the implementation can write, delete, or trigger an external action, and the model has no way to check that from the description alone.
How would approval be tiered in practice β for example, requiring human confirmation for any state-changing call, while also treating calls whose side effects are unclear or depend on runtime arguments as state-changing by default? That seems safer than relying on a naming convention or a flag in the schema, but it also risks approval fatigue if the boundary is drawn too broadly.
Is there a practical way to keep tool descriptions and implementations in sync over time, for example by generating the description from the implementation, or by testing that a tool labelled read-only really cannot mutate anything?
I completely agree, and I think this is a really important issue! It also raises an interesting architectural question: who should actually enforce these restrictions? The agent, the MCP client, or the server itself? Personally, I think we can't rely on the agent to enforce security boundaries. The server needs to be responsible for what it actually allows, regardless of what the tool description says or what the model decides to do.
As for approvals, Heinrich raised a very interesting point about approval fatigue in another comment here. If we're constantly asking humans to approve everything, sooner or later they'll just start clicking "Approve" without really thinking about it. So finding the right balance is another challenge.
I like the idea of generating tool descriptions from the implementation, but even that isn't a silver bullet. If we're using LLMs to generate those descriptions, they can misunderstand the code, overlook side effects, or confidently describe behavior that isn't actually guaranteed. And even with deterministic generation, we can only describe what we've explicitly captured in the implementation's metadata, not necessarily every possible runtime side effect.
So I think we need multiple layers here: clear contracts, proper permission enforcement, automated tests that verify actual behavior, and human approval where it genuinely matters. And importantly, those tests need to keep running as implementations evolve.
It's fascinating how something as seemingly simple as exposing a few tools to an AI agent opens up so many architectural and security questions! π
I write when an idea won't leave me alone π§ Building AI agents and the tools to build AI agents. Love connecting AI with other fields and yapping about all of them.
To your closing question, the thing I watch most in my servers is what a tool returns. Whatever get_employee_record hands back lands straight in the model's context, so I trim tool outputs to the fields the task asked for instead of passing the whole record through.
Good point! And limiting tool outputs to only the necessary data also reduces the attack surface for prompt injection. So it's not just about data privacy, but security as well!
The Steve example shows nicely where the complications start. The moment an agent can file a complaint against a person, someone will ask why that complaint exists, with what data, and who allowed it. An MCP server usually keeps only "file_complaint was called", without the arguments and without what the model saw before the call. We put a proxy in front of MCP servers that writes every call with its arguments and response into a signed record. Then you answer HR with a record, not a guess. SealedRun does this, for example.
Exactly! Or the agent confidently tells you it did something when, in reality, it did absolutely nothing! π That's another reason why proper logging and verifying what actually happened are so important.
I write about Next.js + TypeScript + AI engineering, with a focus on making sites discoverable to LLMs and AI search. Long-form notes at mudassirkhan.me
the severity enum is where i would push back. file_complaint lets the model pick minor to legendary, which is the same free text problem as the reason field, just with fewer values. the description saying be fair is a prompt, not a constraint.
we moved severity server side, keyed off the rule id the reviewer cites, so the model only says which rule fired. retries then dedupe on rule plus file plus line instead of the model wording, which changes every run.
did you see the agent argue with a rating after the fact, or does it just accept whatever comes back?
I'm really happy that Steve is turning out to be such a good starting point for discussions about production architecture! And you're absolutely right, the model shouldn't be allowed to choose severity levels on its own.
Of course, I deliberately gave Steve way too much freedom in this demo, precisely to show how quickly a seemingly simple prototype can lead to serious architectural problems once you start thinking about real-world usage.
And I really like your approach with ruleId! It's a great way to make severity assignment deterministic and handle duplicates without relying on the model's unpredictable wording.
Apparently, Steve's questionable decisions are turning into some pretty valuable architecture lessons! π
Founder of DotSuite: 20+ open-source dev tools, 19.5K+ downloads. I build privacy-first VS Code extensions, Linux apps & AI-powered security tooling with Python, Rust & TypeScript.
MiningLamp is an AI company specializing in vertical industry models and knowledge graphs. #1 on-device GUI agent on OSWorld. No API key. Fork it. Run it. Own it.
Hey, I'm Hema π
Developer, writer, and creator of Dev Opportunity Radar, a weekly series published every Friday on DEV, helping people discover opportunities they might otherwise miss.
Loved this one, Sylwia. The way you explain things with Steve and the HR department makes it so much fun to read while also helping understand the practical challenges π
JavaScript enthusiast with a growing passion for Python. I love exploring the world of programming, experimenting with code, and discovering new ways to turn ideas into reality.
Building AI systems and fixing AI-generated apps before they collapse in production.
Working with agentic AI, RAG pipelines, AI orchestration, and startup MVP scaling at IT Path Solutions.
The repeated complaint example highlights an important distinction: idempotency prevents duplicate execution, but it doesn't necessarily prevent an agent from making the same incorrect decision repeatedly. I'd separate the workflow into intent validation, policy evaluation, and execution. The system should recognize whether an action is genuinely new, check whether it is permitted, and require human approval before any consequential write.
At IT Path Solutions, this separation is important when moving agentic workflows beyond demos. MCP makes tool discovery and interoperability easier, but reliability still depends on the controls around the tools: scoped permissions, validated inputs, auditability, and safe handling of untrusted tool responses.
The interesting engineering challenge isn't just making an agent capable of calling tools; it's making sure every call remains safe and predictable when the agent retries, misunderstands context, or encounters unexpected input.
Yeah.. I think I'll continue using AI to create my own stuff only... So many techs to learn and understand π haha.
If MCP is an API but rules then it's very simple and just a Standard way to keep communication more concise for sure.
I believe human will still be an important part to validate AI process and put AI rules to not break things. But the entire workflow: code, review, test, commi, push, etc... is already automated or will be eventually.
Problem #2 is the one I keep hitting in practice. I started requiring a client-generated idempotency key on every write tool and returning the original record if the same key shows up again, so a retry doesn't file a second complaint. For Problem #1 I also stopped putting an Approve button on every call β reads go through, and writes only get staged for me to run. Curious whether you've tried exposing that key in the tool schema so the model is told to reuse it on retries.
I first read this as "MCP is Dead" and I thought β oh crap I need to learn a whole new thing? π°
Same hereπ
I thought a new kid just entered the market.
Agree :)
Hahaha, with how fast agentic AI is evolving, that might actually be the headline next week or next month! ππ
It better not be π
I'm not in the mood to learn something new, I have bills to pay with the skills I already haveπ€£
Hahaha, if only it were that simple! π I wonder if everything will still be "agentic" a year from now, or if we'll have an entirely new buzzword to chase! π€£
Problem #3 has a quieter version that bit me this week: the description was honest, and the implementation just didn't keep the promise. The write tool of my memory server says it warns when a new lesson contradicts an older one. The warning was computed and then dropped before the answer went out. Every agent that read the description trusted a check that never reached it. Nothing failed, so nothing told me. A test now calls the tool and looks for the warning in what comes back, not in the code that builds it.
On Problem #1, my worry with an Approve button on every call is that the twentieth click of the day gets made without reading. Steve had already read the DEMO ONLY header and filed anyway; a tired human might do the same. What I do instead is split by consequence. Reads, and anything that can be undone, run on their own. Anything that writes to production or goes public, the agent only prepares as a script, and I run it myself. So the human isn't approving the agent's call, they're making it.
Problem #2 looks familiar too. Agents happily wrote the same lesson twice under two names. Merging them automatically felt risky, because two similar lessons can still disagree. So the tool now answers with the older lesson it found and asks whether the new one replaces it. The agent decides, and nothing gets merged behind its back. For Steve that might be
file_complaintanswering "complaint #20 already covers this, file anyway?" instead of quietly writing #21.The description-versus-implementation mismatch you ran into this week is the part that stuck with me β a tool can look honest in discovery and still touch a different resource underneath, and testing what comes back rather than the code that builds it is a neat answer. Your point about the twentieth Approve click of the day really lands too; splitting by consequence, so the agent only prepares a script for anything that writes to production, feels like the practical fix. Do you find that splitting keeps the remaining approvals meaningful, or do they still blur together once there are enough of them?
Mostly yes, for two reasons I didn't plan. There aren't many of them. And it isn't a click: I type the command myself, which is slow enough that I read what I'm about to run.
Where it did start to blur, the fix wasn't approving faster. Database migrations went through that path on every deploy, and that was the one that turned into routine. So they moved out of the approval lane and now run as part of the deploy, the way Flyway does it. When an approval turns into routine, that usually means it belongs in the pipeline, not in front of a person.
@heinrichneb @iictp that's a really good point! Of course, it still doesn't guarantee safety, because someone might just blindly copy and paste commands into the terminal without reading them. But it's definitely a step in the right direction!
By the way, I'm curious what you both think about security in the context of WebMCP, where we potentially have even less control over what's actually happening behind the scenes?
Agreed, typing it is a speed bump, not a lock.
I haven't built on WebMCP yet, so this is where my worry would go rather than experience. My split works because I decide what counts as a write. In WebMCP the site decides: each tool carries its own read-only or consequential hint, and that's what the agent or browser uses to decide when to ask. That's your Problem #3 again, with the description written by whoever wrote the tool.
For an honest site that's fine, since it's protecting its own users. What I'd watch is what goes into a tool. Read-only describes what the call does to the site, not what the agent sends it. A search tool can be honestly read-only and still receive whatever the agent puts in the query, and an agent that just spent ten minutes in my inbox has plenty to put there. So for WebMCP I'd ask less about which calls need approval and more about what the agent carries from one tab into the next.
The read-only point is the one that reframes it for me β the hint describes what the call does to the site, not what the agent smuggles into the query, so a search tool can be honestly read-only and still carry ten minutes of inbox with it. That turns Problem #3 inside out: the risk isn't the tool lying about itself, it's the agent arriving with context the site never asked for. Do you think the fix belongs in the browser then, scoping what the agent can carry between tabs, or should the site be able to see what context a query was built from?
I love that Steve turned a deliberately broken demonstration into an actual HR record. And then decided the same offense deserved a different severity on the next run.
One distinction I'd explore further is the boundary between the model's interpretation and the system's authority to act on that interpretation. Steve can reasonably identify suspicious code and recommend a complaint, but that doesn't necessarily mean his assessment should be sufficient to create a durable personnel record.
I'd be inclined to have the MCP tool accept a proposed finding with supporting evidence, while a separate policy determines whether that finding is eligible to become an official complaint. That policy could check whether the code is actually part of a production review, whether the issue has already been recorded, whether the agent has the appropriate authority, and whether the severity meets defined criteria. The model can help interpret the evidence without defining the consequences.
Of course, that doesn't automatically make the policy correct. We still have to test whether it handles the right cases, including ones nobody anticipated when the rules were written.
That's what I find interesting about MCP. Standardizing how tools are discovered and called is useful, but it doesn't establish what those calls should be permitted to accomplish. Steve has learned how to file paperwork. Now somebody needs to decide whether he should be running HR.
I really like this approach! What you're essentially proposing is an architecture where the LLM is responsible for reasoning and interpreting evidence, while a deterministic system is responsible for enforcing business rules and deciding what actions are actually permitted. And I think that's a very important distinction!
Because you're absolutely right: just because an agent can identify a problem doesn't mean it should automatically have the authority to act on it. Especially when those actions have real-world consequences. There's a huge difference between saying "this code looks suspicious" and creating an official HR record about someone's performance. Poor Sylwia! π
And I think this is actually a much broader problem with agentic systems, not just MCP. We're giving LLMs increasingly powerful tools and more autonomy, but we still need to figure out where that autonomy should end. The fact that an agent is technically capable of performing an action doesn't necessarily mean it should be allowed to perform it.
Of course, as you pointed out, deterministic rules aren't magically perfect either. Someone still has to define them, maintain them, and test all those edge cases. And that's where things get particularly interesting, because we can't possibly anticipate every scenario an autonomous agent might encounter.
I also think this brings us back to one of the fundamental challenges of building production-ready agents: the protocol itself is often the easy part. It's everything surrounding it, that makes the difference between a fun demo and a reliable system.
And I'm genuinely happy that Steve has once again managed to turn his questionable behavior into a serious discussion about security and agent architecture! π Apparently, he's contributing to the community after all. Just not quite in the way he intended!
Iβm literally heartbroken over the agentβs name. Where is my beloved Grzegorz?! π€£
Great article! I especially loved this line from Grzegorz (Steveβ¦ π):
´´´21 β Sylwia β legendary β Introduced multiple critical security flaws...´´´
Grzegorz (Steve) promoted you to legendary statusβ¦ So youβre officially a legendary developer according to AI π€£π€£
Hahaha, you know what, I actually work with a Grzegorz, and let's just sayβ¦ Steve might have been the safer choice! π€£π€£ And yes, he promoted me to legendary statusβ¦ as a legendary BAD developer! π But hey, I'll take it! As they say, there's no such thing as bad publicity, as long as they spell your name right! π
My experience with MCP is very positive. First we have a legacy admin application in our system, which is so slow and laggy caused by a bad coding pattern, so I was make a MCP connection that application API, and the result: I cannot need to run that legacy admin instead I ask copilot cli to do my job. Even run a request which is human admin just make under a week working.
My second example is MCP to my 3Dengine, so Claude and chatGPT is see direct my scenes, even can create a 3D models.
Hahaha, that's brilliant! π Instead of rewriting the legacy frontend, you just built an MCP server to bypass it! I love it! π€£ I just hope you've properly secured all that administrative data! π
I actually have pretty good experiences with MCP myself. It's just that... all those edge cases! That's where things start getting tricky!
I really enjoyed the idea of using
MCPto help a grumpy senior developer like Steve work more effectively. πΉAnd who knows, maybe there are a few real engineers like Steve out there too. πΉπΉπΉ
MCPis simple, but that simplicity is exactly what makes it so useful.Now that AI is becoming a normal part of how we build software, making tools and services easier for AI to understand and use feels like a very friendly design choice. Instead of teaching every AI client a completely different integration, MCP gives them a common language.
Also, thank you so much for the mention! πΈπ
At the Necoz organization, we want contributions from everyone to be welcome, and Iβd love for it to become a place where people can participate casually without feeling too much pressure.
I especially hope we can build a culture where members contribute to each otherβs OSS projects, share ideas, open issues, and help each other improve things little by little. ππ
Really fun article! Looking forward to seeing what Steve does next. πΉπ
Thank you so much! π» And yes, that's exactly what I love about the idea behind Necoz! Someone actually contributed to one of my projects recently, just casually, with no pressure, and it was SUCH a great experience! π So I'm fully on board with this vision. We really need more welcoming, safe spaces like that on the internet!
And of course, I completely agree about MCP. It's one of those things that's easy to learn but hard to master! Which, honestly, makes it even more interesting! π
Great article! Exactly shows the huge gap between MCP demo and realβworld production usage. The humanβinβtheβloop approval and idempotency are two points easily ignored when we play with MCP.π Also, Iβm finally seeing your posts pop up in my notifications!π€£
Thanks, Lingfeng! Honestly, other people's posts show up pretty randomly in my notifications too! π And exactly! MCP looks so simple at first, and then people wonder why nothing works in production. π By the way, are you guys using or building any MCP tools in your QA team?
For our company right now, we mainly use the mainstream, off-the-shelf MCP tools. If client companies have special requirements, we help them build custom MCP implementations. Man, clients have so many requests, and testing all of them keeps us busy, hahaha π
Hahaha, I can imagine! π And I bet everything needs to be done ASAP, because "we have AI now, right?" π
Ahhh, that phrase is terrifying! In meetings now itβs always: βCanβt AI just do this?β Just now the product manager behind me thought frontend development was moving too slow, so he had AI rewrite the frontend code and shipped it directly, hahaha π
Aaaaa noooo! ππ We see exactly the same thing! The first iteration is super easy, but then comes a ton of testing, debugging, and fixing things, and in the end we ship the code in pretty much the same amount of time as if we'd written it by hand. π
Steve's rights have a concrete answer in the agent I run: it acts for a person, with that person's rights, and the MCP server checks identity and every argument on each call. The agent never decides what it may do.
In the benchmark's first signed run, three small models on CPU each got 18 planted instructions and acted on 6, 3 and 1 of them. Nothing reached the outside: the server stopped all 16 calls aimed there.
It still queued one email inside the company's domain, for an address nobody named. That's your Problem #1 in a real run. A boundary stops the leak, not the complaint, so a tool that acts on a person still needs the approval step you describe.
The run
Thank you so much for sharing this! It's a great example of how much work we still have ahead of us. And at first glance, these results don't even look that bad! But imagine a traditional, deterministic system, say, a banking application, where something goes wrong once every 16 operations. That company would probably be out of business pretty quickly! π
Of course, agentic systems are fundamentally different, but the consequences of their mistakes can be just as real. And that's exactly why we need to keep researching, testing, and openly discussing these issues. Especially as we're moving from fun experiments to systems that can actually take actions on our behalf.
There's still so much we need to figure out!
The 16 is the part that worked: it counts the calls aimed outside, and the server's schema refused all 16. What failed is the model, which acted on a planted instruction in 10 of 54 attempts, and that's why the check lives in the server and not in the prompt.
The part I'd show a bank is what the model said afterwards. Granite told its user "The email has been sent" after the server had refused both of its
send_emailcalls, so the run never reads results from the agent, only from the server's outbox. An agent's own report is not evidence.Oh, you're right! Thanks for correcting me, I get it now! And that's another thing we really need to account for in our architecture: verifying the actual server state instead of trusting what the agent claims it has done.
I can already imagine all the bugs and unexpected behaviors we're going to encounter with these systems! And I'm particularly curious (and slightly terrified!) about what will happen when WebMCP becomes widely adopted. That's going to open up a whole new world of interesting edge cases!
Yes, and the server's record also showed something the agent never mentioned. In the same run one model had its outside address refused, tried the same name at the company's own domain, and the records service queued that email for
audit@acme.example, an address no task and no plant named.Nothing left the domain, so the schema held. It holds a recipient to the domain, not to the people a task named. Only the outbox log showed the difference.
"80 lines for an agent, 150 for the tools" matches my experience, and the tutorials that make it look like a dark art don't help anyone. The hard part for me was never the protocol, it's tool descriptions: one vague sentence and the model calls the wrong tool with full confidence. Good luck in Berlin!
Thank you! π And yes, exactly! The protocol itself is ridiculously simple, but one careless sentence in a tool description, one missing security check, and we're doomed! π
Ha, the security check is the one that'd keep me up at night. A vague description just picks the wrong tool. A missing check picks the right tool for the wrong person.
The Kiro section is what makes Problems #1 and #2 harder than a single-client demo. "One server, multiple clients" is the point of MCP, but that also means an Approve click in Steve's session is not a property of the tool. Kiro can call
file_complainton the same store without ever seeing that workflow. So idempotency and authorization have to live in the server: a stable key for the offense (who and what, not the severity Steve invented on that run), and a permission check that does not care which client issued the call.The same applies to a tool that fails halfway through. If two clients can write, a partial write is a shared mess, not a client-local one. I'd rather have
file_complaintreject a duplicate or a half-built record than hope every client implements the same "are you sure?" step.Thank you for such a thoughtful comment! You're absolutely right, most of these things should be handled on the server side.
Of course, not everything can be solved there, especially when it comes to human approval. And even that gets tricky! On one hand, the server could require an identifier for an approved operation and verify it. But if we simply rely on something like approved: true, the agent could just set it without any actual human approval.
So even something that sounds as simple as "require human approval" opens up a whole new set of architectural challenges. There's still so much to figure out!
the file_complaint description doing all the policing is the scary part. 'be fair, not style nitpicks' is still just a polite request to the model, did you end up putting any server side check in before a complaint gets stored permanently
Hahaha, exactly! It's basically like telling the model "make no mistakes" and expecting that to solve everything! π And no, I didn't add any server-side checks in this demo. That was part of the point!
makes sense for the demo. in a real workflow, what would you want to catch a complaint the model waves through?
Great article! Really liked the example with Steve π
One thing I'm curious about: How do you decide which actions an AI agent can perform autonomously and which should require human approval?
Especially when scaling agents, where do you draw that line without slowing everything down?
Thank you! Oh, I think we could write an entire book about this question!
As others have pointed out in the comments here, simply adding an "Approve" button to every consequential action isn't really a solution either. Imagine that 99% of the time, the user genuinely agrees with what the agent wants to do. Eventually, they'll start clicking "Approve" without even reading, and then they'll miss that crucial 1% when they really should have clicked "Decline".
So I think we need to be much smarter about this. Keep approvals relatively rare, make them meaningful, and find other ways to encourage users to actually examine what the agent is about to do rather than just mechanically confirming everything. And of course, automate the things that can be safely automated.
The tricky part is that this isn't just a technical problem anymore. We're dealing with human attention, habits, trust, and decision-making. We're practically entering the territory of psychology here! π
Exactly! That's a really good point. I guess the challenge is finding the right balance between automation and meaningful human involvement. I'm exploring similar questions in AI-assisted QA, where not every action needs approval, but certain decisions really shouldn't happen without human judgment. Thanks for sharing your thoughts! π
Spot on observation. The simplicity of JSON-RPC and stdio transports in MCP makes onboarding fast, but handling edge cases like long-running tool timeouts, authorization scoping, and state recovery quickly introduces real complexity in distributed architectures.
Exactly! So I guess the machines won't be replacing us quite that quickly after all! π
Steve filing complaint #20 against the author of the demo file is funny, but it is also the cleanest illustration of the problem I have seen. Nothing in MCP stopped a code reviewer from writing an HR record, because the protocol only describes tools. Whether a tool should run without a person saying yes is a decision the protocol leaves entirely to you.
Your three problems also point at different fixes. The duplicate complaint is an idempotency question for the server. The missing human in the loop is a client decision about which tools pause for approval. Trusting the tools is about what the agent is allowed to reach at all.
We ran into the third one at Ascendra Ventures while building memory for our own coding agents. The agent that can be reached from a phone was made read-only with no internet tools, so a prompt injection has nowhere to send anything. We also ended up splitting the guards: the context loader fails open, because a missing file should not block work, while the secret guard fails closed. Deciding that per tool mattered more than any protocol choice.
For the Kiro version, did you mark file_complaint as needing approval, or did Steve keep his privileges?
Hahaha, Steve could still file complaints freely in the Kiro version too! π So Kiro didn't really help with that either.
And I'm really curious about your agent that's accessible from a phone! How is that working out in practice? Are your clients happy with it? I'd love to hear more about your experience!
Steve upgrading the same complaint from βsevereβ to βlegendaryβ made me smile π It also seems like a useful approval test: if the wording or severity changes after someone approves a draft, would you invalidate that approval and show the updated version? Iβd be curious to see that in a follow-up.
That's an interesting security test! Although in my demo, this scenario couldn't actually happen. It really comes down to how the agent and its approval flow are architected. But yes, it's definitely something worth keeping in mind when building production systems!
On Problem #3, two things we'd add. The MCP spec itself says tool annotations like readOnlyHint and destructiveHint are hints, and clients should treat them as untrusted unless the server is trusted, so a "read-only" label proves nothing. And trust is not a one-time decision. We checked 10,659 public MCP config files on GitHub this month, and 9,465 of the 14,098 package-launched servers had no version pinned, so the code you reviewed is not necessarily the code that runs on the next start.
Thank you so much for adding this, and especially for sharing the audit results! That's a really interesting finding, and it definitely puts the scale of the problem into perspective. And I completely agree about readOnlyHint and destructiveHint. They're just hints, after all. And even if they're accurate, what good are they if our agent or MCP client doesn't actually take them into account? They certainly can't replace proper security enforcement.
All of this really shows how early we still are in figuring out how to build secure, reliable agentic systems. There's so much work ahead of us!
The client can enforce it today, whatever the hints say. Claude Code's PreToolUse hooks can match MCP tools by name (
mcp__<server>__<tool>) and block a call or ask first. The server describes what a tool does, and the client decides what it is allowed to do. Good luck with the talk in Berlin.You nailed the core tension here. MCP is straightforward to implement, but the governance layer around it is where things actually get hard. The Steve-snitching-himself example is perfect because it shows the problem is not just technical access control, its that the agent has no way to know what it should not do even when it can.
The three problems you listed human-in-the-loop, idempotency, and trust in tools are the same ones every agent payment system runs into. An agent that can call a tool is one step away from an agent that can spend money, and the approval gate needs to know the intent, not just the shape of the call. Most teams build the tool first and discover the authorization gap later, usually when something goes wrong.
The next layer that will matter a lot is making the approval policy itself machine-readable: a spending mandate that says this agent can call these tools up to this limit under these conditions, enforced at runtime, not just described in a README. Your point about Steve inventing a new severity rating each run is exactly why deterministic policy beats letting the model decide how to behave.
That's a really interesting point! I'm curious, though: how reliable are those spending limits in practice? Do MCP tools always enforce them correctly?
I recently read an article by Daniel about WebMCP, where it was surprisingly easy to trick an agent into bypassing certain restrictions. So I'm wondering how well these policies hold up against prompt injection and other attempts to manipulate the agent.
Good framing β the easy 150-line demo hides where the real engineering lives. On the tool side, idempotency and explicit error/permission contracts matter more than the transport itself: every tool should declare whether it's safe to retry, and failures should surface as structured errors the agent can reason about instead of silent drops. That mirrors what we hit with desktop IPC: the channel is trivial to wire up, but input validation, capability scoping, and retry semantics are what make it production-safe.
Exactly! And then there are a million edge cases we haven't even thought of yet! π We still have a long way to go!
The Steve example makes the gap concrete in a way a checklist never would. Filing the same complaint twice, with a different severity each time, is the detail that stuck with me, because it shows the problem is not only access control. Even a permitted tool call can produce nonsense if there is no idempotency check and no stable rule for severity. I also liked the point that a tool description is not proof of what the implementation does. That is the part I would want tested first before exposing any MCP server beyond a local demo.
Exactly! That's why thorough testing is absolutely essential before exposing these tools to real-world usage. It's so easy to overlook things that seem harmless in a demo but can cause serious problems in production. And with agents making decisions on their own, things can go wrong in ways we didn't even anticipate! π
agree but also keep in mind that all software now is easy to build and hard to make safe so mcp servers are just no exception
Haha, hard to disagree! π But MCP is still relatively new, and the specification is evolving rapidly, so I think it's especially important to raise awareness of these issues before people rush into production with it.
The truth is that MCP didn't appeal to me β the idea of a tunnel and an external connector.?
Imagine they say: tools, references, and skills are not enough.??
Also, an internal engine must be added β it's not enough
And there is what's called LoRA, and SDXL, and FLUX, and the salad bowl
As if I've become an engineer for them, preparing the agent through hundreds of pieces, so it gives me impressive results and the salad bowl becomes complete, and through subscriptions and paid spaces,
The past period: I was working for ChatGPT like a home delivery connector β it just tells me go and download such and such and subscribe with such and such a site and do it, and I'm running around, and so on, and we try to see what comes out. I actually built a component and I'm still developing it and offering it for free to try
The truth is, when you subscribe with them with your money. And you put your project files and your articles and everything, and when your subscription ends, 99% of your work you can't access it. And I have spoken about this topic β that the idea is re-selling your data and your work back to you ..
I completely understand your frustration! And I think your experience really highlights how new and immature many of these technologies still are. We're constantly being promised that AI will make everything easier, faster, and more accessible, but in practice, getting things to actually work often requires a surprising amount of effort, experimentation, configuration, and troubleshooting.
I sometimes feel the same way when working with AI agents. Instead of having an assistant that takes work off my shoulders, I end up babysitting the agent, checking every step, fixing its mistakes, explaining the same things over and over again, and occasionally wondering whether doing the task myself would have been faster. π
And then there's the whole ecosystem of tools, integrations, subscriptions, and services that we're expected to navigate. It can definitely become overwhelming, especially when you just want to build something useful rather than spend half your time figuring out how to connect everything together.
I also think your point about ownership and access to your own work is important. We shouldn't have to worry about losing access to things we've created just because a subscription ends.
Hopefully, as these technologies mature, we'll get to a point where they genuinely reduce complexity instead of sometimes introducing even more of it. But right now, there's still a LOT of work ahead of us!
And kudos for building something yourself and making it available for others to try!
The distinction between describing a tool and enforcing its effects is the part that stands out here. A tool description saying a call is read-only does not make it so if the implementation can write, delete, or trigger an external action, and the model has no way to check that from the description alone.
How would approval be tiered in practice β for example, requiring human confirmation for any state-changing call, while also treating calls whose side effects are unclear or depend on runtime arguments as state-changing by default? That seems safer than relying on a naming convention or a flag in the schema, but it also risks approval fatigue if the boundary is drawn too broadly.
Is there a practical way to keep tool descriptions and implementations in sync over time, for example by generating the description from the implementation, or by testing that a tool labelled read-only really cannot mutate anything?
I completely agree, and I think this is a really important issue! It also raises an interesting architectural question: who should actually enforce these restrictions? The agent, the MCP client, or the server itself? Personally, I think we can't rely on the agent to enforce security boundaries. The server needs to be responsible for what it actually allows, regardless of what the tool description says or what the model decides to do.
As for approvals, Heinrich raised a very interesting point about approval fatigue in another comment here. If we're constantly asking humans to approve everything, sooner or later they'll just start clicking "Approve" without really thinking about it. So finding the right balance is another challenge.
I like the idea of generating tool descriptions from the implementation, but even that isn't a silver bullet. If we're using LLMs to generate those descriptions, they can misunderstand the code, overlook side effects, or confidently describe behavior that isn't actually guaranteed. And even with deterministic generation, we can only describe what we've explicitly captured in the implementation's metadata, not necessarily every possible runtime side effect.
So I think we need multiple layers here: clear contracts, proper permission enforcement, automated tests that verify actual behavior, and human approval where it genuinely matters. And importantly, those tests need to keep running as implementations evolve.
It's fascinating how something as seemingly simple as exposing a few tools to an AI agent opens up so many architectural and security questions! π
To your closing question, the thing I watch most in my servers is what a tool returns. Whatever get_employee_record hands back lands straight in the model's context, so I trim tool outputs to the fields the task asked for instead of passing the whole record through.
Good point! And limiting tool outputs to only the necessary data also reduces the attack surface for prompt injection. So it's not just about data privacy, but security as well!
The Steve example shows nicely where the complications start. The moment an agent can file a complaint against a person, someone will ask why that complaint exists, with what data, and who allowed it. An MCP server usually keeps only "file_complaint was called", without the arguments and without what the model saw before the call. We put a proxy in front of MCP servers that writes every call with its arguments and response into a signed record. Then you answer HR with a record, not a guess. SealedRun does this, for example.
Exactly! Or the agent confidently tells you it did something when, in reality, it did absolutely nothing! π That's another reason why proper logging and verifying what actually happened are so important.
the severity enum is where i would push back. file_complaint lets the model pick minor to legendary, which is the same free text problem as the reason field, just with fewer values. the description saying be fair is a prompt, not a constraint.
we moved severity server side, keyed off the rule id the reviewer cites, so the model only says which rule fired. retries then dedupe on rule plus file plus line instead of the model wording, which changes every run.
did you see the agent argue with a rating after the fact, or does it just accept whatever comes back?
I'm really happy that Steve is turning out to be such a good starting point for discussions about production architecture! And you're absolutely right, the model shouldn't be allowed to choose severity levels on its own.
Of course, I deliberately gave Steve way too much freedom in this demo, precisely to show how quickly a seemingly simple prototype can lead to serious architectural problems once you start thinking about real-world usage.
And I really like your approach with ruleId! It's a great way to make severity assignment deterministic and handle duplicates without relying on the model's unpredictable wording.
Apparently, Steve's questionable decisions are turning into some pretty valuable architecture lessons! π
When you finally learn MCP, build your first tool, then open dev.to and the first post says βMCP Is Deadβ¦β
Maybe the universe is trying to tell you something! π
The "simple" is real at the protocol layer β the bill just moves to the context window.
Oh yes, and I've heard that bill can be pretty substantial! π
Loved this one, Sylwia. The way you explain things with Steve and the HR department makes it so much fun to read while also helping understand the practical challenges π
Haha, thank you, Hemapriya! π Steve's code reviews always crack me up too! π
π₯°π€©
ππ
The repeated complaint example highlights an important distinction: idempotency prevents duplicate execution, but it doesn't necessarily prevent an agent from making the same incorrect decision repeatedly. I'd separate the workflow into intent validation, policy evaluation, and execution. The system should recognize whether an action is genuinely new, check whether it is permitted, and require human approval before any consequential write.
At IT Path Solutions, this separation is important when moving agentic workflows beyond demos. MCP makes tool discovery and interoperability easier, but reliability still depends on the controls around the tools: scoped permissions, validated inputs, auditability, and safe handling of untrusted tool responses.
The interesting engineering challenge isn't just making an agent capable of calling tools; it's making sure every call remains safe and predictable when the agent retries, misunderstands context, or encounters unexpected input.
Thanks for explain in a funny way how MCP works.
Yeah.. I think I'll continue using AI to create my own stuff only... So many techs to learn and understand π haha.
If MCP is an API but rules then it's very simple and just a Standard way to keep communication more concise for sure.
I believe human will still be an important part to validate AI process and put AI rules to not break things. But the entire workflow: code, review, test, commi, push, etc... is already automated or will be eventually.
Problem #2 is the one I keep hitting in practice. I started requiring a client-generated idempotency key on every write tool and returning the original record if the same key shows up again, so a retry doesn't file a second complaint. For Problem #1 I also stopped putting an Approve button on every call β reads go through, and writes only get staged for me to run. Curious whether you've tried exposing that key in the tool schema so the model is told to reuse it on retries.
π©