"""
MCP Server with Calculator Tools
This server provides calculator tools for performing mathematical operations.
"""
from mcp.server.fastmcp import FastMCP
import math
import os
import asyncio
from pathlib import Path
# Create the FastMCP server instance with host and port for SSE support
mcp = FastMCP(
"Calculator Server",
host=os.getenv("HOST", "0.0.0.0"),
port=int(os.getenv("PORT", "8000"))
)
# Get the directory where this script is located
SCRIPT_DIR = Path(__file__).parent
MARKDOWN_FILE = SCRIPT_DIR / "Typerscript SDK MCP.md"
TEMPLATE_FILE = SCRIPT_DIR / "templates" / "meeting_summary" / "template.md"
@mcp.tool()
def add(a: float, b: float) -> float:
"""
Add two numbers together.
Args:
a: The first number
b: The second number
Returns:
The sum of a and b
"""
return a + b
@mcp.tool()
def subtract(a: float, b: float) -> float:
"""
Subtract the second number from the first number.
Args:
a: The first number (minuend)
b: The second number (subtrahend)
Returns:
The difference of a and b (a - b)
"""
return a - b
@mcp.tool()
def multiply(a: float, b: float) -> float:
"""
Multiply two numbers together.
Args:
a: The first number
b: The second number
Returns:
The product of a and b
"""
return a * b
@mcp.tool()
def divide(a: float, b: float) -> float:
"""
Divide the first number by the second number.
Args:
a: The dividend (number to be divided)
b: The divisor (number to divide by)
Returns:
The quotient of a divided by b (a / b)
Raises:
ValueError: If b is zero (division by zero)
"""
if b == 0:
raise ValueError("Division by zero is not allowed")
return a / b
@mcp.tool()
def power(base: float, exponent: float) -> float:
"""
Raise a number to a power.
Args:
base: The base number
exponent: The exponent (power to raise the base to)
Returns:
The result of base raised to the power of exponent (base^exponent)
"""
return math.pow(base, exponent)
@mcp.tool()
def square_root(number: float) -> float:
"""
Calculate the square root of a number.
Args:
number: The number to find the square root of
Returns:
The square root of the number
Raises:
ValueError: If number is negative
"""
if number < 0:
raise ValueError("Cannot calculate square root of negative number")
return math.sqrt(number)
@mcp.tool()
def factorial(n: int) -> int:
"""
Calculate the factorial of a non-negative integer.
The factorial of n (written as n!) is the product of all positive integers
less than or equal to n. For example: 5! = 5 × 4 × 3 × 2 × 1 = 120
Args:
n: A non-negative integer
Returns:
The factorial of n
Raises:
ValueError: If n is negative
"""
if n < 0:
raise ValueError("Factorial is only defined for non-negative integers")
return math.factorial(n)
@mcp.tool()
def calculate_percentage(part: float, whole: float) -> float:
"""
Calculate what percentage one number is of another number.
Args:
part: The part (the number you want to find the percentage of)
whole: The whole (the total or reference number)
Returns:
The percentage as a number (e.g., 25.0 means 25%)
Raises:
ValueError: If whole is zero
"""
if whole == 0:
raise ValueError("Cannot calculate percentage when whole is zero")
return (part / whole) * 100
@mcp.resource("typescript-sdk-mcp://documentation")
def get_typescript_sdk_documentation() -> str:
"""
Get the TypeScript SDK MCP documentation.
Returns the full content of the TypeScript SDK MCP markdown documentation file.
"""
try:
if MARKDOWN_FILE.exists():
with open(MARKDOWN_FILE, "r", encoding="utf-8") as f:
return f.read()
else:
return f"Error: Documentation file not found at {MARKDOWN_FILE}"
except Exception as e:
return f"Error reading documentation: {str(e)}"
@mcp.prompt()
def meeting_summary(meeting_date: str, meeting_title: str, transcript: str) -> list[dict]:
"""
Meeting Summary prompt that loads a Markdown template and fills placeholders.
Placeholders supported in the template:
- {{ meeting_date }}
- {{ meeting_title }}
- {{ transcript }}
"""
try:
if not TEMPLATE_FILE.exists():
return [
{
"role": "user",
"content": {
"type": "text",
"text": f"Error: Prompt template not found at {TEMPLATE_FILE}"
},
}
]
content = TEMPLATE_FILE.read_text(encoding="utf-8")
# Simple placeholder substitution
content = (
content
.replace("{{ meeting_date }}", meeting_date)
.replace("{{ meeting_title }}", meeting_title)
.replace("{{ transcript }}", transcript)
)
return [
{
"role": "user",
"content": {"type": "text", "text": content},
}
]
except Exception as e:
return [
{
"role": "user",
"content": {"type": "text", "text": f"Error preparing prompt: {str(e)}"},
}
]
async def main():
"""
Main function that runs the MCP server with the selected transport.
Supports both SSE (Server-Sent Events) and stdio transports.
Set the TRANSPORT environment variable to 'sse' or 'stdio' (default: 'stdio').
"""
transport = os.getenv("TRANSPORT", "stdio")
if transport == 'sse':
# Run the MCP server with SSE transport
print(f"Starting MCP server with SSE transport on {os.getenv('HOST', '0.0.0.0')}:{os.getenv('PORT', '8000')}")
await mcp.run_sse_async()
else:
# Run the MCP server with stdio transport (default)
print("Starting MCP server with stdio transport")
await mcp.run_stdio_async()
if __name__ == "__main__":
asyncio.run(main())