Skip to main content
Glama
saidsef

GitHub PR Issue Analyser

by saidsef

user_activity_query

Query GitHub user activity data across organizations or specific repositories to analyze contributions, commits, pull requests, and issues within defined time periods.

Instructions

Performs a user activity query using GitHub's GraphQL API with support for organization-specific and cross-organization queries.

Query Modes:

  1. Organization-Specific Activity (fastest, most comprehensive):

    • Query organization repositories directly

    • Access all private repos in the org (with proper token scopes)

    • Get detailed commit history, PRs, and issues

    • Variables: {"orgName": "Pelle-Tech", "from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}

    • Variable types: $orgName: String!, $from: GitTimestamp!, $to: GitTimestamp!

  2. Authenticated User Activity Across All Orgs (slower, summary only):

    • Query viewer's contribution collection

    • Includes all orgs where user is a member

    • Summary counts only (no detailed commit messages)

    • Variables: {"from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}

    • Variable types: $from: DateTime!, $to: DateTime!

  3. User Activity in Specific Organization (most restrictive):

    • Query organization repos filtered by user

    • Requires combining org query with author filtering

    • Variables: {"orgName": "Pelle-Tech", "username": "saidsef", "from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}

    • Variable types: $orgName: String!, $username: String!, $from: GitTimestamp!, $to: GitTimestamp!

Performance Tips:

  • Use pagination parameters to limit initial data: first: 50 instead of first: 100

  • Query only required fields to reduce response size

  • Use org-specific queries when possible (faster than viewer queries)

  • For large date ranges, split into smaller queries

  • Cache results for repeated queries

Example Queries:

Fast Org Query with Pagination:

query($orgName: String!, $from: GitTimestamp!, $to: GitTimestamp!, $repoCount: Int = 50) {
  organization(login: $orgName) {
    login
    repositories(first: $repoCount, privacy: PRIVATE, orderBy: {field: PUSHED_AT, direction: DESC}) {
      pageInfo {
        hasNextPage
        endCursor
      }
      nodes {
        name
        isPrivate
        defaultBranchRef {
          target {
            ... on Commit {
              history(since: $from, until: $to, first: 100) {
                totalCount
                pageInfo {
                  hasNextPage
                  endCursor
                }
                nodes {
                  author { 
                    user { login }
                    email
                  }
                  committedDate
                  message
                  additions
                  deletions
                }
              }
            }
          }
        }
        pullRequests(first: 50, states: [OPEN, CLOSED, MERGED], orderBy: {field: UPDATED_AT, direction: DESC}) {
          totalCount
          nodes {
            number
            title
            author { login }
            createdAt
            state
            additions
            deletions
          }
        }
      }
    }
  }
}

User-Filtered Org Query:

query($orgName: String!, $username: String!, $from: GitTimestamp!, $to: GitTimestamp!) {
  organization(login: $orgName) {
    login
    repositories(first: 100, privacy: PRIVATE) {
      nodes {
        name
        defaultBranchRef {
          target {
            ... on Commit {
              history(since: $from, until: $to, author: {emails: [$username]}, first: 100) {
                totalCount
                nodes {
                  author { user { login } }
                  committedDate
                  message
                }
              }
            }
          }
        }
        pullRequests(first: 100, states: [OPEN, CLOSED, MERGED]) {
          nodes {
            author { login }
            title
            createdAt
            state
          }
        }
      }
    }
  }
}

Cross-Org Viewer Query:

query($from: DateTime!, $to: DateTime!) {
  viewer {
    login
    contributionsCollection(from: $from, to: $to) {
      commitContributionsByRepository(maxRepositories: 100) {
        repository { 
          name 
          isPrivate 
          owner { login }
        }
        contributions { totalCount }
      }
      pullRequestContributionsByRepository(maxRepositories: 100) {
        repository { 
          name 
          isPrivate 
          owner { login }
        }
        contributions { totalCount }
      }
      issueContributionsByRepository(maxRepositories: 100) {
        repository { 
          name 
          isPrivate 
          owner { login }
        }
        contributions { totalCount }
      }
    }
    organizations(first: 100) {
      nodes { 
        login 
        viewerCanAdminister
      }
    }
  }
}

Args: variables (dict[str, Any]): Query variables. Supported combinations: - Org-specific: {"orgName": "Pelle-Tech", "from": "...", "to": "..."} - Cross-org: {"from": "...", "to": "..."} - User-filtered org: {"orgName": "Pelle-Tech", "username": "saidsef", "from": "...", "to": "..."} - With pagination: Add {"repoCount": 50, "prCount": 50} for custom limits query (str): GraphQL query string. Must declare correct variable types: - Organization queries: Use GitTimestamp! for $from/$to - Viewer queries: Use DateTime! for $from/$to - Both types accept ISO 8601 format: "YYYY-MM-DDTHH:MM:SSZ"

Returns: Dict[str, Any]: GraphQL response with activity data or error information. - Success: {"data": {...}} - Errors: {"errors": [...], "data": null} - Network error: {"status": "error", "message": "..."}

Error Handling: - Validates response status codes - Logs GraphQL errors with details - Returns structured error responses - Includes traceback for debugging

Required Token Scopes: - repo: Full control of private repositories - read:org: Read org and team membership - read:user: Read user profile data

Performance Notes: - Org queries are ~3x faster than viewer queries - Large date ranges (>1 year) may timeout - Use pagination for repos with >100 commits - Response size correlates with date range and repo count

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
variablesYes
queryYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Core handler implementation for the 'user_activity_query' MCP tool. Executes GitHub GraphQL queries for user activity analysis across repositories, organizations, with pagination support, error handling, and performance optimizations.
    def user_activity_query(self, variables: dict[str, Any], query: str) -> Dict[str, Any]:
        """
        Performs a user activity query using GitHub's GraphQL API with support for organization-specific 
        and cross-organization queries.
    
        **Query Modes**:
        
        1. **Organization-Specific Activity** (fastest, most comprehensive):
           - Query organization repositories directly
           - Access all private repos in the org (with proper token scopes)
           - Get detailed commit history, PRs, and issues
           - Variables: {"orgName": "Pelle-Tech", "from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}
           - Variable types: `$orgName: String!`, `$from: GitTimestamp!`, `$to: GitTimestamp!`
        
        2. **Authenticated User Activity Across All Orgs** (slower, summary only):
           - Query viewer's contribution collection
           - Includes all orgs where user is a member
           - Summary counts only (no detailed commit messages)
           - Variables: {"from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}
           - Variable types: `$from: DateTime!`, `$to: DateTime!`
        
        3. **User Activity in Specific Organization** (most restrictive):
           - Query organization repos filtered by user
           - Requires combining org query with author filtering
           - Variables: {"orgName": "Pelle-Tech", "username": "saidsef", "from": "2024-10-01T00:00:00Z", "to": "2024-10-31T23:59:59Z"}
           - Variable types: `$orgName: String!`, `$username: String!`, `$from: GitTimestamp!`, `$to: GitTimestamp!`
    
        **Performance Tips**:
        - Use pagination parameters to limit initial data: `first: 50` instead of `first: 100`
        - Query only required fields to reduce response size
        - Use org-specific queries when possible (faster than viewer queries)
        - For large date ranges, split into smaller queries
        - Cache results for repeated queries
    
        **Example Queries**:
    
        **Fast Org Query with Pagination**:
        ```graphql
        query($orgName: String!, $from: GitTimestamp!, $to: GitTimestamp!, $repoCount: Int = 50) {
          organization(login: $orgName) {
            login
            repositories(first: $repoCount, privacy: PRIVATE, orderBy: {field: PUSHED_AT, direction: DESC}) {
              pageInfo {
                hasNextPage
                endCursor
              }
              nodes {
                name
                isPrivate
                defaultBranchRef {
                  target {
                    ... on Commit {
                      history(since: $from, until: $to, first: 100) {
                        totalCount
                        pageInfo {
                          hasNextPage
                          endCursor
                        }
                        nodes {
                          author { 
                            user { login }
                            email
                          }
                          committedDate
                          message
                          additions
                          deletions
                        }
                      }
                    }
                  }
                }
                pullRequests(first: 50, states: [OPEN, CLOSED, MERGED], orderBy: {field: UPDATED_AT, direction: DESC}) {
                  totalCount
                  nodes {
                    number
                    title
                    author { login }
                    createdAt
                    state
                    additions
                    deletions
                  }
                }
              }
            }
          }
        }
        ```
    
        **User-Filtered Org Query**:
        ```graphql
        query($orgName: String!, $username: String!, $from: GitTimestamp!, $to: GitTimestamp!) {
          organization(login: $orgName) {
            login
            repositories(first: 100, privacy: PRIVATE) {
              nodes {
                name
                defaultBranchRef {
                  target {
                    ... on Commit {
                      history(since: $from, until: $to, author: {emails: [$username]}, first: 100) {
                        totalCount
                        nodes {
                          author { user { login } }
                          committedDate
                          message
                        }
                      }
                    }
                  }
                }
                pullRequests(first: 100, states: [OPEN, CLOSED, MERGED]) {
                  nodes {
                    author { login }
                    title
                    createdAt
                    state
                  }
                }
              }
            }
          }
        }
        ```
    
        **Cross-Org Viewer Query**:
        ```graphql
        query($from: DateTime!, $to: DateTime!) {
          viewer {
            login
            contributionsCollection(from: $from, to: $to) {
              commitContributionsByRepository(maxRepositories: 100) {
                repository { 
                  name 
                  isPrivate 
                  owner { login }
                }
                contributions { totalCount }
              }
              pullRequestContributionsByRepository(maxRepositories: 100) {
                repository { 
                  name 
                  isPrivate 
                  owner { login }
                }
                contributions { totalCount }
              }
              issueContributionsByRepository(maxRepositories: 100) {
                repository { 
                  name 
                  isPrivate 
                  owner { login }
                }
                contributions { totalCount }
              }
            }
            organizations(first: 100) {
              nodes { 
                login 
                viewerCanAdminister
              }
            }
          }
        }
        ```
    
        Args:
            variables (dict[str, Any]): Query variables. Supported combinations:
                - Org-specific: {"orgName": "Pelle-Tech", "from": "...", "to": "..."}
                - Cross-org: {"from": "...", "to": "..."}
                - User-filtered org: {"orgName": "Pelle-Tech", "username": "saidsef", "from": "...", "to": "..."}
                - With pagination: Add {"repoCount": 50, "prCount": 50} for custom limits
            query (str): GraphQL query string. Must declare correct variable types:
                - Organization queries: Use `GitTimestamp!` for $from/$to
                - Viewer queries: Use `DateTime!` for $from/$to
                - Both types accept ISO 8601 format: "YYYY-MM-DDTHH:MM:SSZ"
    
        Returns:
            Dict[str, Any]: GraphQL response with activity data or error information.
                - Success: {"data": {...}}
                - Errors: {"errors": [...], "data": null}
                - Network error: {"status": "error", "message": "..."}
    
        Error Handling:
            - Validates response status codes
            - Logs GraphQL errors with details
            - Returns structured error responses
            - Includes traceback for debugging
    
        Required Token Scopes:
            - `repo`: Full control of private repositories
            - `read:org`: Read org and team membership
            - `read:user`: Read user profile data
    
        Performance Notes:
            - Org queries are ~3x faster than viewer queries
            - Large date ranges (>1 year) may timeout
            - Use pagination for repos with >100 commits
            - Response size correlates with date range and repo count
        """
        # Validate inputs
        if not query or not isinstance(query, str):
            return {"status": "error", "message": "Query must be a non-empty string"}
        
        if not variables or not isinstance(variables, dict):
            return {"status": "error", "message": "Variables must be a non-empty dictionary"}
        
        # Determine query type for optimized logging
        query_type = "unknown"
        if "orgName" in variables and "username" in variables:
            query_type = "user-filtered-org"
        elif "orgName" in variables:
            query_type = "org-specific"
        elif "from" in variables and "to" in variables:
            query_type = "cross-org-viewer"
        
        logging.info(f"Performing GraphQL query [type: {query_type}] with variables: {variables}")
    
        try:
            # Make GraphQL request with optimized timeout
            response = requests.post(
                'https://api.github.com/graphql',
                json={'query': query, 'variables': variables},
                headers=self._get_headers(),
                timeout=TIMEOUT * 2  # Double timeout for GraphQL queries (can be complex)
            )
            response.raise_for_status()
            query_data = response.json()
    
            # Handle GraphQL errors (API accepts request but query has issues)
            if 'errors' in query_data:
                error_messages = [err.get('message', 'Unknown error') for err in query_data['errors']]
                logging.error(f"GraphQL query errors: {error_messages}")
                
                # Check for common errors and provide helpful messages
                for error in query_data['errors']:
                    error_type = error.get('extensions', {}).get('code')
                    if error_type == 'variableMismatch':
                        logging.error(f"Variable type mismatch: Use GitTimestamp for org queries, DateTime for viewer queries")
                    elif error_type == 'NOT_FOUND':
                        logging.error(f"Resource not found: Check org/user name is correct and case-sensitive")
                    elif error_type == 'FORBIDDEN':
                        logging.error(f"Access forbidden: Check token has required scopes (repo, read:org)")
                
                return query_data  # Return with errors for caller to handle
            
            # Log success with summary
            if 'data' in query_data:
                data_keys = list(query_data['data'].keys())
                logging.info(f"GraphQL query successful [type: {query_type}], returned data keys: {data_keys}")
            
            return query_data
    
        except requests.exceptions.Timeout:
            error_msg = f"GraphQL query timeout after {TIMEOUT * 2}s. Try reducing date range or repo count."
            logging.error(error_msg)
            return {"status": "error", "message": error_msg, "timeout": True}
        
        except requests.exceptions.RequestException as req_err:
            error_msg = f"Request error during GraphQL query: {str(req_err)}"
            logging.error(error_msg)
            traceback.print_exc()
            return {"status": "error", "message": error_msg, "request_exception": True}
        
        except Exception as e:
            error_msg = f"Unexpected error performing GraphQL query: {str(e)}"
            logging.error(error_msg)
            traceback.print_exc()
            return {"status": "error", "message": error_msg, "unexpected": True}
  • Dynamic registration of all public methods from GitHubIntegration instance (including 'user_activity_query') as MCP tools via FastMCP.add_tool()
    def register_tools(self, methods: Any = None) -> None:
        for name, method in inspect.getmembers(methods):
            if (inspect.isfunction(method) or inspect.ismethod(method)) and not name.startswith("_"):
                self.mcp.add_tool(method)
  • Calls register_tools on GitHubIntegration instance to register 'user_activity_query' and other tools.
    def _register_tools(self):
        self.register_tools(self.gi)
        self.register_tools(self.ip)
  • Higher-level helper method 'get_user_org_activity' that internally uses 'user_activity_query' to fetch comprehensive, paginated user activity across all repositories in an organization.
    def get_user_org_activity(
        self, 
        org_name: str, 
        username: str, 
        from_date: str, 
        to_date: str,
        page: int = 1,
        per_page: int = 50
    ) -> Dict[str, Any]:
        """
        Gets comprehensive activity for a SPECIFIC USER across ALL repositories in an organization.
        
        **PAGINATED RESULTS** - Returns a manageable subset of data to prevent context overflow.
        
        Efficiently filters by user at the GraphQL level - does NOT scan entire repos.
        Captures ALL branches, not just main/default branch.
        
        Includes:
        - Commits by the user (paginated)
        - PRs where user was: author, reviewer, merger, commenter, or assigned (paginated)
        - Issues where user was: author, assigned, commenter, or participant (paginated)
        - Handles reviewed, open, merged, closed, and approved PRs
        
        Args:
            org_name (str): GitHub organization name
            username (str): GitHub username to query
            from_date (str): Start date ISO 8601 (e.g., "2024-01-01T00:00:00Z")
            to_date (str): End date ISO 8601 (e.g., "2024-12-31T23:59:59Z")
            page (int): Page number (1-indexed, default: 1)
            per_page (int): Items per page (default: 50, max: 100)
        
        Returns:
            Dict containing: 
            - status: success/error
            - summary: aggregate statistics
            - commits[]: paginated commits (most recent first)
            - prs[]: paginated PRs (most recent first)
            - issues[]: paginated issues (most recent first)
            - pagination: current_page, per_page, total_items, total_pages, has_next_page
        """
        logging.info(f"Fetching ALL activity for '{username}' in '{org_name}' from {from_date} to {to_date}")
        
        # Step 1: Get user's email addresses for efficient commit filtering
        user_emails = self._get_user_emails(username)
        logging.info(f"Found {len(user_emails)} email(s) for filtering commits")
        
        # Step 2: Get repositories where user actually contributed (optimized approach)
        # First try to get repos from user's contribution collection
        contributed_repos = self._get_user_contributed_repos(username, org_name, from_date, to_date)
        
        if contributed_repos:
            logging.info(f"Found {len(contributed_repos)} repos with user contributions via contributionsCollection")
            org_repos = contributed_repos
        else:
            # Fallback: Get ALL repositories in organization
            logging.info(f"Fallback: Scanning all org repos (contributionsCollection returned no results)")
            org_repos = self._get_all_org_repos(org_name)
            logging.info(f"Found {len(org_repos)} total repositories in {org_name}")
        
        if not org_repos:
            return self._empty_activity_response(username, org_name, from_date, to_date, page, per_page)
        
        # Step 3: Process each repo - filter by user at GraphQL level
        all_commits = []
        all_prs = []
        all_issues = []
        repos_with_activity = 0
        
        for repo_info in org_repos:
            repo_name = repo_info.get("name")
            repo_url = repo_info.get("url")
            
            logging.info(f"Scanning {org_name}/{repo_name} for {username}")
            
            # Fetch user-specific data from this repo
            repo_activity = self._fetch_repo_user_activity(
                org_name, repo_name, repo_url, username, user_emails, from_date, to_date
            )
            
            if repo_activity:
                all_commits.extend(repo_activity.get("commits", []))
                all_prs.extend(repo_activity.get("prs", []))
                all_issues.extend(repo_activity.get("issues", []))
                
                if repo_activity.get("has_activity"):
                    repos_with_activity += 1
        
        # Sort by date (most recent first)
        all_commits.sort(key=lambda x: x["date"], reverse=True)
        all_prs.sort(key=lambda x: x["updated_at"], reverse=True)
        all_issues.sort(key=lambda x: x["updated_at"], reverse=True)
        
        # Calculate pagination
        per_page = min(max(1, per_page), 100)  # Clamp between 1-100
        page = max(1, page)  # Must be at least 1
        
        total_commits = len(all_commits)
        total_prs = len(all_prs)
        total_issues = len(all_issues)
        
        # Calculate pages
        commits_total_pages = (total_commits + per_page - 1) // per_page if total_commits > 0 else 1
        prs_total_pages = (total_prs + per_page - 1) // per_page if total_prs > 0 else 1
        issues_total_pages = (total_issues + per_page - 1) // per_page if total_issues > 0 else 1
        
        # Slice data for current page
        start_idx = (page - 1) * per_page
        end_idx = start_idx + per_page
        
        paginated_commits = all_commits[start_idx:end_idx]
        paginated_prs = all_prs[start_idx:end_idx]
        paginated_issues = all_issues[start_idx:end_idx]
        
        # Generate summary (based on ALL data, not just current page)
        user_authored_prs = [pr for pr in all_prs if "Author" in pr["user_roles"]]
        
        summary = {
            "user": username,
            "organization": org_name,
            "date_range": f"{from_date} to {to_date}",
            "total_commits": total_commits,
            "total_prs_involved": total_prs,
            "prs_authored": len(user_authored_prs),
            "prs_reviewed": len([pr for pr in all_prs if any(r in pr["user_roles"] for r in ["Approved", "Requested Changes", "Reviewed"])]),
            "prs_merged": len([pr for pr in all_prs if "Merged" in pr["user_roles"]]),
            "prs_commented": len([pr for pr in all_prs if "Commented" in pr["user_roles"]]),
            "total_issues_involved": len(all_issues),
            "issues_authored": len([issue for issue in all_issues if "Author" in issue["user_roles"]]),
            "issues_assigned": len([issue for issue in all_issues if "Assigned" in issue["user_roles"]]),
            "issues_commented": len([issue for issue in all_issues if "Commented" in issue["user_roles"]]),
            "total_additions": sum(c["additions"] for c in all_commits),
            "total_deletions": sum(c["deletions"] for c in all_commits),
        }
        
        logging.info(f"Activity complete: Page {page}/{max(commits_total_pages, prs_total_pages, issues_total_pages)} - Returning {len(paginated_commits)} commits, {len(paginated_prs)} PRs, {len(paginated_issues)} issues from {repos_with_activity}/{len(org_repos)} repos")
        
        return {
            "status": "success",
            "summary": summary,
            "commits": paginated_commits,
            "prs": paginated_prs,
            "issues": paginated_issues,
            "pagination": {
                "current_page": page,
                "per_page": per_page,
                "commits": {
                    "total": total_commits,
                    "total_pages": commits_total_pages,
                    "has_next_page": page < commits_total_pages,
                    "returned": len(paginated_commits)
                },
                "prs": {
                    "total": total_prs,
                    "total_pages": prs_total_pages,
                    "has_next_page": page < prs_total_pages,
                    "returned": len(paginated_prs)
                },
                "issues": {
                    "total": total_issues,
                    "total_pages": issues_total_pages,
                    "has_next_page": page < issues_total_pages,
                    "returned": len(paginated_issues)
                },
                "repos": {
                    "total_in_org": len(org_repos),
                    "with_user_activity": repos_with_activity
                }
            }
        }
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes key traits: performance characteristics (e.g., 'Org queries are ~3x faster than viewer queries'), error handling (returns structured errors), required token scopes, and limitations like timeouts for large date ranges. It doesn't contradict any annotations, but could be more explicit about side effects or rate limits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with sections like Query Modes, Performance Tips, and Example Queries, but it is overly verbose with full GraphQL examples that could be summarized. While informative, the length may hinder quick comprehension, and some details (e.g., exact query strings) could be streamlined without losing value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (multiple query modes, GraphQL API), no annotations, and an output schema, the description is highly complete. It covers purpose, usage, parameters, performance, error handling, token requirements, and examples, leaving few gaps. The output schema handles return values, so the description appropriately focuses on input and behavior.

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 schema has 0% description coverage, so the description must fully compensate. It provides extensive parameter semantics: it explains the 'variables' dict with supported combinations and examples, details the 'query' string requirements including variable types and formats, and includes multiple GraphQL examples. This adds significant meaning beyond the bare schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool 'Performs a user activity query using GitHub's GraphQL API' with specific resource (GitHub user activity) and verb (query). It distinguishes itself from siblings like 'get_user_org_activity' by detailing three distinct query modes for different scopes (organization-specific, cross-organization, user-filtered), making the purpose highly specific and differentiated.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance on when to use each query mode, including performance trade-offs (e.g., 'fastest, most comprehensive' vs. 'slower, summary only'), prerequisites like token scopes, and alternatives for different scenarios. It also advises on pagination and date range splitting, offering comprehensive usage context.

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/saidsef/mcp-github-pr-issue-analyser'

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