#!/usr/bin/env python from typing import Annotated from arcade_mcp_server import tool from typing_extensions import TypedDict """ 01_tools.py - Tool creation, discovery, and parameter types This example demonstrates: 1. How to create tools with the @tool decorator 2. Different parameter types (simple, lists, TypedDict) 3. How arcade_mcp_server discovers tools automatically To run: python -m arcade_mcp_server # Auto-discover all tools python -m arcade_mcp_server --show-packages # Show what's being loaded python -m arcade_mcp_server stdio # For Claude Desktop """ # === DISCOVERY PATTERNS === """ The arcade_mcp_server CLI discovers tools using these patterns: 1. Current directory: *.py files - Scans all Python files in the current directory - Imports and checks for @tool decorated functions 2. tools/ directory: - If exists, recursively scans for Python files - Common convention for organizing tools 3. arcade_tools/ directory: - Alternative directory name - Also recursively scanned 4. Package loading with --tool-package: python -m arcade_mcp_server --tool-package github - Loads arcade-github package - Can load any installed package in the current python environment 5. Discover all installed with --discover-installed: python -m arcade_mcp_server --discover-installed - Finds all arcade-* packages in the current python environment - Loads all their tools Discovery tips: - Use __init__.py in directories for proper imports - Organize related tools in subdirectories - Use clear, descriptive tool names - Tools are namespaced by their toolkit name """ # === SIMPLE TOOLS === @tool def hello(name: Annotated[str, "Name to greet"]) -> Annotated[str, "Greeting message"]: """Say hello to someone.""" return f"Hello, {name}!" @tool def add( a: Annotated[float, "First number"], b: Annotated[float, "Second number"] ) -> Annotated[float, "Sum of the numbers"]: """Add two numbers together.""" return a + b # === TOOLS WITH LIST PARAMETERS === @tool def calculate_average( numbers: Annotated[list[float], "List of numbers to average"], ) -> Annotated[float, "Average of all numbers"]: """Calculate the average of a list of numbers.""" if not numbers: return 0.0 return sum(numbers) / len(numbers) @tool def factorial(n: Annotated[int, "Non-negative integer"]) -> Annotated[int, "Factorial of n"]: """Calculate the factorial of a number.""" if n < 0: raise ValueError("Factorial not defined for negative numbers") if n == 0: return 1 result = 1 for i in range(1, n + 1): result *= i return result # === TOOLS WITH COMPLEX TYPES (TypedDict) === class PersonInfo(TypedDict): name: str age: int email: str is_active: bool @tool def create_user_profile( person: Annotated[PersonInfo, "Person's information"], ) -> Annotated[str, "Formatted user profile"]: """Create a formatted user profile from person information.""" status = "Active" if person["is_active"] else "Inactive" return f""" User Profile: - Name: {person["name"]} - Age: {person["age"]} - Email: {person["email"]} - Status: {status} """.strip() class CalculationResult(TypedDict): sum: float average: float min: float max: float count: int @tool def analyze_numbers( values: Annotated[list[float], "List of numbers to analyze"], ) -> Annotated[CalculationResult, "Statistical analysis of the numbers"]: """Analyze a list of numbers and return statistics.""" if not values: return {"sum": 0.0, "average": 0.0, "min": 0.0, "max": 0.0, "count": 0} return { "sum": sum(values), "average": sum(values) / len(values), "min": min(values), "max": max(values), "count": len(values), }