Migrate repos toolset to modelcontextprotocol/go-sdk (#1445)

* Initial plan

* WIP: Migrate repos toolset - 7/18 tools complete

Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>

* Complete repositories.go migration - all 18 tools migrated

Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>

* WIP: Update repositories_test.go - partial migration

Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>

* Complete repos toolset migration to go-sdk

Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>

* re-add 18 tools: 15/17 repos, 3/3 stargazers

* add toolsnaps for ListReleases, GetLatestRelease

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: omgitsads <4619+omgitsads@users.noreply.github.com>
Co-authored-by: LuluBeatson <lulubeatson@github.com>
Co-authored-by: Adam Holt <me@adamholt.co.uk>
This commit is contained in:
Copilot
2025-11-24 15:28:09 +01:00
committed by GitHub
parent ba40198c57
commit 001e0a1758
22 changed files with 2495 additions and 2214 deletions
+20 -21
View File
@@ -1,34 +1,33 @@
{
"annotations": {
"title": "Create branch",
"readOnlyHint": false
"title": "Create branch"
},
"description": "Create a new branch in a GitHub repository",
"inputSchema": {
"properties": {
"branch": {
"description": "Name for new branch",
"type": "string"
},
"from_branch": {
"description": "Source branch (defaults to repo default)",
"type": "string"
},
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
"branch"
],
"type": "object"
"properties": {
"branch": {
"type": "string",
"description": "Name for new branch"
},
"from_branch": {
"type": "string",
"description": "Source branch (defaults to repo default)"
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "create_branch"
}
@@ -1,40 +1,10 @@
{
"annotations": {
"title": "Create or update file",
"readOnlyHint": false
"title": "Create or update file"
},
"description": "Create or update a single file in a GitHub repository. If updating, you must provide the SHA of the file you want to update. Use this tool to create or update a file in a GitHub repository remotely; do not use it for local file operations.",
"inputSchema": {
"properties": {
"branch": {
"description": "Branch to create/update the file in",
"type": "string"
},
"content": {
"description": "Content of the file",
"type": "string"
},
"message": {
"description": "Commit message",
"type": "string"
},
"owner": {
"description": "Repository owner (username or organization)",
"type": "string"
},
"path": {
"description": "Path where to create/update the file",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"sha": {
"description": "Required if updating an existing file. The blob SHA of the file being replaced.",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
@@ -43,7 +13,36 @@
"message",
"branch"
],
"type": "object"
"properties": {
"branch": {
"type": "string",
"description": "Branch to create/update the file in"
},
"content": {
"type": "string",
"description": "Content of the file"
},
"message": {
"type": "string",
"description": "Commit message"
},
"owner": {
"type": "string",
"description": "Repository owner (username or organization)"
},
"path": {
"type": "string",
"description": "Path where to create/update the file"
},
"repo": {
"type": "string",
"description": "Repository name"
},
"sha": {
"type": "string",
"description": "Required if updating an existing file. The blob SHA of the file being replaced."
}
}
},
"name": "create_or_update_file"
}
+24 -25
View File
@@ -1,36 +1,35 @@
{
"annotations": {
"title": "Create repository",
"readOnlyHint": false
"title": "Create repository"
},
"description": "Create a new GitHub repository in your account or specified organization",
"inputSchema": {
"properties": {
"autoInit": {
"description": "Initialize with README",
"type": "boolean"
},
"description": {
"description": "Repository description",
"type": "string"
},
"name": {
"description": "Repository name",
"type": "string"
},
"organization": {
"description": "Organization to create the repository in (omit to create in your personal account)",
"type": "string"
},
"private": {
"description": "Whether repo should be private",
"type": "boolean"
}
},
"type": "object",
"required": [
"name"
],
"type": "object"
"properties": {
"autoInit": {
"type": "boolean",
"description": "Initialize with README"
},
"description": {
"type": "string",
"description": "Repository description"
},
"name": {
"type": "string",
"description": "Repository name"
},
"organization": {
"type": "string",
"description": "Organization to create the repository in (omit to create in your personal account)"
},
"private": {
"type": "boolean",
"description": "Whether repo should be private"
}
}
},
"name": "create_repository"
}
+25 -26
View File
@@ -1,33 +1,11 @@
{
"annotations": {
"title": "Delete file",
"readOnlyHint": false,
"destructiveHint": true
"destructiveHint": true,
"title": "Delete file"
},
"description": "Delete a file from a GitHub repository",
"inputSchema": {
"properties": {
"branch": {
"description": "Branch to delete the file from",
"type": "string"
},
"message": {
"description": "Commit message",
"type": "string"
},
"owner": {
"description": "Repository owner (username or organization)",
"type": "string"
},
"path": {
"description": "Path to the file to delete",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
@@ -35,7 +13,28 @@
"message",
"branch"
],
"type": "object"
"properties": {
"branch": {
"type": "string",
"description": "Branch to delete the file from"
},
"message": {
"type": "string",
"description": "Commit message"
},
"owner": {
"type": "string",
"description": "Repository owner (username or organization)"
},
"path": {
"type": "string",
"description": "Path to the file to delete"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "delete_file"
}
+16 -17
View File
@@ -1,29 +1,28 @@
{
"annotations": {
"title": "Fork repository",
"readOnlyHint": false
"title": "Fork repository"
},
"description": "Fork a GitHub repository to your account or specified organization",
"inputSchema": {
"properties": {
"organization": {
"description": "Organization to fork to",
"type": "string"
},
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"organization": {
"type": "string",
"description": "Organization to fork to"
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "fork_repository"
}
+33 -33
View File
@@ -1,46 +1,46 @@
{
"annotations": {
"title": "Get commit details",
"readOnlyHint": true
"readOnlyHint": true,
"title": "Get commit details"
},
"description": "Get details for a commit from a GitHub repository",
"inputSchema": {
"properties": {
"include_diff": {
"default": true,
"description": "Whether to include file diffs and stats in the response. Default is true.",
"type": "boolean"
},
"owner": {
"description": "Repository owner",
"type": "string"
},
"page": {
"description": "Page number for pagination (min 1)",
"minimum": 1,
"type": "number"
},
"perPage": {
"description": "Results per page for pagination (min 1, max 100)",
"maximum": 100,
"minimum": 1,
"type": "number"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"sha": {
"description": "Commit SHA, branch name, or tag name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
"sha"
],
"type": "object"
"properties": {
"include_diff": {
"type": "boolean",
"description": "Whether to include file diffs and stats in the response. Default is true.",
"default": true
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"minimum": 1,
"maximum": 100
},
"repo": {
"type": "string",
"description": "Repository name"
},
"sha": {
"type": "string",
"description": "Commit SHA, branch name, or tag name"
}
}
},
"name": "get_commit"
}
+26 -26
View File
@@ -1,38 +1,38 @@
{
"annotations": {
"title": "Get file or directory contents",
"readOnlyHint": true
"readOnlyHint": true,
"title": "Get file or directory contents"
},
"description": "Get the contents of a file or directory from a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner (username or organization)",
"type": "string"
},
"path": {
"default": "/",
"description": "Path to file/directory (directories must end with a slash '/')",
"type": "string"
},
"ref": {
"description": "Accepts optional git refs such as `refs/tags/{tag}`, `refs/heads/{branch}` or `refs/pull/{pr_number}/head`",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"sha": {
"description": "Accepts optional commit SHA. If specified, it will be used instead of ref",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner (username or organization)"
},
"path": {
"type": "string",
"description": "Path to file/directory (directories must end with a slash '/')",
"default": "/"
},
"ref": {
"type": "string",
"description": "Accepts optional git refs such as `refs/tags/{tag}`, `refs/heads/{branch}` or `refs/pull/{pr_number}/head`"
},
"repo": {
"type": "string",
"description": "Repository name"
},
"sha": {
"type": "string",
"description": "Accepts optional commit SHA. If specified, it will be used instead of ref"
}
}
},
"name": "get_file_contents"
}
@@ -0,0 +1,25 @@
{
"annotations": {
"readOnlyHint": true,
"title": "Get latest release"
},
"description": "Get the latest release in a GitHub repository",
"inputSchema": {
"type": "object",
"required": [
"owner",
"repo"
],
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "get_latest_release"
}
@@ -1,30 +1,30 @@
{
"annotations": {
"title": "Get a release by tag name",
"readOnlyHint": true
"readOnlyHint": true,
"title": "Get a release by tag name"
},
"description": "Get a specific release by its tag name in a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"tag": {
"description": "Tag name (e.g., 'v1.0.0')",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
"tag"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
},
"tag": {
"type": "string",
"description": "Tag name (e.g., 'v1.0.0')"
}
}
},
"name": "get_release_by_tag"
}
+17 -17
View File
@@ -1,30 +1,30 @@
{
"annotations": {
"title": "Get tag details",
"readOnlyHint": true
"readOnlyHint": true,
"title": "Get tag details"
},
"description": "Get details about a specific git tag in a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"tag": {
"description": "Tag name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
"tag"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
},
"tag": {
"type": "string",
"description": "Tag name"
}
}
},
"name": "get_tag"
}
+24 -24
View File
@@ -1,36 +1,36 @@
{
"annotations": {
"title": "List branches",
"readOnlyHint": true
"readOnlyHint": true,
"title": "List branches"
},
"description": "List branches in a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"page": {
"description": "Page number for pagination (min 1)",
"minimum": 1,
"type": "number"
},
"perPage": {
"description": "Results per page for pagination (min 1, max 100)",
"maximum": 100,
"minimum": 1,
"type": "number"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"minimum": 1,
"maximum": 100
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "list_branches"
}
+32 -32
View File
@@ -1,44 +1,44 @@
{
"annotations": {
"title": "List commits",
"readOnlyHint": true
"readOnlyHint": true,
"title": "List commits"
},
"description": "Get list of commits of a branch in a GitHub repository. Returns at least 30 results per page by default, but can return more if specified using the perPage parameter (up to 100).",
"inputSchema": {
"properties": {
"author": {
"description": "Author username or email address to filter commits by",
"type": "string"
},
"owner": {
"description": "Repository owner",
"type": "string"
},
"page": {
"description": "Page number for pagination (min 1)",
"minimum": 1,
"type": "number"
},
"perPage": {
"description": "Results per page for pagination (min 1, max 100)",
"maximum": 100,
"minimum": 1,
"type": "number"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"sha": {
"description": "Commit SHA, branch or tag name to list commits of. If not provided, uses the default branch of the repository. If a commit SHA is provided, will list commits up to that SHA.",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"author": {
"type": "string",
"description": "Author username or email address to filter commits by"
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"minimum": 1,
"maximum": 100
},
"repo": {
"type": "string",
"description": "Repository name"
},
"sha": {
"type": "string",
"description": "Commit SHA, branch or tag name to list commits of. If not provided, uses the default branch of the repository. If a commit SHA is provided, will list commits up to that SHA."
}
}
},
"name": "list_commits"
}
@@ -0,0 +1,36 @@
{
"annotations": {
"readOnlyHint": true,
"title": "List releases"
},
"description": "List releases in a GitHub repository",
"inputSchema": {
"type": "object",
"required": [
"owner",
"repo"
],
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"minimum": 1,
"maximum": 100
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "list_releases"
}
@@ -1,44 +1,44 @@
{
"annotations": {
"title": "List starred repositories",
"readOnlyHint": true
"readOnlyHint": true,
"title": "List starred repositories"
},
"description": "List starred repositories",
"inputSchema": {
"type": "object",
"properties": {
"direction": {
"type": "string",
"description": "The direction to sort the results by.",
"enum": [
"asc",
"desc"
],
"type": "string"
]
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1,
"type": "number"
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"maximum": 100,
"minimum": 1,
"type": "number"
"maximum": 100
},
"sort": {
"type": "string",
"description": "How to sort the results. Can be either 'created' (when the repository was starred) or 'updated' (when the repository was last pushed to).",
"enum": [
"created",
"updated"
],
"type": "string"
]
},
"username": {
"description": "Username to list starred repositories for. Defaults to the authenticated user.",
"type": "string"
"type": "string",
"description": "Username to list starred repositories for. Defaults to the authenticated user."
}
},
"type": "object"
}
},
"name": "list_starred_repositories"
}
+24 -24
View File
@@ -1,36 +1,36 @@
{
"annotations": {
"title": "List tags",
"readOnlyHint": true
"readOnlyHint": true,
"title": "List tags"
},
"description": "List git tags in a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"page": {
"description": "Page number for pagination (min 1)",
"minimum": 1,
"type": "number"
},
"perPage": {
"description": "Results per page for pagination (min 1, max 100)",
"maximum": 100,
"minimum": 1,
"type": "number"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"page": {
"type": "number",
"description": "Page number for pagination (min 1)",
"minimum": 1
},
"perPage": {
"type": "number",
"description": "Results per page for pagination (min 1, max 100)",
"minimum": 1,
"maximum": 100
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "list_tags"
}
+41 -43
View File
@@ -1,50 +1,10 @@
{
"annotations": {
"title": "Push files to repository",
"readOnlyHint": false
"title": "Push files to repository"
},
"description": "Push multiple files to a GitHub repository in a single commit",
"inputSchema": {
"properties": {
"branch": {
"description": "Branch to push to",
"type": "string"
},
"files": {
"description": "Array of file objects to push, each object with path (string) and content (string)",
"items": {
"additionalProperties": false,
"properties": {
"content": {
"description": "file content",
"type": "string"
},
"path": {
"description": "path to the file",
"type": "string"
}
},
"required": [
"path",
"content"
],
"type": "object"
},
"type": "array"
},
"message": {
"description": "Commit message",
"type": "string"
},
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo",
@@ -52,7 +12,45 @@
"files",
"message"
],
"type": "object"
"properties": {
"branch": {
"type": "string",
"description": "Branch to push to"
},
"files": {
"type": "array",
"description": "Array of file objects to push, each object with path (string) and content (string)",
"items": {
"type": "object",
"required": [
"path",
"content"
],
"properties": {
"content": {
"type": "string",
"description": "file content"
},
"path": {
"type": "string",
"description": "path to the file"
}
}
}
},
"message": {
"type": "string",
"description": "Commit message"
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "push_files"
}
+12 -13
View File
@@ -1,25 +1,24 @@
{
"annotations": {
"title": "Star repository",
"readOnlyHint": false
"title": "Star repository"
},
"description": "Star a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "star_repository"
}
+12 -13
View File
@@ -1,25 +1,24 @@
{
"annotations": {
"title": "Unstar repository",
"readOnlyHint": false
"title": "Unstar repository"
},
"description": "Unstar a GitHub repository",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"type": "object",
"required": [
"owner",
"repo"
],
"type": "object"
"properties": {
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name"
}
}
},
"name": "unstar_repository"
}
+13 -25
View File
@@ -147,33 +147,8 @@ func getErrorResult(t *testing.T, result *mcp.CallToolResult) *mcp.TextContent {
}
// getTextResourceResult is a helper function that returns a text result from a tool call.
func getTextResourceResult(t *testing.T, result *mcp.CallToolResult) *mcp.ResourceContents {
t.Helper()
assert.NotNil(t, result)
require.Len(t, result.Content, 2)
content := result.Content[1]
require.IsType(t, mcp.EmbeddedResource{}, content)
resource, ok := content.(*mcp.EmbeddedResource)
require.True(t, ok, "expected content to be of type EmbeddedResource")
require.IsType(t, mcp.ResourceContents{}, resource.Resource)
require.NotEmpty(t, resource.Resource.Text)
return resource.Resource
}
// getBlobResourceResult is a helper function that returns a blob result from a tool call.
func getBlobResourceResult(t *testing.T, result *mcp.CallToolResult) *mcp.ResourceContents {
t.Helper()
assert.NotNil(t, result)
require.Len(t, result.Content, 2)
content := result.Content[1]
require.IsType(t, mcp.EmbeddedResource{}, content)
resource := content.(*mcp.EmbeddedResource)
require.IsType(t, mcp.ResourceContents{}, resource.Resource)
require.NotEmpty(t, resource.Resource.Blob)
return resource.Resource
}
func TestOptionalParamOK(t *testing.T) {
tests := []struct {
@@ -284,3 +259,16 @@ func TestOptionalParamOK(t *testing.T) {
})
}
}
func getResourceResult(t *testing.T, result *mcp.CallToolResult) *mcp.ResourceContents {
t.Helper()
assert.NotNil(t, result)
require.Len(t, result.Content, 2)
content := result.Content[1]
require.IsType(t, &mcp.EmbeddedResource{}, content)
resource, ok := content.(*mcp.EmbeddedResource)
require.True(t, ok, "expected content to be of type EmbeddedResource")
require.IsType(t, &mcp.ResourceContents{}, resource.Resource)
return resource.Resource
}
+1840 -1655
View File
File diff suppressed because it is too large Load Diff
+186 -130
View File
@@ -1,10 +1,7 @@
//go:build ignore
package github
import (
"context"
"encoding/base64"
"encoding/json"
"net/http"
"net/url"
@@ -15,9 +12,11 @@ import (
"github.com/github/github-mcp-server/internal/toolsnaps"
"github.com/github/github-mcp-server/pkg/raw"
"github.com/github/github-mcp-server/pkg/translations"
"github.com/github/github-mcp-server/pkg/utils"
"github.com/google/go-github/v79/github"
"github.com/mark3labs/mcp-go/mcp"
"github.com/google/jsonschema-go/jsonschema"
"github.com/migueleliasweb/go-github-mock/src/mock"
"github.com/modelcontextprotocol/go-sdk/mcp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -29,14 +28,17 @@ func Test_GetFileContents(t *testing.T) {
tool, _ := GetFileContents(stubGetClientFn(mockClient), stubGetRawClientFn(mockRawClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_file_contents", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "path")
assert.Contains(t, tool.InputSchema.Properties, "ref")
assert.Contains(t, tool.InputSchema.Properties, "sha")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "path")
assert.Contains(t, schema.Properties, "ref")
assert.Contains(t, schema.Properties, "sha")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Mock response for raw content
mockRawContent := []byte("# Test Repository\n\nThis is a test repository.")
@@ -108,7 +110,7 @@ func Test_GetFileContents(t *testing.T) {
"ref": "refs/heads/main",
},
expectError: false,
expectedResult: mcp.TextResourceContents{
expectedResult: mcp.ResourceContents{
URI: "repo://owner/repo/refs/heads/main/contents/README.md",
Text: "# Test Repository\n\nThis is a test repository.",
MIMEType: "text/markdown",
@@ -153,9 +155,9 @@ func Test_GetFileContents(t *testing.T) {
"ref": "refs/heads/main",
},
expectError: false,
expectedResult: mcp.BlobResourceContents{
expectedResult: mcp.ResourceContents{
URI: "repo://owner/repo/refs/heads/main/contents/test.png",
Blob: base64.StdEncoding.EncodeToString(mockRawContent),
Blob: mockRawContent,
MIMEType: "image/png",
},
},
@@ -198,9 +200,9 @@ func Test_GetFileContents(t *testing.T) {
"ref": "refs/heads/main",
},
expectError: false,
expectedResult: mcp.BlobResourceContents{
expectedResult: mcp.ResourceContents{
URI: "repo://owner/repo/refs/heads/main/contents/document.pdf",
Blob: base64.StdEncoding.EncodeToString(mockRawContent),
Blob: mockRawContent,
MIMEType: "application/pdf",
},
},
@@ -276,7 +278,7 @@ func Test_GetFileContents(t *testing.T) {
"ref": "refs/heads/main",
},
expectError: false,
expectedResult: mcp.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."),
expectedResult: utils.NewToolResultError("Failed to get file contents. The path does not point to a file or directory, or the file does not exist in the repository."),
},
}
@@ -291,7 +293,7 @@ func Test_GetFileContents(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -303,12 +305,10 @@ func Test_GetFileContents(t *testing.T) {
require.NoError(t, err)
// Use the correct result helper based on the expected type
switch expected := tc.expectedResult.(type) {
case mcp.TextResourceContents:
textResource := getTextResourceResult(t, result)
assert.Equal(t, expected, textResource)
case mcp.BlobResourceContents:
blobResource := getBlobResourceResult(t, result)
assert.Equal(t, expected, blobResource)
case mcp.ResourceContents:
// Handle both text and blob resources
resource := getResourceResult(t, result)
assert.Equal(t, expected, *resource)
case []*github.RepositoryContent:
// Directory content fetch returns a text result (JSON array)
textContent := getTextResult(t, result)
@@ -335,12 +335,15 @@ func Test_ForkRepository(t *testing.T) {
tool, _ := ForkRepository(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "fork_repository", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "organization")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "organization")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Setup mock forked repo for success case
mockForkedRepo := &github.Repository{
@@ -409,7 +412,7 @@ func Test_ForkRepository(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -437,13 +440,16 @@ func Test_CreateBranch(t *testing.T) {
tool, _ := CreateBranch(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "create_branch", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "branch")
assert.Contains(t, tool.InputSchema.Properties, "from_branch")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "branch"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "branch")
assert.Contains(t, schema.Properties, "from_branch")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "branch"})
// Setup mock repository for default branch test
mockRepo := &github.Repository{
@@ -599,7 +605,7 @@ func Test_CreateBranch(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -632,12 +638,15 @@ func Test_GetCommit(t *testing.T) {
tool, _ := GetCommit(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_commit", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "sha")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "sha"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "sha")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "sha"})
mockCommit := &github.RepositoryCommit{
SHA: github.Ptr("abc123def456"),
@@ -725,7 +734,7 @@ func Test_GetCommit(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -761,15 +770,18 @@ func Test_ListCommits(t *testing.T) {
tool, _ := ListCommits(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "list_commits", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "sha")
assert.Contains(t, tool.InputSchema.Properties, "author")
assert.Contains(t, tool.InputSchema.Properties, "page")
assert.Contains(t, tool.InputSchema.Properties, "perPage")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "sha")
assert.Contains(t, schema.Properties, "author")
assert.Contains(t, schema.Properties, "page")
assert.Contains(t, schema.Properties, "perPage")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Setup mock commits for success case
mockCommits := []*github.RepositoryCommit{
@@ -945,7 +957,7 @@ func Test_ListCommits(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -991,16 +1003,19 @@ func Test_CreateOrUpdateFile(t *testing.T) {
tool, _ := CreateOrUpdateFile(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "create_or_update_file", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "path")
assert.Contains(t, tool.InputSchema.Properties, "content")
assert.Contains(t, tool.InputSchema.Properties, "message")
assert.Contains(t, tool.InputSchema.Properties, "branch")
assert.Contains(t, tool.InputSchema.Properties, "sha")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "path", "content", "message", "branch"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "path")
assert.Contains(t, schema.Properties, "content")
assert.Contains(t, schema.Properties, "message")
assert.Contains(t, schema.Properties, "branch")
assert.Contains(t, schema.Properties, "sha")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "path", "content", "message", "branch"})
// Setup mock file content response
mockFileResponse := &github.RepositoryContentResponse{
@@ -1118,7 +1133,7 @@ func Test_CreateOrUpdateFile(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -1158,14 +1173,17 @@ func Test_CreateRepository(t *testing.T) {
tool, _ := CreateRepository(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "create_repository", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "name")
assert.Contains(t, tool.InputSchema.Properties, "description")
assert.Contains(t, tool.InputSchema.Properties, "organization")
assert.Contains(t, tool.InputSchema.Properties, "private")
assert.Contains(t, tool.InputSchema.Properties, "autoInit")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"name"})
assert.Contains(t, schema.Properties, "name")
assert.Contains(t, schema.Properties, "description")
assert.Contains(t, schema.Properties, "organization")
assert.Contains(t, schema.Properties, "private")
assert.Contains(t, schema.Properties, "autoInit")
assert.ElementsMatch(t, schema.Required, []string{"name"})
// Setup mock repository response
mockRepo := &github.Repository{
@@ -1298,7 +1316,7 @@ func Test_CreateRepository(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -1332,14 +1350,17 @@ func Test_PushFiles(t *testing.T) {
tool, _ := PushFiles(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "push_files", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "branch")
assert.Contains(t, tool.InputSchema.Properties, "files")
assert.Contains(t, tool.InputSchema.Properties, "message")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "branch", "files", "message"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "branch")
assert.Contains(t, schema.Properties, "files")
assert.Contains(t, schema.Properties, "message")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "branch", "files", "message"})
// Setup mock objects
mockRef := &github.Reference{
@@ -1631,7 +1652,7 @@ func Test_PushFiles(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -1673,13 +1694,16 @@ func Test_ListBranches(t *testing.T) {
tool, _ := ListBranches(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "list_branches", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "page")
assert.Contains(t, tool.InputSchema.Properties, "perPage")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "page")
assert.Contains(t, schema.Properties, "perPage")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Setup mock branches for success case
mockBranches := []*github.Branch{
@@ -1746,7 +1770,7 @@ func Test_ListBranches(t *testing.T) {
request := createMCPRequest(tt.args)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tt.args)
if tt.wantErr {
require.Error(t, err)
if tt.errContains != "" {
@@ -1784,15 +1808,18 @@ func Test_DeleteFile(t *testing.T) {
tool, _ := DeleteFile(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "delete_file", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "path")
assert.Contains(t, tool.InputSchema.Properties, "message")
assert.Contains(t, tool.InputSchema.Properties, "branch")
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "path")
assert.Contains(t, schema.Properties, "message")
assert.Contains(t, schema.Properties, "branch")
// SHA is no longer required since we're using Git Data API
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "path", "message", "branch"})
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "path", "message", "branch"})
// Setup mock objects for Git Data API
mockRef := &github.Reference{
@@ -1927,7 +1954,7 @@ func Test_DeleteFile(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -1962,11 +1989,14 @@ func Test_ListTags(t *testing.T) {
tool, _ := ListTags(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "list_tags", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Setup mock tags for success case
mockTags := []*github.RepositoryTag{
@@ -2048,7 +2078,7 @@ func Test_ListTags(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -2086,12 +2116,15 @@ func Test_GetTag(t *testing.T) {
tool, _ := GetTag(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_tag", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "tag")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "tag"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "tag")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "tag"})
mockTagRef := &github.Reference{
Ref: github.Ptr("refs/tags/v1.0.0"),
@@ -2202,7 +2235,7 @@ func Test_GetTag(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
@@ -2236,12 +2269,16 @@ func Test_GetTag(t *testing.T) {
func Test_ListReleases(t *testing.T) {
mockClient := github.NewClient(nil)
tool, _ := ListReleases(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "list_releases", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
mockReleases := []*github.RepositoryRelease{
{
@@ -2304,7 +2341,7 @@ func Test_ListReleases(t *testing.T) {
client := github.NewClient(tc.mockedClient)
_, handler := ListReleases(stubGetClientFn(client), translations.NullTranslationHelper)
request := createMCPRequest(tc.requestArgs)
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
if tc.expectError {
require.Error(t, err)
@@ -2327,12 +2364,16 @@ func Test_ListReleases(t *testing.T) {
func Test_GetLatestRelease(t *testing.T) {
mockClient := github.NewClient(nil)
tool, _ := GetLatestRelease(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_latest_release", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
mockRelease := &github.RepositoryRelease{
ID: github.Ptr(int64(1)),
@@ -2388,7 +2429,7 @@ func Test_GetLatestRelease(t *testing.T) {
client := github.NewClient(tc.mockedClient)
_, handler := GetLatestRelease(stubGetClientFn(client), translations.NullTranslationHelper)
request := createMCPRequest(tc.requestArgs)
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
if tc.expectError {
require.Error(t, err)
@@ -2411,12 +2452,15 @@ func Test_GetReleaseByTag(t *testing.T) {
tool, _ := GetReleaseByTag(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_release_by_tag", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "tag")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "tag"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "tag")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo", "tag"})
mockRelease := &github.RepositoryRelease{
ID: github.Ptr(int64(1)),
@@ -2532,7 +2576,7 @@ func Test_GetReleaseByTag(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
if tc.expectError {
require.Error(t, err)
@@ -2920,14 +2964,17 @@ func Test_ListStarredRepositories(t *testing.T) {
tool, _ := ListStarredRepositories(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "list_starred_repositories", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "username")
assert.Contains(t, tool.InputSchema.Properties, "sort")
assert.Contains(t, tool.InputSchema.Properties, "direction")
assert.Contains(t, tool.InputSchema.Properties, "page")
assert.Contains(t, tool.InputSchema.Properties, "perPage")
assert.Empty(t, tool.InputSchema.Required) // All parameters are optional
assert.Contains(t, schema.Properties, "username")
assert.Contains(t, schema.Properties, "sort")
assert.Contains(t, schema.Properties, "direction")
assert.Contains(t, schema.Properties, "page")
assert.Contains(t, schema.Properties, "perPage")
assert.Empty(t, schema.Required) // All parameters are optional
// Setup mock starred repositories
starredAt := time.Now().Add(-24 * time.Hour)
@@ -3040,12 +3087,12 @@ func Test_ListStarredRepositories(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
require.NotNil(t, result)
textResult, ok := result.Content[0].(mcp.TextContent)
textResult, ok := result.Content[0].(*mcp.TextContent)
require.True(t, ok, "Expected text content")
assert.Contains(t, textResult.Text, tc.expectedErrMsg)
} else {
@@ -3076,11 +3123,14 @@ func Test_StarRepository(t *testing.T) {
tool, _ := StarRepository(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "star_repository", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
tests := []struct {
name string
@@ -3135,12 +3185,12 @@ func Test_StarRepository(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
require.NotNil(t, result)
textResult, ok := result.Content[0].(mcp.TextContent)
textResult, ok := result.Content[0].(*mcp.TextContent)
require.True(t, ok, "Expected text content")
assert.Contains(t, textResult.Text, tc.expectedErrMsg)
} else {
@@ -3161,11 +3211,14 @@ func Test_UnstarRepository(t *testing.T) {
tool, _ := UnstarRepository(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "unstar_repository", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
tests := []struct {
name string
@@ -3220,12 +3273,12 @@ func Test_UnstarRepository(t *testing.T) {
request := createMCPRequest(tc.requestArgs)
// Call handler
result, err := handler(context.Background(), request)
result, _, err := handler(context.Background(), &request, tc.requestArgs)
// Verify results
if tc.expectError {
require.NotNil(t, result)
textResult, ok := result.Content[0].(mcp.TextContent)
textResult, ok := result.Content[0].(*mcp.TextContent)
require.True(t, ok, "Expected text content")
assert.Contains(t, textResult.Text, tc.expectedErrMsg)
} else {
@@ -3240,20 +3293,23 @@ func Test_UnstarRepository(t *testing.T) {
}
}
func Test_GetRepositoryTree(t *testing.T) {
func Test_RepositoriesGetRepositoryTree(t *testing.T) {
// Verify tool definition once
mockClient := github.NewClient(nil)
tool, _ := GetRepositoryTree(stubGetClientFn(mockClient), translations.NullTranslationHelper)
require.NoError(t, toolsnaps.Test(tool.Name, tool))
schema, ok := tool.InputSchema.(*jsonschema.Schema)
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
assert.Equal(t, "get_repository_tree", tool.Name)
assert.NotEmpty(t, tool.Description)
assert.Contains(t, tool.InputSchema.Properties, "owner")
assert.Contains(t, tool.InputSchema.Properties, "repo")
assert.Contains(t, tool.InputSchema.Properties, "tree_sha")
assert.Contains(t, tool.InputSchema.Properties, "recursive")
assert.Contains(t, tool.InputSchema.Properties, "path_filter")
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"})
assert.Contains(t, schema.Properties, "owner")
assert.Contains(t, schema.Properties, "repo")
assert.Contains(t, schema.Properties, "tree_sha")
assert.Contains(t, schema.Properties, "recursive")
assert.Contains(t, schema.Properties, "path_filter")
assert.ElementsMatch(t, schema.Required, []string{"owner", "repo"})
// Setup mock data
mockRepo := &github.Repository{
+26 -26
View File
@@ -168,25 +168,25 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
repos := toolsets.NewToolset(ToolsetMetadataRepos.ID, ToolsetMetadataRepos.Description).
AddReadTools(
toolsets.NewServerTool(SearchRepositories(getClient, t)),
// toolsets.NewServerTool(GetFileContents(getClient, getRawClient, t)),
// toolsets.NewServerTool(ListCommits(getClient, t)),
toolsets.NewServerTool(GetFileContents(getClient, getRawClient, t)),
toolsets.NewServerTool(ListCommits(getClient, t)),
toolsets.NewServerTool(SearchCode(getClient, t)),
// toolsets.NewServerTool(GetCommit(getClient, t)),
// toolsets.NewServerTool(ListBranches(getClient, t)),
// toolsets.NewServerTool(ListTags(getClient, t)),
// toolsets.NewServerTool(GetTag(getClient, t)),
// toolsets.NewServerTool(ListReleases(getClient, t)),
// toolsets.NewServerTool(GetLatestRelease(getClient, t)),
// toolsets.NewServerTool(GetReleaseByTag(getClient, t)),
toolsets.NewServerTool(GetCommit(getClient, t)),
toolsets.NewServerTool(ListBranches(getClient, t)),
toolsets.NewServerTool(ListTags(getClient, t)),
toolsets.NewServerTool(GetTag(getClient, t)),
toolsets.NewServerTool(ListReleases(getClient, t)),
toolsets.NewServerTool(GetLatestRelease(getClient, t)),
toolsets.NewServerTool(GetReleaseByTag(getClient, t)),
).
AddWriteTools(
toolsets.NewServerTool(CreateOrUpdateFile(getClient, t)),
toolsets.NewServerTool(CreateRepository(getClient, t)),
toolsets.NewServerTool(ForkRepository(getClient, t)),
toolsets.NewServerTool(CreateBranch(getClient, t)),
toolsets.NewServerTool(PushFiles(getClient, t)),
toolsets.NewServerTool(DeleteFile(getClient, t)),
).
// AddWriteTools(
// toolsets.NewServerTool(CreateOrUpdateFile(getClient, t)),
// toolsets.NewServerTool(CreateRepository(getClient, t)),
// toolsets.NewServerTool(ForkRepository(getClient, t)),
// toolsets.NewServerTool(CreateBranch(getClient, t)),
// toolsets.NewServerTool(PushFiles(getClient, t)),
// toolsets.NewServerTool(DeleteFile(getClient, t)),
// ).
AddResourceTemplates(
toolsets.NewServerResourceTemplate(GetRepositoryResourceContent(getClient, getRawClient, t)),
toolsets.NewServerResourceTemplate(GetRepositoryResourceBranchContent(getClient, getRawClient, t)),
@@ -337,14 +337,14 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
toolsets.NewServerTool(DeleteProjectItem(getClient, t)),
toolsets.NewServerTool(UpdateProjectItem(getClient, t)),
)
// stargazers := toolsets.NewToolset(ToolsetMetadataStargazers.ID, ToolsetMetadataStargazers.Description).
// AddReadTools(
// toolsets.NewServerTool(ListStarredRepositories(getClient, t)),
// ).
// AddWriteTools(
// toolsets.NewServerTool(StarRepository(getClient, t)),
// toolsets.NewServerTool(UnstarRepository(getClient, t)),
// )
stargazers := toolsets.NewToolset(ToolsetMetadataStargazers.ID, ToolsetMetadataStargazers.Description).
AddReadTools(
toolsets.NewServerTool(ListStarredRepositories(getClient, t)),
).
AddWriteTools(
toolsets.NewServerTool(StarRepository(getClient, t)),
toolsets.NewServerTool(UnstarRepository(getClient, t)),
)
labels := toolsets.NewToolset(ToolsetLabels.ID, ToolsetLabels.Description).
AddReadTools(
// get
@@ -375,7 +375,7 @@ func DefaultToolsetGroup(readOnly bool, getClient GetClientFn, getGQLClient GetG
tsg.AddToolset(gists)
tsg.AddToolset(securityAdvisories)
tsg.AddToolset(projects)
// tsg.AddToolset(stargazers)
tsg.AddToolset(stargazers)
tsg.AddToolset(labels)
return tsg