get_tagged_items
Retrieves all tasks, projects, and items in Things 3 that are associated with a given tag.
Instructions
Get items with a specific tag
Args: tag: Tag title to filter by
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tag | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/things_mcp/server.py:235-247 (handler)The handler function for the 'get_tagged_items' tool. It takes a tag parameter, calls things.todos(tag=tag, include_items=True) to fetch items with that tag, formats each todo using format_todo(), and returns them joined by separators.
@mcp.tool async def get_tagged_items(tag: str) -> str: """Get items with a specific tag Args: tag: Tag title to filter by """ todos = things.todos(tag=tag, include_items=True) if not todos: return f"No items found with tag '{tag}'" formatted_todos = [format_todo(todo) for todo in todos] return "\n\n---\n\n".join(formatted_todos) - src/things_mcp/server.py:235-236 (registration)The tool is registered with MCP via the @mcp.tool decorator. The mcp object is a FastMCP instance created on line 19 of server.py and exported via __init__.py.
@mcp.tool async def get_tagged_items(tag: str) -> str: - src/things_mcp/server.py:239-241 (schema)Input schema: the 'tag' parameter is a required string. The docstring describes it as 'Tag title to filter by'. The return type is a plain string.
Args: tag: Tag title to filter by """ - src/things_mcp/formatters.py:40-144 (helper)The format_todo() helper function is used by get_tagged_items to format each todo item into a readable string including title, UUID, type, dates, notes, project, tags, and checklist items.
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