MODULE 12  Β·  Protocols & Standards

MCP (Model Context Protocol): The USB-C of AI Tool Integration

Every AI assistant needs tools. Every tool has a different API. MCP is the universal standard that connects them all.

πŸ“… Mar 2026
⏱ 10 min read
🎯 Episode 78 of 98
MCPProtocolTool IntegrationStandards
In this episode

Every AI assistant needs tools. ChatGPT needs to search the web. Claude needs to read your files. Your custom agent needs to query your database, call APIs, send emails.

But every tool integration is custom. OpenAI has one format. Anthropic has another. LangChain has five. Your framework has its own. You write glue code for each tool, for each model, for each framework.

It's the smartphone charger problem β€” everyone had their own cable until USB-C showed up.

snippet
code
MCP (Model Context Protocol) is Anthropic's answer. One open standard for connecting AI models to tools and data. Any tool. Any model. Any framework. Plug and play.

The Problem MCP Solves

Before MCP, connecting an AI to your tools looked like this:

snippet
code
Your Agent β†’ Custom OpenAI function definition β†’ Your API

Your Agent β†’ Different LangChain tool wrapper β†’ Same API

snippet
code
Your Agent β†’ Another CrewAI tool class β†’ Same API

3 integrations for 1 API. Multiply by 50 tools. Multiply by 5 frameworks.

= 250 custom integrations. All doing the same thing.

With MCP:

Your Agent β†’ MCP Client β†’ MCP Server (your tool)

Any MCP client talks to any MCP server.

Write the server once. Every client works.

It's the difference between NΓ—M integrations and N+M.

⚑

MCP Architecture: Three Primitives

MCP defines three ways for a model to interact with the outside world:

  1. Tools β€” Actions the Model Can Take

Tools are functions the model can call. This is what you're used to from function calling, but standardized:

json

{

"name": "query_database",

"description": "Run a SQL query against the production database",

"inputSchema": {

example
code
"type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "SQL SELECT query to execute"
      }
    },
    "required": ["query"]

}

}

The model decides when to call tools. The user (or client) approves the call. The server executes it and returns results.

  1. Resources β€” Data the Model Can Read

Resources are like a filesystem for the model. They provide context without the model needing to "do" anything:

json

{

"uri": "file:///project/README.md",

"name": "Project README",

"mimeType": "text/markdown",

"description": "Main documentation for the project"

}

Resources can be:

Files on disk

Database rows

API responses

Live data feeds

Screenshots

The key difference from tools: resources are read-only context, tools are actions. The model doesn't "call" a resource β€” it reads it.

  1. Prompts β€” Reusable Templates

Prompts are pre-built interaction patterns that users can invoke:

json

{

"name": "code-review",

"description": "Review code for bugs, style, and best practices",

"arguments": [

example
code
{
      "name": "language",
      "description": "Programming language",
      "required": true
    },
    {
      "name": "code",
      "description": "Code to review",
      "required": true
    }

]

}

When invoked, the prompt returns a structured message sequence that guides the model's behavior.

πŸ”§

How MCP Communication Works

MCP uses JSON-RPC 2.0 over two transport types:

Transport: stdio

For local tools β€” the MCP server runs as a child process:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” stdin/stdout β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ MCP β”‚ ←────────────→ β”‚ MCP Server β”‚

β”‚ Client β”‚ (JSON-RPC) β”‚ (your tool) β”‚

β”‚ (Claude β”‚ β”‚ β”‚

β”‚ Desktop) β”‚ e.g., file β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ system tool β”‚

example
code
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Transport: SSE (Server-Sent Events) / Streamable HTTP

For remote tools β€” the MCP server runs on a network:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β” HTTP/SSE β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ MCP β”‚ ←─────────────→ β”‚ MCP Server β”‚

β”‚ Client β”‚ (JSON-RPC) β”‚ (remote) β”‚

β”‚ β”‚ β”‚ β”‚

β”‚ β”‚ β”‚ e.g., GitHubβ”‚

β”‚ β”‚ β”‚ API server β”‚

β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Protocol Flow

  1. Client β†’ Server: initialize (negotiate capabilities)
  2. Server β†’ Client: initialized (confirm)
  3. Client β†’ Server: tools/list (what tools do you have?)
  4. Server β†’ Client: [list of tools with schemas]
  5. Client β†’ Server: resources/list (what data can I read?)
  6. Server β†’ Client: [list of resources with URIs]

--- User starts chatting ---

  1. Model decides to use a tool
  2. Client β†’ Server: tools/call { name: "query_database", arguments: {...} }
  3. Server β†’ Client: { result: [...rows...] }
  4. Model incorporates result into response

πŸ“Š

Building an MCP Server

Here's a complete MCP server in Python that provides database tools:

python

mcp_database_server.py

from mcp.server import Server

from mcp.types import Tool, TextContent

import sqlite3

import json

snippet
code
server = Server("database-tools")

@server.list_tools()

snippet
code
async def list_tools():
return [
        Tool(
            name="query",
            description="Run a read-only SQL query",
            inputSchema={
                "type": "object",
                "properties": {
                    "sql": {
                        "type": "string",
                        "description": "SQL SELECT query"
                    }
                },
                "required": ["sql"]
            }
        ),
        Tool(
            name="tables",
            description="List all tables in the database",
            inputSchema={
                "type": "object",
                "properties": {}
            }
        )
    ]

@server.call_tool()

async def call_tool(name: str, arguments: dict):

example
code
db = sqlite3.connect("app.db")
example
code
if name == "query":
        sql = arguments["sql"]
        if not sql.strip().upper().startswith("SELECT"):
            return [TextContent(type="text", text="Error: Only SELECT queries allowed")]
example
code
cursor = db.execute(sql)
        columns = [desc[0] for desc in cursor.description]
        rows = cursor.fetchall()
        result = [dict(zip(columns, row)) for row in rows]
        return [TextContent(type="text", text=json.dumps(result, indent=2))]
example
code
elif name == "tables":
        cursor = db.execute(
            "SELECT name FROM sqlite_master WHERE type='table'"
        )
        tables = [row[0] for row in cursor.fetchall()]
        return [TextContent(type="text", text=json.dumps(tables))]

Run with stdio transport

if __name__ == "__main__":

example
code
import asyncio
    from mcp.server.stdio import stdio_server
example
code
asyncio.run(stdio_server(server))

Connecting to Claude Desktop

Add to your Claude Desktop config (claude_desktop_config.json):

json

{

"mcpServers": {

example
code
"database": {
      "command": "python",
      "args": ["mcp_database_server.py"],
      "env": {
        "DATABASE_PATH": "/path/to/app.db"
      }
    }

}

}

Now Claude can query your database. It sees the tools, knows the schema, and asks for permission before running queries.

Building an MCP Client

If you're building your own agent and want to consume MCP tools:

python

from mcp import ClientSession, StdioServerParameters

from mcp.client.stdio import stdio_client

snippet
code
async def main():
# Connect to an MCP server
    server_params = StdioServerParameters(
        command="python",
        args=["mcp_database_server.py"]
    )
async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # Initialize
            await session.initialize()
# Discover tools
            tools = await session.list_tools()
            print(f"Available tools: {[t.name for t in tools.tools]}")
# Call a tool
            result = await session.call_tool(
                "query",
                arguments={"sql": "SELECT * FROM users LIMIT 5"}
            )
            print(f"Result: {result.content[0].text}")
πŸ’‘

MCP Ecosystem: What's Already Built

The MCP ecosystem is growing fast. Here's what exists:

Category MCP Servers What They Do

Files Filesystem, Google Drive, Dropbox Read/write files

CodeGitHub, GitLab, LinearIssues, PRs, code search
DataPostgreSQL, SQLite, BigQueryDatabase queries
WebBrave Search, Puppeteer, FetchWeb search and scraping
CommsSlack, Gmail, DiscordMessages and email
CloudAWS, GCP, KubernetesInfrastructure management
MemoryQdrant, PineconeVector store operations
DevDocker, Sentry, DatadogDevOps and monitoring

bash

Install official MCP servers via npx

npx -y @modelcontextprotocol/server-filesystem /path/to/dir

npx -y @modelcontextprotocol/server-github

npx -y @modelcontextprotocol/server-postgres postgresql://...

πŸ”¬

MCP vs Direct Function Calling

You might ask: why not just use OpenAI function calling directly?

Feature Direct Function Calling MCP

Standard Per-provider (OpenAI, Anthropic, etc.) Universal

DiscoveryHard-coded in promptDynamic (tools/list)
TransportHTTP onlystdio, HTTP, SSE
ResourcesNo conceptFirst-class primitive
PromptsNo conceptFirst-class primitive
EcosystemBuild everything yourselfGrowing library of servers
Server reuseOne-off implementationsWrite once, use everywhere

MCP doesn't replace function calling β€” it standardizes it. An MCP client translates MCP tools into whatever function calling format the underlying model uses (OpenAI, Anthropic, etc.).

πŸ›‘οΈ

Security: Human in the Loop

MCP is designed with security in mind:

Tool approval: The client (not the server) decides whether to execute a tool call. Claude Desktop shows you the tool call and waits for approval.

Resource boundaries: Servers declare what resources they expose. The client controls access.

Transport isolation: stdio servers run as sandboxed child processes.

No arbitrary code: The protocol is JSON-RPC β€” data only, no executable payloads.

User: "Delete all records from the users table"

Claude: "I'll need to run a SQL query to do that."

MCP flow:

  1. Claude generates: tools/call("query", {sql: "DELETE FROM users"})
  2. Client shows user: "Claude wants to run: DELETE FROM users"
  3. User clicks: "Deny" ← Human stays in control

πŸ“¦

Try It Yourself

bash

Quick start: MCP with Claude Desktop

1. Install an MCP server

npm install -g @modelcontextprotocol/server-filesystem

2. Add to Claude Desktop config

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

cat << 'EOF' > claude_desktop_config.json

{

"mcpServers": {

example
code
"filesystem": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-filesystem",
        "/Users/you/projects"
      ]
    }

}

}

EOF

3. Restart Claude Desktop

4. Ask Claude: "What files are in my projects directory?"

Claude will use the filesystem MCP server to list files

πŸš€

Practical Takeaways

MCP standardizes how AI connects to tools β€” one protocol, any model, any framework

Three primitives: Tools (actions), Resources (data), Prompts (templates) β€” covers all integration patterns

JSON-RPC over stdio or HTTP β€” local tools as child processes, remote tools over the network

Write a server once, every client works β€” no more NΓ—M integration problem

Human-in-the-loop by default β€” the client approves tool calls, not the model

The ecosystem is real β€” GitHub, Slack, PostgreSQL, filesystem servers already exist

πŸ”„

What's Next?

Episode 79: OpenAI Function Calling Spec β€” MCP is the protocol. But what does the actual function calling look like at the API level? OpenAI's spec β€” JSON schemas, tool_choice, parallel tool calls β€” is the most widely implemented interface. We'll dissect every parameter.

← Previous

Ep 77: RoPE & Position Encoding

Next β†’

Ep 79: OpenAI Function Calling Spec

Next: Episode 79 β€” OpenAI Function Calling Spec

The model can write essays and solve math, but it can't check the weather. Function calling bridges that gap.

This is part of a 98-episode series covering AI engineering from tokens to production deployment.

← Previous Ep 77: RoPE & Position Encoding: How AI Knows Word Order