Skip to main content
Glama
tallpizza

Dooray MCP Server

by tallpizza

dooray_files

Manage Dooray project files by listing task attachments, retrieving file metadata, and downloading content from tasks or drive storage.

Instructions

Manage Dooray files and images - list task files, get file metadata, download file content from tasks or directly by content ID

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
actionYesAction to perform on files
taskIdNoTask ID (required for task file actions)
fileIdNoFile ID (required for file operations)
projectIdNoProject ID (optional - uses default from environment if not provided, required for task file actions)

Implementation Reference

  • Core handler function for the dooray_files tool. Dispatches to specific action handlers based on the 'action' parameter.
    async def handle(self, arguments: Dict[str, Any]) -> str:
        """Handle files tool requests.
        
        Args:
            arguments: Tool arguments containing action and parameters
            
        Returns:
            JSON string with results
        """
        action = arguments.get("action")
        if not action:
            return json.dumps({"error": "Action parameter is required"})
        
        try:
            if action == "list_task_files":
                return await self._list_task_files(arguments)
            elif action == "get_task_file_metadata":
                return await self._get_task_file_metadata(arguments)
            elif action == "get_task_file_content":
                return await self._get_task_file_content(arguments)
            elif action == "get_drive_file_metadata":
                return await self._get_drive_file_metadata(arguments)
            elif action == "get_drive_file_content":
                return await self._get_drive_file_content(arguments)
            else:
                return json.dumps({"error": f"Unknown action: {action}"})
                
        except Exception as e:
            logger.error(f"Error in files tool: {e}")
            return json.dumps({"error": str(e)})
  • Input schema and tool description for dooray_files, defining available actions and parameters.
    types.Tool(
        name="dooray_files",
        description="Manage Dooray files and images - list task files, get file metadata, download file content from tasks or directly by content ID",
        inputSchema={
            "type": "object",
            "properties": {
                "action": {
                    "type": "string",
                    "enum": ["list_task_files", "get_task_file_metadata", "get_task_file_content", "get_drive_file_metadata", "get_drive_file_content"],
                    "description": "Action to perform on files"
                },
                "taskId": {
                    "type": "string",
                    "description": "Task ID (required for task file actions)"
                },
                "fileId": {
                    "type": "string",
                    "description": "File ID (required for file operations)"
                },
                "projectId": {
                    "type": "string",
                    "description": "Project ID (optional - uses default from environment if not provided, required for task file actions)"
                }
            },
            "required": ["action"]
        }
    ),
  • Registration in the tool dispatcher: instantiates FilesTool and calls its handle method for dooray_files invocations.
    elif name == "dooray_files":
        tool = FilesTool(dooray_client)
        result = await tool.handle(args)
  • Helper method implementing file download from task attachments, including saving to temporary directory with safe filename.
    async def _get_task_file_content(self, arguments: Dict[str, Any]) -> str:
        """Get content of a file attached to a task and save to temporary file."""
        project_id = arguments.get("projectId")
        task_id = arguments.get("taskId")
        file_id = arguments.get("fileId")
        
        if not project_id or not task_id or not file_id:
            return json.dumps({"error": "projectId, taskId, and fileId are required for get_task_file_content action"})
        
        try:
            # Get file metadata first to get filename
            metadata = await self.client.get_task_file_metadata(project_id, task_id, file_id)
            filename = metadata.get("result", {}).get("name", f"file_{file_id}")
            
            # Download file content
            content = await self.client.get_task_file_content(project_id, task_id, file_id)
            
            # Create temporary file
            temp_dir = tempfile.gettempdir()
            dooray_temp_dir = os.path.join(temp_dir, "dooray_files")
            os.makedirs(dooray_temp_dir, exist_ok=True)
            
            # Use original filename but ensure it's safe
            safe_filename = self._make_safe_filename(filename)
            temp_file_path = os.path.join(dooray_temp_dir, f"{task_id}_{file_id}_{safe_filename}")
            
            # Write content to file
            with open(temp_file_path, 'wb') as f:
                f.write(content)
            
            result = {
                "file_path": temp_file_path,
                "filename": filename,
                "size": len(content),
                "content_type": "file",
                "task_id": task_id,
                "file_id": file_id
            }
            
            return json.dumps(result, ensure_ascii=False)
            
        except Exception as e:
            logger.error(f"Error downloading task file: {e}")
            return json.dumps({"error": f"Failed to download file: {str(e)}"})
  • Helper method to list files attached to a specific task.
    async def _list_task_files(self, arguments: Dict[str, Any]) -> str:
        """List files attached to a task."""
        project_id = arguments.get("projectId")
        task_id = arguments.get("taskId")
        
        if not project_id or not task_id:
            return json.dumps({"error": "projectId and taskId are required for list_task_files action"})
        
        result = await self.client.list_task_files(project_id, task_id)
        return json.dumps(result, ensure_ascii=False)
Behavior2/5

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

With no annotations provided, the description carries full burden but only lists actions without disclosing behavioral traits like permissions needed, rate limits, side effects, or response formats. It mentions downloading content but doesn't specify if it's read-only or has destructive potential, leaving key operational details unclear.

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

Conciseness4/5

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

The description is concise and front-loaded, stating the main purpose in the first clause and listing key actions efficiently. It avoids unnecessary words, though it could be slightly more structured by grouping related actions or adding brief context.

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 no annotations and no output schema, the description is incomplete for a tool with 4 parameters and multiple actions. It lacks details on return values, error handling, or prerequisites, making it inadequate for safe and effective use by an AI agent without additional context.

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?

Schema description coverage is 100%, so the schema already documents all parameters well. The description adds minimal value by implying action types but doesn't explain parameter interactions or semantics beyond what the schema provides, meeting the baseline for high coverage.

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 the tool's purpose as managing Dooray files and images, listing specific actions like listing task files, getting metadata, and downloading content. It distinguishes from siblings by focusing on file operations rather than comments, members, tasks, etc., though it doesn't explicitly contrast with them.

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, such as when to choose task-based vs. drive-based actions, or how it differs from other file-related tools if any exist. It lacks context for selection among its own actions or compared to sibling tools.

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/tallpizza/dooray-mcp'

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