Skip to main content
Glama
elizagarate

Things MCP Server

by elizagarate

get_anytime

Retrieve tasks from the Anytime list to access unscheduled to-dos in your Things 3 task manager.

Instructions

Get todos from Anytime list

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The get_anytime handler function: fetches todos from Things' Anytime list via things.anytime(), filters out tasks belonging to Someday projects (matching Things UI behavior), formats each todo using format_todo(), and joins them with separators. Returns 'No items found' if list is empty or entirely filtered.
    async def get_anytime() -> str:
        """Get todos from Anytime list"""
        todos = things.anytime(include_items=True)
        if not todos:
            return "No items found"
        # Filter out tasks from Someday projects
        todos = filter_someday_project_tasks(todos)
        if not todos:
            return "No items found"
        formatted_todos = [format_todo(todo) for todo in todos]
        return "\n\n---\n\n".join(formatted_todos)
  • The @mcp.tool decorator registers get_anytime as an MCP tool on the FastMCP server instance.
    @mcp.tool
    async def get_anytime() -> str:
  • filter_someday_project_tasks helper: filters out tasks belonging to Someday projects. Called by get_anytime (line 120) to exclude tasks from Someday projects, matching Things UI behavior.
    def filter_someday_project_tasks(todos):
        """Filter out tasks that belong to Someday projects.
    
        This matches Things UI behavior where tasks from Someday projects
        don't appear in Today, Upcoming, or Anytime views. Handles both
        direct project membership and tasks under headings in Someday projects.
    
        Args:
            todos: List of todo dictionaries
    
        Returns:
            Filtered list excluding tasks from Someday projects
        """
        someday_project_ids, heading_to_project = _get_someday_context()
        if not someday_project_ids:
            return todos
        return [todo for todo in todos if not _is_in_someday_project(todo, someday_project_ids, heading_to_project)]
  • format_todo helper: formats a single todo dictionary into a readable multi-line string with title, UUID, type, status, dates, notes, project, heading, area, tags, and checklist. Called by get_anytime (line 123) to format each todo.
    def format_todo(todo: dict) -> str:
        """Helper function to format a single todo into a readable string."""
        logger.debug(f"Formatting todo: {todo}")
        todo_text = f"Title: {todo['title']}"
    
        # Add UUID for reference
        todo_text += f"\nUUID: {todo['uuid']}"
    
        # Add type
        todo_text += f"\nType: {todo['type']}"
    
        # Add status if present
        if todo.get('status'):
            todo_text += f"\nStatus: {todo['status']}"
    
        # Look up parent project once (used for both List status and Project display)
        # For heading-level tasks without a project field, resolve heading -> project
        parent_project = None
        if todo.get('project'):
            try:
                parent_project = things.get(todo['project'])
            except Exception:
                pass
        elif todo.get('heading'):
            try:
                heading_obj = things.get(todo['heading'])
                if heading_obj and heading_obj.get('project'):
                    parent_project = things.get(heading_obj['project'])
            except Exception:
                pass
    
        # Add start/list location with Someday inheritance
        if todo.get('start'):
            effective_start = todo['start']
            if effective_start != 'Someday' and parent_project and parent_project.get('start') == 'Someday':
                effective_start = 'Someday'
                todo_text += f"\nList: {effective_start} (inherited from project)"
            else:
                todo_text += f"\nList: {effective_start}"
    
        # Add dates
        if todo.get('start_date'):
            todo_text += f"\nStart Date: {todo['start_date']}"
        if todo.get('deadline'):
            todo_text += f"\nDeadline: {todo['deadline']}"
        if todo.get('stop_date'):  # Completion date
            todo_text += f"\nCompleted: {todo['stop_date']}"
    
        # Add creation and modification dates
        if todo.get('created'):
            todo_text += f"\nCreated: {todo['created']}"
            # Calculate age since creation
            try:
                age_text = _calculate_age(todo['created'])
                todo_text += f"\nAge: {age_text}"
            except (ValueError, TypeError):
                pass
    
        if todo.get('modified'):
            todo_text += f"\nModified: {todo['modified']}"
            # Calculate time since last modification
            try:
                modified_age = _calculate_age(todo['modified'])
                todo_text += f"\nLast modified: {modified_age}"
            except (ValueError, TypeError):
                pass
    
        # Add notes if present
        if todo.get('notes'):
            todo_text += f"\nNotes: {todo['notes']}"
    
        # Add project info if present
        if parent_project:
            todo_text += f"\nProject: {parent_project['title']}"
    
        # Add heading info if present
        if todo.get('heading'):
            try:
                heading = things.get(todo['heading'])
                if heading:
                    todo_text += f"\nHeading: {heading['title']}"
            except Exception:
                pass
    
        # Add area info if present
        if todo.get('area'):
            try:
                area = things.get(todo['area'])
                if area:
                    todo_text += f"\nArea: {area['title']}"
            except Exception:
                pass
    
        # Add tags if present
        if todo.get('tags'):
            todo_text += f"\nTags: {', '.join(todo['tags'])}"
    
        # Add checklist if present and contains items
        if isinstance(todo.get('checklist'), list):
            todo_text += "\nChecklist:"
            for item in todo['checklist']:
                checkbox = "✓" if item.get('status') == 'completed' else "☐"
                todo_text += f"\n  {checkbox} {item['title']}"
    
        return todo_text
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It only states the action without disclosing whether the operation is read-only, any side effects, or rate limits. The verb 'Get' implies reading, but no explicit assurance.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence with no superfluous words. It is front-loaded and efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of 20 sibling tools and no explanation of what 'Anytime list' entails, the description is too sparse. It does not provide enough context for an agent to correctly choose this tool over others, despite having an output schema.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has no parameters and schema description coverage is 100%. The description adds no parameter details, but there is nothing to add. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description 'Get todos from Anytime list' clearly states the verb (get) and resource (todos from Anytime list). It distinguishes from siblings like get_today, get_inbox, etc., by specifying the list context.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives like get_today, get_inbox, or get_upcoming. The description lacks any usage context or exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/elizagarate/things-mcp'

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