Skip to content

Commit c8c1243

Browse files
feat: wire up ListBranches and ListTags to use typed inputs
- ListBranches: ListBranchesInput - ListTags: ListTagsInput Updated tests and toolsnaps for both tools. Co-authored-by: SamMorrowDrums <[email protected]>
1 parent 0a76d95 commit c8c1243

File tree

4 files changed

+118
-202
lines changed

4 files changed

+118
-202
lines changed

pkg/github/__toolsnaps__/list_branches.snap

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,19 @@
1616
"description": "Repository owner"
1717
},
1818
"page": {
19-
"type": "number",
20-
"description": "Page number for pagination (min 1)",
21-
"minimum": 1
19+
"type": "integer",
20+
"description": "Page number for pagination (min 1)"
2221
},
2322
"perPage": {
24-
"type": "number",
25-
"description": "Results per page for pagination (min 1, max 100)",
26-
"minimum": 1,
27-
"maximum": 100
23+
"type": "integer",
24+
"description": "Results per page for pagination (min 1 and max 100)"
2825
},
2926
"repo": {
3027
"type": "string",
3128
"description": "Repository name"
3229
}
33-
}
30+
},
31+
"additionalProperties": false
3432
},
3533
"name": "list_branches"
3634
}

pkg/github/__toolsnaps__/list_tags.snap

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,19 @@
1616
"description": "Repository owner"
1717
},
1818
"page": {
19-
"type": "number",
20-
"description": "Page number for pagination (min 1)",
21-
"minimum": 1
19+
"type": "integer",
20+
"description": "Page number for pagination (min 1)"
2221
},
2322
"perPage": {
24-
"type": "number",
25-
"description": "Results per page for pagination (min 1, max 100)",
26-
"minimum": 1,
27-
"maximum": 100
23+
"type": "integer",
24+
"description": "Results per page for pagination (min 1 and max 100)"
2825
},
2926
"repo": {
3027
"type": "string",
3128
"description": "Repository name"
3229
}
33-
}
30+
},
31+
"additionalProperties": false
3432
},
3533
"name": "list_tags"
3634
}

pkg/github/repositories.go

Lines changed: 80 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -222,89 +222,60 @@ func ListCommits(getClient GetClientFn, t translations.TranslationHelperFunc) (m
222222
}
223223

224224
// ListBranches creates a tool to list branches in a GitHub repository.
225-
func ListBranches(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
226-
tool := mcp.Tool{
227-
Name: "list_branches",
228-
Description: t("TOOL_LIST_BRANCHES_DESCRIPTION", "List branches in a GitHub repository"),
229-
Annotations: &mcp.ToolAnnotations{
230-
Title: t("TOOL_LIST_BRANCHES_USER_TITLE", "List branches"),
231-
ReadOnlyHint: true,
225+
func ListBranches(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[ListBranchesInput, any]) {
226+
return mcp.Tool{
227+
Name: "list_branches",
228+
Description: t("TOOL_LIST_BRANCHES_DESCRIPTION", "List branches in a GitHub repository"),
229+
Annotations: &mcp.ToolAnnotations{
230+
Title: t("TOOL_LIST_BRANCHES_USER_TITLE", "List branches"),
231+
ReadOnlyHint: true,
232+
},
233+
InputSchema: ListBranchesInput{}.MCPSchema(),
232234
},
233-
InputSchema: WithPagination(&jsonschema.Schema{
234-
Type: "object",
235-
Properties: map[string]*jsonschema.Schema{
236-
"owner": {
237-
Type: "string",
238-
Description: "Repository owner",
239-
},
240-
"repo": {
241-
Type: "string",
242-
Description: "Repository name",
235+
func(ctx context.Context, _ *mcp.CallToolRequest, input ListBranchesInput) (*mcp.CallToolResult, any, error) {
236+
opts := &github.BranchListOptions{
237+
ListOptions: github.ListOptions{
238+
Page: input.Page,
239+
PerPage: input.PerPage,
243240
},
244-
},
245-
Required: []string{"owner", "repo"},
246-
}),
247-
}
241+
}
248242

249-
handler := mcp.ToolHandlerFor[map[string]any, any](func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
250-
owner, err := RequiredParam[string](args, "owner")
251-
if err != nil {
252-
return utils.NewToolResultError(err.Error()), nil, nil
253-
}
254-
repo, err := RequiredParam[string](args, "repo")
255-
if err != nil {
256-
return utils.NewToolResultError(err.Error()), nil, nil
257-
}
258-
pagination, err := OptionalPaginationParams(args)
259-
if err != nil {
260-
return utils.NewToolResultError(err.Error()), nil, nil
261-
}
243+
client, err := getClient(ctx)
244+
if err != nil {
245+
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
246+
}
262247

263-
opts := &github.BranchListOptions{
264-
ListOptions: github.ListOptions{
265-
Page: pagination.Page,
266-
PerPage: pagination.PerPage,
267-
},
268-
}
248+
branches, resp, err := client.Repositories.ListBranches(ctx, input.Owner, input.Repo, opts)
249+
if err != nil {
250+
return ghErrors.NewGitHubAPIErrorResponse(ctx,
251+
"failed to list branches",
252+
resp,
253+
err,
254+
), nil, nil
255+
}
256+
defer func() { _ = resp.Body.Close() }()
269257

270-
client, err := getClient(ctx)
271-
if err != nil {
272-
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
273-
}
258+
if resp.StatusCode != http.StatusOK {
259+
body, err := io.ReadAll(resp.Body)
260+
if err != nil {
261+
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
262+
}
263+
return utils.NewToolResultError(fmt.Sprintf("failed to list branches: %s", string(body))), nil, nil
264+
}
274265

275-
branches, resp, err := client.Repositories.ListBranches(ctx, owner, repo, opts)
276-
if err != nil {
277-
return ghErrors.NewGitHubAPIErrorResponse(ctx,
278-
"failed to list branches",
279-
resp,
280-
err,
281-
), nil, nil
282-
}
283-
defer func() { _ = resp.Body.Close() }()
266+
// Convert to minimal branches
267+
minimalBranches := make([]MinimalBranch, 0, len(branches))
268+
for _, branch := range branches {
269+
minimalBranches = append(minimalBranches, convertToMinimalBranch(branch))
270+
}
284271

285-
if resp.StatusCode != http.StatusOK {
286-
body, err := io.ReadAll(resp.Body)
272+
r, err := json.Marshal(minimalBranches)
287273
if err != nil {
288-
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
274+
return nil, nil, fmt.Errorf("failed to marshal response: %w", err)
289275
}
290-
return utils.NewToolResultError(fmt.Sprintf("failed to list branches: %s", string(body))), nil, nil
291-
}
292-
293-
// Convert to minimal branches
294-
minimalBranches := make([]MinimalBranch, 0, len(branches))
295-
for _, branch := range branches {
296-
minimalBranches = append(minimalBranches, convertToMinimalBranch(branch))
297-
}
298276

299-
r, err := json.Marshal(minimalBranches)
300-
if err != nil {
301-
return nil, nil, fmt.Errorf("failed to marshal response: %w", err)
277+
return utils.NewToolResultText(string(r)), nil, nil
302278
}
303-
304-
return utils.NewToolResultText(string(r)), nil, nil
305-
})
306-
307-
return tool, handler
308279
}
309280

310281
// CreateOrUpdateFile creates a tool to create or update a file in a GitHub repository.
@@ -1298,81 +1269,52 @@ func PushFiles(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp
12981269
}
12991270

13001271
// ListTags creates a tool to list tags in a GitHub repository.
1301-
func ListTags(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
1302-
tool := mcp.Tool{
1303-
Name: "list_tags",
1304-
Description: t("TOOL_LIST_TAGS_DESCRIPTION", "List git tags in a GitHub repository"),
1305-
Annotations: &mcp.ToolAnnotations{
1306-
Title: t("TOOL_LIST_TAGS_USER_TITLE", "List tags"),
1307-
ReadOnlyHint: true,
1308-
},
1309-
InputSchema: WithPagination(&jsonschema.Schema{
1310-
Type: "object",
1311-
Properties: map[string]*jsonschema.Schema{
1312-
"owner": {
1313-
Type: "string",
1314-
Description: "Repository owner",
1315-
},
1316-
"repo": {
1317-
Type: "string",
1318-
Description: "Repository name",
1319-
},
1272+
func ListTags(getClient GetClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[ListTagsInput, any]) {
1273+
return mcp.Tool{
1274+
Name: "list_tags",
1275+
Description: t("TOOL_LIST_TAGS_DESCRIPTION", "List git tags in a GitHub repository"),
1276+
Annotations: &mcp.ToolAnnotations{
1277+
Title: t("TOOL_LIST_TAGS_USER_TITLE", "List tags"),
1278+
ReadOnlyHint: true,
13201279
},
1321-
Required: []string{"owner", "repo"},
1322-
}),
1323-
}
1324-
1325-
handler := mcp.ToolHandlerFor[map[string]any, any](func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
1326-
owner, err := RequiredParam[string](args, "owner")
1327-
if err != nil {
1328-
return utils.NewToolResultError(err.Error()), nil, nil
1329-
}
1330-
repo, err := RequiredParam[string](args, "repo")
1331-
if err != nil {
1332-
return utils.NewToolResultError(err.Error()), nil, nil
1333-
}
1334-
pagination, err := OptionalPaginationParams(args)
1335-
if err != nil {
1336-
return utils.NewToolResultError(err.Error()), nil, nil
1337-
}
1280+
InputSchema: ListTagsInput{}.MCPSchema(),
1281+
},
1282+
func(ctx context.Context, _ *mcp.CallToolRequest, input ListTagsInput) (*mcp.CallToolResult, any, error) {
1283+
opts := &github.ListOptions{
1284+
Page: input.Page,
1285+
PerPage: input.PerPage,
1286+
}
13381287

1339-
opts := &github.ListOptions{
1340-
Page: pagination.Page,
1341-
PerPage: pagination.PerPage,
1342-
}
1288+
client, err := getClient(ctx)
1289+
if err != nil {
1290+
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
1291+
}
13431292

1344-
client, err := getClient(ctx)
1345-
if err != nil {
1346-
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
1347-
}
1293+
tags, resp, err := client.Repositories.ListTags(ctx, input.Owner, input.Repo, opts)
1294+
if err != nil {
1295+
return ghErrors.NewGitHubAPIErrorResponse(ctx,
1296+
"failed to list tags",
1297+
resp,
1298+
err,
1299+
), nil, nil
1300+
}
1301+
defer func() { _ = resp.Body.Close() }()
13481302

1349-
tags, resp, err := client.Repositories.ListTags(ctx, owner, repo, opts)
1350-
if err != nil {
1351-
return ghErrors.NewGitHubAPIErrorResponse(ctx,
1352-
"failed to list tags",
1353-
resp,
1354-
err,
1355-
), nil, nil
1356-
}
1357-
defer func() { _ = resp.Body.Close() }()
1303+
if resp.StatusCode != http.StatusOK {
1304+
body, err := io.ReadAll(resp.Body)
1305+
if err != nil {
1306+
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
1307+
}
1308+
return utils.NewToolResultError(fmt.Sprintf("failed to list tags: %s", string(body))), nil, nil
1309+
}
13581310

1359-
if resp.StatusCode != http.StatusOK {
1360-
body, err := io.ReadAll(resp.Body)
1311+
r, err := json.Marshal(tags)
13611312
if err != nil {
1362-
return nil, nil, fmt.Errorf("failed to read response body: %w", err)
1313+
return nil, nil, fmt.Errorf("failed to marshal response: %w", err)
13631314
}
1364-
return utils.NewToolResultError(fmt.Sprintf("failed to list tags: %s", string(body))), nil, nil
1365-
}
13661315

1367-
r, err := json.Marshal(tags)
1368-
if err != nil {
1369-
return nil, nil, fmt.Errorf("failed to marshal response: %w", err)
1316+
return utils.NewToolResultText(string(r)), nil, nil
13701317
}
1371-
1372-
return utils.NewToolResultText(string(r)), nil, nil
1373-
})
1374-
1375-
return tool, handler
13761318
}
13771319

13781320
// GetTag creates a tool to get details about a specific tag in a GitHub repository.

0 commit comments

Comments
 (0)