Skip to main content
Glama

search_issues_full

Search Redmine issues by keyword across subjects, descriptions, and all comments. Filter results by project or limit output for targeted issue discovery.

Instructions

Full-text search for issues by keyword. Returns results with description and all comments. Searches across subject, description, and all comments.

Args:
    query: Search keyword
    project_id: Filter by project ID (all projects if omitted)
    limit: Maximum number of results (all results if omitted)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYes
project_idNo
limitNo

Implementation Reference

  • The MCP tool registration and handler wrapper for search_issues_full.
    def search_issues_full(
        query: str,
        project_id: Optional[str] = None,
        limit: Optional[int] = None,
    ) -> List[Dict[str, Any]]:
        """Full-text search for issues by keyword. Returns results with description and all comments.
        Searches across subject, description, and all comments.
    
        Args:
            query: Search keyword
            project_id: Filter by project ID (all projects if omitted)
            limit: Maximum number of results (all results if omitted)
        """
        logger.info(f"tool=search_issues_full query={query!r} project_id={project_id}")
        try:
            return _client().search_issues_full(
                query=query,
                project_id=project_id,
                limit=limit,
            )
        except RedmineError as e:
            logger.error(f"search_issues_full error: {e}")
            raise
  • The implementation of search_issues_full, which performs a full-text search against the Redmine API and then fetches detailed issue data.
    def search_issues_full(
        self,
        query: str,
        project_id: Optional[str] = None,
        limit: Optional[int] = None,
    ) -> List[Dict[str, Any]]:
        try:
            params: Dict[str, Any] = {
                "q": query,
                "issues": 1,
                "titles_only": 0,
            }
            if project_id is not None:
                params["scope"] = "projects"
                params["project_id"] = project_id
            else:
                params["scope"] = "all"
    
            issue_ids: List[int] = []
            offset = 0
            page_size = 25
            while True:
                params["offset"] = offset
                params["limit"] = page_size
                resp = requests.get(
                    f"{self._url}/search.json",
                    params=params,
                    headers={"X-Redmine-API-Key": self._api_key},
                    timeout=30,
                )
                if resp.status_code != 200:
                    raise RedmineError(
                        f"search_issues_full failed: HTTP {resp.status_code} {resp.text}"
                    )
                data = resp.json()
                results = data.get("results", [])
                for r in results:
                    if r.get("type") == "issue":
                        issue_ids.append(r["id"])
                if limit is not None and len(issue_ids) >= limit:
                    issue_ids = issue_ids[:limit]
                    break
                total = data.get("total_count", 0)
                offset += page_size
                if offset >= total or not results:
                    break
    
            output = []
            for issue_id in issue_ids:
                full = self._redmine.issue.get(
                    issue_id, include=["journals"]
                )
                journals = _safe(full, "journals", [])
                output.append({
                    "id": full.id,
                    "subject": full.subject,
                    "description": _safe(full, "description", ""),
                    "status": _safe(_safe(full, "status"), "name", ""),
                    "tracker": _safe(_safe(full, "tracker"), "name", ""),
                    "priority": _safe(_safe(full, "priority"), "name", ""),
                    "assigned_to": _safe(_safe(full, "assigned_to"), "name", ""),
                    "updated_on": str(_safe(full, "updated_on", "")),
                    "journals": [
                        {
                            "notes": _safe(j, "notes", ""),
                            "created_on": str(_safe(j, "created_on", "")),
                            "user": _safe(_safe(j, "user"), "name", ""),
                        }
                        for j in journals
                        if _safe(j, "notes")
                    ],
                })
            return output
        except (AuthError, ForbiddenError) as e:
            raise RedmineError(f"Authentication failed: {e}") from e
        except Exception as e:
            raise RedmineError(f"search_issues_full failed: {e}") from e

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/daiji-sshr/redmine-mcp-stateless'

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