347 comments

[ 3.0 ms ] story [ 401 ms ] thread
Context is stdin and stdio.

"It kind of breaks the Unix/Linux piping paradigm using these streams for bidirectional communication."

Uhm ... no? They were meant for that.

But the rest of the critique is well founded. "Streamable HTTP" is quite an amateurish move.

I think 'bidirectional' is unclear there, they really mean a back and forth dialogue, interactive bidirectional communication. Which, yeah, a socket (as they said) seems a better choice.
I think stdin and stdio are meant to always be piped forward, and a program further down the pipe cannot modify a tool back in the pipeline, maybe that's what he's trying to convey with "bidirectional"?
I don't think so, because it's a description of a system which does work.

But it's more like an HTTP API, writing or requesting some data, getting a response, doing something else with that, etc. - whereas typically with stdin/stdout you're doing something more like `generate-data | transform | transform2 | store`, manipulating an initial input, not decision-making and providing more input based on the output of early input. Not to say you can't, but it does seem a bit weird to me too.

(To be fair I suppose a shell is an obvious counter-example. Or anything that launches an interactive prompt or interpreter.)

> They were meant for that.

No they weren't. If we look at it from the perspective of pipelines (and not interactive programs that take input directly from the user and display output on the screen), stdin is for receiving data from the program in the pipeline before you, and stdout is for sending data to the thing in the pipeline after you. That's not bidirectional, that's a unidirectional flow.

You are wrong.

STDIN means Standard INPUT.

STDOUT means Standard OUTPUT.

There is no design/hardware/software limitation to reading and writing to them at the same time. That's your bidirectional channel with that one process.

>stdin is for receiving data from the program in the pipeline before you, and stdout is for sending data to the thing in the pipeline after you

Yes, and you took that from my comment here: https://news.ycombinator.com/item?id=43947777

Did you just wanted to ratify my argument, or is there something else you want to add?

It is indeed quite baffline why MCP is taking off, but facts are facts. I would love to be enlightened how MCP is better than an OpenAPI Spec of an existing Server.
I'm not saying MCP is perfect, but it's better than OpenAPI for LLMs for a few reasons.

* MCP tools can be described simply and without a lot of text. OpenAPI specs are often huge. This is important because the more context you provide an LLM the more expensive it is to run, and the larger model you need to use to be effective. If you provide a lot of tools then using OpenAPI specs could take up way too much for context, while the same tools for MCP will use much less.

* LLMs aren't actually making the calls, it's the engine driving it. What happens when an LLM wants to make a call is it responds directly with a block of text that the engine catches and uses to run the command. This allows LLMs to work like they're used to: figuring out text to output. This has a lot of benefits: less tokens to output than a big JSON blob is going to be cheaper.

* OpenAPI specs are static, but MCP allows for more dynamic tool usage. This can mean that different clients can get different specs, or that tools can be added after the client has connected (possibly in response to something the client sent). OpenAPI specs aren't nearly that flexible.

This isn't to say there aren't problems. I think the transport layer can use some work, as OP sent, but if you play around in their repo you can see websocket examples so I wouldn't be surprised if that was coming. Also the idea that "interns" are the ones making the libraries is an absolute joke, as the FastMCP implementation (which was turned into the official spec) is pretty solid. The mixture of hyperbole with some reasonable points really ruins this article.

What does it mean that "different clients can get different specs"? Different in what dimension? I could imagine this makes creating repeatable and reliable workflows problematic.
Using MCP you can send "notifications" to the server, and the server can send back notifications including the availability of new tools.

So this isn't the same as saying "this user agent gets X, this gets Y". It's more like "this client requested access to X set of tools, so we sent back a notification with the list of those additional tools".

This is why I do think websockets make more sense in a lot of ways here, as there's a lot more two way communication here than you'd expect in a typically API. This communication also is very session based, which is another thing that doesn't make sense for most OpenAPI specs which assume a more REST-like stateless setup.

If you look at the actual raw output of tools/list call you may find it surprisingly similar to the OpenAPI spec for the same interface. In fact they are trivially convertible to each other.

Personally I find OpenAPI spec being more practical since it includes not just endpoints with params, but also outputs and authentication.

Know all that from my own experience plugging dozens of APIs to both MCP/Claude and ChatGPT.

> OpenAPI specs are static, but MCP allows for more dynamic tool usage.

This is repeated everywhere, but I don’t get it. OpenAPI specs are served from an HTTP endpoint, there’s nothing stopping you from serving a dynamically rendered spec depending on the client or the rest of the world?

This is one of the few places I think it's obvious why MCP provides value - an OpenAPI document is static and does no lifting for the LLM, forcing the LLM to handle all of the call construction and correctness on its own. MCP servers reduce LLM load by providing abstractions over concepts, with basically the same benefits we get by not having to write assembly by hand.

In a literal sense it's easier, safer, faster, etc for an LLM to remember "use server Foo to do X" than "I read a document that talks about calling api z with token q to get data b, and I can combine three or four api calls using this http library to...."

I believe gp is saying the MCP’s “tool/list” endpoint should return dynamic, but OpenAPI-format, content.

Not that the list of tools and their behavior should be static (which would be much less capable)

My theory is that a lot of the buzz around MCP is actually buzz around the fact that LLM tool usage works pretty well now.

OpenAI plugins flopped back in 2023 because the LLMs at the time weren't reliable enough for tool usage to be anything more than interesting-but-flawed.

MCP's timing was much better.

I'm still having relatively disastrous results compared to just sending pre curated context (i.e. calling tools deterministically upfront) to the model.

Doesn't cover all the use cases, but for information retrieval stuff, the difference is pretty light and day. Not to mention the deterministic context management approach is quite a bit cheaper in terms of tokens.

I find letting the agent iterate search leads to better results. It can direct the search dynamically.
I thinks a lot is timing and also that it's a pretty low bar to write your first mcp server:

    from mcp.server.fastmcp import FastMCP
    mcp = FastMCP("Basic Math Server")

    @mcp.tool()
    def multiply(a: int, b: int) -> int:
        return a * b

    mcp.run()
If you have a large MCP server with many tools the amount of text sent to the LLM can be significant too. I've found that Claude works great with an OpenAPI spec if you provide it with a way to look up details for individual paths and a custom message that explains the basics. For instance https://github.com/runekaagaard/mcp-redmine
That's kind of my point, that the protocols complexity is hidden in py sdk making it feel easy... But taking on large tech dept
I mean isn't this the point of a lot of, if not most successful software? Abstracting away the complexity making it feel easy, where most users of the software have no clue what kind of technical debt they are adopting?

Just think of something like microsoft word/excel for most of its existence. Seems easy to the end user, but attempting to move away from it was complex, the format had binary objects that were hard to unwind, and interactions that were huge security risks.

yeah, but it doesn’t need to be that way. It can be simple and makes it easier adoptable, why over engineering and reinventing the wheel of at least 2 decades experience and better practices.
Simple software is the most difficult software to make.

Historically stated as

>I apologize for such a long letter - I didn't have time to write a short one.

The difficult part is figuring out what kind of abstractions we need MCP servers / clients to support. The transport layer is really not important, so until that is settled, just use the Python / TypeScript SDK.
But the spec is on the transport level. So for the specification, the transport layer is very important.
This is the spec that counts: https://github.com/modelcontextprotocol/modelcontextprotocol...

How exactly those messages get transported is not really relevant for implementing an mcp server, and easy to switch, as long as there is some standard.

You’re ignoring the power of network effects - “shitty but widely adopted” makes “better but just starting adoption harder” to grow. Think about how long it takes to create a new HTTP standard - we’ve had 3 HTTP standards in the past 30 years, the first 19 of which so no major changes. HTTP/2 kind of saw no adoption in practice and HTTP/3 is still a mixed bag. In fact, most of the servers pretend HTTP/1 with layers in front converting the protocols.

Underestimate network effects and ossification at your own peril.

Why is it baffling? Worse is better! Look at PHP, why took that prank of a programming language ever anyone serious?
This all sounds valid, but it’s also the least interesting part of the whole thing. As a developer I’m expecting to be able to reach for a framework that’ll just abstract away all the weird design decisions that he mentions.
You're not the intended audience for this blog post. The people who care about this are the kinds of people who have to implement the protocol on either end, and deal with all of those complexities.

You won't be able to fully insulate yourself from those complexities, though. Unnecessary complexity causes user-visible bugs and incompatibilities. You want to reach for a framework that will abstract all this stuff away, but because of poorly-designed protocols like MCP, those frameworks will end up being more unreliable than they need to be, in ways that will leak out to you.

Just like I saw with protocols like ActivityPub and IPFS, what happens is the developers of these protocols do a couple of reference implementations in their favorite languages, which work, but then when they write the actual "spec" of what they think they did in the code, they never get it fully correct, or even if they do it's messy, incomplete, or not kept up to date.

So as long as you're a developer working in one of those two languages you just take their code and run it, and all is fine. However for someone coming along trying to implement the protocol in a brand new language, it gets discovered that the protocol is insufficient and horrible and attempts to build based on the protocol are therefore doomed to fail.

I'm not saying MCP has already reached this level of chaos, but I'm just saying this is the failure pattern that's fairly common.

MCP is the moat to keep small players outside of the AI market. Not only does implementing it require a team, it is a tarpit of sabotage, where logging and state are almost impossible to track.
Have you tried it though? There are sdks where you can set up logging and MCP server or client in a few lines. Pydantic AI and Logfire as one example
Yes, there are SDKs that abstract away some of the setup. But what exactly is being logged? Where is the data going? How tamper-proof is that logging? How is the network communication implemented? How do you check those logs? What exactly is being sent through the line? It’s hard to audit, especially without deep visibility into the underlying layers which include binary blobs and their tokens for trust. How do you model internal state? How do you write regression tests?
SDKs aren't a spec.

A spec is what I use to write an SDK.

MCP is simple, as protocols go.
I had the idea that maybe it was actually a flytrap for large companies! force them to waste cycles chasing a moving target so they don’t even notice they’re being leapfrogged
(comment deleted)
In the same way that crypto folks speedran "why we have finance regulations and standards", LLM folks are now speedrunning "how to build software paradigms".

The concept they're trying to accomplish (expose possibly remote functions to a caller in an interrogable manner) has plenty of existing examples in DLLs, gRPC, SOAP, IDL, dCOM, etc, but they don't seem to have learned from any of them, let alone be aware that they exist.

Give it more than a couple months though and I think we'll see it mature some more. We just got their auth patterns to use existing rails and concepts, just have to eat the rest of the camel.

Isn't MPC based on JSON-RPC?
Indeed! But seemingly only for the actual object representation - it's a start, and I wonder if JSON is uniquely suited to LLMs because it's so text-first.
I understand those with experience have found that XML works better because it's more redundant.
Is it the redundancy? Or is it because markup is a more natural way to annotate language, which obviously is what LLMs are all about?

Genuinely curious, I don’t know the answer. But intuitively JSON is nice for easy to read payloads for transport but to be able to provide rich context around specific parts of text seems right up XML’s alley?

The lack of inline context is a failing of JSON and a very useful feature of XML.

Two simple but useful examples would be inline markup to define a series of numbers as a date or telephone number or a particular phrase tagged as being a different language from the main document. Inline semantic tags would let LLMs better understand the context of those tokens. JSON can't really do that while it's a native aspect of XML.

Or is is because most text in existence is XML - or more specifically HTML.
Hey, at least they didn't use yaml-rpc.
toml-rpc anyone? :)
I think JSON is preferred because it adds more complexity.
Yes, the protocol seems fine to me in and of itself. It's the transport portion that seems to be a dumpster fire on the HTTP side of things.
Must have used GraphQL as a role model no doubt
GraphQL is transport agnostic
This article feels like an old timer who knows WebSockets just doesn't want to learn what SSE is. I support the decision to ditch WebSockets because WebSockets would only add extra bloat and complexity to your server, whereas SSE is just HTTP. I don't understand though why have "stdio" transport if you could just run an HTTP server locally.
HTTP call may be blocked by firewalls even internally, and it's overkill to force stdio apps to expose http endpoints for this case only.

As in, how MCP client can access `git` command without stdio? You can run a wrapper server for that or use stdio instead

> As in, how MCP client can access `git` command without stdio?

MCP clients don't access any commands. MCP clients access tools that MCP servers expose.

Here's a custom MCP tool I use to run commands and parse stdout / stderr all the time:

    try {
        const execPromise = promisify(exec);
        const { stdout, stderr } = await execPromise(command);
        if (stderr) {
            return {
                content: [{
                    type: "text",
                    text: `Error: ${stderr}`
                }],
                isError: true
            };
        }
        return {
            content: [{
                type: "text",
                text: stdout
            }],
            isError: false
        };
    } catch (error: any) {
        return {
            content: [{
                type: "text",
                text: `Error executing command: ${error.message}`
            }],
            isError: true
        };
    }
Yeah, if you want to be super technical, it's Node that does the actual command running, but in my opinion, that's as good as saying the MCP client is...
The point is that MCP servers expose tools that can do whatever MCP servers want them to do, and it doesn’t have to have anything to do with stdio.
I'm confused by the "old timer" comment, as SSE not only predates WebSockets, but the techniques surrounding its usage go really far back (I was doing SSE-like things--using script blocks to get incrementally-parsed data--back around 1999). If anything, I could see the opposite issue, where someone could argue that the spec was written by someone who just doesn't want to learn how WebSockets works, and is stuck in a world where SSE is the only viable means to implement this? And like, in addition to the complaints from this author, I'll note the session resume feature clearly doesn't work in all cases (as you can't get the session resume token until after you successfully get responses).

That all said, the real underlying mistake here isn't the choice of SSE... it is trying to use JSON-RPC -- a protocol which very explicitly and very proudly is supposed to be stateless -- and to then use it in a way that is stateful in a ton of ways that aren't ignorable, which in turn causes all of this other insanity. If they had correctly factored out the state and not incorrectly attempted to pretend JSON-RPC was capable of state (which might have been more obvious if they used an off-the-shelf JSON-RPC library in their initial implementation, which clearly isn't ever going to be possible with what they threw together), they wouldn't have caused any of this mess, and the question about the transport wouldn't even be an issue.

> I'm confused by the "old timer" comment

SSE only gained traction after HTTP/2 came around with multiplexing.

Also missing in these strict, declarative protocols is a reliance on latent space, and the semantic strengths of LLMs.

Is it sufficient to put a agents.json file in the root of the /.well-known web folder and let agents just "figure it out" through semantic dialogue?

This forces the default use of HTTP as Agent stdio.

Bravo. Agree with both of your examples.
> Give it more than a couple months though and I think we'll see it mature some more.

Or like the early Python ecosystem, mistakes will become ossified at the bottom layers of the stack, as people rapidly build higher level tools that depend on them.

Except unlike early Python, the AI ecosystem community has no excuse, BECAUSE THERE ARE ALREADY HISTORICAL EXAMPLES OF THE EXACT MISTAKES THEY'RE MAKING.

Could you throw on a couple of examples of calcified early mistakes of Python? GIL is/was one, I presume?
Possibly packaging too? though lately that has improved to the point where I'd not really consider it ossified at all.
CPython in particular exposes so much detail about its internal implementation that other implementations essentially have to choose between compatibility and performance. Contrast this with, say, JavaScript, which is implemented according to a language standard and which, despite the many issues with the language, is still implemented by three distinct groups, all reasonably performant, yet all by and large compatible.
Static functions (len, map/filter,...) that should have been methods on objects.
This one frustrates me so, so much.
What’s the root cause?

It certainly makes functional semantics in Python suck. Comprehensions don’t make up for it.

How so, given that those are also free-standing functions in most languages that are considered purely or mostly functional? (e.g. ML, Haskell)
I don’t mind those, tbh (maybe because I came to Python from C and Lisp).

Contrary, I dislike NumPy’s decision to make reduce/accumulate methods of operations (e.g. np.add.reduce and np.mul.accumulate), not higher order functions or methods of NumPy arrays.

map() and filter() work on any iterable, so it's not clear which type you'd expect them to be methods on (keeping in mind that the notion of "iterable" in Python is expressed through duck typing, so there's no interface like say .NET IEnumerable where they would naturally belong).

len() guarantees that what you get back is an integer. If some broken type implements __len__() poorly by returning something else, len() will throw TypeError. You can argue that this is out of place for Python given it overall loose duck typing behavior, but it can still be convenient to rely on certain fundamental functions always behaving well. Similar reasoning goes for str(), repr(), type() and some others.

One can reasonably argue that Python should have something similar to C# extension methods - i.e. a way to define a function that can be called like a method, but which doesn't actually belong to any particular type - and then all those things would be such functions. But, given the facilities that Python does have, the design of those functions makes sense.

I guess there's an incentive to quickly get a first version out the door so people will start building around your products rather than your competitors.

And now you will outsource part of the thinking process. Everyone will show you examples when it doesn't work.

Hey there, expecting basically literacy or comprehension out of a sub-industry seemingly dedicated to minimising human understanding and involvement is bridge too far.

Clearly if these things are problems, AI will simply solve them, duhhh.

/s

You joke, but with the right prompt, I am almost certain that an LLM would've written a better spec than MCP. Like others said, there are many protocols that can be used as inspiration for what MCP tries to achieve, so LLMs should "know" how it should be done... which is definitely NOT by using SSE and a freaking separate "write" endpoint.
> with the right prompt

That's LLM in a nutshell though. A naive prompt + taking the first output = high probability of garbage. A thoughtful prompt informed by subject matter expertise + evaluating, considering, and iterating on output = better than human-alone.

But the pre-knowledge and creative curation are key components of reliable utility.

To this date I have not found a good explanation what an MCP is.

What is it in old dev language?

A RPC standard that plays nicely with LLMs?
In a nutshell: RPC with builtin discoverability for LLMs.
old dev language is deterministic, llm in the loop now so the language is stochastic.
it is amazing we used to prize determinism, but now it's like determinism is slowing me down. I mean how do you even write test cases for LLM agents. Do you have another LLM judge the results as close enough, or not close enough?
Yes, and you have to do it in a loop on every request. Not joking. It’s called “LLM as judge.”
What an amazing business to convince people to use. Making people pay to use LLMs to supervise the LLMs they pay for in order to get decent results is diabolically genius.

At the risk of offending some folks it feels like the genius of the Mormon church making its "customers" pay the church AND work for it for free AND market it for free in person AND shame anyone who wants to leave. Why have cost centers if you don't have to!

It's a business model I wasn't smart or audacious enough to even come up with.

It's a bit like paying more for AWS logging services than for the AWS services that provide the services your customers actually consume.
It's a read/write protocol for making external data/services available to a LLM. You can write a tool/endpoint to the MCP protocol and plug it into Claude Desktop, for example. Claude Desktop has MCP support built-in and automatically queries your MCP endpoint to discover its functionality, and makes those functions available to Claude by including their descriptions in the prompt. Claude can then instruct Claude Desktop to call those functions as it sees fit. Claude Desktop will call the functions and then include the results in the prompt, allowing Claude to generate with relevant data in context.

Since Claude Desktop has MCP support built-in, you can just plug off the shelf MCP endpoints into it. Like you could plug your Gmail account, and your Discord, and your Reddit into Claude Desktop provided that MCP integrations exist for those services. So you can tell Claude "look up my recent activity on reddit and send a summary email to my friend Bob about it" or whatever, and Claude will accomplish that task using the available MCPs. There's like a proliferation of MCP tools and marketplaces being built.

If you know JSON-RPC: it's a JSON-RPC wrapper exposed for AI use and discovery.

If you know REST / http request:

it's single endpoint-only, partitioned / routed by single "type" or "method" parameter, with some different specification, for AI.

Wasn't the point of REST supposed to be runtime discoverability though? Of course REST in practice just seems to be json-rpc without the easy discoverability which seems to have been bolted on with Swagger or whatnot. But what does MCP do that (properly implemented) REST can't?
Half the point of MCP is just making it easy for an LLM to use some language in a standard way to talk to some other tool. I mean MCP is partly a standard schema for tools to interact and discover each other, and part of it is just allowing non-webserver based communication (like stdio piping, especially useful since initial the use case is running local scripts
> Of course REST in practice just seems to be json-rpc

That's so wrong. REST in practice is more like HTTP with JSON payloads. If you find anything similar to json-rpc calling itself REST just please ask them politely to stop doing that.

It's a classic Worse is Better situation.

Most users don't care about the implementation. They care about the way that MCP makes it easier to Do Cool Stuff by gluing little boxes of code together with minimal effort.

So this will run ahead because it catches developer imagination and lowers cost of entry.

The implementation could certainly be improved. I'm not convinced websockets are a better option because they're notorious for firewall issues, which can be showstoppers for this kind of work.

If the docs are improved there's no reason a custom implementation in Go or Arm assembler or whatever else takes your fancy shouldn't be possible.

Don't forget you can ask an LLM to do this for you. God only knows what you'll get with the current state of the art, but we are getting to the point where this kind of information can be explored interactively with questions and AI codegen, instead of being kept in a fixed document that has to be updated manually (and usually isn't anyway) and hand coded.

I agree they should learn from DLLs, gRPC, SOAP, IDL, dCOM, etc.

But they should also learn from how NeWS was better than X-Windows because instead of a fixed protocol, it allowed you to send executable PostScript code that runs locally next to the graphics hardware and input devices, interprets efficient custom network protocols, responds to local input events instantly, implements a responsive user interface while minimizing network traffic.

For the same reason the client-side Google Maps via AJAX of 20 years ago was better than the server-side Xerox PARC Map Viewer via http of 32 years ago.

I felt compelled to write "The X-Windows Disaster" comparing X-Windows and NeWS, and I would hate if 37 years from now, when MCP is as old as X11, I had to write about "The MCP-Token-Windows Disaster", comparing it to a more efficient, elegant, underdog solution that got out worse-is-bettered. It doesn't have to be that way!

https://donhopkins.medium.com/the-x-windows-disaster-128d398...

It would be "The World's Second Fully Modular Software Disaster" if we were stuck with MCP for the next 37 years, like we still are to this day with X-Windows.

And you know what they say about X-Windows:

>Even your dog won’t like it. Complex non-solutions to simple non-problems. Garbage at your fingertips. Artificial Ignorance is our most important resource. Don’t get frustrated without it. A mistake carried out to perfection. Dissatisfaction guaranteed. It could be worse, but it’ll take time. Let it get in your way. Power tools for power fools. Putting new limits on productivity. Simplicity made complex. The cutting edge of obsolescence. You’ll envy the dead. [...]

Instead, how about running and exposing sandboxed JavaScript/WASM engines on the GPU servers themselves, that can instantly submit and respond to tokens, cache and procedurally render prompts, and intelligently guide the completion in real time, and orchestrate between multiple models, with no network traffic or latency?

They're probably already doing that anyway, just not exposing Turing-complete extensibility for public consumption.

Ok, so maybe Adobe's compute farm runs PostScript by the GPU instead of JavaScript. I'd be fine with that, I love writing PostScript! ;) And there's a great WASM based Forth called WAForth, too.

https://news.ycombinator.com/item?id=34374057

It really doesn't matter how bad the language is, just look at the success and perseverance of TCL/Tk! It just needs to be extensible at runtime.

NeWS applications were much more responsive than X11 applications, since you download PostScript code into the window server to locally handle input events, provide immediate feedback, translate them to higher level events or even completely handle them locally, using a user interface toolkit that runs in the server, and only sends high level events over the network, using optimized application specific protocols.

You know, just what all web browsers have been doing for decades with JavaScript and calling it AJAX?

Now it's all about rendering and responding to tokens instead of pixels and mouse clicks.

Protocols that fix the shape of interaction (like X11 or MCP) can become ossified, limiting innovation. Extensible, programmable environments allow evolution and responsiveness.

Speed run that!

It reminds me a bit of LSP, which feels to me like a similar speed-run and a pile of assumptions baked in which were more parochial aspects of the original application... now shipped as a standard.

And yeah, sounds like it's explicitly a choice to follow that model.

"Why do I need to implement OAuth2 if I'm using HTTP as transport, while an API key is enough for stdio?"

Because one is made for local and the other for connecting through the internet.

You need something like OAuth because you don't want your end users generating API keys for every service they want to use via LLM.
Maybe we should though
I hate API keys. Get a horrible feeling when I see one. When will this have to expire and how do I remember to recycle it. And if it doesn't expire that is an issue too.
> However, I'm astonished by the apparent lack of mature engineering practices.

Exactly.

MCP is one of the worst 'standards' that I have seen come out from anywhere since JSON Web Tokens (JWTs) and the author rightfully points out the lack of engineering practices of a 'standard' that is to be widely used like any properly designed standard with industry-wide input.

> Increased Attack Surface: The multiple entry points for session creation and SSE connections expand the attack surface. Each entry point represents a potential vulnerability that an attacker could exploit.

JWTs have this same issue with multiple algorithms to use including the horrific 'none' algorithm. Now we have a similar issue with MCP with multiple entry points to chose from which is more ways to attack the protocol.

This one is the most damning.

> Python and JavaScript are probably one of the worst choices of languages for something you want to work on anyone else's computer. The authors seem to realize this since all examples are available as Docker containers.

Another precise point and I have to say that our industry is once again embracing the worst technologies to design immature standards like this.

The MCP spec appears to be designed without consideration for security or with any input from external companies like a normal RFC proposal should and is quite frankly repeating the same issues like JWTs.

I think it's clear that they want a proprietary solution that takes a year or more for others to copy. That gives them another year head start on the competition.
Who is "they"?
The AI houses buying up the entire market of GPUs. Have you heard about them?
(comment deleted)
This is paranoid drivel....

Tell me which is more likely.

1. There is a cabal of companies painstakingly working together to make the most convoluted software possible from scratch so they can dominate the market.

or

2. A few people threw together a bit of code to attempt to get something working without any deep engineering or systematic view of what they were trying to accomplish, getting something to work well enough that it took off quickly in a time where everyone wants to have tool use on LLMs.

I've been on the internet a long time and number 2 is a common software paradigm on things that are 'somewhat' open and fast moving. Number 1 does happen but it either is started and kept close by a single company, or you have a Microsoft "embrace, extend, extinguish" which isn't going on here.

3. The internal & enterprise models are better and not based on Python.
there is a 1.5 option: VC-funded company decides what they want to achieve and inexperient engineers come up with a bugged implementation (that still focus on what VC-funded wanted, in this case more LLM calls with bloated context)
2 works when you're making software, but not when you're making a specification.

The entire point of a specification is that it's well thought out. You SHOULD be considering ways it can be misused, vulnerabilities that might sneak into implementations.

This critical look focuses just on the protocol. The fun starts with the actual MCP server implementations... Seems that providing an MCP server is the to be or not to be for all sorts of vendors. All REST APIs get wrapped into an MCP to make products LLM-compatible and tick checkmarks on newly extended checklists.

Many pass REST responses directly to LLMs that quickly leads to token burn. Wish providers took a closer look on the actual engineering practices for the servers.

Has someone seen a good implementation of an MCP server with a comprehensive test suite?

Agreed with basically the entire article. Also happy to hear that someone else was as bewildered as me when they visited the MCP site and they found nothing of substance. RFCs can be a pain to read, but they're much better than 'please just use our SDK library'.
Glad to here, also thought I was alone :)
Agree... this is an important blog. People need to press pause on MCP in terms of adoption...it was simply not designed with a solid enough technical foundation that would make it suitable to be an industry standard. People are hyped about it, kind of like they were for LangChain and many other projects, but people are going to gradually (after diving into implementations) that it's not actually what they were looking for..It's basically a hack thrown together by a few people and there are tons of questionable decisions, with websockets being just one example of a big miss.
(comment deleted)
The Langchain repo is actually hilariously bad if you ever go read the source. I can't believe they raised money with that crap. Right place right time I guess.
Isn't that what a lot of this is about? It's a blue ocean and everyone are full of fomo.
Software quality be damned!
My first surprise on it:

I made an error trying with aws bedrock where I used "bedrock" instead of "bedrock-runtime".

The native library will give you an error back.

Langchain didn't try and do anything, just kept parsing the json and gave me a KeyError.

I was able to get a small fix, but was surprised they have no error like ConfigurationError that goes across all their backends at all.

The best I could get them to add was ValueError and worked with the devs to make the text somewhat useful.

But was pretty surprised, I'd expect a badly configured endpoint to be the kind of thing that happens when setting stuff up for the first time, relatively often.

Yeah agree. I spent a few hours looking at the langchain repo when it first hit the scene and could not for the life of me understand what value it actually provided. It (at least at the time) was just a series of wrappers and a few poorly thought through data structures. I could find almost no actual business logic.
It provides negative value by marrying your project to a bunch of unnecessary oop bullshit lol
I wish there was a clear spec on the site but there isn't https://modelcontextprotocol.io/specification/2025-03-26

It seems like half of it is Sonnet output and it doesn't describe how the protocol actually works.

For all its warts, the GraphQL spec is very well written https://spec.graphql.org/October2021/

I didn’t believe you before clicking the link, but hot damn. That reads like the ideas I scribbled down in school about all the cool projects I could build. There is literally zero substance in there. Amazing.
I thought it was just me. When I first saw all the hype around MCP I went to go read this mess and still have no idea what MCP even is.
It's JSON-RCP 2 with a specific life cycle and events. https://www.jsonrpc.org/specification

I found an explanation on a site once but haven't found any official docs. I suppose you could reverse enegiener the SDKs.

(comment deleted)
And then you read the SDK code and the bewildering doesn't stop at the code quality, organization, complete lack of using exiting tools to solve their problems, it's an absolute mess for a spec that's like 5 JSON schemas in a trench coat.
MCP is a microcosm of LLM.

Everything looks great works snappy and fast, until you look deeper inside or try to get it to do more complex stuff.

The post misses the mark on why a stateless protocol like MCP actually makes sense today. Most modern devs aren’t spinning up custom servers or fiddling with sticky sessions—they’re using serverless platforms like AWS Lambda or Cloudflare Workers because they’re cheaper, easier to scale, and less of a headache to manage. MCP’s statelessness fits right into that model and makes life simpler, not harder.

Sure, if you’re running your own infrastructure, you’ve got other problems to worry about—and MCP won’t be the thing holding you back. Complaining that it doesn’t cater to old-school setups kind of misses the point. It’s built for the way things work now, not the way they used to.

It's not really stateless. How do you want to support SSE or "Streamable HTTP" on your lambda? Each request will hit a new random worker, but your response is supposed to go on some other long-running SSE stream.

The protocol is absolute mess both for clients and servers. The whole thing could have been avoided if they picked any sane bidirectional transport, even websocket.

> Each request will hit a new random worker, but your response is supposed to go on some other long-running SSE stream.

It seems your knowledge is a little out of date. The big difference between the older SSE transport and the new "Streamable HTTP" transport is that the JSON-RPC response is supposed to be in the HTTP response body for the POST request containing the JSON-RPC request, not "some other long-running SSE stream". The response to the POST can be a text/event-stream if you want to send things like progress notifications before the final JSON-RPC response, or it can be a plain application/json response with a single JSON-RPC response message.

If you search the web for "MCP Streamable HTTP Lambda", you'll find plenty of working examples. I'm a little sympathetic to the argument that MCP is currently underspecified in some ways. For example, the spec doesn't currently mandate that the server MUST include the JSON-RPC response directly in the HTTP response body to the initiating POST request. Instead, it's something the spec says the server SHOULD do.

Currently, for my client-side Streamable implementation in the MCP C# SDK, we consider it an error if the response body ends without a JSON-RPC response we're expecting, and we haven't gotten complaints yet, but it's still very early. For now, it seems better to raise what's likely to be an error rather than wait for a timeout. However, we might change the behavior if and when we add resumability/redelivery support.

I think a lot of people in the comments are complaining about the Streamable HTTP transport without reading it [1]. I'm not saying it's perfect. It's still undergoing active development. Just on the Streamable HTTP front, we've removed batching support [2], because it added a fair amount of additional complexity without much additional value, and I'm sure we'll make plenty more changes. As someone who's implemented a production HTTP/1, HTTP/2 and HTTP/3 server that implements [3], and also helped implement automatic OpenAPI Document generation [4], no protocol is perfect. The HTTP spec misspells "referrer" and it has a race condition when a client tries to send a request over an idle "keep-alive" connection at the same time the server tries to close it. The HTTP/2 spec lets the client just open and RST streams without the server having any way to apply backpressure on new requests. I don't have big complaints about HTTP/3 yet (and I'm sure part of that is a lot of the complexity in HTTP/2 was properly handled by the transport layer which for Kestrel means msquic), but give it more time and usage and I'm sure I'll have some. That's okay though, real artists ship.

1: https://modelcontextprotocol.io/specification/2025-03-26/bas...

2: https://github.com/modelcontextprotocol/modelcontextprotocol...

3: https://learn.microsoft.com/aspnet/core/fundamentals/servers...

4: https://learn.microsoft.com/aspnet/core/fundamentals/openapi...

Client is allowed to start a new request providing sessionid which should maintain the state from previous request.

Where do you store this state?

I find the discussing of the quality of the MCP protocol funny. This space is constantly evolving very quickly. I consider MCP completely throw away, and I'm willing to deal with it as unimportant in that rapidly evolving space. I'm sure there will be a different implementation and approach in 6-12 months, or not. From the speed I'm able to turn on MCP integrations I don't think it'll take that long to swap to another protocol. We're in the sone age here. MCP may be crappy but it's a flint and steel versus a bowstring. Eventually we'll get to central or zoned heating.

I'm using MCP locally on my laptop, the security requirements are different there than on a server. Logging can be done at the actual integration with external api level if you have standard clients and logging, which I do and push for.

To me what is important right now is to glue my apis, data sources, and tools, to the AI tools my people are using. MCP seems to do that easily. Honestly I don't care about the protocol, at the end of the day, protocols are just ways for things to talk to each other, if they're interesting in and of themselves to you you're focusing on other things than I am. My goal is delivering power with the integration.

MCP may be messy, but the AI tools I'm using them with seem just fine and dealing with that mess to help me build more power into the AI tools. That, at the end of the day is what I care about, can I get the info and power into the tools so that my employees can do stuff they couldn't do before. MCP seems to do that just fine. If we move to some other protocol in 6 months, I'm assuming I can do that with AI tools on a pretty quick basis, as fast as I'm building it right now.

I haven't dug too deeply into MCP yet so I may very well be wrong here, but it feels like get another attempt to paper over the fact that we abandoned REST APIs nearly 20 years ago.

XML is ugly and building APIs that describe both the data and available actions is tough.

Instead we picked JSON RPCs that we still call REST, and we inevitably run into situations like Alexa or LLMs where we want a machine to understand what actions are supported in an API and what the data schema is.

OpenAPI/Swagger already solves the machine-discoverable API problem MCP is attempting to address, with years of maturity and tooling support. The real innovation needed isn't yet another protocol but better LLM understanding of existing API description formats.
You must understand that when you deal with AI people, you deal with children. Imagine the author of the spec you're trying to implement is a new grad in San Francisco (Mission, not Mission Street, thanks).

He feels infallible because he's smart enough to get into a hot AI startup and hasn't ever failed. He's read TCP 973 and 822 and 2126 and admitted the vibe or rigor but can't tell you why we have SYN and Message-ID or what the world might have been had alternatives one.

He has strong opinions about package managers for the world's most important programming languages. (Both of them.) But he doesn't understand that implementation is incidental. He's the sort of person to stick "built in MyFavoriteFramework" above the food on his B2B SaaS burrito site. He doesn't appreciate that he's not the customer and customers don't give a fuck. Maybe he doesn't care, because he's never had to turn a real profit in his life.

This is the sort of person building perhaps the most important human infrastructure since the power grid and the Internet itself. You can't argue with them in the way the author of the MCP evaluation article does. They don't comprehend. They CANNOT comprehend. Their brains do not have a theory of mind sufficient for writing a spec robust to implementation by other minds.

That's why they ship SDKs. It's the only thing they can. Their specs might as well be "Servers SHOULD do the right thing. They MUST have good vibes." Pathetic.

God help us.

…what? Literally nothing you wrote is accurate.
You'll come around to my perspective in time. Don't take it personally. This generation isn't any worse than prior ones. We go through this shit every time the tech industry turns over.
The people who built MCP are seasoned software engineers, as are most folks who work for these labs. What are you even on about?
LOL
Okay, well, clearly you have some funny beliefs, and I won’t try to convince you otherwise. Just think first before posting weird screeds with no basis in reality next time.
> weird

Adj, something the speaker wants the audience to dislike without the speaker being on the hook for explaining why.

> screed

Noun, document the speaker doesn't like but can't rebut.

It's funny how people in the blue tribe milieu use the same effete vocabulary. I'll continue writing at the object level instead of affecting seven zillion layers of affected fake kindness, thanks.

The people building MCP are in the same cohort as the Doge "hackers". And we can see the result.
I think you are wrong, but I upvoted anyway because it is so funny :-)
(comment deleted)
(comment deleted)
my dude really got angry but forgot almost all cloud message queue offerings over HTTP works like this (minus SSE). Eventually MCP will take the same route as WS which started clunky with the http upgrade thing being standard but not often used and evolved. Then it will migrate to any other way of doing remote interface, as GRPC, REST and so on.
I mean…the cloud message queues that use HTTP are not good examples of quality software. They all end up being mediocre to poor on every axis: they’re not generalizable enough to be high quality low level components in complex data routing (e.g. SQS’s design basically precludes rapid redelivery on client failure, and is resistant to heterogenous workloads by requiring an up-front redelivery/deadletter timeout); simultaneously, HTTP’s statelessness at the client makes extremely basic use cases flaky since e.g. consumer acknowledgment/“pop” failures are hard to differentiate as server-side issues, incorrect client behavior, or conceptual partitions in the consume transaction network link…”conceptual” because that connection doesn’t actually exist, leading to all these problems. Transactionality between stream operations, too, is either a hell-no or a hella-slow (requiring all the hoop-jumping mentioned in TFA for clients’ operations to find the server session that “owns” the transaction’s pseudo connection) if built on top of HTTP.

In other words, you can’t emulate a stateful connection on top of stateless RPC—well, you can, but nobody does because it’d be slow and require complicated clients. Instead, they staple a few headers on top of RPC and assert that it’s just as good as a socket. Dear reader: it is not.

This isn’t an endorsement of AMQP 0.9 and the like or anything. The true messaging/streaming protocols have plenty of their own issues. But at least they don’t build on a completely self-sabotaged foundation.

Like, I get it. HTTP is popular and a lot of client ecosystems balk at more complex protocols. But in the case of stateful duplex communication (of which queueing is a subset), you don’t save on complexity by building on HTTP. You just move the complexity into the reliability domain rather than the implementation domain.

It will probably never work. Companies have spend probably the last decade(s?) closing everything on Internet: * no more RSS feed * paywall * the need to have an "app" to access a service * killing open protocols

And all of the sudden, everyone will expose their data through simple API calls ?

Indeed I think a lot of companies will hate the idea of losing their analytics and app mediated control over their users.

I see it working in a B2B context where customers demand that their knowledge management systems (ticketing, docs, etc...) have an MCP interface.

I think it is a huge opportunity to dethrone established players that don't want to open up that way. Users will want it, and whoever gives it to them, wins.
You either do it, or someone wraps you with one using browser_use or similar.
I don’t agree with MCP being a bad standard, remember it’s supposed to be as simple and easy as possible to not take up a lot of tokens and for the LLM to use.

More complex stuff you can build on the “outside”. So keeping it local seems ok, because it’s just the LLM facing part.

I am the founder of one of the MCP registries (https://glama.ai/mcp/servers).

I somewhat agree with author’s comments, but also want to note that the protocol is in the extremely early stages of development, and it will likely evolve a lot over the next year.

I think that no one (including me) anticipated just how much attention this will get straight out the door. When I started working on the registry, there were fewer than a few dozen servers. Then suddenly a few weeks later there was a thousand, and numbers just kept growing.

However, lots and lots of those servers do not work. Majority of my time has gone into trying to identify servers that work (using various automated tests). All of this is in large part because MCP got picked up by the mainstream AI audience before the protocol reached any maturity.

Things are starting to look better now though. We have a few frameworks that abstract the hard parts of the protocol. We have a few registries that do a decent job surfacing servers that work vs those that do not. We have a dozen or so clients that support MCPs, etc. All of this in less than half a year is unheard of.

So yes, while it is easy to find flaws in MCP, we have to acknowledge that all of it happened in a super short amount of time – I cannot even think of comparisons to make. If the velocity remains the same, MCP future is very bright.

For those getting started, I maintain a few resources that could be valuable:

* https://github.com/punkpeye/awesome-mcp-servers/

* https://github.com/punkpeye/awesome-mcp-devtools/

* https://github.com/punkpeye/awesome-mcp-clients/

Agree with basically all of this.

The actual protocol of MCP is…whatever. I’m sure it will continue to evolve and mature. It was never going to be perfect out of the gate, because what is?

But the standardization of agentic tooling APIs is mind bogglingly powerful, regardless of what the standard itself actually looks like.

I can write and deploy code and then the AI just..immediately knows how to use it. Something you have to experience yourself to really get it.

Yup. It's easy to focus on what’s missing or broken in early-stage tech, but I’m more excited about where this kind of standardization could take us. Sometimes you need to look beyond imperfections and see the possibilities ahead.
What are the possibilities that you see?
Kind of my fear exactly. We are moving so fast and that mcp would create an accept a transport protocol that might take years or decades to get rid off for something better.

Kind of reminds me of the browser wars during 90s where everyone tried to run the fastest an created splits in standards and browsers what we didn't really det rid of for a good 20 year or more. IE11 was around for far to long

I think that transport is a non-issue.

Whatever the transport evolves to, it is easy to create proxies that convert from one transport to another, e.g. https://github.com/punkpeye/mcp-proxy

As an example, every server that you see on Glama MCP registry today is hosted using stdio. However, the proxy makes them available over SSE, and could theoretically make them available over WS, 'streamable HTTP', etc

Glama is just one example of doing this, but I think that other registries/tools will emerge that will effectively make the transport the server chooses to implement irrelevant.

Do you think WebTransport and HTTP3 could provide better alternatives for transport?
> I somewhat agree with author’s comments, but also want to note that the protocol is in the extremely early stages of development, and it will likely evolve a lot over the next year.

And that's why it's so important to spec with humility. When you make mistakes early in protocol design, you live with them FOREVER. Do you really want to live with a SSE Rube Goldberg machine forever? Who the hell does? Do you think you can YOLO a breaking change to the protocol? That might work in NPM but enterprise customers will scream like banshees if you do, so in practice, you're stuck with your mistakes.

Just focusing on worst-case scenarios tends to spread more FUD than move things forward. If you have specific proposals for how the protocol could be designed differently, I’m sure the community would love to hear them – https://github.com/orgs/modelcontextprotocol/discussions
The worst case scenario being, what, someone implementing the spec instead of using the SDK and doing it in a way you didn't anticipate? Security and interoperability will not yield to concerns about generating FUD. These concerns are important whether you like them or not. You might as well be whispering that ill news is a ill guest.

At the least, MCP needs to clarify things like "SHOULD rate limit" in more precise terms. Imagine someone who is NOT YOU, someone who doesn't go to your offsites, someone who doesn't give a fuck about your CoC, implementing your spec TO THE LETTER in a way you didn't anticipate. You going to sit there and complain that you obviously didn't intend to do the things that weird but compliant server is doing? You don't have a recourse.

The recent MCP annotations work is especially garbage. What the fuck is "read only"? What's "destructive"? With respect to what? And hoo boy, "open world". What the fuck? You expect people to read your mind?

What would be the point of creating GH issues to discuss these problems? The kind of mind that writes things like this isn't the kind of mind that will understand why they need fixing.

they already did though. the late-2024 version and the early-2025 version have completely incompatible SSE rube goldberg machines
(comment deleted)
Then have a convo with all your devs to stop spamming the glory of MCP all over the damn place. Have some patience and finish writing and testing it first.
MCP was invented by some very young LLM experts probably with limited experience in "protocol" design. They'll probably see this article you wrote criticizing it and realize they made a mistake. I bet there's a way to wrap that stdio stuff with WebSockets, like was recommended in the blog/article.

Frankly I'm not sure why an ordinary REST service (just HTTP posts) wasn't considered ok, but I haven't used MCP yet myself.

What MCP got right was very powerful of course which I'd summarize as giving all AI-related software the ability to call functions that reside on other servers during inference (i.e. tool calls), or get documents and prompt templates in a more organized way where said docs are specifically intended for consumption by AIs residing anywhere in the world (i.e. on other servers). I see MCP as sort of a 'function call' version of the internet where AIs are doing the calling. So MCP is truly like "The Internet for AIs". So it's huge.

But just like JavaScript sucks bad, yet we run the entire web on it, it won't be that bad if the MCP protocol is jank, as long as it works. Sure would better to have a clean protocol tho, so I agree with the article.

There isn't much detailed technical spec on MCP on the spec site, but they have a link to a schema [1]. You can add that schema to a Claude project, and then examine it. That's very helpful, although you will quickly run into unsupported things, for example embedded resources in tool call responses in Claude Desktop.

I think MCP will be a huge deal for Practal. Implementing Practal as an MCP server, I basically don't need a frontend.

[1] https://github.com/modelcontextprotocol/modelcontextprotocol...

One major obstacle to grasping high-level abstractions and their implementations lies in poorly designed systems or language limitations. At this stage, any human-produced effort—be it documentation, explanations, or naming—should be reviewed by AI. Language models often excel at crafting clearer analogies and selecting more meaningful or intuitive naming conventions than we do. In short, let LLMs handle the documentation.

— written by ai