๐ŸŸก Intermediate

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

๐Ÿ› ๏ธ AI Engineering Toolsโฑ 15 min read๐Ÿ—“ May 2026

Model Context Protocol (MCP) is an open standard developed by Anthropic that defines how AI models connect to external tools and data sources. Think of it as USB-C for AI โ€” a universal connector that lets any AI application work with any tool or service through a common interface.

The Problem MCP Solves

Before MCP, every AI application needed custom integrations for each tool:

With MCP, tools expose a standard interface. AI apps implement the MCP client protocol once. Result: any MCP-compatible app works with any MCP-compatible tool โ€” the "N ร— M problem" becomes "N + M."

The analogy: Before USB, every device had its own connector. USB standardized it. Before MCP, every AI tool had a custom API. MCP standardizes the AI-to-tool interface.

MCP Architecture

MCP has three layers:

Communication happens over:

MCP Primitives: Tools, Resources & Prompts

Tools

Functions the model can call with arguments. Like function calling โ€” but standardized and reusable across any MCP-compatible AI.

Resources

Data the model can read. Files, database rows, API responses โ€” exposed as URIs the model can access.

Prompts

Reusable prompt templates that users can invoke. Parameterized, versioned, and shared via the server.

Building an MCP Server in Python

# Install: pip install mcp
from mcp.server.fastmcp import FastMCP
from typing import Optional
import httpx
import json

# Create the MCP server
mcp = FastMCP("my-company-tools")

@mcp.tool()
async def get_customer_info(customer_id: str) -> str:
    """
    Get detailed information about a customer by their ID.

    Args:
        customer_id: The unique customer identifier (e.g., 'CUST-12345')

    Returns:
        JSON string with customer name, email, plan, and account status
    """
    # In production, query your actual database
    # Here we simulate it
    customers = {
        "CUST-001": {
            "name": "Alice Johnson",
            "email": "alice@example.com",
            "plan": "Enterprise",
            "status": "active",
            "mrr": 2499.00
        }
    }
    customer = customers.get(customer_id)
    if not customer:
        return json.dumps({"error": f"Customer {customer_id} not found"})
    return json.dumps(customer)

@mcp.tool()
async def search_knowledge_base(query: str, limit: int = 5) -> str:
    """
    Search the company knowledge base for relevant articles.

    Args:
        query: Search query in natural language
        limit: Maximum number of results to return (1-20)
    """
    # Connect to your actual search backend
    async with httpx.AsyncClient() as client:
        response = await client.get(
            "https://your-kb-api.internal/search",
            params={"q": query, "limit": min(limit, 20)},
            headers={"Authorization": "Bearer your-internal-token"}
        )
        results = response.json()
    return json.dumps(results)

@mcp.tool()
async def create_support_ticket(
    customer_id: str,
    subject: str,
    description: str,
    priority: str = "normal"
) -> str:
    """
    Create a support ticket for a customer.

    Args:
        customer_id: Customer identifier
        subject: Brief subject line (max 100 chars)
        description: Detailed description of the issue
        priority: Ticket priority - 'low', 'normal', 'high', 'urgent'
    """
    if priority not in ("low", "normal", "high", "urgent"):
        return json.dumps({"error": "Invalid priority. Use: low, normal, high, urgent"})

    # Create ticket in your ticketing system
    ticket = {
        "ticket_id": "TKT-98765",
        "customer_id": customer_id,
        "subject": subject,
        "priority": priority,
        "status": "open",
        "created_at": "2026-05-30T10:00:00Z"
    }
    return json.dumps({"success": True, "ticket": ticket})

# Expose a resource (readable data)
@mcp.resource("config://company/support-policies")
async def get_support_policies() -> str:
    """Read-only access to support policies."""
    return """
    SUPPORT POLICIES (v2.1, updated 2026-05):
    - Response SLA: 4h (normal), 1h (high), 15min (urgent)
    - Refund policy: Full refund within 30 days, pro-rated after
    - Escalation: VP of Support for enterprise customers
    """

# Run the server (stdio mode for Claude Desktop)
if __name__ == "__main__":
    mcp.run(transport="stdio")

MCP Server Configuration

Configure Claude Desktop or Claude Code to use your server by adding it to the MCP config file:

# claude_desktop_config.json (Mac: ~/Library/Application Support/Claude/)
{
  "mcpServers": {
    "my-company-tools": {
      "command": "python",
      "args": ["/path/to/your/mcp_server.py"],
      "env": {
        "DATABASE_URL": "postgresql://...",
        "API_KEY": "your-internal-api-key"
      }
    },

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

    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."
      }
    }
  }
}

Using MCP from Your Own Application

# Connect to MCP servers from your Python application
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

async def use_mcp_tools():
    server_params = StdioServerParameters(
        command="python",
        args=["mcp_server.py"]
    )

    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            # Initialize
            await session.initialize()

            # List available 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(
                "get_customer_info",
                {"customer_id": "CUST-001"}
            )
            print(f"Tool result: {result.content[0].text}")

            # Read a resource
            resource = await session.read_resource(
                "config://company/support-policies"
            )
            print(f"Resource: {resource.contents[0].text}")

asyncio.run(use_mcp_tools())

Popular Pre-Built MCP Servers

Install via: npx -y @modelcontextprotocol/server-github

MCP vs direct tool calling: Direct tool calling embeds tools in your application code. MCP separates tool implementation from AI application โ€” tools are standalone servers that any MCP-compatible AI can use. Choose MCP when you want reusable tools across multiple AI applications or teams.

Key Takeaways