MCP-Server-Demo

akshattewari/MCP-Server-Demo

3.2

If you are the rightful owner of MCP-Server-Demo and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

The Model Context Protocol (MCP) server demo is a Python-based project that demonstrates how to connect AI assistants to external data sources and tools using the MCP standard.

Tools
3
Resources
0
Prompts
0

MCP Server Demo

A simple demonstration of the Model Context Protocol (MCP) with Python. This project includes both an MCP server with basic tools and a client that uses those tools.

What is MCP?

The Model Context Protocol (MCP) is a standard for connecting AI assistants to external data sources and tools. It allows AI models to securely access and interact with various services and resources.

Project Structure

  • mcp_server.py - MCP server implementation with calculator and file operation tools
  • mcp_client.py - MCP client that connects to and uses the server
  • example.py - Simple examples showing how to use the MCP tools
  • main.py - Original demo file (kept for compatibility)

Features

The MCP server provides three simple tools:

  1. Calculator - Perform basic arithmetic operations (add, subtract, multiply, divide)
  2. File Info - Get information about files (size, type, modification time)
  3. List Directory - List contents of directories

Installation

  1. Install dependencies:
pip install -e .

Or using uv (recommended):

uv sync

Usage

Running the Server

To run the MCP server:

python mcp_server.py

The server will start and wait for client connections via stdio.

Running the Client

To run the MCP client with demo examples:

python mcp_client.py

This will connect to the server and demonstrate all available tools.

Running Simple Examples

To run the simple example script:

python example.py

This provides both automated examples and an interactive mode.

Example Output

When running the client, you'll see output like:

Starting MCP Client Demo...
Connected to MCP server!

=== Available Tools ===
Calculator: Perform basic arithmetic operations
File_info: Get information about a file
List_directory: List contents of a directory

=== Calculator Demo ===
Calculator: 10 add 5 = 15
Calculator: 10 subtract 3 = 7
Calculator: 4 multiply 7 = 28
Calculator: 15 divide 3 = 5.0
Calculator: 10 divide 0 = Error: Division by zero

=== File Operations Demo ===
File info for 'mcp_server.py':
File info: {
  "path": "mcp_server.py",
  "exists": true,
  "size": 1234,
  "is_file": true,
  "is_directory": false,
  "modified": 1234567890.0
}

Directory listing:
Directory contents of '.':
- mcp_server.py
- mcp_client.py
- example.py
- README.md
- pyproject.toml

How It Works

  1. Server: The MCP server (mcp_server.py) implements the MCP protocol and provides tools via stdio communication
  2. Client: The MCP client (mcp_client.py) connects to the server and can call the available tools
  3. Protocol: Communication happens via JSON-RPC over stdio streams

Extending the Example

You can extend this example by:

  1. Adding more tools to the server
  2. Implementing different types of tools (resources, prompts)
  3. Adding authentication or security features
  4. Creating more sophisticated client applications

Learn More

Developer Guide

This section explains the project at a file and function level so a new developer can quickly understand how it works.

Architecture Overview

  • Protocol: The project implements MCP (Model Context Protocol) over stdio using the official Python SDK. Communication is JSON-RPC carried over the server process stdin/stdout.
  • Server: mcp_server.py provides tools via MCP handlers. It declares capabilities and exposes three tools.
  • Client: mcp_client.py launches the server subprocess via stdio and drives a ClientSession using in-memory streams.
  • Examples: example.py and test_client.py show different ways to drive the client.

High-level flow:

  1. Client starts a server subprocess (Python mcp_server.py) over stdio.
  2. Client initializes a ClientSession and requests server capabilities.
  3. Client lists tools, then calls call_tool with a name and JSON arguments.
  4. Server validates arguments (via MCP SDK) and returns tool output as content blocks.

File-by-file breakdown

mcp_server.py — MCP server and tools
  • Class: SimpleMCPServer

    • Responsibility: Instantiate an MCP Server, register handlers, and run the stdio transport.
  • Method: __init__(self)

    • Creates self.server = Server("simple-mcp-server") and calls self.setup_handlers() to register handlers.
  • Method: setup_handlers(self)

    • Registers two handler types via decorators provided by the MCP SDK:
      • @self.server.list_tools(): Declares the available tool definitions.
        • Returns a plain Python list[Tool]. The SDK internally caches these for validation and discovery.
        • Tools declared:
          • calculator with JSON input schema: { operation: add|subtract|multiply|divide, a: number, b: number }
          • file_info with JSON input schema: { filepath: string }
          • list_directory with JSON input schema: { directory: string }
      • @self.server.call_tool(): Handles invocations for any tool name. Routes to the corresponding implementation methods.
        • Expected return value: an iterable of MCP content blocks (here, a list of TextContent). The SDK wraps these into a CallToolResult for you.
  • Method: _handle_calculator(self, arguments: Dict[str, Any])

    • Reads operation, a, b from arguments and performs the calculation.
    • Returns [TextContent(type="text", text=...)] describing the result or an error (e.g., division by zero).
  • Method: _handle_file_info(self, arguments: Dict[str, Any])

    • Reads filepath, checks existence, gathers os.stat information, and returns a human-readable JSON string in a TextContent block.
  • Method: _handle_list_directory(self, arguments: Dict[str, Any])

    • Reads directory, ensures it exists/is a directory, lists entries, and returns a formatted list as TextContent.
  • Method: run(self)

    • Creates an stdio server transport with async with stdio_server() as (read_stream, write_stream).
    • Calls self.server.run(...) with:
      • InitializationOptions: name, version, and computed capabilities from self.server.get_capabilities(...).
      • NotificationOptions(tools_changed=True): the server advertises support for tools list change notifications.
  • Module-level async def main() and guard if __name__ == "__main__": run the server when executed directly.

Why we return list[Tool] and list[TextContent]:

  • The MCP SDK decorators expect:
    • list_tools → a list of Tool instances.
    • call_tool → a sequence of content blocks (and optionally a structured payload). Returning CallToolResult directly is not required; the SDK builds the result.
mcp_client.py — MCP client and demos
  • Class: SimpleMCPClient

    • Holds server_params for launching the stdio server subprocess and provides convenience methods to list tools and call tools.
  • Method: connect(self, server_command: List[str])

    • Builds StdioServerParameters with command and args (e.g., ["python", "mcp_server.py"]).
    • Note: This does not establish the session yet; actual connections are done inside context managers in subsequent calls.
  • Method: list_tools(self) -> List[Dict[str, Any]]

    • async with stdio_client(self.server_params) as (read_stream, write_stream) creates the transport.
    • async with ClientSession(read_stream, write_stream) as session: creates an MCP client session.
    • await session.initialize() establishes the session, then await session.list_tools() fetches tool definitions.
    • Converts the list of Tool objects to simple dictionaries for printing.
  • Method: call_tool(self, name: str, arguments: Dict[str, Any]) -> str

    • Uses the same transport/session pattern as list_tools.
    • Calls await session.call_tool(name=name, arguments=arguments).
    • Extracts text from returned content blocks and joins into a printable string.
  • Method: disconnect(self)

    • No-op because context managers close the session and process cleanly.
  • Demo helpers:

    • demo_calculator(client): Exercises four math operations and division by zero.
    • demo_file_operations(client): Calls file_info for mcp_server.py and list_directory for ..
  • main()

    • Creates SimpleMCPClient, builds server_command, prints tools, and runs both demos.

Key client SDK types used:

  • stdio_client(...) (transport) → yields (read_stream, write_stream)
  • ClientSession(read_stream, write_stream)initialize(), list_tools(), call_tool(...) APIs
  • StdioServerParameters(command, args, env, cwd, ...) → configures the server subprocess
example.py — interactive/simple examples
  • Provides:
    • simple_example(): Connects, calls calculator and file_info, then disconnects.
    • interactive_example(): Shows an interactive menu to call tools with user input (operation, filepath, directory).
    • main(): Asks which example to run.

This file is useful if you want a quick manual test or a demo during onboarding.

test_client.py — minimal diagnostic client
  • A compact script that:
    • Builds ClientSession from stdio transport.
    • Initializes the session, lists tools, and exercises calculator.
    • Captures server stderr to server_stderr.log for troubleshooting when TaskGroup exceptions occur.

This is helpful for debugging transport or server errors without the larger demo flow.

main.py
  • A minimal entry-point used in the original skeleton. It’s not involved in MCP flows and can be ignored for MCP usage.

Data flow and types

  • Tool discovery:
    • Client → list_tools()
    • Server → returns list[Tool] with JSON inputSchema (and optional outputSchema).
  • Tool call:
    • Client → call_tool(name, arguments: dict)
    • SDK validates arguments against the declared inputSchema.
    • Server implementation returns a sequence of content blocks (unstructured text) and optionally structured content; the SDK wraps into CallToolResult.
  • Notifications:
    • Server advertises tools_changed capability. This demo does not emit notifications but is configured to do so.

Running and troubleshooting

  • Run the client demos:
python mcp_client.py
  • Run the examples:
python example.py
  • Common issues:
    • On Windows PowerShell, avoid &&; use separate commands or ; where supported.
    • If you see AttributeError: 'NoneType' object has no attribute 'tools_changed', ensure NotificationOptions(...) is passed to get_capabilities(...) on the server.
    • If you see unhandled errors in a TaskGroup, verify the client is using ClientSession(read_stream, write_stream) and the server handlers return the expected types (see mcp_server.py).

Extending the server

  • To add a new tool:
    1. In list_tools, append a new Tool(name=..., description=..., inputSchema=...).
    2. In handle_call_tool, add a branch for the new tool name that calls a new handler method.
    3. Implement the handler method to return a list of TextContent (and optionally structured content). The SDK will wrap/validate the response.
    4. Update the README examples if needed.

This guide should give you a clear map of how each component works and interacts so you can confidently extend the project.