Skip to main content
Glama

Apple Find My MCP Server

by batteryshark
credentials.py3.4 kB
""" Credentials elicitation for Apple Find My authentication. """ from dataclasses import dataclass from fastmcp import Context from secrets_manager import secrets_manager @dataclass class AppleCredentials: """Apple ID credentials.""" apple_id: str password: str async def elicit_credentials(ctx: Context) -> tuple[str, str]: """Elicit Apple ID and password from user.""" credentials = await ctx.elicit( "Please provide your Apple ID credentials:", response_type=AppleCredentials ) if credentials.action == "cancel": raise ValueError("Authentication cancelled") if credentials.action == "decline": raise ValueError("Apple ID credentials required") apple_id = credentials.data.apple_id.strip() password = credentials.data.password.strip() if not apple_id: raise ValueError("Apple ID cannot be empty") if not password: raise ValueError("Password cannot be empty") # Store both Apple ID and password in our secrets manager secrets_manager.store_secret("APPLE_ID", apple_id) secrets_manager.store_secret("APPLE_PASSWORD", password) await ctx.info("✅ Apple ID and password stored securely") return apple_id, password async def get_apple_id_from_secrets() -> str: """Get Apple ID from secrets manager.""" return secrets_manager.retrieve_secret("APPLE_ID") or "" async def get_apple_password_from_secrets() -> str: """Get Apple password from secrets manager.""" return secrets_manager.retrieve_secret("APPLE_PASSWORD") or "" async def get_2fa_code(ctx: Context) -> str: """Elicit 2FA verification code.""" while True: code_result = await ctx.elicit( "Enter 6-digit verification code from your Apple device:", response_type=str ) if code_result.action == "cancel": raise ValueError("Authentication cancelled") if code_result.action == "decline": raise ValueError("Verification code required") code = code_result.data.strip() if len(code) == 6 and code.isdigit(): return code await ctx.info("❌ Invalid code format. Enter 6 digits.") async def select_device(ctx: Context, devices: list) -> int: """Elicit device selection for 2SA.""" device_list = [ f"{i}: {d.get('deviceName', f'SMS to {d.get("phoneNumber", "Unknown")}')}" for i, d in enumerate(devices) ] await ctx.info("Available devices:\n" + "\n".join(device_list)) device_result = await ctx.elicit( f"Select device (0-{len(devices)-1}):", response_type=[str(i) for i in range(len(devices))] ) if device_result.action == "cancel": raise ValueError("Authentication cancelled") if device_result.action == "decline": raise ValueError("Device selection required") return int(device_result.data) async def get_2sa_code(ctx: Context) -> str: """Elicit 2SA verification code.""" code_result = await ctx.elicit( "Enter verification code:", response_type=str ) if code_result.action == "cancel": raise ValueError("Authentication cancelled") if code_result.action == "decline": raise ValueError("Verification code required") code = code_result.data.strip() if not code: raise ValueError("Code cannot be empty") return code

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/batteryshark/mcp-findmy'

If you have feedback or need assistance with the MCP directory API, please join our Discord server