Duibonduil's picture
Upload 6 files
f376f50 verified
# coding: utf-8
# Copyright (c) 2025 inclusionAI.
"""
Simple calculator MCP server example.
"""
import argparse
import os
import time
from typing import List, Dict, Any, Optional
from pydantic import Field
from aworld.mcp_client.decorator import mcp_server
@mcp_server(
name="simple-calculator",
mode="sse",
host="127.0.0.1",
port=8500,
sse_path="/calculator/sse",
auto_start=True # if False you can start manually in main()
)
class Calculator:
"""Provides basic mathematical functions, including addition, subtraction, multiplication, division, and calculation history management."""
def __init__(self):
self.history = []
def add(self,
a: float = Field(description="First addend"),
b: float = Field(description="Second addend")
) -> Dict[str, Any]:
"""
Add two numbers
:param a: First addend
:param b: Second addend
:return: Dictionary containing the result
"""
result = a + b
self.history.append(f"{a} + {b} = {result}")
print(f"add:{a} + {b} = {result}")
return {"result": result}
def subtract(self,
a: float = Field(description="Minuend"),
b: float = Field(description="Subtrahend")
) -> Dict[str, Any]:
"""
Subtract the second number from the first number
:param a: Minuend
:param b: Subtrahend
:return: Dictionary containing the result
"""
result = a - b
self.history.append(f"{a} - {b} = {result}")
print(f"subtract:{a} - {b} = {result}")
return {"result": result}
def multiply(self,
a: float = Field(description="First factor"),
b: float = Field(description="Second factor")
) -> Dict[str, Any]:
"""
Multiply two numbers
:param a: First factor
:param b: Second factor
:return: Dictionary containing the result
"""
result = a * b
self.history.append(f"{a} * {b} = {result}")
print(f"multiply:{a} * {b} = {result}")
return {"result": result}
def divide(self,
a: float = Field(description="Dividend"),
b: float = Field(description="Divisor")
) -> Dict[str, Any]:
"""
Divide the first number by the second number
:param a: Dividend
:param b: Divisor
:return: Dictionary containing the result
"""
if b == 0:
raise ValueError("Divisor cannot be zero")
result = a / b
self.history.append(f"{a} / {b} = {result}")
print(f"divide:{a} / {b} = {result}")
return {"result": result}
def get_history(self) -> Dict[str, List[str]]:
"""
Get calculation history
:return: Dictionary containing the history
"""
return {"history": self.history}
def clear_history(self) -> Dict[str, str]:
"""
Clear calculation history
:return: Dictionary containing operation status
"""
self.history = []
return {"status": "History cleared"}
@mcp_server(
name="weather",
mode="sse",
host="127.0.0.1",
port=8200,
sse_path="/weather/sse",
auto_start=False # Don't auto-start, we'll start manually in main()
)
class WeatherService:
"""A service that can query and manage city weather information, supports adding cities and getting city weather data."""
def __init__(self):
self.locations = {
"Beijing": {"temp": 20, "humidity": 60, "weather": "Sunny"},
"Shanghai": {"temp": 25, "humidity": 70, "weather": "Cloudy"},
"Guangzhou": {"temp": 30, "humidity": 80, "weather": "Rainy"}
}
def get_current_weather(self,
location: str = Field(description="City name")
) -> Dict[str, Any]:
"""
Get current weather for a specified city
:param location: City name
:return: Dictionary containing weather information
"""
if location not in self.locations:
return {"error": f"City {location} does not exist"}
return {"weather": self.locations[location]}
def get_locations(self) -> Dict[str, List[str]]:
"""
Get list of all available cities
:return: Dictionary containing city list
"""
return {"locations": list(self.locations.keys())}
def add_location(self,
location: str = Field(description="City name"),
temp: float = Field(description="Temperature (Celsius)"),
humidity: float = Field(description="Humidity (percentage)"),
weather: str = Field(description="Weather description")
) -> Dict[str, str]:
"""
Add or update weather information for a city
:param location: City name
:param temp: Temperature (Celsius)
:param humidity: Humidity (percentage)
:param weather: Weather description
:return: Dictionary containing operation status
"""
self.locations[location] = {
"temp": temp,
"humidity": humidity,
"weather": weather
}
return {"status": f"Weather information for {location} has been updated"}
@mcp_server(
name="async-calculator",
mode="sse",
host="127.0.0.1",
port=8200,
sse_path="/async-calculator/sse",
auto_start=False # Don't auto-start, we'll start manually in main()
)
class AsyncCalculator:
"""Provides asynchronous version of basic mathematical functions, including addition, subtraction, multiplication, division, and calculation history management."""
def __init__(self):
self.history = []
async def add(self,
a: float = Field(description="First addend"),
b: float = Field(description="Second addend")
) -> Dict[str, Any]:
"""
Add two numbers (async version)
:param a: First addend
:param b: Second addend
:return: Dictionary containing the result
"""
result = a + b
self.history.append(f"{a} + {b} = {result}")
print(f"async_add:{a} + {b} = {result}")
return {"result": result}
async def subtract(self,
a: float = Field(description="Minuend"),
b: float = Field(description="Subtrahend")
) -> Dict[str, Any]:
"""
Subtract the second number from the first number (async version)
:param a: Minuend
:param b: Subtrahend
:return: Dictionary containing the result
"""
result = a - b
self.history.append(f"{a} - {b} = {result}")
print(f"async_subtract:{a} - {b} = {result}")
return {"result": result}
async def multiply(self,
a: float = Field(description="First factor"),
b: float = Field(description="Second factor")
) -> Dict[str, Any]:
"""
Multiply two numbers (async version)
:param a: First factor
:param b: Second factor
:return: Dictionary containing the result
"""
result = a * b
self.history.append(f"{a} * {b} = {result}")
print(f"async_multiply:{a} * {b} = {result}")
return {"result": result}
async def divide(self,
a: float = Field(description="Dividend"),
b: float = Field(description="Divisor")
) -> Dict[str, Any]:
"""
Divide the first number by the second number (async version)
:param a: Dividend
:param b: Divisor
:return: Dictionary containing the result
"""
if b == 0:
raise ValueError("Divisor cannot be zero")
result = a / b
self.history.append(f"{a} / {b} = {result}")
print(f"async_divide:{a} / {b} = {result}")
return {"result": result}
async def get_history(self) -> Dict[str, List[str]]:
"""
Get calculation history (async version)
:return: Dictionary containing the history
"""
return {"history": self.history}
async def clear_history(self) -> Dict[str, str]:
"""
Clear calculation history (async version)
:return: Dictionary containing operation status
"""
self.history = []
return {"status": "History cleared"}
def main():
parser = argparse.ArgumentParser(description="MCP Simple Calculator Server")
parser.add_argument("--server-type", choices=["calculator", "weather", "async-calculator"], default="calculator",
help="Server type, options: 'calculator', 'weather', or 'async-calculator'")
parser.add_argument("--mode", choices=["stdio", "sse"], default="sse",
help="Server running mode, options: 'stdio' or 'sse'")
parser.add_argument("--host", default="127.0.0.1", help="Server host address, default is 127.0.0.1")
parser.add_argument("--port", type=int, default=8200, help="Server port number, default is 8200")
parser.add_argument("--sse-path", default=None, help="SSE path, defaults based on server type")
args = parser.parse_args()
# Read configuration from environment variables if set
server_type = os.environ.get("MCP_SERVER_TYPE", args.server_type)
mode = os.environ.get("MCP_MODE", args.mode)
host = os.environ.get("MCP_HOST", args.host)
# Handle integer type
try:
port = int(os.environ.get("MCP_PORT", args.port))
except (ValueError, TypeError):
port = args.port
# Create server instance based on type
if server_type == "calculator":
server = Calculator()
default_sse_path = "/calculator/sse"
elif server_type == "async-calculator":
server = AsyncCalculator()
default_sse_path = "/async-calculator/sse"
else:
server = WeatherService()
default_sse_path = "/weather/sse"
# Set SSE path from args, env, or default
sse_path = os.environ.get("MCP_SSE_PATH", args.sse_path or default_sse_path)
print(f"Using configuration: server_type={server_type}, mode={mode}, host={host}, port={port}, sse_path={sse_path}")
# Run server with provided configuration
server.run(mode=mode, host=host, port=port, sse_path=sse_path)
def auto_start_example():
Calculator()
print("Auto-starting calculator has been initialized.")
print("Server is running in background. Press Ctrl+C to exit.")
try:
# Keep main thread alive
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Exiting...")
if __name__ == "__main__":
auto_start_example()