From 79a9380fae3a0b2208f7878a63df8a4bb8461d76 Mon Sep 17 00:00:00 2001 From: William Martin Date: Thu, 3 Apr 2025 13:30:28 +0200 Subject: [PATCH 1/2] Make JSONRPC easier in conformance tests --- conformance/conformance_test.go | 58 +++++++++++++-------------------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/conformance/conformance_test.go b/conformance/conformance_test.go index 899ce38e2..282551c13 100644 --- a/conformance/conformance_test.go +++ b/conformance/conformance_test.go @@ -130,8 +130,11 @@ func TestCapabilities(t *testing.T) { anthropicServer := start(t, anthropic) githubServer := start(t, github) - req := newInitializeRequest( - initializeRequestParams{ + req := initializeRequest{ + JSONRPC: "2.0", + ID: 1, + Method: "initialize", + Params: initializeParams{ ProtocolVersion: "2025-03-26", Capabilities: clientCapabilities{}, ClientInfo: clientInfo{ @@ -139,7 +142,7 @@ func TestCapabilities(t *testing.T) { Version: "0.0.1", }, }, - ) + } require.NoError(t, anthropicServer.send(req)) @@ -274,6 +277,14 @@ func (s server) receive(res response) error { return res.unmarshal(line) } +type request interface { + marshal() ([]byte, error) +} + +type response interface { + unmarshal([]byte) error +} + type jsonRPRCRequest[params any] struct { JSONRPC string `json:"jsonrpc"` ID int `json:"id"` @@ -281,6 +292,10 @@ type jsonRPRCRequest[params any] struct { Params params `json:"params"` } +func (r jsonRPRCRequest[any]) marshal() ([]byte, error) { + return json.Marshal(r) +} + type jsonRPRCResponse[result any] struct { JSONRPC string `json:"jsonrpc"` ID int `json:"id"` @@ -288,34 +303,13 @@ type jsonRPRCResponse[result any] struct { Result result `json:"result"` } -type request interface { - marshal() ([]byte, error) -} - -type response interface { - unmarshal([]byte) error -} - -func newInitializeRequest(params initializeRequestParams) initializeRequest { - return initializeRequest{ - jsonRPRCRequest: jsonRPRCRequest[initializeRequestParams]{ - JSONRPC: "2.0", - ID: 1, - Method: "initialize", - Params: params, - }, - } -} - -type initializeRequest struct { - jsonRPRCRequest[initializeRequestParams] +func (r *jsonRPRCResponse[any]) unmarshal(b []byte) error { + return json.Unmarshal(b, r) } -func (r initializeRequest) marshal() ([]byte, error) { - return json.Marshal(r) -} +type initializeRequest = jsonRPRCRequest[initializeParams] -type initializeRequestParams struct { +type initializeParams struct { ProtocolVersion string `json:"protocolVersion"` Capabilities clientCapabilities `json:"capabilities"` ClientInfo clientInfo `json:"clientInfo"` @@ -328,13 +322,7 @@ type clientInfo struct { Version string `json:"version"` } -type initializeResponse struct { - jsonRPRCResponse[initializeResult] -} - -func (r *initializeResponse) unmarshal(b []byte) error { - return json.Unmarshal(b, r) -} +type initializeResponse = jsonRPRCResponse[initializeResult] type initializeResult struct { ProtocolVersion string `json:"protocolVersion"` From e3dc62a820878fc87c77a28180b278293069056a Mon Sep 17 00:00:00 2001 From: William Martin Date: Thu, 3 Apr 2025 22:23:10 +0200 Subject: [PATCH 2/2] Conform list tools --- README.md | 40 +++--- cmd/mcpcurl/README.md | 2 +- conformance/conformance_test.go | 85 ++++++++++++ go.mod | 1 + pkg/github/code_scanning.go | 4 +- pkg/github/code_scanning_test.go | 16 +-- pkg/github/pullrequests.go | 40 +++--- pkg/github/pullrequests_test.go | 182 ++++++++++++------------- pkg/github/repositories.go | 6 +- pkg/github/repositories_test.go | 6 +- pkg/github/repository_resource.go | 4 +- pkg/github/repository_resource_test.go | 2 +- pkg/github/search.go | 2 +- pkg/github/search_test.go | 2 +- 14 files changed, 239 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 5b9084c4b..6c14ca756 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `direction`: Sort direction ('asc', 'desc') (string, optional) - `since`: Filter by date (ISO 8601 timestamp) (string, optional) - `page`: Page number (number, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) - **update_issue** - Update an existing issue in a GitHub repository @@ -177,7 +177,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - **list_pull_requests** - List and filter repository pull requests @@ -186,14 +186,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `state`: PR state (string, optional) - `sort`: Sort field (string, optional) - `direction`: Sort direction (string, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) - `page`: Page number (number, optional) - **merge_pull_request** - Merge a pull request - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - `commit_title`: Title for the merge commit (string, optional) - `commit_message`: Message for the merge commit (string, optional) - `merge_method`: Merge method (string, optional) @@ -202,41 +202,41 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - **get_pull_request_status** - Get the combined status of all status checks for a pull request - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - **update_pull_request_branch** - Update a pull request branch with the latest changes from the base branch - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) - - `expected_head_sha`: The expected SHA of the pull request's HEAD ref (string, optional) + - `pullNumber`: Pull request number (number, required) + - `expectedHeadSha`: The expected SHA of the pull request's HEAD ref (string, optional) - **get_pull_request_comments** - Get the review comments on a pull request - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - **get_pull_request_reviews** - Get the reviews on a pull request - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - **create_pull_request_review** - Create a review on a pull request review - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pull_number`: Pull request number (number, required) + - `pullNumber`: Pull request number (number, required) - `body`: Review comment text (string, optional) - `event`: Review action ('APPROVE', 'REQUEST_CHANGES', 'COMMENT') (string, required) - - `commit_id`: SHA of commit to review (string, optional) + - `commitId`: SHA of commit to review (string, optional) - `comments`: Line-specific comments array of objects, each object with path (string), position (number), and body (string) (array, optional) - **create_pull_request** - Create a new pull request @@ -276,14 +276,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `sort`: Sort field (string, optional) - `order`: Sort order (string, optional) - `page`: Page number (number, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) - **create_repository** - Create a new GitHub repository - `name`: Repository name (string, required) - `description`: Repository description (string, optional) - `private`: Whether the repository is private (boolean, optional) - - `auto_init`: Auto-initialize with README (boolean, optional) + - `autoInit`: Auto-initialize with README (boolean, optional) - **get_file_contents** - Get contents of a file or directory @@ -311,7 +311,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `sha`: Branch name, tag, or commit SHA (string, optional) - `path`: Only commits containing this file path (string, optional) - `page`: Page number (number, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) ### Search @@ -321,14 +321,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `sort`: Sort field (string, optional) - `order`: Sort order (string, optional) - `page`: Page number (number, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) - **search_users** - Search for GitHub users - `query`: Search query (string, required) - `sort`: Sort field (string, optional) - `order`: Sort order (string, optional) - `page`: Page number (number, optional) - - `per_page`: Results per page (number, optional) + - `perPage`: Results per page (number, optional) ### Code Scanning @@ -336,7 +336,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `alert_number`: Alert number (number, required) + - `alertNumber`: Alert number (number, required) - **list_code_scanning_alerts** - List code scanning alerts for a repository - `owner`: Repository owner (string, required) @@ -391,11 +391,11 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description - **Get Repository Content for a Specific Pull Request** Retrieves the content of a repository at a specific path for a given pull request. - - **Template**: `repo://{owner}/{repo}/refs/pull/{pr_number}/head/contents{/path*}` + - **Template**: `repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}` - **Parameters**: - `owner`: Repository owner (string, required) - `repo`: Repository name (string, required) - - `pr_number`: Pull request number (string, required) + - `prNumber`: Pull request number (string, required) - `path`: File or directory path (string, optional) ## License diff --git a/cmd/mcpcurl/README.md b/cmd/mcpcurl/README.md index f7b7ea2bf..06ce26ee0 100644 --- a/cmd/mcpcurl/README.md +++ b/cmd/mcpcurl/README.md @@ -72,7 +72,7 @@ Use "mcpcurl tools [command] --help" for more information about a command. Get help for a specific tool: ```bash - % ./mcpcurl --stdio-server-cmd "docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN mcp/github" tools get_issue --help + % ./mcpcurl --stdio-server-cmd "docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN mcp/github" tools get_issue --help Get details of a specific issue in a GitHub repository. Usage: diff --git a/conformance/conformance_test.go b/conformance/conformance_test.go index 282551c13..cd69e013a 100644 --- a/conformance/conformance_test.go +++ b/conformance/conformance_test.go @@ -6,6 +6,7 @@ import ( "bufio" "context" "encoding/json" + "errors" "fmt" "io" "os" @@ -17,6 +18,8 @@ import ( "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" "github.com/docker/docker/pkg/stdcopy" + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" ) @@ -230,6 +233,69 @@ func diffNonNilFields(a, b interface{}, path string) string { return sb.String() } +func TestListTools(t *testing.T) { + anthropicServer := start(t, anthropic) + githubServer := start(t, github) + + req := listToolsRequest{ + JSONRPC: "2.0", + ID: 1, + Method: "tools/list", + } + + require.NoError(t, anthropicServer.send(req)) + + var anthropicListToolsResponse listToolsResponse + require.NoError(t, anthropicServer.receive(&anthropicListToolsResponse)) + + require.NoError(t, githubServer.send(req)) + + var ghListToolsResponse listToolsResponse + require.NoError(t, githubServer.receive(&ghListToolsResponse)) + + require.NoError(t, isToolListSubset(anthropicListToolsResponse.Result, ghListToolsResponse.Result), "expected the github list tools response to be a subset of the anthropic list tools response") +} + +func isToolListSubset(subset, superset listToolsResult) error { + // Build a map from tool name to Tool from the superset + supersetMap := make(map[string]tool) + for _, tool := range superset.Tools { + supersetMap[tool.Name] = tool + } + + var err error + for _, tool := range subset.Tools { + sup, ok := supersetMap[tool.Name] + if !ok { + return fmt.Errorf("tool %q not found in superset", tool.Name) + } + + // Intentionally ignore the description fields because there are lots of slight differences. + // if tool.Description != sup.Description { + // return fmt.Errorf("description mismatch for tool %q, got %q expected %q", tool.Name, tool.Description, sup.Description) + // } + + // Ignore any description fields within the input schema properties for the same reason + ignoreDescOpt := cmp.FilterPath(func(p cmp.Path) bool { + // Look for a field named "Properties" somewhere in the path + for _, ps := range p { + if sf, ok := ps.(cmp.StructField); ok && sf.Name() == "Properties" { + return true + } + } + return false + }, cmpopts.IgnoreMapEntries(func(k string, _ any) bool { + return k == "description" + })) + + if diff := cmp.Diff(tool.InputSchema, sup.InputSchema, ignoreDescOpt); diff != "" { + err = errors.Join(err, fmt.Errorf("inputSchema mismatch for tool %q:\n%s", tool.Name, diff)) + } + } + + return err +} + type serverStartResult struct { server server err error @@ -348,3 +414,22 @@ type serverInfo struct { Name string `json:"name"` Version string `json:"version"` } + +type listToolsRequest = jsonRPRCRequest[struct{}] + +type listToolsResponse = jsonRPRCResponse[listToolsResult] + +type listToolsResult struct { + Tools []tool `json:"tools"` +} +type tool struct { + Name string `json:"name"` + Description string `json:"description,omitempty"` + InputSchema inputSchema `json:"inputSchema"` +} + +type inputSchema struct { + Type string `json:"type"` + Properties map[string]any `json:"properties,omitempty"` + Required []string `json:"required,omitempty"` +} diff --git a/go.mod b/go.mod index 324ebccd8..cf96ca5de 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.23.7 require ( github.com/aws/smithy-go v1.22.3 github.com/docker/docker v28.0.4+incompatible + github.com/google/go-cmp v0.7.0 github.com/google/go-github/v69 v69.2.0 github.com/mark3labs/mcp-go v0.18.0 github.com/migueleliasweb/go-github-mock v1.1.0 diff --git a/pkg/github/code_scanning.go b/pkg/github/code_scanning.go index 380dc02cf..81ee2c314 100644 --- a/pkg/github/code_scanning.go +++ b/pkg/github/code_scanning.go @@ -24,7 +24,7 @@ func getCodeScanningAlert(client *github.Client, t translations.TranslationHelpe mcp.Required(), mcp.Description("The name of the repository."), ), - mcp.WithNumber("alert_number", + mcp.WithNumber("alertNumber", mcp.Required(), mcp.Description("The number of the alert."), ), @@ -38,7 +38,7 @@ func getCodeScanningAlert(client *github.Client, t translations.TranslationHelpe if err != nil { return mcp.NewToolResultError(err.Error()), nil } - alertNumber, err := requiredInt(request, "alert_number") + alertNumber, err := requiredInt(request, "alertNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } diff --git a/pkg/github/code_scanning_test.go b/pkg/github/code_scanning_test.go index 9dd301374..ec4d671ef 100644 --- a/pkg/github/code_scanning_test.go +++ b/pkg/github/code_scanning_test.go @@ -22,8 +22,8 @@ func Test_GetCodeScanningAlert(t *testing.T) { 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, "alert_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alert_number"}) + assert.Contains(t, tool.InputSchema.Properties, "alertNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alertNumber"}) // Setup mock alert for success case mockAlert := &github.Alert{ @@ -50,9 +50,9 @@ func Test_GetCodeScanningAlert(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "alert_number": float64(42), + "owner": "owner", + "repo": "repo", + "alertNumber": float64(42), }, expectError: false, expectedAlert: mockAlert, @@ -69,9 +69,9 @@ func Test_GetCodeScanningAlert(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "alert_number": float64(9999), + "owner": "owner", + "repo": "repo", + "alertNumber": float64(9999), }, expectError: true, expectedErrMsg: "failed to get alert", diff --git a/pkg/github/pullrequests.go b/pkg/github/pullrequests.go index ddec1e6ef..c02336ca0 100644 --- a/pkg/github/pullrequests.go +++ b/pkg/github/pullrequests.go @@ -25,7 +25,7 @@ func getPullRequest(client *github.Client, t translations.TranslationHelperFunc) mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -39,7 +39,7 @@ func getPullRequest(client *github.Client, t translations.TranslationHelperFunc) if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -186,7 +186,7 @@ func mergePullRequest(client *github.Client, t translations.TranslationHelperFun mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -209,7 +209,7 @@ func mergePullRequest(client *github.Client, t translations.TranslationHelperFun if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -266,7 +266,7 @@ func getPullRequestFiles(client *github.Client, t translations.TranslationHelper mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -280,7 +280,7 @@ func getPullRequestFiles(client *github.Client, t translations.TranslationHelper if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -321,7 +321,7 @@ func getPullRequestStatus(client *github.Client, t translations.TranslationHelpe mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -335,7 +335,7 @@ func getPullRequestStatus(client *github.Client, t translations.TranslationHelpe if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -390,11 +390,11 @@ func updatePullRequestBranch(client *github.Client, t translations.TranslationHe mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), - mcp.WithString("expected_head_sha", + mcp.WithString("expectedHeadSha", mcp.Description("The expected SHA of the pull request's HEAD ref"), ), ), @@ -407,11 +407,11 @@ func updatePullRequestBranch(client *github.Client, t translations.TranslationHe if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } - expectedHeadSHA, err := optionalParam[string](request, "expected_head_sha") + expectedHeadSHA, err := optionalParam[string](request, "expectedHeadSha") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -460,7 +460,7 @@ func getPullRequestComments(client *github.Client, t translations.TranslationHel mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -474,7 +474,7 @@ func getPullRequestComments(client *github.Client, t translations.TranslationHel if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -520,7 +520,7 @@ func getPullRequestReviews(client *github.Client, t translations.TranslationHelp mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -534,7 +534,7 @@ func getPullRequestReviews(client *github.Client, t translations.TranslationHelp if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -574,7 +574,7 @@ func createPullRequestReview(client *github.Client, t translations.TranslationHe mcp.Required(), mcp.Description("Repository name"), ), - mcp.WithNumber("pull_number", + mcp.WithNumber("pullNumber", mcp.Required(), mcp.Description("Pull request number"), ), @@ -585,7 +585,7 @@ func createPullRequestReview(client *github.Client, t translations.TranslationHe mcp.Required(), mcp.Description("Review action ('APPROVE', 'REQUEST_CHANGES', 'COMMENT')"), ), - mcp.WithString("commit_id", + mcp.WithString("commitId", mcp.Description("SHA of commit to review"), ), mcp.WithArray("comments", @@ -622,7 +622,7 @@ func createPullRequestReview(client *github.Client, t translations.TranslationHe if err != nil { return mcp.NewToolResultError(err.Error()), nil } - pullNumber, err := requiredInt(request, "pull_number") + pullNumber, err := requiredInt(request, "pullNumber") if err != nil { return mcp.NewToolResultError(err.Error()), nil } @@ -646,7 +646,7 @@ func createPullRequestReview(client *github.Client, t translations.TranslationHe } // Add commit ID if provided - commitID, err := optionalParam[string](request, "commit_id") + commitID, err := optionalParam[string](request, "commitId") if err != nil { return mcp.NewToolResultError(err.Error()), nil } diff --git a/pkg/github/pullrequests_test.go b/pkg/github/pullrequests_test.go index 761de5010..b666e8a8b 100644 --- a/pkg/github/pullrequests_test.go +++ b/pkg/github/pullrequests_test.go @@ -23,8 +23,8 @@ func Test_GetPullRequest(t *testing.T) { 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, "pull_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock PR for success case mockPR := &github.PullRequest{ @@ -62,9 +62,9 @@ func Test_GetPullRequest(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedPR: mockPR, @@ -81,9 +81,9 @@ func Test_GetPullRequest(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(999), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(999), }, expectError: true, expectedErrMsg: "failed to get pull request", @@ -265,11 +265,11 @@ func Test_MergePullRequest(t *testing.T) { 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, "pull_number") + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") assert.Contains(t, tool.InputSchema.Properties, "commit_title") assert.Contains(t, tool.InputSchema.Properties, "commit_message") assert.Contains(t, tool.InputSchema.Properties, "merge_method") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock merge result for success case mockMergeResult := &github.PullRequestMergeResult{ @@ -303,7 +303,7 @@ func Test_MergePullRequest(t *testing.T) { requestArgs: map[string]interface{}{ "owner": "owner", "repo": "repo", - "pull_number": float64(42), + "pullNumber": float64(42), "commit_title": "Merge PR #42", "commit_message": "Merging awesome feature", "merge_method": "squash", @@ -323,9 +323,9 @@ func Test_MergePullRequest(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: true, expectedErrMsg: "failed to merge pull request", @@ -376,8 +376,8 @@ func Test_GetPullRequestFiles(t *testing.T) { 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, "pull_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock PR files for success case mockFiles := []*github.CommitFile{ @@ -416,9 +416,9 @@ func Test_GetPullRequestFiles(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedFiles: mockFiles, @@ -435,9 +435,9 @@ func Test_GetPullRequestFiles(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(999), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(999), }, expectError: true, expectedErrMsg: "failed to get pull request files", @@ -492,8 +492,8 @@ func Test_GetPullRequestStatus(t *testing.T) { 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, "pull_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock PR for successful PR fetch mockPR := &github.PullRequest{ @@ -553,9 +553,9 @@ func Test_GetPullRequestStatus(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedStatus: mockStatus, @@ -572,9 +572,9 @@ func Test_GetPullRequestStatus(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(999), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(999), }, expectError: true, expectedErrMsg: "failed to get pull request", @@ -595,9 +595,9 @@ func Test_GetPullRequestStatus(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: true, expectedErrMsg: "failed to get combined status", @@ -653,9 +653,9 @@ func Test_UpdatePullRequestBranch(t *testing.T) { 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, "pull_number") - assert.Contains(t, tool.InputSchema.Properties, "expected_head_sha") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.Contains(t, tool.InputSchema.Properties, "expectedHeadSha") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock update result for success case mockUpdateResult := &github.PullRequestBranchUpdateResponse{ @@ -684,10 +684,10 @@ func Test_UpdatePullRequestBranch(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "expected_head_sha": "abcd1234", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "expectedHeadSha": "abcd1234", }, expectError: false, expectedUpdateResult: mockUpdateResult, @@ -703,9 +703,9 @@ func Test_UpdatePullRequestBranch(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedUpdateResult: mockUpdateResult, @@ -722,9 +722,9 @@ func Test_UpdatePullRequestBranch(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: true, expectedErrMsg: "failed to update pull request branch", @@ -769,8 +769,8 @@ func Test_GetPullRequestComments(t *testing.T) { 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, "pull_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock PR comments for success case mockComments := []*github.PullRequestComment{ @@ -819,9 +819,9 @@ func Test_GetPullRequestComments(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedComments: mockComments, @@ -838,9 +838,9 @@ func Test_GetPullRequestComments(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(999), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(999), }, expectError: true, expectedErrMsg: "failed to get pull request comments", @@ -896,8 +896,8 @@ func Test_GetPullRequestReviews(t *testing.T) { 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, "pull_number") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number"}) + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber"}) // Setup mock PR reviews for success case mockReviews := []*github.PullRequestReview{ @@ -942,9 +942,9 @@ func Test_GetPullRequestReviews(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), }, expectError: false, expectedReviews: mockReviews, @@ -961,9 +961,9 @@ func Test_GetPullRequestReviews(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(999), + "owner": "owner", + "repo": "repo", + "pullNumber": float64(999), }, expectError: true, expectedErrMsg: "failed to get pull request reviews", @@ -1019,12 +1019,12 @@ func Test_CreatePullRequestReview(t *testing.T) { 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, "pull_number") + assert.Contains(t, tool.InputSchema.Properties, "pullNumber") assert.Contains(t, tool.InputSchema.Properties, "body") assert.Contains(t, tool.InputSchema.Properties, "event") - assert.Contains(t, tool.InputSchema.Properties, "commit_id") + assert.Contains(t, tool.InputSchema.Properties, "commitId") assert.Contains(t, tool.InputSchema.Properties, "comments") - assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pull_number", "event"}) + assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "pullNumber", "event"}) // Setup mock review for success case mockReview := &github.PullRequestReview{ @@ -1061,17 +1061,17 @@ func Test_CreatePullRequestReview(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "body": "Looks good!", - "event": "APPROVE", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "body": "Looks good!", + "event": "APPROVE", }, expectError: false, expectedReview: mockReview, }, { - name: "successful review creation with commit_id", + name: "successful review creation with commitId", mockedClient: mock.NewMockedHTTPClient( mock.WithRequestMatchHandler( mock.PostReposPullsReviewsByOwnerByRepoByPullNumber, @@ -1085,12 +1085,12 @@ func Test_CreatePullRequestReview(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "body": "Looks good!", - "event": "APPROVE", - "commit_id": "abcdef123456", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "body": "Looks good!", + "event": "APPROVE", + "commitId": "abcdef123456", }, expectError: false, expectedReview: mockReview, @@ -1121,11 +1121,11 @@ func Test_CreatePullRequestReview(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "body": "Some issues to fix", - "event": "REQUEST_CHANGES", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "body": "Some issues to fix", + "event": "REQUEST_CHANGES", "comments": []interface{}{ map[string]interface{}{ "path": "file1.go", @@ -1154,10 +1154,10 @@ func Test_CreatePullRequestReview(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "event": "REQUEST_CHANGES", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "event": "REQUEST_CHANGES", "comments": []interface{}{ map[string]interface{}{ "path": "file1.go", @@ -1181,11 +1181,11 @@ func Test_CreatePullRequestReview(t *testing.T) { ), ), requestArgs: map[string]interface{}{ - "owner": "owner", - "repo": "repo", - "pull_number": float64(42), - "body": "Looks good!", - "event": "APPROVE", + "owner": "owner", + "repo": "repo", + "pullNumber": float64(42), + "body": "Looks good!", + "event": "APPROVE", }, expectError: true, expectedErrMsg: "failed to create pull request review", diff --git a/pkg/github/repositories.go b/pkg/github/repositories.go index e4302b889..112eb3740 100644 --- a/pkg/github/repositories.go +++ b/pkg/github/repositories.go @@ -32,7 +32,7 @@ func listCommits(client *github.Client, t translations.TranslationHelperFunc) (t mcp.WithNumber("page", mcp.Description("Page number"), ), - mcp.WithNumber("per_page", + mcp.WithNumber("perPage", mcp.Description("Number of records per page"), ), ), @@ -204,7 +204,7 @@ func createRepository(client *github.Client, t translations.TranslationHelperFun mcp.WithBoolean("private", mcp.Description("Whether repo should be private"), ), - mcp.WithBoolean("auto_init", + mcp.WithBoolean("autoInit", mcp.Description("Initialize with README"), ), ), @@ -221,7 +221,7 @@ func createRepository(client *github.Client, t translations.TranslationHelperFun if err != nil { return mcp.NewToolResultError(err.Error()), nil } - autoInit, err := optionalParam[bool](request, "auto_init") + autoInit, err := optionalParam[bool](request, "autoInit") if err != nil { return mcp.NewToolResultError(err.Error()), nil } diff --git a/pkg/github/repositories_test.go b/pkg/github/repositories_test.go index 4ae450831..bb6579f85 100644 --- a/pkg/github/repositories_test.go +++ b/pkg/github/repositories_test.go @@ -486,7 +486,7 @@ func Test_ListCommits(t *testing.T) { assert.Contains(t, tool.InputSchema.Properties, "repo") assert.Contains(t, tool.InputSchema.Properties, "sha") assert.Contains(t, tool.InputSchema.Properties, "page") - assert.Contains(t, tool.InputSchema.Properties, "per_page") + assert.Contains(t, tool.InputSchema.Properties, "perPage") assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo"}) // Setup mock commits for success case @@ -822,7 +822,7 @@ func Test_CreateRepository(t *testing.T) { assert.Contains(t, tool.InputSchema.Properties, "name") assert.Contains(t, tool.InputSchema.Properties, "description") assert.Contains(t, tool.InputSchema.Properties, "private") - assert.Contains(t, tool.InputSchema.Properties, "auto_init") + assert.Contains(t, tool.InputSchema.Properties, "autoInit") assert.ElementsMatch(t, tool.InputSchema.Required, []string{"name"}) // Setup mock repository response @@ -868,7 +868,7 @@ func Test_CreateRepository(t *testing.T) { "name": "test-repo", "description": "Test repository", "private": true, - "auto_init": true, + "autoInit": true, }, expectError: false, expectedRepo: mockRepo, diff --git a/pkg/github/repository_resource.go b/pkg/github/repository_resource.go index 9fa74c3c6..8efb67e6a 100644 --- a/pkg/github/repository_resource.go +++ b/pkg/github/repository_resource.go @@ -56,7 +56,7 @@ func getRepositoryResourceTagContent(client *github.Client, t translations.Trans // getRepositoryResourcePrContent defines the resource template and handler for getting repository content for a pull request. func getRepositoryResourcePrContent(client *github.Client, t translations.TranslationHelperFunc) (mcp.ResourceTemplate, server.ResourceTemplateHandlerFunc) { return mcp.NewResourceTemplate( - "repo://{owner}/{repo}/refs/pull/{pr_number}/head/contents{/path*}", // Resource template + "repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}", // Resource template t("RESOURCE_REPOSITORY_CONTENT_PR_DESCRIPTION", "Repository Content for specific pull request"), ), repositoryResourceContentsHandler(client) @@ -101,7 +101,7 @@ func repositoryResourceContentsHandler(client *github.Client) func(ctx context.C if ok && len(tag) > 0 { opts.Ref = "refs/tags/" + tag[0] } - prNumber, ok := request.Params.Arguments["pr_number"].([]string) + prNumber, ok := request.Params.Arguments["prNumber"].([]string) if ok && len(prNumber) > 0 { opts.Ref = "refs/pull/" + prNumber[0] + "/head" } diff --git a/pkg/github/repository_resource_test.go b/pkg/github/repository_resource_test.go index 0a5b0b0f0..adad8744d 100644 --- a/pkg/github/repository_resource_test.go +++ b/pkg/github/repository_resource_test.go @@ -279,5 +279,5 @@ func Test_getRepositoryResourceTagContent(t *testing.T) { func Test_getRepositoryResourcePrContent(t *testing.T) { tmpl, _ := getRepositoryResourcePrContent(nil, translations.NullTranslationHelper) - require.Equal(t, "repo://{owner}/{repo}/refs/pull/{pr_number}/head/contents{/path*}", tmpl.URITemplate.Raw()) + require.Equal(t, "repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}", tmpl.URITemplate.Raw()) } diff --git a/pkg/github/search.go b/pkg/github/search.go index e02c3d0c0..f9a20be14 100644 --- a/pkg/github/search.go +++ b/pkg/github/search.go @@ -23,7 +23,7 @@ func searchRepositories(client *github.Client, t translations.TranslationHelperF mcp.WithNumber("page", mcp.Description("Page number for pagination"), ), - mcp.WithNumber("per_page", + mcp.WithNumber("perPage", mcp.Description("Results per page (max 100)"), ), ), diff --git a/pkg/github/search_test.go b/pkg/github/search_test.go index 44513b1f5..2485c4c26 100644 --- a/pkg/github/search_test.go +++ b/pkg/github/search_test.go @@ -22,7 +22,7 @@ func Test_SearchRepositories(t *testing.T) { assert.NotEmpty(t, tool.Description) assert.Contains(t, tool.InputSchema.Properties, "query") assert.Contains(t, tool.InputSchema.Properties, "page") - assert.Contains(t, tool.InputSchema.Properties, "per_page") + assert.Contains(t, tool.InputSchema.Properties, "perPage") assert.ElementsMatch(t, tool.InputSchema.Required, []string{"query"}) // Setup mock search results pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy