Skip to main content
Glama
cdmx-in
by cdmx-in

create_task

Add new tasks to Goodday projects with details like title, assignee, dates, priority, and estimates to organize work effectively.

Instructions

Create a new task in Goodday.

Args: project_id: Task project ID title: Task title from_user_id: Task created by user ID
parent_task_id: Parent task ID to create a subtask message: Task description/initial message to_user_id: Assigned To/Action required user ID task_type_id: Task type ID start_date: Task start date (YYYY-MM-DD) end_date: Task end date (YYYY-MM-DD) deadline: Task deadline (YYYY-MM-DD) estimate: Task estimate in minutes story_points: Task story points estimate priority: Task priority (1-10), 50 - Blocker, 100 - Emergency

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
project_idYes
titleYes
from_user_idYes
parent_task_idNo
messageNo
to_user_idNo
task_type_idNo
start_dateNo
end_dateNo
deadlineNo
estimateNo
story_pointsNo
priorityNo

Implementation Reference

  • The handler function for the 'create_task' MCP tool. It constructs a POST request payload for the Goodday API endpoint '/tasks', sends it using make_goodday_request, handles errors, and formats the response using format_task.
    async def create_task(
        project_id: str,
        title: str,
        from_user_id: str,
        parent_task_id: Optional[str] = None,
        message: Optional[str] = None,
        to_user_id: Optional[str] = None,
        task_type_id: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        deadline: Optional[str] = None,
        estimate: Optional[int] = None,
        story_points: Optional[int] = None,
        priority: Optional[int] = None
    ) -> str:
        """Create a new task in Goodday.
    
        Args:
            project_id: Task project ID
            title: Task title
            from_user_id: Task created by user ID  
            parent_task_id: Parent task ID to create a subtask
            message: Task description/initial message
            to_user_id: Assigned To/Action required user ID
            task_type_id: Task type ID
            start_date: Task start date (YYYY-MM-DD)
            end_date: Task end date (YYYY-MM-DD)
            deadline: Task deadline (YYYY-MM-DD)
            estimate: Task estimate in minutes
            story_points: Task story points estimate
            priority: Task priority (1-10), 50 - Blocker, 100 - Emergency
        """
        data = {
            "projectId": project_id,
            "title": title,
            "fromUserId": from_user_id
        }
        
        if parent_task_id:
            data["parentTaskId"] = parent_task_id
        if message:
            data["message"] = message
        if to_user_id:
            data["toUserId"] = to_user_id
        if task_type_id:
            data["taskTypeId"] = task_type_id
        if start_date:
            data["startDate"] = start_date
        if end_date:
            data["endDate"] = end_date
        if deadline:
            data["deadline"] = deadline
        if estimate:
            data["estimate"] = estimate
        if story_points:
            data["storyPoints"] = story_points
        if priority:
            data["priority"] = priority
        
        result = await make_goodday_request("tasks", "POST", data)
        
        if not result:
            return "Unable to create task: No response received"
        
        if isinstance(result, dict) and "error" in result:
            return f"Unable to create task: {result.get('error', 'Unknown error')}"
        
        return f"Task created successfully: {format_task(result)}"
  • Helper function to format the task dictionary returned from the API into a human-readable string, used in the create_task response.
    def format_task(task: dict) -> str:
        """Format a task into a readable string with safe checks."""
        if not isinstance(task, dict):
            return f"Invalid task data: {repr(task)}"
    
        # Defensive defaults in case nested keys are not dicts
        status = task.get('status') if isinstance(task.get('status'), dict) else {}
        project = task.get('project') if isinstance(task.get('project'), dict) else {}
    
        return f"""
    **Task ID:** {task.get('shortId', 'N/A')}
    **Title:** {task.get('name', 'N/A')}
    **Status:** {status.get('name', 'N/A')}
    **Project:** {project.get('name', 'N/A')}
    **Assigned To:** {task.get('assignedToUserId', 'N/A')}
    **Priority:** {task.get('priority', 'N/A')}
    **Start Date:** {task.get('startDate', 'N/A')}
    **End Date:** {task.get('endDate', 'N/A')}
    **Description:** {task.get('message', 'No description')}
    """.strip()
  • Core helper function that makes authenticated HTTP requests to the Goodday API, used by create_task to POST to the /tasks endpoint.
    async def make_goodday_request(endpoint: str, method: str = "GET", data: dict = None, subfolders: bool = True) -> dict[str, Any] | list[Any] | None:
        """Make a request to the Goodday API with proper error handling."""
        api_token = os.getenv("GOODDAY_API_TOKEN")
        if not api_token:
            raise ValueError("GOODDAY_API_TOKEN environment variable is required")
        
        headers = {
            "User-Agent": USER_AGENT,
            "gd-api-token": api_token,
            "Content-Type": "application/json"
        }
        
        # Automatically add subfolders=true for project task and document endpoints if not already present
        if subfolders and endpoint.startswith("project/") and ("/tasks" in endpoint or "/documents" in endpoint):
            if "?" in endpoint:
                if "subfolders=" not in endpoint:
                    endpoint += "&subfolders=true"
            else:
                endpoint += "?subfolders=true"
        
        url = f"{GOODDAY_API_BASE}/{endpoint.lstrip('/')}"
        
        async with httpx.AsyncClient() as client:
            try:
                if method.upper() == "POST":
                    response = await client.post(url, headers=headers, json=data, timeout=30.0)
                elif method.upper() == "PUT":
                    response = await client.put(url, headers=headers, json=data, timeout=30.0)
                elif method.upper() == "DELETE":
                    response = await client.delete(url, headers=headers, timeout=30.0)
                else:
                    response = await client.get(url, headers=headers, timeout=30.0)
    
                response.raise_for_status()
                return response.json()
    
            except httpx.HTTPStatusError as e:
                raise Exception(f"HTTP error {e.response.status_code}: {e.response.text}")
            except httpx.RequestError as e:
                raise Exception(f"Request error: {str(e)}")
            except Exception as e:
                raise Exception(f"Unexpected error: {str(e)}")
Behavior2/5

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

With no annotations provided, the description carries full burden for behavioral disclosure. While 'Create' implies a write/mutation operation, the description doesn't mention authentication requirements, rate limits, error conditions, or what happens on success (e.g., returns task ID). It also doesn't clarify if creating subtasks via parent_task_id has special behavior. This leaves significant gaps for a mutation tool.

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

Conciseness3/5

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

The description is appropriately sized but not optimally structured. The opening sentence is clear, but the parameter documentation uses inconsistent formatting and mixes explanations with format notes. Some redundancy exists (e.g., 'Task' repeated in many parameter descriptions). While all information is valuable given the poor schema coverage, the presentation could be more polished.

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

Completeness3/5

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

For a mutation tool with 13 parameters, no annotations, and no output schema, the description provides good parameter semantics but lacks critical behavioral context. The agent knows what each parameter means but not what authentication is needed, what happens on success/failure, or how this tool relates to others in the system. The parameter documentation is strong, but other aspects are underdeveloped.

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

Parameters5/5

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

With 0% schema description coverage (titles only show parameter names), the description provides crucial semantic information for all 13 parameters. It explains what each parameter represents (e.g., 'Task project ID', 'Task title', 'Task created by user ID'), clarifies data formats (YYYY-MM-DD for dates), defines numeric ranges (priority 1-10 with special values 50 and 100), and explains relationships (parent_task_id creates a subtask). This fully compensates for the schema's lack of descriptions.

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

Purpose4/5

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

The description clearly states 'Create a new task in Goodday' which is a specific verb+resource combination. It distinguishes this from sibling tools like 'update_task_status' or 'get_task' by focusing on creation rather than modification or retrieval. However, it doesn't explicitly differentiate from 'create_project' which creates a different resource type.

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?

The description provides no guidance on when to use this tool versus alternatives. There's no mention of prerequisites (like needing valid project/user IDs), when not to use it, or how it relates to sibling tools like 'create_project' or 'update_task_status'. The agent must infer usage from the tool name and parameter list alone.

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/cdmx-in/goodday-mcp'

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