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
访问服务器

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>

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选