#!/usr/bin/env python3
"""
Calculator MCP Server
A simple calculator server implementing the Model Context Protocol
"""
import asyncio
import json
from typing import Any
from mcp.server import Server
from mcp.types import Tool, TextContent
import mcp.server.stdio
# Create server instance
app = Server("calculator-server")
@app.list_tools()
async def list_tools() -> list[Tool]:
"""List available calculator 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="subtract",
description="Subtract second number from first number",
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="divide",
description="Divide first number by second number",
inputSchema={
"type": "object",
"properties": {
"a": {
"type": "number",
"description": "Numerator"
},
"b": {
"type": "number",
"description": "Denominator (cannot be zero)"
}
},
"required": ["a", "b"]
}
),
Tool(
name="power",
description="Raise first number to the power of second number",
inputSchema={
"type": "object",
"properties": {
"base": {
"type": "number",
"description": "Base number"
},
"exponent": {
"type": "number",
"description": "Exponent"
}
},
"required": ["base", "exponent"]
}
),
Tool(
name="sqrt",
description="Calculate square root of a number",
inputSchema={
"type": "object",
"properties": {
"number": {
"type": "number",
"description": "Number to calculate square root of (must be non-negative)"
}
},
"required": ["number"]
}
),
Tool(
name="percentage",
description="Calculate percentage of a number",
inputSchema={
"type": "object",
"properties": {
"number": {
"type": "number",
"description": "The number to calculate percentage of"
},
"percent": {
"type": "number",
"description": "The percentage value"
}
},
"required": ["number", "percent"]
}
)
]
@app.call_tool()
async def call_tool(name: str, arguments: Any) -> list[TextContent]:
"""Handle tool calls for calculator operations."""
try:
if name == "add":
a = arguments["a"]
b = arguments["b"]
result = a + b
return [TextContent(
type="text",
text=f"{a} + {b} = {result}"
)]
elif name == "subtract":
a = arguments["a"]
b = arguments["b"]
result = a - b
return [TextContent(
type="text",
text=f"{a} - {b} = {result}"
)]
elif name == "multiply":
a = arguments["a"]
b = arguments["b"]
result = a * b
return [TextContent(
type="text",
text=f"{a} × {b} = {result}"
)]
elif name == "divide":
a = arguments["a"]
b = arguments["b"]
if b == 0:
return [TextContent(
type="text",
text="Error: Division by zero is not allowed"
)]
result = a / b
return [TextContent(
type="text",
text=f"{a} ÷ {b} = {result}"
)]
elif name == "power":
base = arguments["base"]
exponent = arguments["exponent"]
result = base ** exponent
return [TextContent(
type="text",
text=f"{base}^{exponent} = {result}"
)]
elif name == "sqrt":
number = arguments["number"]
if number < 0:
return [TextContent(
type="text",
text="Error: Cannot calculate square root of negative number"
)]
result = number ** 0.5
return [TextContent(
type="text",
text=f"√{number} = {result}"
)]
elif name == "percentage":
number = arguments["number"]
percent = arguments["percent"]
result = (number * percent) / 100
return [TextContent(
type="text",
text=f"{percent}% of {number} = {result}"
)]
else:
return [TextContent(
type="text",
text=f"Error: Unknown tool '{name}'"
)]
except Exception as e:
return [TextContent(
type="text",
text=f"Error: {str(e)}"
)]
async def main():
"""Run the calculator MCP server."""
async with mcp.server.stdio.stdio_server() as (read_stream, write_stream):
await app.run(
read_stream,
write_stream,
app.create_initialization_options()
)
if __name__ == "__main__":
asyncio.run(main())