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