Command Palette

Search for a command to run...

UnylyUnyly
Весь каталог

Learning Server

БесплатноНе проверен

A learning-focused MCP server that provides tools for current time, arithmetic, random quotes, mock weather, and UUID generation, demonstrating the Model Contex

GitHubEmbed

Описание

A learning-focused MCP server that provides tools for current time, arithmetic, random quotes, mock weather, and UUID generation, demonstrating the Model Context Protocol end-to-end.

README

A complete educational project demonstrating the Model Context Protocol (MCP) end-to-end.

This project is designed for developers who are completely new to MCP and want to understand:

  • What an MCP Server is
  • What an MCP Client is
  • How they communicate
  • How tools are registered and discovered
  • How requests flow and responses return

📋 Table of Contents


🎯 Project Overview

This project implements:

Component Description
MCP Server A FastMCP server exposing 5 tools via stdio transport
Interactive Client A Rich-powered CLI that discovers and calls tools
Chat Interface A natural language chatbot that maps queries to tools
Pydantic Validation Type-safe input validation with friendly errors
Logging Structured logs with INFO/WARNING/ERROR levels
Architecture Diagrams Mermaid diagrams explaining every component

Tech Stack

  • Python 3.11+
  • uv package manager
  • Official MCP Python SDK (mcp[cli] with FastMCP)
  • asyncio
  • Pydantic v2
  • Rich library

🏗️ Architecture

High-Level Architecture

┌─────────────────────┐          ┌─────────────────────┐
│     MCP Client      │   stdio  │     MCP Server      │
│                     │◄────────►│                     │
│  • Rich CLI/Chat    │  JSON-   │  • FastMCP Router   │
│  • ClientSession    │  RPC 2.0 │  • 5 Registered     │
│  • Tool Discovery   │          │    Tools            │
└─────────────────────┘          └─────────────────────┘

Request Flow

User
 ↓
Client UI (Rich terminal)
 ↓
ClientSession.call_tool(name, arguments)
 ↓
JSON-RPC 2.0 Request (serialized)
 ↓
stdio Transport (stdin pipe to server subprocess)
 ↓
FastMCP Server (deserializes, routes by tool name)
 ↓
@mcp.tool() Function → Pydantic validation → Business logic
 ↓
JSON Response (consistent format)
 ↓
stdio Transport (stdout pipe back to client)
 ↓
ClientSession (deserializes response)
 ↓
Rich UI (pretty-prints with syntax highlighting)
 ↓
User sees the result ✅

Tool Discovery Flow

Client                          Server
  |                               |
  |──── initialize() ───────────►|
  |◄──── capabilities ──────────|
  |                               |
  |──── list_tools() ───────────►|
  |◄──── tool schemas ──────────|
  |       (name, description,     |
  |        inputSchema)           |
  |                               |
  |  Client now knows all tools!  |

📌 Key MCP advantage: The client doesn't need hardcoded endpoints. It discovers tools dynamically!


📁 Folder Structure

mcp-learning-project/
│
├── server/                    # MCP Server (the "backend")
│   ├── __init__.py           # Package marker
│   ├── server.py             # FastMCP setup + tool registration
│   ├── tools.py              # Pure business logic (no MCP dependency)
│   ├── models.py             # Pydantic validation models
│   └── quotes.py             # Hardcoded quote data
│
├── client/                    # MCP Client (the "frontend")
│   ├── __init__.py           # Package marker
│   ├── client.py             # Interactive CLI client
│   ├── chat.py               # Natural language chat interface
│   └── ui.py                 # Rich terminal UI helpers
│
├── diagrams/                  # Documentation
│   └── architecture.md       # Mermaid architecture diagrams
│
├── logs/                      # Generated at runtime
│   └── app.log               # Structured application logs
│
├── screenshots/               # Screenshots placeholder
│
├── README.md                  # This file
├── pyproject.toml            # Project configuration
├── uv.lock                   # Dependency lock file (auto-generated)
└── .gitignore                # Git ignore rules

Why Each File Exists

File Purpose
server/server.py MCP registration layer — connects business logic to the MCP protocol using @mcp.tool() decorators
server/tools.py Business logic — pure Python functions that can be tested without MCP
server/models.py Validation — Pydantic models that enforce type safety at the input boundary
server/quotes.py Data — separates data from logic for clean architecture
client/client.py Interactive client — demonstrates the full MCP client workflow
client/chat.py Chat interface — shows how natural language maps to tool calls
client/ui.py Presentation — all Rich formatting in one place

🚀 Installation

Prerequisites

  • Python 3.11 or higher
  • uv package manager

Setup

# 1. Clone the repository
git clone <repository-url>
cd mcp-learning-project

# 2. Create a virtual environment and install dependencies
uv sync

# This will:
# - Create a .venv/ directory
# - Install mcp[cli], pydantic, and rich
# - Generate uv.lock for reproducibility

▶️ Running the Project

Option 1: Interactive Client (Recommended)

The client automatically starts the server as a subprocess — you only need one terminal:

uv run python -m client.client

Option 2: Chat Interface

uv run python -m client.chat

Option 3: Server Only (for debugging)

If you want to run the server independently (e.g., to test with MCP Inspector):

uv run python -m server.server

⚠️ The server uses stdio transport, so it reads from stdin and writes to stdout. Running it directly will wait for JSON-RPC input — this is expected behavior.

Testing with MCP Inspector

The MCP Inspector is a visual debugging tool:

npx -y @modelcontextprotocol/inspector uv run python -m server.server

🧰 Available Tools

1. current_time

Returns the current UTC time in ISO 8601 format.

Input None
Output {"success": true, "data": {"current_time": "2026-07-01T12:00:00Z"}}

2. calculator

Performs arithmetic operations on two numbers.

Input {"a": 10, "b": 20, "operation": "add"}
Operations add, subtract, multiply, divide
Output {"success": true, "data": {"result": 30.0}}
Division by zero {"success": false, "error": "Division by zero is not allowed"}

3. random_quote

Returns a random inspirational quote from an internal list of 25 quotes.

Input None
Output {"success": true, "data": {"quote": "Stay hungry, stay foolish. — Steve Jobs"}}

4. weather

Returns mock weather data for Indian cities.

Input {"city": "Jaipur"}
Supported Cities Jaipur, Delhi, Mumbai, Bangalore, Chennai, Kolkata, Hyderabad, Pune
Output {"success": true, "data": {"city": "Jaipur", "temperature": "35°C", "condition": "Sunny"}}
Unknown city {"success": false, "error": "City 'London' not found. Available cities: ..."}

5. uuid_generator

Generates a random UUID (version 4).

Input None
Output {"success": true, "data": {"uuid": "550e8400-e29b-41d4-a716-446655440000"}}

💻 Example Execution

Interactive Client

╭─────────────────────────────────────────────╮
│ 🔌 MCP Learning Client                     │
│    Connected to MCP Server via stdio        │
╰─────────────────────────────────────────────╯

┌──────────────────────────────────────────────┐
│            📋 Available Tools                │
├────┬────────────────┬────────────────────────┤
│ #  │ Tool Name      │ Description            │
├────┼────────────────┼────────────────────────┤
│ 1  │ current_time   │ Get the current UTC    │
│    │                │ time in ISO 8601       │
├────┼────────────────┼────────────────────────┤
│ 2  │ calculator     │ Perform arithmetic     │
│    │                │ operations             │
├────┼────────────────┼────────────────────────┤
│ 3  │ random_quote   │ Get a random           │
│    │                │ inspirational quote    │
├────┼────────────────┼────────────────────────┤
│ 4  │ weather        │ Get mock weather data  │
├────┼────────────────┼────────────────────────┤
│ 5  │ uuid_generator │ Generate a random UUID │
└────┴────────────────┴────────────────────────┘

>>> 2
Enter calculator inputs:
  First number (a): 45
  Second number (b): 87
  Operation (add/subtract/multiply/divide): multiply
⏳ Calling calculator...
╭─── ✅ Success ───╮
│ {                │
│   "result": 3915 │
│ }                │
╰──────────────────╯
⏱  Completed in 0.023s

>>> info weather
📌 weather

Get mock weather data for an Indian city.

📥 Input Schema:
{
  "type": "object",
  "properties": {
    "city": { "type": "string" }
  },
  "required": ["city"]
}

>>> exit
👋 Goodbye!

Chat Interface

🤖 MCP Chat Interface
Ask me about weather, calculations, time, quotes, or UUIDs.
Type 'exit' to quit.

You: What is the weather in Jaipur?
⏳ Calling weather tool...
╭─── 🤖 Assistant ───╮
│ 🌤️  Weather in      │
│ Jaipur: 35°C, Sunny │
╰─────────────────────╯

You: Multiply 45 and 87
⏳ Calling calculator tool...
╭─── 🤖 Assistant ───╮
│ 🔢 The answer is:   │
│ 3915.0               │
╰─────────────────────╯

You: Give me an inspirational quote
⏳ Calling random_quote tool...
╭───── 🤖 Assistant ─────╮
│ 💬 "Stay hungry, stay   │
│ foolish. — Steve Jobs"  │
╰─────────────────────────╯

Example Log Output (logs/app.log)

2026-07-08 10:30:15 | INFO    | mcp.server | FastMCP server instance created: 'MCP Learning Server'
2026-07-08 10:30:15 | INFO    | mcp.server | Starting MCP Learning Server (stdio transport)...
2026-07-08 10:30:16 | INFO    | mcp.client | Client starting — connecting to MCP server...
2026-07-08 10:30:16 | INFO    | mcp.client | stdio transport established
2026-07-08 10:30:16 | INFO    | mcp.client | MCP session initialized
2026-07-08 10:30:16 | INFO    | mcp.client | Discovered 5 tools: ['current_time', 'calculator', ...]
2026-07-08 10:30:20 | INFO    | mcp.client | Calling tool: calculator with args: {'a': 45, 'b': 87, 'operation': 'multiply'}
2026-07-08 10:30:20 | INFO    | mcp.server | Tool called: calculator(a=45.0, b=87.0, op=multiply)
2026-07-08 10:30:20 | INFO    | mcp.server | Tool result: calculator → {'success': True, 'data': {'result': 3915.0}}
2026-07-08 10:30:20 | INFO    | mcp.client | Tool calculator completed in 0.023s

📚 MCP Learning Notes

What is MCP?

The Model Context Protocol (MCP) is a standardized protocol for connecting AI models to external tools and data sources. Think of it as a "USB-C for AI" — a universal interface that lets any AI assistant use any tool without custom integrations.

How MCP Registers Tools

from mcp.server.fastmcp import FastMCP

mcp = FastMCP("My Server")

@mcp.tool(
    name="calculator",
    description="Perform arithmetic operations"
)
def calculator(a: float, b: float, operation: str) -> str:
    # FastMCP auto-generates a JSON Schema from the function signature:
    # {
    #   "type": "object",
    #   "properties": {
    #     "a": {"type": "number"},
    #     "b": {"type": "number"},
    #     "operation": {"type": "string"}
    #   },
    #   "required": ["a", "b", "operation"]
    # }
    ...

When @mcp.tool() is called:

  1. FastMCP inspects the function's type hints
  2. Generates a JSON Schema for the inputs
  3. Stores the tool in an internal registry
  4. When list_tools() is called, returns all registered schemas

How the Client Discovers Tools

from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

# 1. Define how to launch the server
server_params = StdioServerParameters(
    command="uv",
    args=["run", "python", "-m", "server.server"]
)

# 2. Connect via stdio
async with stdio_client(server_params) as (read, write):
    async with ClientSession(read, write) as session:
        # 3. Initialize the session (handshake)
        await session.initialize()

        # 4. Discover all tools
        tools = await session.list_tools()
        # tools.tools → list of Tool objects with name, description, inputSchema

        # 5. Call a specific tool
        result = await session.call_tool("calculator", {"a": 10, "b": 20, "operation": "add"})

How Requests are Serialized

MCP uses JSON-RPC 2.0 over the stdio transport:

// Client → Server (request)
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "calculator",
    "arguments": {"a": 10, "b": 20, "operation": "add"}
  }
}

// Server → Client (response)
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"success\": true, \"data\": {\"result\": 30.0}}"
      }
    ]
  }
}

How Transport Works

This project uses stdio transport:

  • The client spawns the server as a subprocess
  • JSON-RPC messages flow through the subprocess's stdin (requests) and stdout (responses)
  • This is why we never print() to stdout in the server — it would corrupt the protocol!

Other MCP transports include:

  • SSE (Server-Sent Events): HTTP-based, good for remote servers
  • Streamable HTTP: Newer HTTP transport for production use

How MCP Differs from REST

Aspect REST API MCP
Discovery You need documentation/OpenAPI spec list_tools() returns schemas dynamically
Protocol HTTP request/response JSON-RPC 2.0 (bidirectional)
Schema OpenAPI (optional) JSON Schema (built-in)
Transport Always HTTP stdio, SSE, Streamable HTTP
Standardization Varies per API One protocol for all tools
AI Integration Custom per model Universal — any model, any tool

How to Add a New Tool

Adding a tool takes 3 steps:

  1. Business logic — Add a function to server/tools.py:
def my_tool(input_param: str) -> dict[str, Any]:
    """Do something useful."""
    return ToolResponse.ok(result="Hello!")
  1. Validation (optional) — Add a Pydantic model to server/models.py:
class MyToolInput(BaseModel):
    input_param: str = Field(..., min_length=1)
  1. Registration — Add a @mcp.tool() decorator in server/server.py:
@mcp.tool(name="my_tool", description="Does something useful")
def tool_my_tool(input_param: str) -> str:
    return json.dumps(my_tool(input_param))

That's it! The client will auto-discover the new tool on next connection.


⚠️ Common Errors

Error Cause Solution
Server script not found Running from wrong directory cd to project root
ModuleNotFoundError: server Missing uv sync or wrong Python Run uv sync first
ConnectionError Server failed to start Check logs/app.log for details
Invalid operation Typo in operation name Use: add, subtract, multiply, divide
Division by zero b=0 with divide operation Expected — handled gracefully
City not found City not in mock data Use: Jaipur, Delhi, Mumbai, Bangalore, Chennai, Kolkata
Broken pipe / garbled output Printing to stdout in server Always use logging or stderr

🔮 Future Improvements

  • Add LLM integration for intelligent intent parsing
  • Implement SSE transport for remote server access
  • Add tool caching and rate limiting
  • Build a web-based UI alongside the CLI
  • Add unit tests for each tool
  • Implement MCP Resources and Prompts (beyond Tools)
  • Add authentication and authorization
  • Create a tool that chains multiple other tools

📄 License

MIT License — Feel free to use this for learning and education.


Built as an educational project to understand the Model Context Protocol (MCP).

from github.com/somyabhadada/mcp_server

Установка Learning Server

У этого сервера нет опубликованного пакета — он собирается из исходников. Открой репозиторий и следуй инструкции в README.

▸ github.com/somyabhadada/mcp_server

FAQ

Learning Server MCP бесплатный?

Да, Learning Server MCP бесплатный — установка в пару кликов через Unyly без оплаты.

Нужен ли API-ключ для Learning Server?

Нет, Learning Server работает без API-ключей и переменных окружения.

Learning Server — hosted или self-hosted?

Self-hosted: сервер запускается локально на твоей машине командой из раздела установки.

Как установить Learning Server в Claude Desktop, Claude Code или Cursor?

Открой Learning Server на unyly.org, выбери вкладку своего клиента (Claude Desktop, Claude Code, Cursor) и нажми Install — конфиг сгенерируется автоматически, без правки JSON.

Похожие MCP

Compare Learning Server with

Не уверен что выбрать?

Найди свой стек за 60 секунд

Автор?

Embed-бейдж для README

Похожее

Все в категории development