Files
microsoft--mcp-for-beginners/03-GettingStarted/05-stdio-server/solution/python/server.py
T
2026-07-13 13:31:35 +08:00

124 lines
4.1 KiB
Python

#!/usr/bin/env python3
"""
MCP stdio server example - Updated for MCP Specification 2025-06-18
This server demonstrates the recommended stdio transport instead of the
deprecated SSE transport. The stdio transport is simpler, more secure,
and provides better performance.
"""
import asyncio
import logging
from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
# Configure logging to stderr (never use stdout for logging in stdio servers)
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[logging.StreamHandler()]
)
logger = logging.getLogger(__name__)
# Create the server
server = Server("example-stdio-server")
# Define tools using list_tools and call_tool handlers
@server.list_tools()
async def list_tools() -> list[Tool]:
"""List available tools"""
return [
Tool(
name="add",
description="Add two numbers together",
inputSchema={
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"}
},
"required": ["a", "b"]
}
),
Tool(
name="multiply",
description="Multiply two numbers together",
inputSchema={
"type": "object",
"properties": {
"a": {"type": "number", "description": "First number"},
"b": {"type": "number", "description": "Second number"}
},
"required": ["a", "b"]
}
),
Tool(
name="get_greeting",
description="Generate a personalized greeting",
inputSchema={
"type": "object",
"properties": {
"name": {"type": "string", "description": "Name to greet"}
},
"required": ["name"]
}
),
Tool(
name="get_server_info",
description="Get information about this MCP server",
inputSchema={"type": "object", "properties": {}}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
"""Handle tool calls"""
if name == "add":
result = arguments["a"] + arguments["b"]
logger.info(f"Adding {arguments['a']} + {arguments['b']} = {result}")
return [TextContent(type="text", text=str(result))]
elif name == "multiply":
result = arguments["a"] * arguments["b"]
logger.info(f"Multiplying {arguments['a']} * {arguments['b']} = {result}")
return [TextContent(type="text", text=str(result))]
elif name == "get_greeting":
greeting = f"Hello, {arguments['name']}! Welcome to the MCP stdio server."
logger.info(f"Generated greeting for {arguments['name']}")
return [TextContent(type="text", text=greeting)]
elif name == "get_server_info":
info = {
"server_name": "example-stdio-server",
"version": "1.0.0",
"transport": "stdio",
"capabilities": ["tools"],
"description": "Example MCP server using stdio transport (MCP 2025-06-18 specification)"
}
return [TextContent(type="text", text=str(info))]
else:
raise ValueError(f"Unknown tool: {name}")
async def main():
"""Main server function using stdio transport"""
logger.info("Starting MCP stdio server...")
try:
# Use stdio transport - this is the recommended approach
async with stdio_server() as (read_stream, write_stream):
logger.info("Server connected via stdio transport")
await server.run(
read_stream,
write_stream,
server.create_initialization_options()
)
except Exception as e:
logger.error(f"Server error: {e}")
raise
if __name__ == "__main__":
asyncio.run(main())