Skip to content

Repository files navigation

πŸ”Œ MCP Server & Client Examples

A graded collection of Model Context Protocol servers and clients, from "hello world" to a production-shaped secure API gateway and a Claude-powered agent. Every example works with Claude (Claude Code, Claude Desktop, claude.ai connectors) and ChatGPT (developer-mode connectors), because they all use the transports those clients speak: stdio for local servers and Streamable HTTP for remote ones.

πŸ—ΊοΈ The big picture

MCP is the USB port between AI models and your code: the client (an AI app) discovers what a server offers and calls it on the model's behalf.

flowchart LR
    subgraph AI["πŸ€– AI clients"]
        C1["Claude Code / Desktop"]
        C2["claude.ai / ChatGPT<br/>connectors"]
        C3["Your own client<br/>(clients/ folder)"]
    end

    subgraph S["πŸ–₯️ MCP server (this repo)"]
        T["πŸ› οΈ Tools<br/>functions the AI can call"]
        R["πŸ“„ Resources<br/>data the AI can read"]
        P["πŸ’¬ Prompts<br/>reusable templates"]
    end

    EXT["🌍 The real world<br/>APIs · databases · files"]

    C1 -- "stdio / HTTP" --> S
    C2 -- "HTTPS (tunnel)" --> S
    C3 -- "stdio / HTTP" --> S
    S --> EXT
Loading

πŸ“š The learning path

Work through them in order β€” each README explains the new concepts it adds.

πŸ–₯️ Servers

# Example Transport Auth What it teaches
1️⃣ hello-world stdio β€” 🐣 The absolute minimum: one file, two tools
2️⃣ remote-basic Streamable HTTP none 🌐 A remote server: tools + a resource + a prompt
3️⃣ remote-auth Streamable HTTP πŸ”‘ bearer token πŸ”’ The same server, locked down properly
4️⃣ tool-features Streamable HTTP none βš™οΈ Typed params, structured output, errors, async HTTP calls, progress + logging
5️⃣ task-manager Streamable HTTP none πŸ’Ύ A stateful app: SQLite-backed CRUD the AI can drive
6️⃣ secure-gateway Streamable HTTP πŸ”‘ bearer token 🏰 Everything combined: auth + external API + caching + rate limiting + health endpoint

πŸ” Clients β€” clients/

# Client Pairs with What it teaches
1️⃣ stdio client server 01 🐣 Launch a server subprocess; initialize β†’ list β†’ call
2️⃣ HTTP client server 02 🌐 Remote connections; resources and prompts
3️⃣ auth client server 03 πŸ”‘ Bearer-token headers; handling rejection
4️⃣ advanced client server 04 πŸ“Š Live progress bars + server log streaming
5️⃣ interactive CLI any server 🧰 A generic inspector for any MCP URL
6️⃣ Claude agent any server πŸ€– The full agentic loop: Claude plans and calls your tools
flowchart LR
    A["1️⃣ hello-world<br/>stdio basics"] --> B["2️⃣ remote-basic<br/>go remote"]
    B --> C["3️⃣ remote-auth<br/>lock it down"]
    C --> D["4️⃣ tool-features<br/>great tools"]
    D --> E["5️⃣ task-manager<br/>real state"]
    E --> F["6️⃣ secure-gateway<br/>production shape"]
    F --> G["πŸ€– clients/06<br/>Claude drives it all"]

    style A fill:#1a7f37,color:#fff
    style F fill:#8250df,color:#fff
    style G fill:#cf222e,color:#fff
Loading

🚚 Two transports, one protocol

flowchart TB
    subgraph LOCAL["πŸ“Ÿ stdio β€” local (example 01)"]
        direction LR
        H["AI client"] -- "launches subprocess,<br/>JSON-RPC over stdin/stdout" --> SRV1["server.py"]
    end

    subgraph REMOTE["🌐 Streamable HTTP β€” remote (examples 02-06)"]
        direction LR
        H2["AI client"] -- "POST /mcp<br/>(+ Authorization header)" --> SRV2["server on a port"]
    end
Loading
  • stdio β†’ Claude Desktop & Claude Code launch the server themselves. No port, no auth needed β€” only your machine can reach it.
  • Streamable HTTP β†’ a real network service. claude.ai and ChatGPT connectors need this (over an HTTPS tunnel), and it's what you secure in examples 03 and 06.

⚑ Quick start

Run one example directly

pip install -r requirements.txt
python 02-remote-basic/server.py
# -> Streamable HTTP MCP server on http://localhost:8102/mcp

Run all the remote examples at once (Docker) 🐳

cp .env.example .env      # then set MCP_AUTH_TOKEN (e.g. openssl rand -hex 24)
docker compose up -d --build
Example URL
2️⃣ remote-basic http://localhost:8102/mcp
3️⃣ remote-auth http://localhost:8103/mcp
4️⃣ tool-features http://localhost:8104/mcp
5️⃣ task-manager http://localhost:8105/mcp
6️⃣ secure-gateway http://localhost:8106/mcp

πŸ”— Connecting the AI clients

Claude Code (CLI)

# local stdio server
claude mcp add hello -- python 01-hello-world/server.py

# remote server, no auth
claude mcp add --transport http remote-basic http://localhost:8102/mcp

# remote server with bearer auth
claude mcp add --transport http remote-auth http://localhost:8103/mcp \
  --header "Authorization: Bearer <MCP_AUTH_TOKEN>"

Claude Desktop (local stdio servers)

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "hello": {
      "command": "python",
      "args": ["C:/path/to/mcp-server-examples/01-hello-world/server.py"]
    }
  }
}

claude.ai and ChatGPT (remote connectors) 🌍

Both need a publicly reachable HTTPS URL. From your machine, tunnel one example:

cloudflared tunnel --url http://localhost:8102     # or: ngrok http 8102

Then add https://<tunnel-host>/mcp as a custom connector. For the authenticated examples (03, 06), also supply the Authorization: Bearer <token> header in the connector's auth settings.

πŸ’‘ ChatGPT: connectors are added under Settings β†’ Connectors (developer mode must be enabled for custom MCP connectors).

πŸ” The security ladder

What a request goes through in the capstone gateway (example 06):

flowchart TD
    REQ["πŸ“¨ Incoming request"] --> HP{"/health?"}
    HP -- yes --> OK200["βœ… 200 β€” always open<br/>for monitors & load balancers"]
    HP -- no --> AUTH{"πŸ”‘ Bearer token valid?<br/>(constant-time compare)"}
    AUTH -- no --> R401["β›” 401 + WWW-Authenticate"]
    AUTH -- yes --> RATE{"🚦 Under 30 req/min?"}
    RATE -- no --> R429["🐌 429 + Retry-After"]
    RATE -- yes --> CACHE{"⚑ Cached (< 5 min)?"}
    CACHE -- yes --> HIT["βœ… Serve from memory"]
    CACHE -- no --> UP["🌍 Call upstream API<br/>β†’ cache β†’ respond"]
Loading
  • 1️⃣–2️⃣ have no auth. Fine for localhost experiments; never tunnel these.
  • 3️⃣ shows the minimum viable protection: a static bearer token checked in constant time, and a server that refuses to start without one.
  • 6️⃣ adds the rest: rate limiting, an open /health probe, upstream caching.
  • ⚠️ Plain HTTP means the token is visible on-path β€” for anything beyond your LAN, terminate TLS in front (a cloudflared/ngrok tunnel does this for you).

πŸ€– The agentic loop (client 06)

What actually happens when Claude drives your MCP server:

sequenceDiagram
    participant U as πŸ§‘ You
    participant A as πŸ€– Claude (tool runner)
    participant M as πŸ”Œ MCP server
    participant W as 🌍 External API

    U->>A: "Should I cycle in Manchester this weekend?"
    A->>M: find_city("Manchester")
    M-->>A: coordinates
    A->>M: get_weather(53.48, -2.24, days=3)
    M->>W: Open-Meteo forecast
    W-->>M: forecast data
    M-->>A: structured forecast
    A-->>U: "Saturday looks dry with light wind β€” go for it. 🚴"
Loading

πŸ“¦ Requirements

  • 🐍 Python 3.11+ β€” pip install -r requirements.txt (the mcp SDK, httpx, uvicorn, and anthropic[mcp] for client 06)
  • 🐳 Docker Desktop only if you want the compose setup
  • πŸ”‘ An Anthropic API key only for client 06

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages