@@ -26,8 +26,17 @@ import (
2626 "github.com/shurcooL/githubv4"
2727)
2828
29+ type GetCommitInput struct {
30+ Owner string `json:"owner"`
31+ Repo string `json:"repo"`
32+ SHA string `json:"sha"`
33+ Detail string `json:"detail,omitempty"`
34+ Page * int `json:"page,omitempty"`
35+ PerPage * int `json:"perPage,omitempty"`
36+ }
37+
2938func GetCommit (t translations.TranslationHelperFunc ) inventory.ServerTool {
30- return NewTool (
39+ return NewTool [ GetCommitInput , MinimalCommit ] (
3140 ToolsetMetadataRepos ,
3241 mcp.Tool {
3342 Name : "get_commit" ,
@@ -62,30 +71,26 @@ func GetCommit(t translations.TranslationHelperFunc) inventory.ServerTool {
6271 }),
6372 },
6473 scopes .PublicRead (scopes .Repo ),
65- func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , args map [string ]any ) (* mcp.CallToolResult , any , error ) {
66- owner , err := RequiredParam [string ](args , "owner" )
67- if err != nil {
68- return utils .NewToolResultError (err .Error ()), nil , nil
74+ func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , input GetCommitInput ) (* mcp.CallToolResult , MinimalCommit , error ) {
75+ if input .Owner == "" {
76+ return utils .NewToolResultError ("missing required parameter: owner" ), MinimalCommit {}, nil
6977 }
70- repo , err := RequiredParam [string ](args , "repo" )
71- if err != nil {
72- return utils .NewToolResultError (err .Error ()), nil , nil
78+ if input .Repo == "" {
79+ return utils .NewToolResultError ("missing required parameter: repo" ), MinimalCommit {}, nil
7380 }
74- sha , err := RequiredParam [string ](args , "sha" )
75- if err != nil {
76- return utils .NewToolResultError (err .Error ()), nil , nil
81+ if input .SHA == "" {
82+ return utils .NewToolResultError ("missing required parameter: sha" ), MinimalCommit {}, nil
7783 }
78- detailRaw , err := OptionalParam [ string ]( args , "detail" )
84+ detail , err := parseCommitDetail ( input . Detail )
7985 if err != nil {
80- return utils .NewToolResultError (err .Error ()), nil , nil
86+ return utils .NewToolResultError (err .Error ()), MinimalCommit {} , nil
8187 }
82- detail , err := parseCommitDetail ( detailRaw )
83- if err != nil {
84- return utils . NewToolResultError ( err . Error ()), nil , nil
88+ pagination := PaginationParams { Page : 1 , PerPage : 30 }
89+ if input . Page != nil {
90+ pagination . Page = * input . Page
8591 }
86- pagination , err := OptionalPaginationParams (args )
87- if err != nil {
88- return utils .NewToolResultError (err .Error ()), nil , nil
92+ if input .PerPage != nil {
93+ pagination .PerPage = * input .PerPage
8994 }
9095
9196 opts := & github.ListOptions {
@@ -95,47 +100,61 @@ func GetCommit(t translations.TranslationHelperFunc) inventory.ServerTool {
95100
96101 client , err := deps .GetClient (ctx )
97102 if err != nil {
98- return nil , nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
103+ return nil , MinimalCommit {} , fmt .Errorf ("failed to get GitHub client: %w" , err )
99104 }
100- commit , resp , err := client .Repositories .GetCommit (ctx , owner , repo , sha , opts )
105+ commit , resp , err := client .Repositories .GetCommit (ctx , input . Owner , input . Repo , input . SHA , opts )
101106 if err != nil {
102107 return ghErrors .NewGitHubAPIErrorResponse (ctx ,
103- fmt .Sprintf ("failed to get commit: %s" , sha ),
108+ fmt .Sprintf ("failed to get commit: %s" , input . SHA ),
104109 resp ,
105110 err ,
106- ), nil , nil
111+ ), MinimalCommit {} , nil
107112 }
108113 defer func () { _ = resp .Body .Close () }()
109114
110115 if resp .StatusCode != 200 {
111116 body , err := io .ReadAll (resp .Body )
112117 if err != nil {
113- return nil , nil , fmt .Errorf ("failed to read response body: %w" , err )
118+ return nil , MinimalCommit {} , fmt .Errorf ("failed to read response body: %w" , err )
114119 }
115- return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get commit" , resp , body ), nil , nil
120+ return ghErrors .NewGitHubAPIStatusErrorResponse (ctx , "failed to get commit" , resp , body ), MinimalCommit {} , nil
116121 }
117122
118123 // Convert to minimal commit
119124 minimalCommit := convertToMinimalCommit (commit , detail )
120125
121126 r , err := json .Marshal (minimalCommit )
122127 if err != nil {
123- return nil , nil , fmt .Errorf ("failed to marshal response: %w" , err )
128+ return nil , MinimalCommit {} , fmt .Errorf ("failed to marshal response: %w" , err )
124129 }
125130
126131 result := utils .NewToolResultText (string (r ))
127132 // Commit content is reachable from the repo's history; in public
128133 // repos anyone can land it via a PR (untrusted), in private repos
129134 // only collaborators can (trusted). Confidentiality follows repo
130135 // visibility.
131- result = attachRepoVisibilityIFCLabel (ctx , deps , client , owner , repo , result , ifc .LabelCommitContents )
132- return result , nil , nil
136+ result = attachRepoVisibilityIFCLabel (ctx , deps , client , input . Owner , input . Repo , result , ifc .LabelCommitContents )
137+ return result , minimalCommit , nil
133138 },
139+ normalizeTypedReadArgumentsPreservingZero (nil ),
134140 )
135141}
136142
137143// ListCommits creates a tool to get the list of commits of a branch in a GitHub
138144// repository.
145+ type ListCommitsInput struct {
146+ Owner string `json:"owner"`
147+ Repo string `json:"repo"`
148+ SHA string `json:"sha,omitempty"`
149+ Author string `json:"author,omitempty"`
150+ Path string `json:"path,omitempty"`
151+ Since string `json:"since,omitempty"`
152+ Until string `json:"until,omitempty"`
153+ Fields []string `json:"fields,omitempty"`
154+ Page * int `json:"page,omitempty"`
155+ PerPage * int `json:"perPage,omitempty"`
156+ }
157+
139158func ListCommits (t translations.TranslationHelperFunc ) inventory.ServerTool {
140159 schema := & jsonschema.Schema {
141160 Type : "object" ,
@@ -177,7 +196,7 @@ func ListCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
177196 )
178197 WithPagination (schema )
179198
180- return NewTool (
199+ return NewTool [ ListCommitsInput , [] MinimalCommit ] (
181200 ToolsetMetadataRepos ,
182201 mcp.Tool {
183202 Name : "list_commits" ,
@@ -189,66 +208,43 @@ func ListCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
189208 InputSchema : schema ,
190209 },
191210 scopes .PublicRead (scopes .Repo ),
192- func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , args map [string ]any ) (* mcp.CallToolResult , any , error ) {
193- owner , err := RequiredParam [string ](args , "owner" )
194- if err != nil {
195- return utils .NewToolResultError (err .Error ()), nil , nil
196- }
197- repo , err := RequiredParam [string ](args , "repo" )
198- if err != nil {
199- return utils .NewToolResultError (err .Error ()), nil , nil
200- }
201- sha , err := OptionalParam [string ](args , "sha" )
202- if err != nil {
203- return utils .NewToolResultError (err .Error ()), nil , nil
204- }
205- author , err := OptionalParam [string ](args , "author" )
206- if err != nil {
207- return utils .NewToolResultError (err .Error ()), nil , nil
208- }
209- path , err := OptionalParam [string ](args , "path" )
210- if err != nil {
211- return utils .NewToolResultError (err .Error ()), nil , nil
212- }
213- fields , err := OptionalStringArrayParam (args , "fields" )
214- if err != nil {
215- return utils .NewToolResultError (err .Error ()), nil , nil
211+ func (ctx context.Context , deps ToolDependencies , _ * mcp.CallToolRequest , input ListCommitsInput ) (* mcp.CallToolResult , []MinimalCommit , error ) {
212+ if input .Owner == "" {
213+ return utils .NewToolResultError ("missing required parameter: owner" ), nil , nil
216214 }
217- sinceStr , err := OptionalParam [string ](args , "since" )
218- if err != nil {
219- return utils .NewToolResultError (err .Error ()), nil , nil
215+ if input .Repo == "" {
216+ return utils .NewToolResultError ("missing required parameter: repo" ), nil , nil
220217 }
221- untilStr , err := OptionalParam [ string ]( args , "until" )
222- if err != nil {
223- return utils . NewToolResultError ( err . Error ()), nil , nil
218+ pagination := PaginationParams { Page : 1 , PerPage : 30 }
219+ if input . Page != nil {
220+ pagination . Page = * input . Page
224221 }
225- pagination , err := OptionalPaginationParams (args )
226- if err != nil {
227- return utils .NewToolResultError (err .Error ()), nil , nil
222+ if input .PerPage != nil {
223+ pagination .PerPage = * input .PerPage
228224 }
229225 // Set default perPage to 30 if not provided
230226 perPage := pagination .PerPage
231227 if perPage == 0 {
232228 perPage = 30
233229 }
234230 opts := & github.CommitsListOptions {
235- SHA : sha ,
236- Path : path ,
237- Author : author ,
231+ SHA : input . SHA ,
232+ Path : input . Path ,
233+ Author : input . Author ,
238234 ListOptions : github.ListOptions {
239235 Page : pagination .Page ,
240236 PerPage : perPage ,
241237 },
242238 }
243- if sinceStr != "" {
244- sinceTime , err := parseISOTimestamp (sinceStr )
239+ if input . Since != "" {
240+ sinceTime , err := parseISOTimestamp (input . Since )
245241 if err != nil {
246242 return utils .NewToolResultError (fmt .Sprintf ("invalid since timestamp: %s" , err )), nil , nil
247243 }
248244 opts .Since = sinceTime
249245 }
250- if untilStr != "" {
251- untilTime , err := parseISOTimestamp (untilStr )
246+ if input . Until != "" {
247+ untilTime , err := parseISOTimestamp (input . Until )
252248 if err != nil {
253249 return utils .NewToolResultError (fmt .Sprintf ("invalid until timestamp: %s" , err )), nil , nil
254250 }
@@ -259,10 +255,10 @@ func ListCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
259255 if err != nil {
260256 return nil , nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
261257 }
262- commits , resp , err := client .Repositories .ListCommits (ctx , owner , repo , opts )
258+ commits , resp , err := client .Repositories .ListCommits (ctx , input . Owner , input . Repo , opts )
263259 if err != nil {
264260 return ghErrors .NewGitHubAPIErrorResponse (ctx ,
265- fmt .Sprintf ("failed to list commits: %s" , sha ),
261+ fmt .Sprintf ("failed to list commits: %s" , input . SHA ),
266262 resp ,
267263 err ,
268264 ), nil , nil
@@ -285,8 +281,8 @@ func ListCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
285281
286282 filtered := false
287283 var payload any = minimalCommits
288- if len (fields ) > 0 {
289- filteredCommits , err := filterEachField (minimalCommits , fields )
284+ if len (input . Fields ) > 0 {
285+ filteredCommits , err := filterEachField (minimalCommits , input . Fields )
290286 if err != nil {
291287 return utils .NewToolResultErrorFromErr ("failed to filter commits" , err ), nil , nil
292288 }
@@ -305,9 +301,13 @@ func ListCommits(t translations.TranslationHelperFunc) inventory.ServerTool {
305301 // Commit content is reachable from the repo's history; integrity
306302 // follows the same public-untrusted / private-trusted rule as file
307303 // contents. Confidentiality follows repo visibility.
308- result = attachRepoVisibilityIFCLabel (ctx , deps , client , owner , repo , result , ifc .LabelCommitContents )
309- return result , nil , nil
304+ result = attachRepoVisibilityIFCLabel (ctx , deps , client , input .Owner , input .Repo , result , ifc .LabelCommitContents )
305+ if len (input .Fields ) > 0 {
306+ return result , nil , nil
307+ }
308+ return result , minimalCommits , nil
310309 },
310+ normalizeTypedReadArgumentsPreservingZero (nil ),
311311 )
312312}
313313
0 commit comments