Skip to main content
Glama
AstroMined
by AstroMined

list_issues

Retrieve and filter GitHub repository issues based on criteria like state, labels, sorting, and date, using intelligent parameter handling and pagination support.

Instructions

List issues from a GitHub repository.

Args: params: Parameters for listing issues including: - owner: Repository owner (user or organization) - repo: Repository name - state: Issue state (open, closed, all) - labels: Filter by labels - sort: Sort field (created, updated, comments) - direction: Sort direction (asc, desc) - since: Filter by date - page: Page number for pagination - per_page: Number of results per page (max 100) Returns: List of issues from GitHub API

Input Schema

NameRequiredDescriptionDefault
paramsYes

Input Schema (JSON Schema)

{ "$defs": { "ListIssuesParams": { "description": "Parameters for listing issues.", "properties": { "direction": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Sort direction: asc, desc", "title": "Direction" }, "labels": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "default": null, "description": "Filter by labels (list of label names)", "title": "Labels" }, "owner": { "description": "Repository owner (username or organization)", "title": "Owner", "type": "string" }, "page": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Page number for pagination (1-based)", "title": "Page" }, "per_page": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Results per page (max 100)", "title": "Per Page" }, "repo": { "description": "Repository name", "title": "Repo", "type": "string" }, "since": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "default": null, "description": "Filter by date (ISO 8601 format with timezone: YYYY-MM-DDThh:mm:ssZ)", "title": "Since" }, "sort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Sort by: created, updated, comments", "title": "Sort" }, "state": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Issue state: open, closed, all", "title": "State" } }, "required": [ "owner", "repo" ], "title": "ListIssuesParams", "type": "object" } }, "properties": { "params": { "$ref": "#/$defs/ListIssuesParams" } }, "required": [ "params" ], "title": "list_issuesArguments", "type": "object" }

Implementation Reference

  • MCP tool handler for list_issues. Validates input with ListIssuesParams, calls operations.issues.list_issues, formats response as JSON text or error.
    def list_issues(params: ListIssuesParams) -> dict: """List issues from a GitHub repository. Args: params: Parameters for listing issues including: - owner: Repository owner (user or organization) - repo: Repository name - state: Issue state (open, closed, all) - labels: Filter by labels - sort: Sort field (created, updated, comments) - direction: Sort direction (asc, desc) - since: Filter by date - page: Page number for pagination - per_page: Number of results per page (max 100) Returns: List of issues from GitHub API """ try: logger.debug(f"list_issues called with params: {params}") # Pass the Pydantic model directly to the operation result = issues.list_issues(params) logger.debug(f"Got result: {result}") response = {"content": [{"type": "text", "text": json.dumps(result, indent=2)}]} logger.debug(f"Returning response: {response}") return response except GitHubError as e: logger.error(f"GitHub error: {e}") return { "content": [{"type": "error", "text": format_github_error(e)}], "is_error": True } except Exception as e: logger.error(f"Unexpected error: {e}") logger.error(traceback.format_exc()) error_msg = str(e) if str(e) else "An unexpected error occurred" return { "content": [{"type": "error", "text": f"Internal server error: {error_msg}"}], "is_error": True }
  • Pydantic schema for ListIssuesParams, including input validation for parameters like state, labels, sort, direction, since, page, per_page.
    class ListIssuesParams(RepositoryRef): """Parameters for listing issues.""" model_config = ConfigDict(strict=True) state: Optional[str] = Field( None, description=f"Issue state: {', '.join(VALID_ISSUE_STATES)}" ) labels: Optional[List[str]] = Field( None, description="Filter by labels (list of label names)" ) sort: Optional[str] = Field( None, description=f"Sort by: {', '.join(VALID_SORT_VALUES)}" ) direction: Optional[str] = Field( None, description=f"Sort direction: {', '.join(VALID_DIRECTION_VALUES)}" ) since: Optional[datetime] = Field( None, description="Filter by date (ISO 8601 format with timezone: YYYY-MM-DDThh:mm:ssZ)" ) page: Optional[int] = Field( None, description="Page number for pagination (1-based)" ) per_page: Optional[int] = Field( None, description="Results per page (max 100)" ) @field_validator('state') @classmethod def validate_state(cls, v): """Validate that state is one of the allowed values.""" if v is not None and v not in VALID_ISSUE_STATES: raise ValueError(f"Invalid state: {v}. Must be one of: {', '.join(VALID_ISSUE_STATES)}") return v @field_validator('sort') @classmethod def validate_sort(cls, v): """Validate that sort is one of the allowed values.""" if v is not None and v not in VALID_SORT_VALUES: raise ValueError(f"Invalid sort value: {v}. Must be one of: {', '.join(VALID_SORT_VALUES)}") return v @field_validator('direction') @classmethod def validate_direction(cls, v): """Validate that direction is one of the allowed values.""" if v is not None and v not in VALID_DIRECTION_VALUES: raise ValueError(f"Invalid direction: {v}. Must be one of: {', '.join(VALID_DIRECTION_VALUES)}") return v @field_validator('page') @classmethod def validate_page(cls, v): """Validate that page is a positive integer.""" if v is not None and v < 1: raise ValueError("Page number must be a positive integer") return v @field_validator('per_page') @classmethod def validate_per_page(cls, v): """Validate that per_page is a positive integer <= 100.""" if v is not None: if v < 1: raise ValueError("Results per page must be a positive integer") if v > 100: raise ValueError("Results per page cannot exceed 100") return v @field_validator('since', mode='before') @classmethod def validate_since(cls, v): """Convert string dates to datetime objects. Accepts: - ISO 8601 format strings with timezone (e.g., "2020-01-01T00:00:00Z") - ISO 8601 format strings with timezone without colon (e.g., "2020-01-01T12:30:45-0500") - ISO 8601 format strings with short timezone (e.g., "2020-01-01T12:30:45+05") - ISO 8601 format strings with single digit timezone (e.g., "2020-01-01T12:30:45-5") - datetime objects Returns: - datetime object Raises: - ValueError: If the string cannot be converted to a valid datetime object """ if isinstance(v, str): # Basic validation - must have 'T' and some form of timezone indicator if not ('T' in v and ('+' in v or 'Z' in v or '-' in v.split('T')[1])): raise ValueError( f"Invalid ISO format datetime: {v}. " f"Must include date, time with 'T' separator, and timezone." ) try: # Try to convert using our flexible converter return convert_iso_string_to_datetime(v) except ValueError as e: # Only raise if conversion actually fails raise ValueError(f"Invalid ISO format datetime: {v}. {str(e)}") return v
  • Registers the list_issues tool (and other issue tools) with the MCP server instance using register_tools.
    def register(mcp: FastMCP) -> None: """Register all issue tools with the MCP server. Args: mcp: The MCP server instance """ from pygithub_mcp_server.tools import register_tools # List of all issue tools to register issue_tools = [ create_issue, list_issues, get_issue, update_issue, add_issue_comment, list_issue_comments, update_issue_comment, delete_issue_comment, add_issue_labels, remove_issue_label, ] register_tools(mcp, issue_tools) logger.debug(f"Registered {len(issue_tools)} issue tools")
  • Core implementation that performs the actual GitHub API call to list issues using PyGithub repository.get_issues, handles pagination and conversion.
    def list_issues(params: ListIssuesParams) -> List[Dict[str, Any]]: """List issues in a repository. Args: params: Validated parameters for listing issues Returns: List of issues from GitHub API Raises: GitHubError: If the API request fails """ try: # No need for parameter validation as Pydantic already validated the input client = GitHubClient.get_instance() repository = client.get_repo(f"{params.owner}/{params.repo}") # Default to 'open' if state is None state = params.state or 'open' # Build kwargs for get_issues using fields from the Pydantic model kwargs = {"state": state} # Add optional parameters only if provided if params.sort: kwargs["sort"] = params.sort if params.direction: kwargs["direction"] = params.direction if params.since: kwargs["since"] = params.since logger.debug(f"Using UTC since parameter: {params.since.isoformat()}") if params.labels is not None: # Convert to PyGithub-compatible format from ..converters.parameters import convert_labels_parameter kwargs["labels"] = convert_labels_parameter(params.labels) logger.debug(f"Using labels filter: {kwargs['labels']}") # Get paginated issues logger.debug(f"Getting issues for {params.owner}/{params.repo} with kwargs: {kwargs}") try: paginated_issues = repository.get_issues(**kwargs) logger.debug(f"Got PaginatedList of issues: {paginated_issues}") except AssertionError as e: logger.error(f"PyGithub assertion error: {e}") logger.error(f"Error type: {type(e)}") logger.error(f"Error args: {e.args}") raise GitHubError("Invalid parameter values for get_issues") except GithubException as e: # Let the GitHub client handle the exception properly raise GitHubClient.get_instance()._handle_github_exception(e) except Exception as e: logger.error(f"Error getting issues: {e}") logger.error(f"Error type: {type(e)}") logger.error(f"Error args: {e.args}") raise GitHubError(f"Failed to get issues: {str(e)}") try: # Use our pagination utility to safely handle paginated lists issues = get_paginated_items(paginated_issues, params.page, params.per_page) logger.debug(f"Retrieved {len(issues)} issues") # Convert each issue to our schema converted_issues = [convert_issue(issue) for issue in issues] logger.debug(f"Converted {len(converted_issues)} issues to schema") return converted_issues except Exception as e: logger.error(f"Error handling pagination: {str(e)}") raise GitHubError(f"Error retrieving issues: {str(e)}") except GithubException as e: # Convert PyGithub exception to our error type error = GitHubClient.get_instance()._handle_github_exception(e) raise error

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/AstroMined/pygithub-mcp-server'

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