Available for Q3 2026 projects — Laravel, AI agents & automation
Build With Abdallah logo Build With Abdallah Software · AI · Automation
APIs 7 min read Jun 03, 2026

Build Your First MCP Server — Connect AI to Real Data in 15 Minutes

Learn how to build an MCP server that connects Claude Desktop to your real business data — SQLite, APIs, files — in 15 minutes with Python.

A
Abdallah Mohamed
Senior Full-Stack Engineer

Build Your First MCP Server — Connect AI to Real Data in 15 Minutes

Content ID: 2026-06-03-mcp-server-tutorial
Type: Tutorial
Target: Developers, technical founders, AI-curious small business owners
Reading time: ~8 minutes


What is MCP?

MCP (Model Context Protocol) is an open standard that lets AI assistants connect to your real-world data — databases, APIs, files, and business tools. Think of it as "USB-C for AI."

Instead of asking ChatGPT generic questions, you can ask it to:

  • "Show me yesterday's Shopify orders"
  • "How many support tickets are open?"
  • "Draft an invoice from my CRM data"

Created by: Anthropic (late 2024)
Now supported by: OpenAI, Google, LangChain, VS Code, Cursor, and more.


Why Should You Care?

Small businesses don't need another chatbot. They need AI that actually does things — query databases, check inventory, update records.

MCP makes this possible without building a custom backend for every integration.


What We're Building

A Python MCP server that exposes a SQLite customer database to Claude Desktop. You'll be able to ask Claude natural-language questions about your data.


Prerequisites

  • Python 3.10+ installed
  • pip package manager
  • Basic familiarity with SQL and Python

Step 1 — Install the MCP SDK

pip install "mcp[cli]"

The mcp package includes both the server SDK and the Claude Desktop integration tool. (No need to install sqlite3 — it ships with Python's standard library. The quotes keep shells like zsh from choking on the brackets.)


Step 2 — Create Your Database

Create a sample SQLite database with customer data:

# setup_db.py
import sqlite3

conn = sqlite3.connect("customers.db")
cursor = conn.cursor()

cursor.execute("""
    CREATE TABLE IF NOT EXISTS customers (
        id INTEGER PRIMARY KEY,
        name TEXT,
        email TEXT,
        plan TEXT,
        signup_date TEXT,
        monthly_spend REAL
    )
""")

sample_data = [
    (1, "Sarah Chen", "sarah@designstudio.com", "Pro", "2025-03-15", 149.00),
    (2, "Mike Ross", "mike@legaltech.io", "Starter", "2025-06-01", 29.00),
    (3, "Aisha Patel", "aisha@retailplus.com", "Enterprise", "2024-11-20", 499.00),
    (4, "Tom Wilson", "tom@consulting.co", "Pro", "2025-01-10", 149.00),
    (5, "Lisa Park", "lisa@startup.xyz", "Starter", "2025-05-22", 29.00),
]

cursor.executemany(
    "INSERT INTO customers VALUES (?, ?, ?, ?, ?, ?)",
    sample_data
)

conn.commit()
conn.close()
print("Database created with 5 sample customers")

Run it:

python setup_db.py

Step 3 — Build the MCP Server

Create server.py — this is your MCP server:

from mcp.server.fastmcp import FastMCP
import sqlite3
import json

mcp = FastMCP("customer-insights")

# --- RESOURCES (read-only data) ---

@mcp.resource("customers://all")
def get_all_customers() -> str:
    """Returns all customer records as JSON."""
    conn = sqlite3.connect("customers.db")
    conn.row_factory = sqlite3.Row
    rows = [dict(row) for row in conn.execute("SELECT * FROM customers")]
    conn.close()
    return json.dumps(rows, indent=2)

@mcp.resource("customers://summary")
def get_customer_summary() -> str:
    """Returns customer count and total monthly revenue."""
    conn = sqlite3.connect("customers.db")
    count, revenue = conn.execute(
        "SELECT COUNT(*), COALESCE(SUM(monthly_spend), 0) FROM customers"
    ).fetchone()
    conn.close()
    return json.dumps({
        "total_customers": count,
        "monthly_revenue": round(revenue, 2)
    }, indent=2)


# --- TOOLS (actions the AI can invoke) ---

@mcp.tool()
def search_customers_by_plan(plan: str) -> str:
    """Search customers by subscription plan (Starter, Pro, Enterprise)."""
    conn = sqlite3.connect("customers.db")
    conn.row_factory = sqlite3.Row
    rows = [dict(row) for row in conn.execute(
        "SELECT * FROM customers WHERE plan = ?", (plan,)
    )]
    conn.close()
    return json.dumps(rows, indent=2)

@mcp.tool()
def get_high_value_customers(min_spend: float) -> str:
    """Find customers spending at or above a monthly threshold."""
    conn = sqlite3.connect("customers.db")
    conn.row_factory = sqlite3.Row
    rows = [dict(row) for row in conn.execute(
        "SELECT * FROM customers WHERE monthly_spend >= ?", (min_spend,)
    )]
    conn.close()
    return json.dumps(rows, indent=2)


# --- RUN SERVER ---

if __name__ == "__main__":
    mcp.run()

Note: We're using FastMCP, the high-level SDK API — it auto-generates the tool/resource schemas from your type hints and docstrings, and mcp.run() handles the stdio transport for you. (There's also a lower-level Server class if you ever need full control over the protocol.)


Step 4 — Test the Server Locally

Run the server to verify it starts without errors:

python server.py

You should see no output (it's waiting for MCP protocol messages). Hit Ctrl+C to stop.


Step 5 — Connect to Claude Desktop

Install Claude Desktop if you haven't: claude.ai/download

The fast way: the mcp[cli] package can wire it up for you —

mcp install server.py

This registers the server in Claude Desktop automatically. Prefer to do it by hand? Edit the config:

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

Windows: %APPDATA%\Claude\claude_desktop_config.json

Add your server:

{
  "mcpServers": {
    "customer-insights": {
      "command": "/absolute/path/to/python3",
      "args": ["/absolute/path/to/your/server.py"]
    }
  }
}

Important: Use absolute paths for both the Python interpreter and server.py — Claude Desktop doesn't inherit your shell's PATH. Run which python3 to get the interpreter path.

Restart Claude Desktop.


Step 6 — Query Your Data with Natural Language

Open Claude Desktop. You should see a hammer icon (🔨) indicating MCP tools are available.

Try these prompts:

  • "Show me all my customers"
    → Claude reads the customers://all resource

  • "How much revenue do I have?"
    → Claude checks customers://summary

  • "Which customers are on the Pro plan?"
    → Claude calls search_customers_by_plan tool

  • "Who are my high-value customers spending over $100?"
    → Claude calls get_high_value_customers with min_spend=100


How It Works (The Architecture)

┌─────────────────────────────────────────────┐
│           Claude Desktop (MCP Host)          │
│  ┌─────────────────────────────────────┐   │
│  │         MCP Client                   │   │
│  │  - Discovers tools/resources         │   │
│  │  - Sends JSON-RPC 2.0 requests       │   │
│  └────────────────┬────────────────────┘   │
└───────────────────┼─────────────────────────┘
                    │ stdio or HTTP/SSE
                    ▼
┌─────────────────────────────────────────────┐
│           Your MCP Server                    │
│  ┌─────────────────────────────────────┐   │
│  │  - Resources (read-only data)       │   │
│  │  - Tools (actions with arguments)   │   │
│  │  - Prompts (pre-defined workflows)  │   │
│  └─────────────────────────────────────┘   │
└───────────────────┬─────────────────────────┘
                    │
                    ▼
            ┌─────────────┐
            │  customers.db │
            │   (SQLite)    │
            └─────────────┘

Key concepts:

  • Resources = read-only data your AI can access
  • Tools = actions the AI can invoke with arguments
  • Prompts = pre-built workflows (optional, not covered here)

Extending This — Real Business Use Cases

Replace the SQLite database with real sources:

Data Source What You'd Build
Shopify "How many orders pending?"
PostgreSQL "Revenue this month vs last month"
Stripe "List customers with failed payments"
Airtable "Which projects are overdue?"
REST API "Check server status across all regions"

Security Checklist

⚠️ Before deploying to production:

  • Never expose database credentials in tool schemas
  • Use read-only database users when possible
  • Add rate limiting to prevent abuse
  • Validate all tool arguments before executing queries
  • Log all tool invocations for audit trails
  • For remote servers, use OAuth 2.1 authentication

Troubleshooting

"Server not showing in Claude"

  • Check the path in claude_desktop_config.json is absolute
  • Restart Claude Desktop after config changes
  • Check Claude logs: ~/Library/Logs/Claude/ (Mac)

"Tool call failed"

  • Verify customers.db exists in the same directory as server.py
  • Check Python errors in the Claude logs
  • Ensure SQLite database isn't locked by another process

"Permission denied"

  • Make sure the Python path in config points to the right interpreter
  • Use which python3 to get the full path

Next Steps

  1. Add write tools — let Claude update records (UPDATE, INSERT)
  2. Add prompts — pre-built workflows like "Generate monthly report"
  3. Deploy remotely — host on a server and connect via HTTP/SSE
  4. Add multiple data sources — connect multiple databases or APIs
  5. Build an MCP client — integrate into your own app, not just Claude

Resources


Built with 💙 by Build With Abdallah — custom software, automation, and AI agents for growing businesses.

Questions? Drop a comment or reach out at buildwithabdallah.com