akshattewari/MCP-Server-Demo
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.
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 toolsmcp_client.py- MCP client that connects to and uses the serverexample.py- Simple examples showing how to use the MCP toolsmain.py- Original demo file (kept for compatibility)
Features
The MCP server provides three simple tools:
- Calculator - Perform basic arithmetic operations (add, subtract, multiply, divide)
- File Info - Get information about files (size, type, modification time)
- List Directory - List contents of directories
Installation
- 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
- Server: The MCP server (
mcp_server.py) implements the MCP protocol and provides tools via stdio communication - Client: The MCP client (
mcp_client.py) connects to the server and can call the available tools - Protocol: Communication happens via JSON-RPC over stdio streams
Extending the Example
You can extend this example by:
- Adding more tools to the server
- Implementing different types of tools (resources, prompts)
- Adding authentication or security features
- 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.pyprovides tools via MCP handlers. It declares capabilities and exposes three tools. - Client:
mcp_client.pylaunches the server subprocess via stdio and drives aClientSessionusing in-memory streams. - Examples:
example.pyandtest_client.pyshow different ways to drive the client.
High-level flow:
- Client starts a server subprocess (Python
mcp_server.py) over stdio. - Client initializes a
ClientSessionand requests server capabilities. - Client lists tools, then calls
call_toolwith a name and JSON arguments. - 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.
- Responsibility: Instantiate an MCP
-
Method:
__init__(self)- Creates
self.server = Server("simple-mcp-server")and callsself.setup_handlers()to register handlers.
- Creates
-
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:
calculatorwith JSON input schema:{ operation: add|subtract|multiply|divide, a: number, b: number }file_infowith JSON input schema:{ filepath: string }list_directorywith JSON input schema:{ directory: string }
- Returns a plain Python
@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 aCallToolResultfor you.
- Expected return value: an iterable of MCP content blocks (here, a list of
- Registers two handler types via decorators provided by the MCP SDK:
-
Method:
_handle_calculator(self, arguments: Dict[str, Any])- Reads
operation,a,bfromargumentsand performs the calculation. - Returns
[TextContent(type="text", text=...)]describing the result or an error (e.g., division by zero).
- Reads
-
Method:
_handle_file_info(self, arguments: Dict[str, Any])- Reads
filepath, checks existence, gathersos.statinformation, and returns a human-readable JSON string in aTextContentblock.
- Reads
-
Method:
_handle_list_directory(self, arguments: Dict[str, Any])- Reads
directory, ensures it exists/is a directory, lists entries, and returns a formatted list asTextContent.
- Reads
-
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 computedcapabilitiesfromself.server.get_capabilities(...).NotificationOptions(tools_changed=True): the server advertises support for tools list change notifications.
- Creates an stdio server transport with
-
Module-level
async def main()and guardif __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 ofToolinstances.call_tool→ a sequence of content blocks (and optionally a structured payload). ReturningCallToolResultdirectly is not required; the SDK builds the result.
mcp_client.py — MCP client and demos
-
Class:
SimpleMCPClient- Holds
server_paramsfor launching the stdio server subprocess and provides convenience methods to list tools and call tools.
- Holds
-
Method:
connect(self, server_command: List[str])- Builds
StdioServerParameterswithcommandandargs(e.g.,["python", "mcp_server.py"]). - Note: This does not establish the session yet; actual connections are done inside context managers in subsequent calls.
- Builds
-
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, thenawait session.list_tools()fetches tool definitions.- Converts the list of
Toolobjects 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.
- Uses the same transport/session pattern as
-
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): Callsfile_infoformcp_server.pyandlist_directoryfor..
-
main()- Creates
SimpleMCPClient, buildsserver_command, prints tools, and runs both demos.
- Creates
Key client SDK types used:
stdio_client(...)(transport) → yields(read_stream, write_stream)ClientSession(read_stream, write_stream)→initialize(),list_tools(),call_tool(...)APIsStdioServerParameters(command, args, env, cwd, ...)→ configures the server subprocess
example.py — interactive/simple examples
- Provides:
simple_example(): Connects, callscalculatorandfile_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
ClientSessionfrom stdio transport. - Initializes the session, lists tools, and exercises
calculator. - Captures server stderr to
server_stderr.logfor troubleshooting when TaskGroup exceptions occur.
- Builds
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 JSONinputSchema(and optionaloutputSchema).
- Client →
- Tool call:
- Client →
call_tool(name, arguments: dict) - SDK validates
argumentsagainst the declaredinputSchema. - Server implementation returns a sequence of content blocks (unstructured text) and optionally structured content; the SDK wraps into
CallToolResult.
- Client →
- Notifications:
- Server advertises
tools_changedcapability. This demo does not emit notifications but is configured to do so.
- Server advertises
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', ensureNotificationOptions(...)is passed toget_capabilities(...)on the server. - If you see
unhandled errors in a TaskGroup, verify the client is usingClientSession(read_stream, write_stream)and the server handlers return the expected types (seemcp_server.py).
- On Windows PowerShell, avoid
Extending the server
- To add a new tool:
- In
list_tools, append a newTool(name=..., description=..., inputSchema=...). - In
handle_call_tool, add a branch for the new tool name that calls a new handler method. - Implement the handler method to return a list of
TextContent(and optionally structured content). The SDK will wrap/validate the response. - Update the README examples if needed.
- In
This guide should give you a clear map of how each component works and interacts so you can confidently extend the project.