A FastMCP server providing mathematical operations and calculations
The server provides 9 basic arithmetic and mathematical tools with visible input schemas and descriptions. However, there are significant quality gaps: (1) Tool names lack action verbs, they are nouns ('add', 'subtract', 'multiply') rather than verb_noun patterns like 'calculate_sum' or 'perform_addition', which weakens LLM intent inference. (2) Descriptions are verbose (200-400 chars) and include implementation details (exception handling, logging format) irrelevant to LLM tool selection, they should focus on WHAT, WHEN, and prerequisites. (3) Parameter descriptions are minimal (e.g., 'First number', 'Second number') and do not explain constraints, ranges, or edge cases. (4) Output schemas are not documented, responses are shown as examples in descriptions but no formal schema is provided, making it hard for LLMs to plan downstream operations. (5) Error handling is basic (try/except with generic messages) and does not guide recovery or categorize error types. (6) No tool annotations (readOnlyHint, destructiveHint, idempotentHint) despite all tools being read-only operations. (7) Parameter types are correct (float) but descriptions lack context about valid ranges (e.g., for sqrt/factorial). This is a straightforward utility server that works, but falls short of production-grade quality in several key areas.
Perform addition of two numbers provided in the `data` object. Args: data (TwoNumberOperation): An object containing two numbers `a` and `b` to be added. Returns: Dict[str, Any]: A dictionary containing the operation name ("add") and the result of the addition if successful, or an error message if an exception occurs. Logs: Logs the operation and result in the format: "ADD | {data.a} + {data.b} = {result}"
Perform division of two numbers provided in the `TwoNumberOperation` object. Args: data (TwoNumberOperation): An object containing two numbers, `a` and `b`, where `a` is the numerator and `b` is the denominator. Returns: Dict[str, Any]: A dictionary containing the operation result or an error message. Raises: ZeroDivisionError: If the denominator (`b`) is zero. Notes: - Logs the division operation and its result. - Returns a success response if the operation is successful. - Returns an error response if an exception occurs.
Calculate the factorial of a given number. Args: data (SingleNumberOperation): An object containing the input number `a`. Returns: Dict[str, Any]: A dictionary containing the operation result or an error message. Raises: ValueError: If the input is negative or not an integer. Notes: - Only works with non-negative integers. - Logs the operation and result.
Calculate the modulus (remainder) of two numbers provided in the `data` object. Args: data (TwoNumberOperation): An object containing two numbers, `a` and `b`. Returns: Dict[str, Any]: A dictionary containing the operation result if successful, or an error message if an exception occurs. Raises: ZeroDivisionError: If the second number (`b`) is zero, as modulus by zero is not allowed. Logs: Logs the operation and result in the format "MOD | a % b = result" if successful. Example: data = TwoNumberOperation(a=10, b=3) result = modulus(data) # result -> {"status": "success", "operation": "modulus", "result": 1}
Tool names lack action verbs. All nine tools use bare nouns ('add', 'divide', 'sqrt') instead of verb_noun patterns ('calculate_sum', 'perform_division', 'calculate_square_root'). LLMs rely on verbs to infer intent, bare nouns reduce clarity and increase misselection risk when many tools are available.
Parameter descriptions are minimal and lack constraint information. E.g., 'First number' does not specify: valid range, whether Inf/-Inf are allowed, precision limits, or edge cases. For 'sqrt' and 'factorial', negative inputs are invalid but descriptions do not explicitly state this constraint or suggest recovery ('Must be non-negative').
Output schemas are not formally documented. Responses are shown as inline examples ('result -> {"status": "success", ...}') in descriptions rather than declared output schemas. LLMs cannot reliably infer downstream field availability, forcing extra discovery or assumption-based reasoning.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 52 | <=2025-11-25 | v2 |
Perform multiplication of two numbers provided in the `data` object. Args: data (TwoNumberOperation): An object containing two numbers `a` and `b` to be multiplied. Returns: Dict[str, Any]: A dictionary containing the result of the multiplication operation or an error message in case of failure. Logs: Logs the multiplication operation in the format: "MUL | {data.a} * {data.b} = {result}" Exceptions: Catches any exceptions that occur during the operation and returns an error response with the exception message.
Calculate the power of a given base raised to a given exponent. Args: data (PowerOperation): An object containing the base and exponent values. Returns: Dict[str, Any]: A dictionary containing the operation result or an error message. Logs: Logs the operation in the format "POW | base ^ exponent = result". Exceptions: Catches any exceptions during the calculation and returns an error response.
Calculate the square root of a given number. Args: data (SingleNumberOperation): An object containing the input number `a`. Returns: Dict[str, Any]: A dictionary containing the operation name, result, and status of the operation. Raises: ValueError: If the input number `a` is negative. Notes: - Logs the operation and result using the logger. - Returns a success response if the operation is successful. - Returns an error response if an exception occurs.
Calculate the square of a given number. Args: data (SingleNumberOperation): An object containing the number to be squared. Returns: Dict[str, Any]: A dictionary containing the operation name ("square") and the result of squaring the input number. In case of an error, returns an error response. Logs: Logs the operation and the result in the format "SQUARE | <input>^2 = <result>". Raises: Exception: If an error occurs during the calculation.
Perform subtraction of two numbers provided in the `data` object. Args: data (TwoNumberOperation): An object containing two numbers, `a` and `b`. Returns: Dict[str, Any]: A dictionary containing the operation name ("subtract") and the result of the subtraction if successful, or an error message if an exception occurs. Logs: Logs the subtraction operation and its result in the format: "SUB | {data.a} - {data.b} = {result}".
Tool descriptions include implementation details (logging format 'ADD | ... = ...', exception handling steps) irrelevant to LLM tool selection. Descriptions should focus on WHAT the tool does and WHEN to call it, not HOW it logs or catches errors. This wastes tokens and buries the key intent.
No tool annotations despite all tools being read-only, idempotent operations. Adding readOnlyHint=true and idempotentHint=true would allow agents to optimize caching and safely retry calls without side-effect concerns.
Error handling is generic. All tools catch exceptions and return {"status": "error", "message": str(e)}. Errors do not categorize as retryable/user-fixable/fatal or suggest recovery actions. E.g., 'Division by zero is not allowed.' should suggest 'Ensure the divisor (b) is non-zero' or offer alternative operations.