Skip to main content
Glama

githubSearchPullRequests

Search GitHub pull requests by keywords, state, or author to identify relevant PRs. Fetch head/base branch SHAs for detailed commit analysis or retrieve all PR commits with file changes for deeper insights.

Instructions

Search GitHub PRs by keywords, state, or author. Returns head/base SHAs for github_fetch_content (branch=SHA). Can fetch all PR commits with changes using getCommitData=true.

SEARCH STRATEGY FOR BEST RESULTS:

  • Use minimal search terms for broader coverage (2-3 words max)

  • Separate searches for different aspects vs complex queries

  • Use filters to narrow scope after getting initial results

  • Use getCommitData=true to get all commits in PR with file changes

  • Use github_search_commits with head_sha/base_sha from results to get code changes

COMMIT DATA FETCHING (getCommitData=true):

  • Fetches all commits in the PR using 'gh pr view --json commits'

  • For each commit, fetches detailed changes using GitHub API

  • Shows commit SHA, message, author, and file changes

  • Includes up to 10 commits per PR with detailed diffs

  • Each commit shows changed files with additions/deletions/patches

  • Example: Shows individual commits like "Fix bug in component" with specific file changes

EXAMPLE OUTPUT WITH getCommitData=true: { "commits": { "total_count": 3, "commits": [ { "sha": "abc123", "message": "Fix bug in component", "author": "username", "diff": { "changed_files": 2, "additions": 15, "deletions": 3, "files": [...] } } ] } }

NOTE: The head_sha and base_sha fields in the PR results can be used as the 'hash' parameter in github_search_commits to look up the exact commit and get actual code changes.

TOKEN OPTIMIZATION:

  • getCommitData=true is expensive in tokens. Use only when necessary.

  • Consider using github_search_commits with head_sha/base_sha instead for specific commits

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
appNoFilter by GitHub App author
archivedNoFilter by repository archived state
assigneeNoGitHub username of assignee
authorNoGitHub username of PR author
baseNoFilter on base branch name
checksNoFilter by checks status
closedNoFilter by closed date (e.g., >2020-01-01)
commenterNoUser who commented on PR
commentsNoInclude comment content in search results. This is a very expensive operation in tokens and should be used with caution.
createdNoFilter by created date (e.g., >2020-01-01)
draftNoFilter by draft state
getCommitDataNoSet to true to fetch all commits in the PR with their changes. Shows commit messages, authors, and file changes. WARNING: EXTREMELY expensive in tokens - fetches diff/patch content for each commit.
headNoFilter on head branch name
interactionsNoTotal interactions (reactions + comments)
involvesNoUser involved in any way
labelNoFilter by label
languageNoRepository language
limitNoMaximum number of results to fetch
lockedNoFilter by locked conversation status
matchNoRestrict search to specific fields
mentionsNoPRs mentioning this user
mergedNoFilter by merged state
merged-atNoFilter by merged date (e.g., >2020-01-01)
milestoneNoMilestone title
no-assigneeNoFilter by missing assignee
no-labelNoFilter by missing label
no-milestoneNoFilter by missing milestone
no-projectNoFilter by missing project
orderNoOrder of results (requires --sort)desc
ownerNoRepository owner (use with repo param)
projectNoProject board owner/number
queryYesSearch query for PR content (keep minimal for broader results)
reactionsNoFilter by number of reactions
repoNoRepository name (use with owner param)
reviewNoFilter by review status
review-requestedNoUser/team requested for review
reviewed-byNoUser who reviewed the PR
sortNoSort fetched results
stateNoFilter by state: open or closed
team-mentionsNoFilter by team mentions
updatedNoFilter by updated date (e.g., >2020-01-01)
visibilityNoRepository visibility

Implementation Reference

  • Zod schema for input validation of github_search_pull_requests tool, defining parameters like query, owner, repo, filters (state, assignee, etc.), sorting, limits, and output shaping options.
    export const GitHubPullRequestSearchBulkQuerySchema = createBulkQuerySchema( TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, GitHubPullRequestSearchQuerySchema );
  • Registers the 'github_search_pull_requests' tool with the MCP server, specifying schema, annotations, and security-wrapped handler function.
    export function registerSearchGitHubPullRequestsTool( server: McpServer, callback?: ToolInvocationCallback ) { return server.registerTool( TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, { description: DESCRIPTIONS[TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS], inputSchema: GitHubPullRequestSearchBulkQuerySchema, annotations: { title: 'GitHub Pull Request Search', readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true, }, }, withSecurityValidation( TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, async ( args: { queries: GitHubPullRequestSearchQuery[]; }, authInfo, sessionId ): Promise<CallToolResult> => { let queries = args.queries || []; if (callback) { try { await callback(TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, queries); } catch { // ignore } } const longQueryIndex = queries.findIndex(hasQueryLengthError); if (longQueryIndex !== -1) { queries = queries.map((q, i) => i === longQueryIndex ? addValidationError(q, VALIDATION_MESSAGES.QUERY_TOO_LONG) : q ); } if (queries.length > 0 && !queries.some(hasValidSearchParams)) { queries = queries.map((q, i) => i === 0 ? addValidationError(q, VALIDATION_MESSAGES.MISSING_PARAMS) : q ); } return searchMultipleGitHubPullRequests(queries, authInfo, sessionId); } ) ); }
  • Bulk handler that processes multiple PR search queries, performs validation, calls the GitHub API, handles errors, and formats results.
    async function searchMultipleGitHubPullRequests( queries: GitHubPullRequestSearchQuery[], authInfo?: AuthInfo, sessionId?: string ): Promise<CallToolResult> { return executeBulkOperation( queries, async (query: GitHubPullRequestSearchQuery, _index: number) => { try { const validationError = (query as unknown as Record<string, unknown>) ?._validationError; if (validationError && typeof validationError === 'string') { return createErrorResult(query, validationError); } const apiResult = await searchGitHubPullRequestsAPI( query, authInfo, sessionId ); const apiError = handleApiError(apiResult, query); if (apiError) return apiError; const pullRequests = apiResult.pull_requests || []; return createSuccessResult( query, { pull_requests: pullRequests, total_count: apiResult.total_count || pullRequests.length, incomplete_results: apiResult.incomplete_results, }, pullRequests.length > 0, 'GITHUB_SEARCH_PULL_REQUESTS' ); } catch (error) { return handleCatchError(error, query); } }, { toolName: TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, keysPriority: [ 'pull_requests', 'total_count', 'incomplete_results', 'error', ] satisfies Array<keyof PullRequestSearchResult>, } ); }
  • Core implementation of GitHub Pull Request search using Octokit: supports search queries, repo-specific lists, single PR fetch; includes data transformation, caching, content sanitization, and optional file/comments/commits fetching.
    export async function searchGitHubPullRequestsAPI( params: GitHubPullRequestsSearchParams, authInfo?: AuthInfo, sessionId?: string ): Promise<PullRequestSearchResult> { const cacheKey = generateCacheKey('gh-api-prs', params, sessionId); const result = await withDataCache<PullRequestSearchResult>( cacheKey, async () => { return await searchGitHubPullRequestsAPIInternal( params, authInfo, sessionId ); }, { shouldCache: (value: PullRequestSearchResult) => !value.error, } ); return result; } async function searchGitHubPullRequestsAPIInternal( params: GitHubPullRequestsSearchParams, authInfo?: AuthInfo, _sessionId?: string ): Promise<PullRequestSearchResult> { try { if ( params.prNumber && params.owner && params.repo && !Array.isArray(params.owner) && !Array.isArray(params.repo) ) { return await fetchGitHubPullRequestByNumberAPIInternal(params, authInfo); } const octokit = await getOctokit(authInfo); const shouldUseSearch = shouldUseSearchForPRs(params); if ( !shouldUseSearch && params.owner && params.repo && !Array.isArray(params.owner) && !Array.isArray(params.repo) ) { // Use REST API for simple repository-specific searches (like gh pr list) return await searchPullRequestsWithREST(octokit, params); } const searchQuery = buildPullRequestSearchQuery(params); if (!searchQuery) { await logSessionError( TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, SEARCH_ERRORS.NO_VALID_PARAMETERS.code ); return { pull_requests: [], total_count: 0, error: SEARCH_ERRORS.NO_VALID_PARAMETERS.message, hints: ['Provide search query or filters like owner/repo'], }; } const sortValue = params.sort && params.sort !== 'best-match' && params.sort !== 'created' ? params.sort : undefined; const searchResult = await octokit.rest.search.issuesAndPullRequests({ q: searchQuery, sort: sortValue as | 'comments' | 'reactions' | 'created' | 'updated' | undefined, order: params.order || 'desc', per_page: Math.min(params.limit || 30, 100), }); const pullRequests = searchResult.data.items?.filter( (item: Record<string, unknown>) => item.pull_request ) || []; const transformedPRs: GitHubPullRequestItem[] = await Promise.all( pullRequests.map(async (item: Record<string, unknown>) => { return await transformPullRequestItem(item, params, octokit); }) ); const owner = Array.isArray(params.owner) ? params.owner[0] : params.owner || ''; const repo = Array.isArray(params.repo) ? params.repo[0] : params.repo || ''; const formattedPRs = transformedPRs.map(pr => ({ id: 0, // We don't have this in our format number: pr.number, title: pr.title, url: pr.url, html_url: pr.url, state: pr.state as 'open' | 'closed', draft: pr.draft ?? false, merged: pr.state === 'closed' && !!pr.merged_at, created_at: pr.created_at, updated_at: pr.updated_at, closed_at: pr.closed_at ?? undefined, merged_at: pr.merged_at, author: { login: pr.author, id: 0, avatar_url: '', html_url: `https://github.com/${pr.author}`, }, head: { ref: pr.head || '', sha: pr.head_sha || '', repo: owner && repo ? `${owner}/${repo}` : '', }, base: { ref: pr.base || '', sha: pr.base_sha || '', repo: owner && repo ? `${owner}/${repo}` : '', }, body: pr.body, comments: pr.comments?.length || 0, review_comments: 0, commits: pr.commits?.length || 0, additions: pr.file_changes?.files.reduce((sum, file) => sum + file.additions, 0) || 0, deletions: pr.file_changes?.files.reduce((sum, file) => sum + file.deletions, 0) || 0, changed_files: pr.file_changes?.total_count || 0, ...(pr.file_changes && { file_changes: pr.file_changes.files?.map(file => ({ filename: file.filename, status: file.status, additions: file.additions, deletions: file.deletions, patch: file.patch, })), }), ...(pr.commits && { commit_details: pr.commits, }), })); return { pull_requests: formattedPRs, total_count: searchResult.data.total_count, incomplete_results: searchResult.data.incomplete_results, }; } catch (error: unknown) { const apiError = handleGitHubAPIError(error); await logSessionError( TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, SEARCH_ERRORS.PULL_REQUEST_SEARCH_FAILED.code ); return { pull_requests: [], total_count: 0, error: SEARCH_ERRORS.PULL_REQUEST_SEARCH_FAILED.message(apiError.error), hints: [`Verify authentication and search parameters`], }; } }
  • Tool configuration entry that includes the registration function for github_search_pull_requests in the list of default tools.
    export const GITHUB_SEARCH_PULL_REQUESTS: ToolConfig = { name: TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS, description: getDescription(TOOL_NAMES.GITHUB_SEARCH_PULL_REQUESTS), isDefault: true, type: 'history', fn: registerSearchGitHubPullRequestsTool, };

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/bgauryy/octocode-mcp'

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