@@ -21,6 +21,7 @@ import {
21
21
ForkRepositorySchema ,
22
22
GetFileContentsSchema ,
23
23
GetIssueSchema ,
24
+ GetPullRequestSchema ,
24
25
GitHubCommitSchema ,
25
26
GitHubContentSchema ,
26
27
GitHubCreateUpdateFileResponseSchema ,
@@ -36,6 +37,8 @@ import {
36
37
IssueCommentSchema ,
37
38
ListCommitsSchema ,
38
39
ListIssuesOptionsSchema ,
40
+ ListPullRequestsSchema ,
41
+ CreatePullRequestReviewSchema ,
39
42
PushFilesSchema ,
40
43
SearchCodeResponseSchema ,
41
44
SearchCodeSchema ,
@@ -715,6 +718,86 @@ async function getIssue(
715
718
return GitHubIssueSchema . parse ( await response . json ( ) ) ;
716
719
}
717
720
721
+ async function getPullRequest (
722
+ owner : string ,
723
+ repo : string ,
724
+ pullNumber : number
725
+ ) : Promise < GitHubPullRequest > {
726
+ const response = await fetch (
727
+ `https://api.github.com/repos/${ owner } /${ repo } /pulls/${ pullNumber } ` ,
728
+ {
729
+ headers : {
730
+ Authorization : `token ${ GITHUB_PERSONAL_ACCESS_TOKEN } ` ,
731
+ Accept : "application/vnd.github.v3+json" ,
732
+ "User-Agent" : "github-mcp-server" ,
733
+ } ,
734
+ }
735
+ ) ;
736
+
737
+ if ( ! response . ok ) {
738
+ throw new Error ( `GitHub API error: ${ response . statusText } ` ) ;
739
+ }
740
+
741
+ return GitHubPullRequestSchema . parse ( await response . json ( ) ) ;
742
+ }
743
+
744
+ async function listPullRequests (
745
+ owner : string ,
746
+ repo : string ,
747
+ options : Omit < z . infer < typeof ListPullRequestsSchema > , 'owner' | 'repo' >
748
+ ) : Promise < GitHubPullRequest [ ] > {
749
+ const url = new URL ( `https://api.github.com/repos/${ owner } /${ repo } /pulls` ) ;
750
+
751
+ if ( options . state ) url . searchParams . append ( 'state' , options . state ) ;
752
+ if ( options . head ) url . searchParams . append ( 'head' , options . head ) ;
753
+ if ( options . base ) url . searchParams . append ( 'base' , options . base ) ;
754
+ if ( options . sort ) url . searchParams . append ( 'sort' , options . sort ) ;
755
+ if ( options . direction ) url . searchParams . append ( 'direction' , options . direction ) ;
756
+ if ( options . per_page ) url . searchParams . append ( 'per_page' , options . per_page . toString ( ) ) ;
757
+ if ( options . page ) url . searchParams . append ( 'page' , options . page . toString ( ) ) ;
758
+
759
+ const response = await fetch ( url . toString ( ) , {
760
+ headers : {
761
+ Authorization : `token ${ GITHUB_PERSONAL_ACCESS_TOKEN } ` ,
762
+ Accept : "application/vnd.github.v3+json" ,
763
+ "User-Agent" : "github-mcp-server" ,
764
+ } ,
765
+ } ) ;
766
+
767
+ if ( ! response . ok ) {
768
+ throw new Error ( `GitHub API error: ${ response . statusText } ` ) ;
769
+ }
770
+
771
+ return z . array ( GitHubPullRequestSchema ) . parse ( await response . json ( ) ) ;
772
+ }
773
+
774
+ async function createPullRequestReview (
775
+ owner : string ,
776
+ repo : string ,
777
+ pullNumber : number ,
778
+ options : Omit < z . infer < typeof CreatePullRequestReviewSchema > , 'owner ' | 'repo ' | 'pull_number '>
779
+ ) : Promise < any > {
780
+ const response = await fetch (
781
+ `https://api.github.com/repos/${ owner } /${ repo } /pulls/${ pullNumber } /reviews` ,
782
+ {
783
+ method : 'POST' ,
784
+ headers : {
785
+ Authorization : `token ${ GITHUB_PERSONAL_ACCESS_TOKEN } ` ,
786
+ Accept : "application/vnd.github.v3+json" ,
787
+ "User-Agent" : "github-mcp-server" ,
788
+ "Content-Type" : "application/json" ,
789
+ } ,
790
+ body : JSON . stringify ( options ) ,
791
+ }
792
+ ) ;
793
+
794
+ if ( ! response . ok ) {
795
+ throw new Error ( `GitHub API error: ${ response . statusText } ` ) ;
796
+ }
797
+
798
+ return await response . json ( ) ;
799
+ }
800
+
718
801
server . setRequestHandler ( ListToolsRequestSchema , async ( ) => {
719
802
return {
720
803
tools : [
@@ -806,6 +889,21 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
806
889
name : "get_issue" ,
807
890
description : "Get details of a specific issue in a GitHub repository." ,
808
891
inputSchema : zodToJsonSchema ( GetIssueSchema )
892
+ } ,
893
+ {
894
+ name : "get_pull_request" ,
895
+ description : "Get details of a specific pull request in a GitHub repository" ,
896
+ inputSchema : zodToJsonSchema ( GetPullRequestSchema )
897
+ } ,
898
+ {
899
+ name : "list_pull_requests" ,
900
+ description : "List pull requests in a GitHub repository with filtering options" ,
901
+ inputSchema : zodToJsonSchema ( ListPullRequestsSchema )
902
+ } ,
903
+ {
904
+ name : "create_pull_request_review" ,
905
+ description : "Create a review on a pull request" ,
906
+ inputSchema : zodToJsonSchema ( CreatePullRequestReviewSchema )
809
907
}
810
908
] ,
811
909
} ;
@@ -1011,6 +1109,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
1011
1109
return { toolResult : issue } ;
1012
1110
}
1013
1111
1112
+ case "get_pull_request" : {
1113
+ const args = GetPullRequestSchema . parse ( request . params . arguments ) ;
1114
+ const pullRequest = await getPullRequest ( args . owner , args . repo , args . pull_number ) ;
1115
+ return { toolResult : pullRequest } ;
1116
+ }
1117
+
1118
+ case "list_pull_requests" : {
1119
+ const args = ListPullRequestsSchema . parse ( request . params . arguments ) ;
1120
+ const { owner, repo, ...options } = args ;
1121
+ const pullRequests = await listPullRequests ( owner , repo , options ) ;
1122
+ return { toolResult : pullRequests } ;
1123
+ }
1124
+
1125
+ case "create_pull_request_review" : {
1126
+ const args = CreatePullRequestReviewSchema . parse ( request . params . arguments ) ;
1127
+ const { owner, repo, pull_number, ...options } = args ;
1128
+ const review = await createPullRequestReview ( owner , repo , pull_number , options ) ;
1129
+ return { toolResult : review } ;
1130
+ }
1131
+
1014
1132
default :
1015
1133
throw new Error ( `Unknown tool: ${ request . params . name } ` ) ;
1016
1134
}
0 commit comments