Skip to main content
Glama
snowild

Redmine MCP Server

by snowild

get_issue

Retrieve detailed information about a specific Redmine issue by providing its ID, including optional descriptions, comments, and attachments for project management tasks.

Instructions

取得指定的 Redmine 議題詳細資訊

Args:
    issue_id: 議題 ID
    include_details: 是否包含詳細資訊(描述、備註、附件等)

Returns:
    議題的詳細資訊,以易讀格式呈現

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
issue_idYes
include_detailsNo

Implementation Reference

  • Primary MCP tool handler for 'get_issue'. Fetches raw issue data from RedmineClient and formats detailed information including basic details, attachments, and journals/notes.
    @mcp.tool()
    def get_issue(issue_id: int, include_details: bool = True) -> str:
        """
        取得指定的 Redmine 議題詳細資訊
        
        Args:
            issue_id: 議題 ID
            include_details: 是否包含詳細資訊(描述、備註、附件等)
        
        Returns:
            議題的詳細資訊,以易讀格式呈現
        """
        try:
            client = get_client()
            include_params = []
            if include_details:
                include_params = ['attachments', 'changesets', 'children', 'journals', 'relations', 'watchers']
            
            # 使用新的 get_issue_raw 方法取得完整資料
            issue_data = client.get_issue_raw(issue_id, include=include_params)
            
            # 格式化基本議題資訊
            # 處理父議題資訊
            parent_info = "無父議題"
            if 'parent' in issue_data and issue_data['parent']:
                parent_info = f"#{issue_data['parent']['id']} - {issue_data['parent'].get('subject', 'N/A')}"
            
            result = f"""議題 #{issue_data['id']}: {issue_data['subject']}
    
    基本資訊:
    - 專案: {issue_data['project'].get('name', 'N/A')} (ID: {issue_data['project'].get('id', 'N/A')})
    - 追蹤器: {issue_data['tracker'].get('name', 'N/A')}
    - 狀態: {issue_data['status'].get('name', 'N/A')}
    - 優先級: {issue_data['priority'].get('name', 'N/A')}
    - 建立者: {issue_data['author'].get('name', 'N/A')}
    - 指派給: {issue_data.get('assigned_to', {}).get('name', '未指派') if issue_data.get('assigned_to') else '未指派'}
    - 父議題: {parent_info}
    - 完成度: {issue_data.get('done_ratio', 0)}%
    - 開始日期: {issue_data.get('start_date', '未設定')}
    - 完成日期: {issue_data.get('due_date', '未設定')}
    - 預估工時: {issue_data.get('estimated_hours', '未設定')} 小時
    - 建立時間: {issue_data.get('created_on', 'N/A')}
    - 更新時間: {issue_data.get('updated_on', 'N/A')}
    
    描述:
    {issue_data.get('description', '無描述')}"""
    
            # 加入附件資訊
            if include_details and 'attachments' in issue_data and issue_data['attachments']:
                result += f"\n\n附件 ({len(issue_data['attachments'])} 個):"
                for attachment in issue_data['attachments']:
                    file_size = attachment.get('filesize', 0)
                    file_size_mb = file_size / (1024 * 1024) if file_size > 0 else 0
                    size_text = f"{file_size_mb:.2f} MB" if file_size_mb >= 1 else f"{file_size} bytes"
                    
                    result += f"""
    - 檔名: {attachment.get('filename', 'N/A')}
      大小: {size_text}
      類型: {attachment.get('content_type', 'N/A')}
      上傳者: {attachment.get('author', {}).get('name', 'N/A')}
      上傳時間: {attachment.get('created_on', 'N/A')}
      下載連結: {client.config.redmine_domain}/attachments/download/{attachment.get('id', '')}/{attachment.get('filename', '')}"""
    
            # 加入備註/歷史記錄
            if include_details and 'journals' in issue_data and issue_data['journals']:
                # 過濾出有備註內容的記錄
                notes_journals = [j for j in issue_data['journals'] if j.get('notes', '').strip()]
                
                if notes_journals:
                    result += f"\n\n備註/歷史記錄 ({len(notes_journals)} 筆):"
                    for i, journal in enumerate(notes_journals, 1):
                        author_name = journal.get('user', {}).get('name', 'N/A')
                        created_on = journal.get('created_on', 'N/A')
                        notes = journal.get('notes', '').strip()
                        
                        result += f"""
    
    #{i} - {author_name} ({created_on}):
    {notes}"""
    
            return result
            
        except RedmineAPIError as e:
            return f"取得議題失敗: {str(e)}"
        except Exception as e:
            return f"系統錯誤: {str(e)}"
  • Core helper method in RedmineClient that retrieves the raw JSON response for a specific issue from the Redmine API, used by the get_issue tool handler.
    def get_issue_raw(self, issue_id: int, include: Optional[List[str]] = None) -> Dict[str, Any]:
        """取得單一議題的原始 API 資料(包含 journals 和 attachments)"""
        params = {}
        if include:
            params['include'] = ','.join(include)
        
        response = self._make_request('GET', f'/issues/{issue_id}.json', params=params)
        
        if 'issue' not in response:
            raise RedmineAPIError(f"議題 {issue_id} 不存在")
        
        return response['issue']
  • The @mcp.tool() decorator registers the get_issue function as an MCP tool.
    @mcp.tool()

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