I’ve been playing with Anthropic’s MCP for a little while now, and I have a few gripes. I understand it is undergoing a kind of Cambrian explosion right now, but I am not very impressed with it. Maybe it’s echoes of TRON, but I can’t bring myself to like it.
Pointless Complexity
I was looking at the Python SDK, and all I could see was wrappers inside wrappers into accessors and decorators that could probably be replaced by a few snippets of JSON and a dictionary. I understand that cosplaying as Java developers (or, worse, TypeScript) is a common affliction in modern Python codebases, but I kept wondering exactly why I would need to create a new server to expose an existing API, which leads me to my next point:
Zero Re-use of Existing API Surfaces
If I want an LLM to use an existing service, why don’t I have the LLM just consume the API directly? Why do I need to create a new server that wraps the existing API? We have had REST and Swagger for a long time now, and it would be a lot easier to just take a Swagger spec and generate a simplified JSON schema from it that aligned with the usual tool definitions. Maybe FastOpenAPI would be a good fit for this, at least for some modern APIs.
I also don’t see a lot of emphasis on security, access control, or anything that would make me feel comfortable exposing an MCP server to an LLM. I get that this is a work in progress, but it feels like a lot of effort is being wasted on creating a new server for every API instead of just using the existing ones.
Persistent Connections
I get that MCP is being designed to be a kind of “universal” interface for LLMs, but the fact that it is connection-oriented and stateful means that it is not necessarily a good fit for API-based applications.
The design seems to assume you are either running a bunch of servers locally (as subprocesses, which, again, raises a few interesting security issues) or talking to something with enough compute power to run a stateful server, and isn’t really a good fit for the way we use APIs today, considering many are usually run in stateless hosting environments like AWS Lambda or Cloudflare Workers.
At least Anthropic had the good taste to use server-sent events (which is not popular with the SocketIO crowd, of course), but even if I remove the network component, the way local MCP servers are integrated and run as separate processes feels messy and wasteful (and don’t get me started on the overuse of uv
or uvx
to pack everything into isolated environments).
Too Many Options
My limited experimentation quickly surfaced another issue, which is that MCP tends to crowd the model context with too many options. There doesn’t seem to be a clear way to set priorities or a set of good examples to expose MCP server metadata–so your model API calls will just pack all the stuff an MCP server can do and shove it into the context, which is both wasteful of tokens and leads to erratic behavior from models.
I think MCP is missing some form of “routing” or stepwise, selective exposure of options, which would allow you to expose only the relevant options for a given task.
Conclusion
Right now, I’m not overly excited by MCP over “standard” tool calling. I much prefer agents.json
and the concepts around endpoint discovery, which feel much more natural if you are working with APIs.
But of course everything around AI and LLMs is in a chaotic state of flux, and I’ve been around for long enough to know that the best ideas often take a while to surface. For now, I will most likely stick to standard tool calling.