The First Two Laps

A couple of weeks ago, I wrote up a scrappy MCP (Model Context Protocol) Server and Client. Beyond the fact that everyone is creating MCP servers, there were two reasons I wanted to write these:

  1. I wasn’t able to find a way to test the newly introduced Streamable HTTP transport in the Model Context Protocol, either on the server or client. At the time of writing, the MCP Inspector didn’t seem to support this transport; it supported SSE (Server-side Events) and Stdio transport mechanisms. I was also not aware of a server that supported Streamable HTTP, though this was relatively easy to write. The hard part seemed to be the client app, though it’s entirely possible that I missed something obvious.
  2. There were even fewer pointers to MCP clients that required authorization support from servers, which had been running mostly on local desktops. Now with Streamable HTTP transport, remote servers were beginning to emerge.

So I prototyped an MCP client that used device flow based OAuth and used Streamable HTTP transport to communicate with servers. As a command line client, it required a custom MCP server with OAuth that was slightly different than anything I could find publicly, either via the MCP Inspector or CloudFlare Remote MCP Servers.

Last week, I prototyped an MCP client that mimicked a browser-based experience similar to the MCP Inspector, but one that supported Streamable HTTP transport. This allowed me to drop down one level to work with the end-to-end sequence of messages exchanged between the client and server, from authorization to tool execution and follow up notifications.

This has been a lot of fun and after the first two laps of this marathon, I’ve been reflecting on what I learned.

Takeaways

The most interesting takeaway was that vibe coding is awesome to learn a new language or programming paradigm. It may also be good enough to build a prototype. However, in this journey, I quickly hit a wall when I could no longer fully follow what was happening and couldn’t get myself unstuck. For example, one day I couldn’t debug why the authorization flow was going into a loop. That day I ran out of my model call limit just trying different guesses. Then I had to fall back on my own understanding and it frustrated me that I hadn’t come to understand what I was doing.

The next day, I built the whole app from scratch myself, one step at a time. I used the code from the prior iteration to fill in the gaps as I went along. When I had it running in a day, I realized this alternative journey had been far more satisfying than the imaginary one, where I’d have been happy to simply have something working one time.

My sense is that most programmers building something meaningful that continously evolves will run into this performance wall sooner or later. They will come to value learning for its own sake as learning can help us get a lot more stuff done.

My growing conviction is that we have a “fast learning” button at our fingertips today not a “generate code” button. Software by definition is meant meant to evolve… and writing software that’s not been written before will likely remain in our own hands.

Next Steps

Could I create a shopping agent that plugs into my Amazon account? Or a Midjourney agent that might help me reimagine my living room? Or a personal agent that could do my taxes? How might multi-modal data travel on the MCP wires?