Skip to main content
Glama
snowild

Redmine MCP Server

by snowild

add_issue_note

Add notes to Redmine issues and optionally record time spent. Specify activity type and mark notes as private when needed.

Instructions

為議題新增備註,可同時記錄時間

Args:
    issue_id: 議題 ID
    notes: 備註內容
    private: 是否為私有備註(預設否)
    spent_hours: 耗用工時(小時)
    activity_name: 活動名稱(與 activity_id 二選一)
    activity_id: 活動 ID(與 activity_name 二選一)
    spent_on: 記錄日期 YYYY-MM-DD 格式(可選,預設今日)

Returns:
    新增結果訊息

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
issue_idYes
notesYes
privateNo
spent_hoursNo
activity_nameNo
activity_idNo
spent_onNo

Implementation Reference

  • The add_issue_note tool handler function, decorated with @mcp.tool() for automatic registration and schema inference from type hints and docstring. Handles adding notes to Redmine issues, optionally with time tracking.
    @mcp.tool()
    def add_issue_note(issue_id: int, notes: str, private: bool = False, 
                       spent_hours: float = None, activity_name: str = None, 
                       activity_id: int = None, spent_on: str = None) -> str:
        """
        為議題新增備註,可同時記錄時間
        
        Args:
            issue_id: 議題 ID
            notes: 備註內容
            private: 是否為私有備註(預設否)
            spent_hours: 耗用工時(小時)
            activity_name: 活動名稱(與 activity_id 二選一)
            activity_id: 活動 ID(與 activity_name 二選一)
            spent_on: 記錄日期 YYYY-MM-DD 格式(可選,預設今日)
        
        Returns:
            新增結果訊息
        """
        try:
            if not notes.strip():
                return "錯誤: 備註內容不能為空"
            
            client = get_client()
            time_entry_id = None
            
            # 處理時間記錄
            if spent_hours is not None:
                if spent_hours <= 0:
                    return "錯誤: 耗用工時必須大於 0"
                
                # 處理活動參數
                final_activity_id = activity_id
                if activity_name:
                    final_activity_id = client.find_time_entry_activity_id_by_name(activity_name)
                    if not final_activity_id:
                        available_activities = client.get_available_time_entry_activities()
                        return f"找不到時間追蹤活動名稱:「{activity_name}」\n\n可用活動:\n" + "\n".join([f"- {name}" for name in available_activities.keys()])
                
                if not final_activity_id:
                    return "錯誤: 必須提供 activity_id 或 activity_name 參數"
                
                # 建立時間記錄
                try:
                    time_entry_id = client.create_time_entry(
                        issue_id=issue_id,
                        hours=spent_hours,
                        activity_id=final_activity_id,
                        comments=notes.strip(),
                        spent_on=spent_on
                    )
                except Exception as e:
                    return f"建立時間記錄失敗: {str(e)}"
            
            # 準備更新資料(新增備註)
            update_data = {'notes': notes.strip()}
            if private:
                update_data['private_notes'] = True
            
            # 執行更新
            client.update_issue(issue_id, **update_data)
            
            # 取得議題資訊
            issue = client.get_issue(issue_id)
            
            privacy_text = "私有" if private else "公開"
            result = f"""備註新增成功!
    
    議題: #{issue_id} - {issue.subject}
    備註類型: {privacy_text}
    備註內容:
    {notes.strip()}"""
    
            # 如果有建立時間記錄,添加相關資訊
            if time_entry_id:
                from datetime import date
                actual_date = spent_on if spent_on else date.today().strftime('%Y-%m-%d')
                activity_name_display = activity_name if activity_name else f"ID {final_activity_id}"
                result += f"""
    
    時間記錄新增成功!
    - 時間記錄 ID: {time_entry_id}
    - 耗用工時: {spent_hours} 小時
    - 活動: {activity_name_display}
    - 記錄日期: {actual_date}"""
    
            return result
            
        except RedmineAPIError as e:
            return f"新增議題備註失敗: {str(e)}"
        except Exception as e:
            return f"系統錯誤: {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. It states the tool creates ('新增') notes and can record time, implying a write/mutation operation. However, it doesn't disclose critical behavioral traits: whether this requires specific permissions, what happens on failure, if notes are editable/deletable, rate limits, or authentication needs. The return is vaguely described as '新增結果訊息' (add result message) without format details.

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 well-structured and appropriately sized. It starts with a clear purpose statement, then lists all parameters with helpful explanations, and ends with return information. Every sentence earns its place, though the return statement could be more specific. The bilingual nature (Chinese purpose, mixed parameter labels) is slightly inconsistent but functional.

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?

Given the tool's complexity (7 parameters, mutation operation) and lack of annotations/output schema, the description is partially complete. It excels at parameter semantics but lacks behavioral context (permissions, errors, etc.) and detailed return format. For a write tool with no structured safety hints, more disclosure about side effects and response structure would be beneficial.

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?

The description adds significant semantic value beyond the input schema, which has 0% description coverage. It explains all 7 parameters in Chinese with clarifications: 'issue_id: 議題 ID' (issue ID), 'notes: 備註內容' (note content), 'private: 是否為私有備註(預設否)' (whether private note, default no), 'spent_hours: 耗用工時(小時)' (hours spent), 'activity_name: 活動名稱(與 activity_id 二選一)' (activity name, choose one with activity_id), 'activity_id: 活動 ID(與 activity_name 二選一)' (activity ID, choose one with activity_name), 'spent_on: 記錄日期 YYYY-MM-DD 格式(可選,預設今日)' (record date YYYY-MM-DD format, optional, default today). 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 the tool's purpose: '為議題新增備註,可同時記錄時間' (Add notes to an issue, can also record time). It specifies the verb ('新增備註' - add notes) and resource ('議題' - issue), and mentions the additional time-tracking capability. However, it doesn't explicitly differentiate from sibling tools like 'update_issue_content' which might also modify issues.

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. It doesn't mention sibling tools like 'update_issue_content' or 'close_issue', nor does it specify prerequisites, constraints, or appropriate contexts for use. The agent must infer usage from the purpose 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/snowild/redmine-mcp'

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