mcp-demo-server

mcp-demo-server

Provides a weather lookup tool and greeting resource via MCP, enabling AI agents to fetch current conditions and personalized messages through natural language.

Category
Visit Server

README

MCP Demo — Python Agent Tooling from the Ground Up

<p align="center"> <img src="https://img.shields.io/badge/Python-3.10+-blue?style=for-the-badge&logo=python&logoColor=white" alt="Python Version"> <img src="https://img.shields.io/badge/MCP-SDK-orange?style=for-the-badge&logo=modelcontextprotocol&logoColor=white" alt="MCP SDK"> <img src="https://img.shields.io/badge/Transport-stdio-green?style=for-the-badge" alt="Transport"> <img src="https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge" alt="License"> </p>

<p align="center"> <strong>A production-oriented, runnable example of the <a href="https://modelcontextprotocol.io/">Model Context Protocol (MCP)</a> using Python, the official MCP Python SDK, stdio transport, Pydantic, and OpenAI function calling.</strong> </p>


What is MCP?

MCP (Model Context Protocol) is a standardized protocol that lets AI applications discover and use external tools, resources, and prompts through one consistent interface.

Instead of every AI framework inventing a different integration for every database, API, filesystem, or internal service, an MCP host can connect to an MCP server and use the same protocol surface.

Problems MCP Solves

Problem MCP Solution
Vendor lock-in Integrations expose capabilities through MCP rather than tying to one model provider or agent framework
Inconsistent tool-calling Tools have machine-readable schemas and standardized discovery/call semantics
No context persistence MCP separates context/tool providers from the model, enabling long-lived connections
Dynamic data sources Databases, APIs, files, and internal systems wrapped as MCP resources/tools without embedding implementation into model runtime

On the wire, MCP uses JSON-RPC 2.0 messages over transports such as stdio and HTTP-based transports (SSE/Streamable HTTP). This repository uses stdio: the client launches the server as a subprocess, sends protocol messages through stdin, and receives responses through stdout.


Architecture

flowchart TD
    A[User: "What's the weather in London?"] --> B[AI Agent<br/>OpenAI Responses API]
    B --> C[1. Discovers MCP tools]
    B --> D[2. Decides whether to call]
    B --> E[3. Emits function call]
    E --> F[MCP Client<br/>ClientSession + stdio]
    F --> G[initialize]
    F --> H[tools/list]
    F --> I[tools/call]
    I --> J[JSON-RPC 2.0<br/>stdin/stdout]
    J --> K[MCP Server subprocess]
    K --> L[get_current_weather tool]
    K --> M[greeting://{name} resource]

Why the Official SDK?

This repository uses the official Python MCP SDK instead of reimplementing the protocol. The SDK supplies:

  • Protocol lifecycle & validation
  • Transport abstraction (stdio, HTTP/SSE)
  • Typed client/server APIs

The application code still makes the important MCP concepts explicit: server registration, tool schemas, initialize, tools/list, tools/call, resource reads, and stdio process management.

The current SDK's stable v2 API uses MCPServer for server construction and ClientSession/stdio_client for stdio clients.


Project Layout

mcp-demo/
├── README.md
├── requirements.txt
├── .env.example
├── pyproject.toml
├── src/
│   ├── mcp_server/
│   │   ├── __init__.py
│   │   ├── server.py      # MCP server entry point
│   │   ├── tools.py       # Tool implementations
│   │   ├── handlers.py    # Request handlers
│   │   └── utils.py       # Shared utilities
│   ├── mcp_client/
│   │   ├── __init__.py
│   │   ├── client.py      # MCP client wrapper
│   │   ├── agent.py       # OpenAI agent integration
│   │   └── runner.py      # Demo runner
│   └── shared/
│       ├── __init__.py
│       └── types.py       # Shared Pydantic models
├── tests/
│   ├── test_server.py
│   └── test_client.py
├── examples/
│   └── demo.ipynb
└── scripts/
    └── run_demo.sh

Requirements

  • Python 3.10+
  • OpenAI API key (for the AI-agent demo)
  • No weather API key required — the weather tool uses deterministic sample data so the MCP path works offline

Quick Start

1. Create Virtual Environment

python -m venv .venv
source .venv/bin/activate        # Linux/macOS
.venv\Scripts\Activate.ps1       # Windows PowerShell

2. Install Dependencies

python -m pip install --upgrade pip
pip install -r requirements.txt

3. Configure OpenAI

cp .env.example .env

Edit .env with your credentials:

OPENAI_API_KEY=your_api_key_here
OPENAI_MODEL=gpt-4.1-mini

The server itself does not need the OpenAI key.


Run the Demo

From Repository Root

python src/mcp_client/runner.py

What the runner does:

Step Description
1️⃣ Launches src/mcp_server/server.py as a child process
2️⃣ Performs MCP initialization handshake
3️⃣ Calls tools/list
4️⃣ Converts discovered MCP schemas → OpenAI function tools
5️⃣ Asks model to answer a natural-language question
6️⃣ When model chooses get_current_weather, sends tools/call through MCP
7️⃣ Sends MCP result back to model
8️⃣ Prints final answer
9️⃣ Shuts down server cleanly

Alternative: Shell Wrapper

bash scripts/run_demo.sh

Expected Output

Exact wording varies by model, but the log flow looks like:

INFO mcp_client.client: -> MCP initialize
INFO mcp_client.client: <- MCP initialize: server=mcp-demo-server
INFO mcp_client.client: -> MCP tools/list
INFO mcp_client.client: <- MCP tools/list: ["get_current_weather"]
INFO mcp_client.agent: User: What's the weather in London?
INFO mcp_client.agent: OpenAI requested tool: get_current_weather {"city":"London","units":"metric"}
INFO mcp_client.client: -> MCP tools/call name=get_current_weather arguments={"city":"London","units":"metric"}
INFO mcp_server.tools: weather lookup city=London units=metric
INFO mcp_client.client: <- MCP tools/call result={"city":"London","temperature":18.0,...}
INFO mcp_client.agent: Final: London is 18°C and partly cloudy.

The logs deliberately show MCP semantic messages at the application boundary. The SDK handles JSON-RPC framing internally.


Run MCP Server Standalone

python src/mcp_server/server.py

A stdio MCP server appears to "hang" — this is expected. It waits for protocol messages on stdin. A host/client should launch it and own the stdio pipes.

Interactive Protocol Inspection

pip install "mcp[cli]"
mcp dev src/mcp_server/server.py

MCP Methods Demonstrated

The official SDK handles the JSON-RPC lifecycle:

Method Direction Purpose
initialize Client → Server Handshake & capability negotiation
tools/list Client → Server Discover available tools
tools/call Client → Server Invoke a tool
resources/list Client → Server Discover available resources
resources/read Client → Server Read a resource

The client explicitly calls initialize() before listing or invoking capabilities. The server's decorators generate tool/resource schemas from Python type annotations.


Tool: get_current_weather

get_current_weather(
    city: str,
    units: Literal["metric", "imperial"] = "metric"
) -> WeatherResponse

Returns structured Pydantic-backed payload:

{
  "city": "London",
  "temperature": 18.0,
  "units": "metric",
  "condition": "partly cloudy",
  "humidity_percent": 72
}

Unknown cities fail with a controlled MCP tool error rather than crashing the server.


Agent Integration Flow

The agent uses plain OpenAI function calling (no extra framework) to keep the demo focused:

flowchart LR
    A[MCP Tool Schema] --> B[OpenAI Function Tool]
    B --> C[Model Chooses Function]
    C --> D[MCP ClientSession.call_tool]
    D --> E[MCP Server Executes Tool]
    E --> F[Function Call Output]
    F --> G[Final Model Answer]

This is the same pattern agent frameworks wrap: discover MCP tools → expose schemas to model → route selected calls back through MCP → feed results into next model turn.


Testing

pytest -q

Test suite covers:

  • ✅ Tool execution (metric weather)
  • ✅ Tool execution (imperial weather)
  • ✅ Validation/error behavior (unknown city)
  • ✅ In-process MCP client discovery & tool invocation

Tests use the SDK's in-memory client where possible — avoids subprocess flakiness while exercising the real MCP protocol layer.


Formatting & Linting

This project uses Ruff:

# Check
ruff check .
ruff format --check .

# Format
ruff format .

Production Notes

This demo is deliberately small, but represents several production concerns:

Concern Implementation
stdout discipline Server never prints app logs to stdout (belongs to MCP); logs go to stderr via logging
Typed I/O Pydantic models validate tool inputs/outputs at application boundary
Controlled failures Tool exceptions → MCP error results (SDK), not process crashes
Subprocess lifecycle SDK's stdio context manager owns process startup/shutdown
Least-privilege env MCP stdio client explicitly passes env vars needed by child process
Dynamic discovery Agent doesn't hard-code weather tool schema; discovers via tools/list

For real external data sources: replace deterministic weather with authenticated API/database calls, add timeouts, retries, rate limiting, observability, and secrets management.


Protocol Mental Model

Simplified JSON-RPC sequence:

// Client -> Server
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}

// Server -> Client
{"jsonrpc":"2.0","id":1,"result":{...}}

// Client -> Server
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}

// Server -> Client
{"jsonrpc":"2.0","id":2,"result":{"tools":[...]}}

// Client -> Server
{"jsonrpc":"2.0","id":3,"method":"tools/call",
 "params":{"name":"get_current_weather","arguments":{"city":"London"}}}

// Server -> Client
{"jsonrpc":"2.0","id":3,"result":{"content":[...],"structuredContent":{...}}}

The exact protocol schema is maintained by the MCP specification and the SDK. The above is intentionally simplified for teaching.


References

  • Official MCP Python SDK: https://py.sdk.modelcontextprotocol.io/
  • MCP Specification: https://modelcontextprotocol.io/specification/
  • OpenAI Function Calling: https://platform.openai.com/docs/guides/function-calling

<p align="center"> Made with ❤️ for the MCP community </p>

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured