Beyond the Chatbox: Why Anthropic's MCP is the Secret Weapon for the Next Generation of Agentic Apps

Hey everyone, Alex here. Welcome back to another edition of Coding with Alex at sysseder.com.

If you’ve been tracking the AI space lately, you’ve probably noticed a massive shift in how we talk about Large Language Models. We are rapidly moving away from the "chatbot" paradigm—where a human types a prompt and waits for a text block—and moving headfirst into the era of agentic workflows. We want our LLMs to act, execute, orchestrate, and play.

Just this week, a fascinating project caught my eye on Hacker News: Clawfight.ai. It's an agentic game where AI agents battle each other. But what makes it technically brilliant isn't just the gameplay—it's how it's built under the hood. Clawfight leverages Anthropic’s open-source Model Context Protocol (MCP) to drive its agentic actions.

This got me thinking: while everyone is obsessing over prompting techniques, the real architectural revolution for developers is happening in how we connect LLMs to data sources and tools. Today, we are going to dive deep into MCP, understand why it's a game-changer for developer workflows, and write some code to see how you can build your own MCP-driven agents.

What is the Model Context Protocol (MCP)?

Before we look at the code, we need to understand the problem MCP solves. Historically, if you wanted to give an LLM access to external tools or data (like your database, GitHub repository, or local filesystem), you had to write custom, ad-hoc integrations. You’d write some glue code, format it as JSON Schema for OpenAI's function calling or Anthropic's tool use API, and handle the execution lifecycle yourself.

This approach has a major drawback: it doesn't scale. Every time you switch models, change frameworks, or want to expose a new tool, you end up rewriting the integration layer.

Anthropic introduced the Model Context Protocol (MCP) to establish an open standard for how applications provide context and tools to LLMs. Think of MCP as "LSP (Language Server Protocol) but for AI." Just as LSP decoupled programming language intelligence from specific IDEs, MCP decouples data sources and developer tools from LLM clients.

The architecture is elegantly split into three main components:

  • MCP Hosts: Client applications (like Claude Desktop, cursor, or your custom agentic app) that initiate connections and orchestrate the LLM's reasoning loop.
  • MCP Clients: The protocol implementation inside the host that maintains a secure, bidirectional connection with the servers.
  • MCP Servers: Lightweight, modular services that expose specific capabilities (like reading a database, querying an API, or compiling code) via standard JSON-RPC 2.0 messages.

The MCP Conceptual Architecture

┌─────────────────────────────────────────────────────────┐
│                       MCP Host                          │
│  ┌─────────────────┐             ┌───────────────────┐  │
│  │   LLM Engine    │◀───────────▶│    MCP Client     │  │
│  └─────────────────┘             └───────────────────┘  │
└────────────────────────────────────────────▲────────────┘
                                             │
                                  JSON-RPC   │ (STDIO or SSE)
                                  Protocol   │
                                             ▼
┌─────────────────────────────────────────────────────────┐
│                      MCP Server                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │ Exposed Resources, Prompts, and Tools             │  │
│  │ (e.g., PostgreSQL, Git, File System, Game Engine)  │  │
│  └───────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────┘

Why MCP is Perfect for Agentic Applications (Like Clawfight.ai)

In a project like Clawfight.ai, agents need to interact with a dynamic environment. They need to query the state of the game board, decide on a strategy, and execute moves.

Without MCP, you would have to hardcode the game loop inside your LLM wrapper. With MCP, the game engine itself runs as an MCP Server. The AI agent acts as the MCP Host. The agent queries the server for the current game state (using Resources), asks for recommended strategies (using Prompts), and executes its moves (using Tools).

This decoupling means you can swap the AI model from Claude 3.5 Sonnet to GPT-4o, or even a local Llama-3 model, without changing a single line of your game engine code! The game engine simply exposes its interface via the standardized protocol.

Hands-On: Building Your First MCP Tool Server in TypeScript

Let's move away from theory and build something practical. We are going to build a custom MCP Server using TypeScript. This server will expose a developer tool: a secure system resource monitor that lets an LLM agent inspect CPU load and memory usage to diagnose performance issues.

First, let's set up our project directory and install the official Anthropic MCP SDK:

mkdir system-monitor-mcp
cd system-monitor-mcp
npm init -y
npm install @modelcontextprotocol/sdk systeminformation
npm install --save-dev typescript @types/node tsx
npx tsc --init

Now, let's write our server code. Create a file named index.ts. We will use the systeminformation library to pull real metrics and expose them as an MCP tool.

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import si from "systeminformation";

// 1. Initialize the MCP Server
const server = new Server(
  {
    name: "system-monitor-mcp",
    version: "1.0.0",
  },
  {
    capabilities: {
      tools: {}, // We are registering tools capabilities
    },
  }
);

// 2. Define the tools available on this server
server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: "get_system_metrics",
        description: "Retrieves real-time CPU load, memory utilization, and platform details from the host machine.",
        inputSchema: {
          type: "object",
          properties: {},
        },
      },
    ],
  };
});

// 3. Implement the tool execution logic
server.setRequestHandler(CallToolRequestSchema, async (request) => {
  if (request.params.name !== "get_system_metrics") {
    throw new Error(`Tool not found: ${request.params.name}`);
  }

  try {
    const cpu = await si.currentLoad();
    const mem = await si.mem();
    const osInfo = await si.osInfo();

    const metrics = {
      platform: osInfo.platform,
      distro: osInfo.distrib,
      cpuLoadPercent: Math.round(cpu.currentLoad),
      memoryUsedGB: (mem.active / 1024 / 1024 / 1024).toFixed(2),
      memoryTotalGB: (mem.total / 1024 / 1024 / 1024).toFixed(2),
      memoryFreePercent: Math.round((mem.free / mem.total) * 100),
    };

    return {
      content: [
        {
          type: "text",
          text: JSON.stringify(metrics, null, 2),
        },
      ],
    };
  } catch (error) {
    return {
      isError: true,
      content: [
        {
          type: "text",
          text: `Failed to retrieve system metrics: ${(error as Error).message}`,
        },
      ],
    };
  }
});

// 4. Start the server using standard input/output (STDIO) transport
async function run() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
  console.error("System Monitor MCP Server running on stdio");
}

run().catch((error) => {
  console.error("Fatal error running MCP server:", error);
  process.exit(1);
});

Why STDIO?

You'll notice we used StdioServerTransport. In the MCP world, standard input/output is the preferred IPC (Inter-Process Communication) mechanism when the server and the host run on the same machine. The host spawns the server as a subprocess and communicates with it using JSON-RPC messages piped over stdin and stdout. It's incredibly secure because the server doesn't expose any open network ports for bad actors to exploit.

Connecting Your Custom Server to an MCP Host

Now that we have our server code written, how do we let an LLM agent use it? The easiest way to test this is by configuring the Claude Desktop app as our host.

First, build your TypeScript file into executable JavaScript:

npx tsc

Next, find your Claude Desktop configuration file. On macOS, this is located at:

~/Library/Application Support/Claude/claude_desktop_config.json

On Windows, it is located at:

%APPDATA%\Claude\claude_desktop_config.json

Open that file (create it if it doesn't exist) and add your server configuration under the mcpServers key:

{
  "mcpServers": {
    "system-monitor": {
      "command": "node",
      "args": ["/absolute/path/to/system-monitor-mcp/index.js"]
    }
  }
}

Restart your Claude Desktop app. If everything is configured correctly, you’ll see a little plug/hammer icon in your input box. You can now type a prompt like: "Hey Claude, check if my local machine is running low on memory, and let me know if I need to close some applications."

Claude will intercept this, recognize it needs system metrics, call your node process via JSON-RPC, receive the system metrics payload, analyze it, and write a natural language response back to you. You've officially built an agentic tool!

The Security Paradigm Shift with MCP

As security-minded developers, your alarm bells should be ringing. Giving an LLM access to execute code or read local system state is inherently risky (remember prompt injection?).

MCP addresses this security boundary beautifully through its architectural constraints:

  • Local-First execution: Because the standard transport is STDIO, the tools execute inside your defined host environment (e.g., your local machine, a secure sandbox, or a Docker container). The LLM provider (like Anthropic’s cloud) never gets direct network access to your machine; it only receives the textual result of the tool's execution returned by your client.
  • Granular tool schemas: The server strictly defines what inputs it accepts. The LLM cannot execute arbitrary bash commands unless you explicitly write a tool that allows it (which you shouldn't!).
  • User Consent: Modern MCP hosts require explicit confirmation before executing state-changing tools (like writing files or executing API calls).

Conclusion: The Future of Developer Tooling

Projects like Clawfight.ai are demonstrating that agents are no longer just toys; they are capable of orchestrating complex workflows when given the right boundaries and tools. The Model Context Protocol is turning into the standard bridging layer that will power this new wave of software.

Imagine a development environment where your IDE, your terminal, your database client, and your CI/CD pipelines all expose standardized MCP endpoints. An AI agent could seamlessly navigate this ecosystem to debug a failing unit test, patch the code, and deploy it, all while operating under a uniform, secure protocol. That is the future we are building toward.

What are your thoughts? Have you played around with MCP or integrated it into your workflows yet? Let me know in the comments below!

Until next time, happy coding!

— Alex

Post a Comment

Previous Post Next Post