Skip to main content
Glama
snowild

Redmine MCP Server

by snowild

update_issue_content

Modify Redmine issue details including title, description, priority, progress, tracker, dates, and estimated hours to keep project information current.

Instructions

更新議題內容(標題、描述、優先級、完成度、追蹤器、日期、工時等)

Args:
    issue_id: 議題 ID
    subject: 新的議題標題(可選)
    description: 新的議題描述(可選)
    priority_id: 新的優先級 ID(與 priority_name 二選一)
    priority_name: 新的優先級名稱(與 priority_id 二選一)
    done_ratio: 新的完成百分比 0-100(可選)
    tracker_id: 新的追蹤器 ID(與 tracker_name 二選一)
    tracker_name: 新的追蹤器名稱(與 tracker_id 二選一)
    parent_issue_id: 新的父議題 ID(可選)
    remove_parent: 是否移除父議題關係(可選)
    start_date: 新的開始日期 YYYY-MM-DD 格式(可選)
    due_date: 新的完成日期 YYYY-MM-DD 格式(可選)
    estimated_hours: 新的預估工時(可選)

Returns:
    更新結果訊息

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
issue_idYes
subjectNo
descriptionNo
priority_idNo
priority_nameNo
done_ratioNo
tracker_idNo
tracker_nameNo
parent_issue_idNo
remove_parentNo
start_dateNo
due_dateNo
estimated_hoursNo

Implementation Reference

  • The core handler function for the 'update_issue_content' MCP tool. It is registered via the @mcp.tool() decorator. Handles input validation, name-to-ID resolution using cache, calls RedmineClient.update_issue(), fetches updated issue details, and formats a success message with changes summary.
    @mcp.tool()
    def update_issue_content(issue_id: int, subject: str = None, description: str = None, 
                            priority_id: int = None, priority_name: str = None,
                            done_ratio: int = None, tracker_id: int = None, tracker_name: str = None,
                            parent_issue_id: int = None, remove_parent: bool = False, start_date: str = None, due_date: str = None,
                            estimated_hours: float = None) -> str:
        """
        更新議題內容(標題、描述、優先級、完成度、追蹤器、日期、工時等)
        
        Args:
            issue_id: 議題 ID
            subject: 新的議題標題(可選)
            description: 新的議題描述(可選)
            priority_id: 新的優先級 ID(與 priority_name 二選一)
            priority_name: 新的優先級名稱(與 priority_id 二選一)
            done_ratio: 新的完成百分比 0-100(可選)
            tracker_id: 新的追蹤器 ID(與 tracker_name 二選一)
            tracker_name: 新的追蹤器名稱(與 tracker_id 二選一)
            parent_issue_id: 新的父議題 ID(可選)
            remove_parent: 是否移除父議題關係(可選)
            start_date: 新的開始日期 YYYY-MM-DD 格式(可選)
            due_date: 新的完成日期 YYYY-MM-DD 格式(可選)
            estimated_hours: 新的預估工時(可選)
        
        Returns:
            更新結果訊息
        """
        try:
            client = get_client()
            
            # 準備更新資料
            update_data = {}
            changes = []
            
            if subject is not None:
                update_data['subject'] = subject.strip()
                changes.append(f"標題: {subject}")
            
            if description is not None:
                update_data['description'] = description
                changes.append("描述已更新")
            
            # 處理優先級參數
            if priority_name:
                priority_id = client.find_priority_id_by_name(priority_name)
                if not priority_id:
                    return f"找不到優先級名稱:「{priority_name}」\n\n可用優先級:\n" + "\n".join([f"- {name}" for name in client.get_available_priorities().keys()])
            
            if priority_id is not None:
                update_data['priority_id'] = priority_id
                changes.append(f"優先級 ID: {priority_id}")
            
            if done_ratio is not None:
                if not (0 <= done_ratio <= 100):
                    return "錯誤: 完成百分比必須在 0-100 之間"
                update_data['done_ratio'] = done_ratio
                changes.append(f"完成度: {done_ratio}%")
            
            # 處理追蹤器參數
            if tracker_name:
                tracker_id = client.find_tracker_id_by_name(tracker_name)
                if not tracker_id:
                    return f"找不到追蹤器名稱:「{tracker_name}」\n\n可用追蹤器:\n" + "\n".join([f"- {name}" for name in client.get_available_trackers().keys()])
            
            if tracker_id is not None:
                update_data['tracker_id'] = tracker_id
                changes.append(f"追蹤器 ID: {tracker_id}")
            
            if remove_parent:
                update_data['parent_issue_id'] = None
                changes.append("移除父議題關係")
            elif parent_issue_id is not None:
                update_data['parent_issue_id'] = parent_issue_id
                changes.append(f"父議題 ID: {parent_issue_id}")
            
            if start_date is not None:
                # 驗證日期格式
                try:
                    from datetime import datetime
                    datetime.strptime(start_date, '%Y-%m-%d')
                    update_data['start_date'] = start_date
                    changes.append(f"開始日期: {start_date}")
                except ValueError:
                    return "錯誤: 開始日期格式必須為 YYYY-MM-DD"
            
            if due_date is not None:
                # 驗證日期格式
                try:
                    from datetime import datetime
                    datetime.strptime(due_date, '%Y-%m-%d')
                    update_data['due_date'] = due_date
                    changes.append(f"完成日期: {due_date}")
                except ValueError:
                    return "錯誤: 完成日期格式必須為 YYYY-MM-DD"
            
            if estimated_hours is not None:
                if estimated_hours < 0:
                    return "錯誤: 預估工時不能為負數"
                update_data['estimated_hours'] = estimated_hours
                changes.append(f"預估工時: {estimated_hours} 小時")
            
            if not update_data and not changes:
                return "錯誤: 請至少提供一個要更新的欄位"
            
            # 執行更新
            client.update_issue(issue_id, **update_data)
            
            # 取得更新後的議題資訊
            updated_issue = client.get_issue(issue_id)
            
            result = f"""議題內容更新成功!
    
    議題: #{issue_id} - {updated_issue.subject}
    已更新的欄位:
    {chr(10).join(f"- {change}" for change in changes)}
    
    目前狀態:
    - 追蹤器: {updated_issue.tracker.get('name', 'N/A')}
    - 狀態: {updated_issue.status.get('name', 'N/A')}
    - 優先級: {updated_issue.priority.get('name', 'N/A')}
    - 完成度: {updated_issue.done_ratio}%"""
    
            return result
            
        except RedmineAPIError as e:
            return f"更新議題內容失敗: {str(e)}"
        except Exception as e:
            return f"系統錯誤: {str(e)}"
  • Helper method in RedmineClient that performs the actual Redmine API PUT request to update issue content. Called by the tool handler.
    def update_issue(self, issue_id: int, **kwargs) -> bool:
        """更新議題"""
        update_data = {'issue': {}}
        
        # 支援的更新欄位
        if 'subject' in kwargs:
            update_data['issue']['subject'] = kwargs['subject']
        if 'description' in kwargs:
            update_data['issue']['description'] = kwargs['description']
        if 'status_id' in kwargs:
            update_data['issue']['status_id'] = kwargs['status_id']
        if 'priority_id' in kwargs:
            update_data['issue']['priority_id'] = kwargs['priority_id']
        if 'assigned_to_id' in kwargs:
            update_data['issue']['assigned_to_id'] = kwargs['assigned_to_id']
        if 'done_ratio' in kwargs:
            update_data['issue']['done_ratio'] = kwargs['done_ratio']
        if 'tracker_id' in kwargs:
            update_data['issue']['tracker_id'] = kwargs['tracker_id']
        if 'parent_issue_id' in kwargs:
            # 如果 parent_issue_id 為 None,則移除父議題關係
            if kwargs['parent_issue_id'] is None:
                update_data['issue']['parent_issue_id'] = ""
            else:
                update_data['issue']['parent_issue_id'] = kwargs['parent_issue_id']
        if 'start_date' in kwargs:
            update_data['issue']['start_date'] = kwargs['start_date']
        if 'due_date' in kwargs:
            update_data['issue']['due_date'] = kwargs['due_date']
        if 'estimated_hours' in kwargs:
            update_data['issue']['estimated_hours'] = kwargs['estimated_hours']
        if 'notes' in kwargs:
            update_data['issue']['notes'] = kwargs['notes']
        
        if not update_data['issue']:
            raise RedmineAPIError("沒有提供要更新的欄位")
        
        self._make_request('PUT', f'/issues/{issue_id}.json', json=update_data)
        return True

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/snowild/redmine-mcp'

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