The Protocol That Cleaned Up Our Agent Architecture | Towards Data Science
MCP (Model Context Protocol) is an open standard for how agents discover and call tools. Instead of scattering tool definitions across multiple agent files, you run tools on a separate server that agents connect to at runtime. The protocol provides a clean interoperability boundary—any MCP-compatible client can call any MCP-compatible server without integration work. For teams with multiple overlapping agents, this eliminates schema drift, simplifies approval gates, and decouples the tool layer from the orchestration layer.
Transcript
Justy Okay, so we've got this article about MCP—Model Context Protocol—and it's basically the story of a team drowning in scattered tool definitions across seven agents and deciding that instead of defining tools everywhere, they'd just… run them on a separate server.
Cody Right.
Justy Which sounds obvious until you realize nobody's actually doing this at scale yet.
Cody Mm-hm. So the problem is real—they had the same tool definition living in four different files. One agent had it, another validation agent had a slightly different version, someone wrote a utility module with a third version that was already out of date. Schema change meant touching every one separately and hoping nothing broke downstream.
Justy And the author's honest about why they built it that way: LangGraph's tool calling is local by design. You define tools where you need them, you call them where you call them, you own all the plumbing. Fine for two agents, complete chaos at seven.
Cody Yeah, but here's the thing—they could've just built a centralized tool registry and injected it at startup. The author actually mentions this, says they did that in another system.
Justy And?
Cody And MCP gives you something a registry doesn't: an interoperability boundary. It's a protocol, not a library. A TypeScript client can call a Python server without integration work. A different framework next year? Still works. A registry is just a list you pass around inside your codebase.
Justy That is such a Cody thing to land on—the boundary is the feature, not the registry itself.
Cody It also solves a team ownership problem. Their ML team owns the tools, the application team owns the graph. Before MCP, they shared code. After, they have a clean contract without a shared codebase.
Justy Okay, so how does it actually work? They're using FastMCP, which is the Python SDK—you write a function, decorate it with @tool, the server handles the rest. Schema generation from type hints, protocol lifecycle, all of it.
Cody One thing the article hammers on: never write to stdout if you're using stdio transport. The MCP protocol uses stdout as the communication channel. A stray print() call corrupts the message stream in ways that are incredibly confusing to debug.
Justy That is the kind of gotcha that kills a Friday afternoon.
Cody Yeah. They log to stderr instead, keep stdout clean for the protocol.
Justy And then there's the transport choice—stdio vs HTTP. That's not a small decision.
Cody Stdio runs the server as a subprocess. Single-digit millisecond latency, no network, minimal setup. Right for local development, single-machine deployments, anywhere the server and client live in the same process tree. HTTP runs it as an independent service—scales, works with serverless, fits data residency. And switching between them in FastMCP is literally one line: change the transport parameter in mcp.run().
Justy That flexibility is huge. You're not locked into a choice early on.
Cody The code example they show is pretty straightforward too. MultiServerMCPClient handles the subprocess lifecycle, does the tool discovery handshake, translates MCP schemas into LangChain-compatible tool objects. You wire it into the graph, bind the tools to the LLM, and tools_condition routes to the tool executor or exits.
Justy One thing that jumped out at me—MultiServerMCPClient creates a new MCP session per tool call by default. So if your agent chains five tool calls, that's five handshakes.
Cody Right.
Justy Fine on stdio on the same machine, but on HTTP with a remote server you'd notice it. For production workloads they recommend pinning multiple calls to one session with async context.
Cody Which is why understanding the tradeoff matters. You're not just choosing a transport; you're choosing how many round trips you're willing to pay.
Justy But here's the move that actually sold me on this—approval gates. Before MCP, they had human-in-the-loop logic wired directly into graph edges. One custom implementation per tool. Adding a sensitive tool meant three-team coordination, updating the UI every time.
Cody And after?
Justy The gate moves to a single layer between LangGraph and the MCP client. A SENSITIVE_TOOLS set—one frozenset—controls which tools require approval. New sensitive tool? Add it to the set. Graph doesn't change. UI doesn't change. Product and compliance can update the rules from a config file at startup without a code deployment.
Cody That is genuinely clean.
Justy Right? It's not revolutionary, but it's the kind of simplification that compounds across your whole org.
Cody They also talk briefly about what breaks in production. Server crashes mid-execution—the client gets an error on the next tool call. LangGraph surfaces it to the LLM as a tool error. Whether the model recovers or loops depends on your system prompt. But if you're not logging subprocess stderr separately, debugging is guesswork.
Justy Yeah, and MCP doesn't protect you from the LLM calling the wrong tool. That's still on you.
Cody Right. The protocol doesn't validate intent; it validates the call itself.
Justy So if you're sitting on a team that's already got three or four agents sharing overlapping tools, this is probably worth a week to explore. If you're just starting out with one agent, skip it for now.
Cody Fair. But the moment you hit the scattered-definition problem, you'll wish you'd read this first.
Justy Exactly. Anyway—catch you next week?
Cody Yep.