DEV Community

Cover image for The weekend I fell down the MCP rabbit hole
Ana Jimenez Santamaria
Ana Jimenez Santamaria

Posted on

The weekend I fell down the MCP rabbit hole

👋This is the start of a series where I document what I'm learning about Model Context Protocol Architecture and Tool implementations

I'd been reading about MCP for a while and felt like I had a good grasp of the concepts, but I hadn't actually shared any builds yet. So this series is me finally putting my hands on it, documenting what I'm learning (from Zero to Beginner), and sharing it in case it's useful to others going through the same thing

My learning is coming from a mix of things: Some books, a few YouTube tutorials, conversations with DevRel peers exploring similar things, and a fair amount of AI assistance to help me understand concepts along the way 😄 Let's start!

An Intro to Model Context Protocol (MCP)

In the MCP Standard book, by Srinivasan Sekar there is a perfect analogy to explain the problem MCP solves.

Picture this: you have "M" AI models and "N" tools you want to connect to them.

  • The Old Way: Without a standard, you'd have to build a unique integration for every single combination. That’s ‭$M \times N$‬‭‬ different connections and a total nightmare to maintain!
  • The MCP Way: MCP acts as the universal plug. You build your tool once to the MCP standard, and it instantly works with any model that speaks it.

Does this scenario sound familiar? It's what happened with containerization before Kubernetes. Kubernetes came along and said: Here's the standard. MCP is doing the same thing for AI tooling.

The 3 MCP Roles to Understand

Before building anything, there are three roles to wrap your head around:

  • The Host is the app the user interacts with directly. It decides which tools to call, keeps the conversation context, and manages clients. Think Claude Desktop, Goose, VS Code, Cursor.

  • The Client lives inside the host. It maintains the connection with a concrete MCP Server.

  • The Server answers client requests and exposes tools, resources, and prompts through the MCP protocol.

Before MCP, the AI agent was doing everything (fetching data, formatting it, calling the model, returning the answer. One giant piece of logic. Hard to test and hard to scale). After MCP, the agent only does one thing: reason.

Level 0: Let's build a Calculator

Not glamorous, but the perfect hello world for understanding the fundamentals

1. Using the MCP Python SDK

To build an MCP server you don't need to implement the protocol from scratch. There is an official open source SDK (under MIT license) under the modelcontextprotocol organisation on GitHub.

Without the SDK you'd have to manually handle the JSON-RPC messages that flow between host and server via stdin/stdout, implement the handshake, route requests, serialize responses, etc. It's totally doable, but the SDK abstracts all of that.

2. Create the Server (server.py)

Inside the Python SDK, and I decided to go with FastMCP option.

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("calculator")

@mcp.tool()
def multiply(a: float, b: float) -> float:
    """Multiply 2 numbers"""
    return a * b

# + add, subtract, divide...

if __name__ == "__main__":
    mcp.run()
Enter fullscreen mode Exit fullscreen mode

💡Your server.py is the MCP Server. It exposes tools through the protocol. No Host has connected to it yet.

3. Test Server and Tools

Before connecting to any AI host, I tested it with the official MCP Inspector

uv run mcp dev server.py
Enter fullscreen mode Exit fullscreen mode

A browser UI opens. You'll see: status "Connected", server name "calculator", SDK version, and the history.

💡 The MCP Inspector is acting as both Host and Client here: doing the handshake, maintaining the connection, calling your tools

4. Connect to a Host

I tested three options:

🪿 Goose

Goose is an open-source AI agent that can act as an MCP Client and has a visual form to configure the extension name, type (STDIO), and the command it runs every time it starts. Internally, it stores config in a YAML file you never touch.

✳️ Claude Desktop

Claude Desktop needs you to configure a manual JSON such as:

{
  "mcpServers": {
    "calculator": {
      "command": "/path/to/uv",
      "args": ["run", "--directory", "/path/to/project", "python3", "server.py"]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

🤖 VS Code + Copilot

Same JSON approach as Claude Desktop inside settings.json.

Goose Claude Desktop VS Code + Copilot
Model Llama 3.3-70b Claude Opus 4.6 GPT-4o
Provider Groq Anthropic GitHub Copilot
MCP Config Visual UI - YAML config Manual JSON config Manual JSON config
API Cost 14,400 req/day Pay per use Free tier (50 chats/month)
Local model option Yes (Ollama) No No

💡 Each host manages its own MCP Client internally. You don't write client code (the host handles that). Your job as a "server developer" is just to make sure your server speaks valid MCP.

5. Full MCP Cycle Overview

As a takeaway, let's summarize the process into this 8-step cycle:

  • 1 User type the query and the Host receives it
  • 2 Host passes it to the LLM for initial reasoning. LLM decides: "I need an external tool for this"
  • 3 LLM signals tool invocation intent to the Host
  • 4 Host delegates to the Client (the messenger)
  • 5 Client serializes the request in JSON-RPC and sends it to your MCP Server via stdin/stdout
  • 6 Server validates and executes your Python function
  • 7 Server returns a standard MCP response
  • 8 Host shows the result to the user

What's Next?

The calculator was self-contained (all logic lived in server.py). In my next post, I'll share my experience in building a GitHub Stats server to talk to an external API and how to handle authentication, rate limits, and what data to expose to the LLM.

Resources

Top comments (0)