17  Model Context Protocol (MCP)

Note📍 Chapter Overview

Time: ~75 minutes | Level: Advanced | Prerequisites: Chapter 15

“MCP is to AI what USB is to computers — a universal standard that makes everything plug in.”

17.1 15.1 The Tool Integration Problem

Before MCP, every AI assistant had its own way of connecting to external tools:

  • OpenAI had “Function Calling”
  • Anthropic had “Tool Use”
  • LangChain had its own tool format
  • Custom applications built yet another format

If you built a database connector for one system, it wouldn’t work with another. Every integration was a custom project.

MCP solves this with a universal standard.


17.2 15.2 What is the Model Context Protocol?

MCP (Model Context Protocol) is an open standard introduced by Anthropic in 2024 that defines a universal interface between AI models and external tools, data sources, and capabilities.

graph LR
    A[AI Model<br/>Claude/GPT/Gemini] <-->|MCP Protocol| B[MCP Server]
    B <--> C[📁 File System]
    B <--> D[🗄️ Database]
    B <--> E[🌐 Web APIs]
    B <--> F[📧 Email/Calendar]
    B <--> G[💻 Code Execution]

17.2.1 The Key Insight

Before MCP: - 10 AI apps × 10 integrations = 100 custom implementations 😫

After MCP: - 10 MCP servers × any AI app = 10 implementations, infinite combinations 🎉


17.3 15.3 MCP Architecture

sequenceDiagram
    participant Host as Host App (Claude Desktop)
    participant Client as MCP Client
    participant Server as MCP Server
    participant Resource as External Resource

    Host->>Client: User request needing tool
    Client->>Server: List available tools
    Server->>Client: [search_web, read_file, run_sql...]
    Client->>Host: Here are available tools
    Host->>Client: Call search_web("AI trends 2025")
    Client->>Server: tool_call: search_web
    Server->>Resource: Execute search
    Resource->>Server: Results
    Server->>Client: Tool result
    Client->>Host: Here are the results

17.3.1 Three Core Primitives

Primitive Description Example
Resources Data the AI can read Files, database records, API responses
Tools Actions the AI can execute Run query, send email, call API
Prompts Reusable prompt templates “Summarise this document”, “Review this code”

17.4 15.4 Building Your First MCP Server

# file: mcp_server.py
from mcp.server import Server
from mcp.server.models import InitializationOptions
from mcp.types import (
    Resource, Tool, TextContent, CallToolResult
)
import mcp.server.stdio
import json
import asyncio

# Create MCP server
server = Server("business-analytics-mcp")

# ============================================================
# RESOURCES: Data the AI can read
# ============================================================

@server.list_resources()
async def list_resources():
    """Expose available data resources."""
    return [
        Resource(
            uri="analytics://sales-summary",
            name="Sales Summary",
            description="Current month sales data summary",
            mimeType="application/json"
        ),
        Resource(
            uri="analytics://kpi-dashboard",
            name="KPI Dashboard",
            description="Key performance indicators",
            mimeType="application/json"
        )
    ]

@server.read_resource()
async def read_resource(uri: str):
    """Return resource content."""
    if uri == "analytics://sales-summary":
        # In reality, query your database
        data = {
            "month": "March 2026",
            "total_revenue": 2_450_000,
            "units_sold": 1_234,
            "top_product": "AI Training Platform",
            "growth_vs_last_month": "+12.3%"
        }
        return TextContent(type="text", text=json.dumps(data, indent=2))

    raise ValueError(f"Unknown resource: {uri}")

# ============================================================
# TOOLS: Actions the AI can take
# ============================================================

@server.list_tools()
async def list_tools():
    """Expose available tools."""
    return [
        Tool(
            name="run_sales_query",
            description="Query sales database with SQL",
            inputSchema={
                "type": "object",
                "properties": {
                    "query": {"type": "string", "description": "SQL query to run"},
                    "limit": {"type": "integer", "description": "Max rows", "default": 100}
                },
                "required": ["query"]
            }
        ),
        Tool(
            name="generate_report",
            description="Generate a formatted business report",
            inputSchema={
                "type": "object",
                "properties": {
                    "topic": {"type": "string"},
                    "format": {"type": "string", "enum": ["pdf", "markdown", "html"]}
                },
                "required": ["topic", "format"]
            }
        ),
        Tool(
            name="send_notification",
            description="Send a Slack notification to a channel",
            inputSchema={
                "type": "object",
                "properties": {
                    "channel": {"type": "string"},
                    "message": {"type": "string"}
                },
                "required": ["channel", "message"]
            }
        )
    ]

@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list:
    """Execute a tool call."""
    if name == "run_sales_query":
        # Mock database response
        result = f"Query executed: {arguments['query']}\nRows returned: 42\nSample: [row1, row2, ...]"
        return [TextContent(type="text", text=result)]

    elif name == "generate_report":
        result = f"Report generated: {arguments['topic']} in {arguments['format']} format"
        return [TextContent(type="text", text=result)]

    elif name == "send_notification":
        result = f"Notification sent to #{arguments['channel']}: {arguments['message']}"
        return [TextContent(type="text", text=result)]

    raise ValueError(f"Unknown tool: {name}")

# ============================================================
# Run the server
# ============================================================
async def main():
    async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
        await server.run(
            read_stream, write_stream,
            InitializationOptions(
                server_name="business-analytics-mcp",
                server_version="1.0.0"
            )
        )

if __name__ == "__main__":
    asyncio.run(main())

17.5 15.5 MCP Configuration for Claude Desktop

// ~/.config/claude/claude_desktop_config.json
{
  "mcpServers": {
    "business-analytics": {
      "command": "python",
      "args": ["/path/to/mcp_server.py"],
      "env": {
        "DATABASE_URL": "postgresql://...",
        "SLACK_TOKEN": "xoxb-..."
      }
    },
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/bongo/Documents"]
    }
  }
}

17.6 15.6 The MCP Ecosystem

As of 2025, hundreds of MCP servers exist for:

  • Databases: PostgreSQL, MySQL, MongoDB, SQLite
  • Cloud services: AWS, Google Cloud, Azure
  • Productivity: Slack, Gmail, Google Docs, Notion
  • Dev tools: GitHub, GitLab, Jira, Linear
  • Data: Airtable, Snowflake, BigQuery
  • Web: Playwright (browser automation), web scraping

17.7 Chapter Summary

  • MCP provides a universal standard for AI-tool integration
  • Three primitives: Resources (data), Tools (actions), Prompts (templates)
  • MCP servers are language-agnostic and reusable across AI platforms
  • The ecosystem has hundreds of ready-made servers
  • Custom MCP servers give your AI access to proprietary data and systems

17.8 What’s Next

Chapter 16: Advanced MCP Concepts — build your own production MCP server with authentication, error handling, and streaming.


Note📚 Further Reading