Skip to main content
C carlos.enredando.me CTO · Advisor · Builder

Mastering Agentic AI: The Model Context Protocol (MCP) Pattern

·1373 words·7 mins
Carlos Prados
Author
Carlos Prados
Telecommunications Engineer, Entrepreneur, CTO & CIO, Team Leader & Manager, IoT-M2M-Big Data Consultant, Pre-sales Engineer, Product-Service Manager & Strategist.

In the previous post, Learning and Adaptation closed the loop on how agents improve over time without retraining. We’ve now covered the loops, the memory, the reasoning. There’s one piece left in Part 2 of the book, and it’s the most external of all the patterns: how agents talk to the rest of the world.

That’s MCP. And of all the patterns in this series, it’s the one that has changed the agentic landscape the fastest.

Pattern #10: Model Context Protocol
#

The Problem
#

Every agent framework, every LLM provider, every “tools” abstraction has its own way of plugging into the outside world. LangChain has tools. OpenAI has functions. Google ADK has its own primitives. CrewAI has another. If you build an integration for one — a Slack connector, a GitHub bridge, a database reader — it doesn’t transfer to the others. You rewrite it. Every time.

Multiply this by N agent frameworks and M services you want to integrate, and you get the N×M integration problem. Every framework reinvents every connector, every connector gets rewritten when the API changes, every team builds the same five integrations from scratch. It’s the same mess HTTP solved for documents in the 90s and USB-C solved for ports more recently: a thousand bespoke interfaces where one good protocol would do.

Model Context Protocol is what happens when someone — in this case Anthropic, but it’s now well beyond them — finally says: enough. Define one protocol, build it once per service, consume it from anywhere.

The Solution
#

MCP is a client-server protocol. The agent is the client. External capabilities — tools, data sources, prompt templates — live behind MCP servers. The protocol defines how they discover each other, how the client asks what’s available, and how it invokes what it finds.

An MCP server can expose three kinds of things:

  • Tools — invokable functions (the analogue of what we saw in Chapter 5).
  • Resources — read-only data the agent can pull (files, documents, query results).
  • Prompts — reusable prompt templates the server suggests to the client.

For most practical work, tools are 90% of what you’ll touch. Here’s the simplest possible MCP server, using FastMCP — a Python library that turns a function into an MCP server with a single decorator:

from fastmcp import FastMCP, tool

mcp_server = FastMCP("GreetingServer")

@tool()
def greet(name: str) -> str:
    """Generates a personalized greeting.

    Args:
        name: The name of the person to greet.
    """
    return f"Hello, {name}! Nice to meet you."

if __name__ == "__main__":
    mcp_server.run()  # Serves on http://localhost:8000 by default

That’s the entire server. The @tool() decorator emits the tool’s name, signature, and docstring through the MCP schema — exactly what a client needs to discover and call it. Notice that this looks almost identical to a LangChain @tool. That’s intentional. The mental model is the same; the difference is who can call it. A LangChain @tool is consumable only inside that framework. An MCP @tool is consumable by any MCP-aware client.

On the other side, a LangChain client wraps the remote MCP call as a regular agent tool:

@tool
def greet_via_mcp(name: str) -> str:
    """Calls the MCP server's greet tool to get a personalized greeting."""
    response = requests.post(
        f"{MCP_SERVER_URL}/call-tool",
        json={"name": "greet", "arguments": {"name": name}},
    )
    data = response.json()
    for item in data.get("content", []):
        if item.get("type") == "text":
            return item["text"]
    return str(data)

agent = create_react_agent(llm, [greet_via_mcp])
agent.invoke({"messages": [{"role": "user", "content": "Greet Charlie using the MCP service."}]})

From the agent’s perspective, greet_via_mcp is just another tool. The fact that the implementation lives in a separate process, possibly on a different machine, possibly written in a different language, is invisible. The agent thinks, decides to call a tool, the call goes out over HTTP, the result comes back. The ReAct loop we built in Chapter 5 doesn’t change at all.

Note: in production you’d use the official MCP client library (or LangChain’s MCP adapter) rather than crafting HTTP calls manually. The example above is intentionally low-level to make the protocol mechanics visible — once you’ve seen how it works under the hood, you can let the SDK handle it.

Transport: stdio, HTTP, SSE
#

MCP supports multiple transports. The two that matter in practice:

  • stdio — the server is a local subprocess; messages flow over stdin/stdout. This is how desktop clients (Claude Desktop, Cursor, IDE integrations) typically connect to local MCP servers. Zero network overhead, perfect for filesystem access or local tools.
  • HTTP/SSE — the server is a long-running service exposed over HTTP, with Server-Sent Events for streaming. This is the right choice when the server lives elsewhere, when multiple clients share it, or when you want to deploy it like any other web service.

The protocol is the same. You pick the transport that fits how the server is deployed.

Why This Matters
#

MCP isn’t a clever pattern. It’s infrastructure. The reason it belongs in this book is exactly that — it changes the cost model of building agentic systems.

What changes when MCP is in your stack:

  • Integrations are written once. A team builds an MCP server for an internal CRM. Every agent in the company — across frameworks, across runtimes — can use it. The cost of the next agent that needs CRM access drops from “weeks” to “minutes.”
  • The ecosystem becomes plug-and-play. There are now official and community MCP servers for GitHub, Slack, Google Drive, Postgres, filesystem access, web browsers, and dozens more. You compose them. You don’t write them.
  • Boundaries become enforceable. The MCP server is the perimeter. Auth, rate limiting, audit logging, allow-listing — all happen at the server, not inside every agent. The Guardrails pattern (Chapter 18) becomes vastly easier to implement when the surface area is one server interface instead of N tool functions.
  • Frameworks become commoditized. Whether your agent is LangChain, ADK, CrewAI, or hand-rolled, it consumes the same servers. That’s good for everyone except framework lock-in strategists.

Trade-offs to be honest about:

  • Latency. A local Python function call is microseconds. An HTTP round-trip to an MCP server is milliseconds. For chatty tools, this adds up. Use stdio for local servers; reserve HTTP for things that genuinely benefit from being out-of-process.
  • Operational overhead. An MCP server is another process to deploy, monitor, version, and secure. For a single-team prototype with one integration, a plain @tool is simpler. MCP earns its keep when integrations are shared.
  • Maturity is uneven. The protocol is young (originally specified late 2024). Some clients support it natively; others through adapter libraries. Some transports are more stable than others. Expect rough edges in the SDKs for another year or two — though the protocol itself is settling fast.
  • Protocol lock-in is still lock-in. Adopting MCP means betting that it (or its eventual successor) becomes the standard. Bet that’s true — given current adoption — but recognize you’re betting.

Rule of thumb: build an MCP server when the integration will be consumed by more than one agent or more than one team. Build a plain LangChain @tool when it’s local, single-purpose, and unlikely to need to be shared.


The Bigger Picture
#

This is post #10 in my series documenting Antonio Gulli’s Agentic Design Patterns. As always, full credit for the conceptual framework goes to him.

MCP composes with everything else we’ve built. Tool Use (Chapter 5) is the local-process version of the same idea; MCP is the cross-process, cross-framework generalization. Multi-Agent systems (Chapter 7) become easier because every agent can share the same MCP-exposed services. Guardrails (Chapter 18) get a natural place to live. Memory (Chapter 8) can itself be exposed as an MCP resource server, making “the team’s institutional knowledge” something every agent can read from.

All the code from this post is in my repository: carlosprados/Agentic_Design_Patterns, under 10_Model_Context_Protocol_MCP/. Two runnable examples — a FastMCP server and a LangChain client that consumes it. Run them in two terminals and watch the agent call across the process boundary.


What’s Next
#

In the next post we’ll tackle Goal Setting and Monitoring — the pattern where an agent isn’t just told what to do but given an objective and the means to track its own progress toward it. This is where agentic systems start to look less like reactive tools and more like autonomous workers.

Stay tuned.