first off, very well done. this article captures exactly the uneasiness i've felt as an mcp implementer.
doing seemingly in-the-box, mundane things like asking the server to dynamically register a new resource after a tool call yields new local files is met with surprising errors like "resources cannot be registered after transport connection."
i reached for the official kotlin sdk, found it did not work (mcp clients refused stdio comms), looked at the source and saw that the transport layer had recently been converted to a proprietary implementation, leaving commented-out code in-place that showed the previous transport details. reimplementing the former, assumedly-functional interface yielded the same broken stdio behavior, and everything being package-private meant i couldn't easily modify sdk components to fiddle with a solution without rewriting the entire transport mechanism. i wasn't willing to do this on a lark and hope the rest of the sdk behaved as promised, so my team is now stuck with a typescript mcp server that no one is comfortable maintaining.
what's really concerning is that openai threw in the towel on a competing standard, so we're now being corraled into accepting mcp as the only reliable tool interface, because every llm (frontier, and derivatives trained on these models) will end up conforming to mcp whether they intend to or not.
i haven't yet mentioned that there's an implicit hierarchy in the three capabilities exposed to mcp clients/servers -- tools above resources and resources above prompts, the latter of which is flat-out ignored by clients. the instructions aspect of server initialization was the only reliable way to bootstrap context with actionable exemplars, and that's just a big, inlined markdown document.
all of that said, the mcp contract is not pretty, but it works. in ~200 lines of code, i can spin up a wrapper over existing APIs (web and/or local binaries) and provide a workable plugin that adds real value to my team's day-to-day activities. mcp hasn't really promised more than that, and what it's promised, it's delivered.
doing seemingly in-the-box, mundane things like asking the server to dynamically register a new resource after a tool call yields new local files is met with surprising errors like "resources cannot be registered after transport connection."
i reached for the official kotlin sdk, found it did not work (mcp clients refused stdio comms), looked at the source and saw that the transport layer had recently been converted to a proprietary implementation, leaving commented-out code in-place that showed the previous transport details. reimplementing the former, assumedly-functional interface yielded the same broken stdio behavior, and everything being package-private meant i couldn't easily modify sdk components to fiddle with a solution without rewriting the entire transport mechanism. i wasn't willing to do this on a lark and hope the rest of the sdk behaved as promised, so my team is now stuck with a typescript mcp server that no one is comfortable maintaining.
what's really concerning is that openai threw in the towel on a competing standard, so we're now being corraled into accepting mcp as the only reliable tool interface, because every llm (frontier, and derivatives trained on these models) will end up conforming to mcp whether they intend to or not.
i haven't yet mentioned that there's an implicit hierarchy in the three capabilities exposed to mcp clients/servers -- tools above resources and resources above prompts, the latter of which is flat-out ignored by clients. the instructions aspect of server initialization was the only reliable way to bootstrap context with actionable exemplars, and that's just a big, inlined markdown document.
all of that said, the mcp contract is not pretty, but it works. in ~200 lines of code, i can spin up a wrapper over existing APIs (web and/or local binaries) and provide a workable plugin that adds real value to my team's day-to-day activities. mcp hasn't really promised more than that, and what it's promised, it's delivered.