check_auth
Validate your authentication token and retrieve current user information, including status and details.
Instructions
Check if authentication token is valid.
Returns: Auth status and user info
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||
Implementation Reference
- src/rtm_mcp/tools/utilities.py:48-81 (handler)The check_auth tool handler: calls RTM auth.checkToken API, returns authenticated status with user info (id, username, fullname) and permissions on success, or not_authenticated status on error.
@mcp.tool() async def check_auth(ctx: Context) -> dict[str, Any]: """Check if authentication token is valid. Returns: Auth status and user info """ from ..client import RTMClient client: RTMClient = await get_client() try: result = await client.check_token() auth = result.get("auth", {}) user = auth.get("user", {}) return build_response( data={ "status": "authenticated", "user": { "id": user.get("id"), "username": user.get("username"), "fullname": user.get("fullname"), }, "permissions": auth.get("perms"), }, ) except Exception as e: return build_response( data={ "status": "not_authenticated", "error": str(e), }, ) - src/rtm_mcp/tools/utilities.py:10-16 (registration)The register_utility_tools function registers the check_auth tool (and others) via the @mcp.tool() decorator, binding them to the MCP server.
def register_utility_tools(mcp: Any, get_client: Any) -> None: """Register utility and diagnostic tools.""" @mcp.tool() async def test_connection(ctx: Context) -> dict[str, Any]: """Test connection to RTM API. - The build_response helper formats consistent MCP responses with data and metadata (including fetched_at timestamp), used by check_auth.
def build_response( data: dict[str, Any] | list[Any], analysis: dict[str, Any] | None = None, transaction_id: str | None = None, ) -> dict[str, Any]: """Build a consistent response structure. Args: data: The main response data analysis: Optional analysis/insights transaction_id: Optional transaction ID for undo support Returns: Structured response dict """ response = { "data": data, "metadata": { "fetched_at": datetime.now().isoformat(), }, } if analysis: response["analysis"] = analysis if transaction_id: response["metadata"]["transaction_id"] = transaction_id return response def _convert_rtm_date(due: str, timezone: str | None) -> str: """Convert RTM date (UTC) to user's timezone. Args: due: Date string from RTM (ISO 8601 format, typically with Z suffix) timezone: User's IANA timezone (e.g., 'Europe/Warsaw') Returns: ISO 8601 date string in user's timezone, or original if conversion fails """ if not timezone: return due try: from zoneinfo import ZoneInfo # Parse the UTC date from RTM due_dt = datetime.fromisoformat(due.replace("Z", "+00:00")) # Convert to user's timezone user_tz = ZoneInfo(timezone) due_local = due_dt.astimezone(user_tz) # Return ISO format in user's timezone return due_local.isoformat() except Exception: # If conversion fails, return original return due def format_task( task: dict[str, Any], include_ids: bool = True, timezone: str | None = None ) -> dict[str, Any]: """Format a task for response. Args: task: Raw task data from RTM include_ids: Whether to include task IDs timezone: User's IANA timezone for date conversion (e.g., 'Europe/Warsaw') Returns: Formatted task dict """ # Convert dates to user's timezone due_display = None due_raw = task.get("due") if due_raw: due_display = _convert_rtm_date(due_raw, timezone) start_display = None start_raw = task.get("start") if start_raw: start_display = _convert_rtm_date(start_raw, timezone) formatted = { "name": task.get("name", ""), "priority": _priority_label(task.get("priority", "N")), "due": due_display, "start": start_display, "completed": task.get("completed") or None, "tags": task.get("tags", []), "url": task.get("url") or None, "notes_count": len(task.get("notes", [])), "estimate": task.get("estimate") or None, "modified": task.get("modified") or None, } if include_ids: formatted["id"] = task.get("id") formatted["taskseries_id"] = task.get("taskseries_id") formatted["list_id"] = task.get("list_id") return formatted def format_list(lst: dict[str, Any]) -> dict[str, Any]: """Format a list for response.""" return { "id": lst.get("id"), "name": lst.get("name"), "smart": lst.get("smart") == "1", "archived": lst.get("archived") == "1", "locked": lst.get("locked") == "1", } def _priority_label(priority: str) -> str: """Convert priority code to label.""" labels = { "1": "high", "2": "medium", "3": "low", "N": "none", } return labels.get(priority, "none") def priority_to_code(priority: str | int | None) -> str: """Convert priority label/number to RTM code.""" if priority is None: return "N" priority_str = str(priority).lower() mapping = { "high": "1", "1": "1", "medium": "2", "2": "2", "low": "3", "3": "3", "none": "N", "0": "N", "n": "N", } return mapping.get(priority_str, "N") def parse_tasks_response(result: dict[str, Any]) -> list[dict[str, Any]]: """Parse RTM tasks response into flat task list. RTM returns nested structure: tasks.list[].taskseries[].task[] We flatten this to a simple list with all IDs attached. """ tasks = [] task_lists = result.get("tasks", {}).get("list", []) if isinstance(task_lists, dict): task_lists = [task_lists] for tl in task_lists: list_id = tl.get("id") taskseries_list = tl.get("taskseries", []) if isinstance(taskseries_list, dict): taskseries_list = [taskseries_list] for ts in taskseries_list: task_data = ts.get("task", []) if isinstance(task_data, dict): task_data = [task_data] # Parse tags tags_data = ts.get("tags", []) if isinstance(tags_data, dict): tags = tags_data.get("tag", []) if isinstance(tags, str): tags = [tags] else: tags = [] # Parse notes notes_data = ts.get("notes", []) notes = [] if isinstance(notes_data, dict): notes = notes_data.get("note", []) if isinstance(notes, dict): notes = [notes] for t in task_data: tasks.append( { "id": t.get("id"), "taskseries_id": ts.get("id"), "list_id": list_id, "name": ts.get("name"), "due": t.get("due") or None, "has_due_time": t.get("has_due_time") == "1", "start": t.get("start") or None, "has_start_time": t.get("has_start_time") == "1", "completed": t.get("completed") or None, "deleted": t.get("deleted") or None, "priority": t.get("priority", "N"), "postponed": int(t.get("postponed", 0)), "estimate": t.get("estimate") or None, "tags": tags if tags else [], "notes": notes, "url": ts.get("url") or None, "location_id": ts.get("location_id") or None, "created": ts.get("created") or None, "modified": ts.get("modified") or None, } ) return tasks def parse_lists_response(result: dict[str, Any]) -> list[dict[str, Any]]: """Parse RTM lists response.""" lists = result.get("lists", {}).get("list", []) if isinstance(lists, dict): lists = [lists] return [ { "id": lst.get("id"), "name": lst.get("name"), "deleted": lst.get("deleted") == "1", "locked": lst.get("locked") == "1", "archived": lst.get("archived") == "1", "position": int(lst.get("position", -1)), "smart": lst.get("smart") == "1", "filter": lst.get("filter"), "sort_order": lst.get("sort_order"), } for lst in lists ] def get_transaction_id(result: dict[str, Any]) -> str | None: """Extract transaction ID from response for undo support.""" transaction = result.get("transaction", {}) return transaction.get("id") - src/rtm_mcp/client.py:145-147 (helper)The client.check_token method calls the RTM API's rtm.auth.checkToken endpoint.
async def check_token(self) -> dict[str, Any]: """Check if auth token is valid (rtm.auth.checkToken).""" return await self.call("rtm.auth.checkToken") - src/rtm_mcp/server.py:102-107 (registration)Top-level registration call in server.py that triggers register_utility_tools (and thus check_auth).
# Register all tools register_task_tools(mcp, get_client) register_list_tools(mcp, get_client) register_note_tools(mcp, get_client) register_utility_tools(mcp, get_client)