Skip to content

Commit 131d9f7

Browse files
committed
Conform list tools
1 parent 10a396b commit 131d9f7

14 files changed

+239
-153
lines changed

README.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
149149
- `direction`: Sort direction ('asc', 'desc') (string, optional)
150150
- `since`: Filter by date (ISO 8601 timestamp) (string, optional)
151151
- `page`: Page number (number, optional)
152-
- `per_page`: Results per page (number, optional)
152+
- `perPage`: Results per page (number, optional)
153153

154154
- **update_issue** - Update an existing issue in a GitHub repository
155155

@@ -176,7 +176,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
176176

177177
- `owner`: Repository owner (string, required)
178178
- `repo`: Repository name (string, required)
179-
- `pull_number`: Pull request number (number, required)
179+
- `pullNumber`: Pull request number (number, required)
180180

181181
- **list_pull_requests** - List and filter repository pull requests
182182

@@ -185,14 +185,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
185185
- `state`: PR state (string, optional)
186186
- `sort`: Sort field (string, optional)
187187
- `direction`: Sort direction (string, optional)
188-
- `per_page`: Results per page (number, optional)
188+
- `perPage`: Results per page (number, optional)
189189
- `page`: Page number (number, optional)
190190

191191
- **merge_pull_request** - Merge a pull request
192192

193193
- `owner`: Repository owner (string, required)
194194
- `repo`: Repository name (string, required)
195-
- `pull_number`: Pull request number (number, required)
195+
- `pullNumber`: Pull request number (number, required)
196196
- `commit_title`: Title for the merge commit (string, optional)
197197
- `commit_message`: Message for the merge commit (string, optional)
198198
- `merge_method`: Merge method (string, optional)
@@ -201,41 +201,41 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
201201

202202
- `owner`: Repository owner (string, required)
203203
- `repo`: Repository name (string, required)
204-
- `pull_number`: Pull request number (number, required)
204+
- `pullNumber`: Pull request number (number, required)
205205

206206
- **get_pull_request_status** - Get the combined status of all status checks for a pull request
207207

208208
- `owner`: Repository owner (string, required)
209209
- `repo`: Repository name (string, required)
210-
- `pull_number`: Pull request number (number, required)
210+
- `pullNumber`: Pull request number (number, required)
211211

212212
- **update_pull_request_branch** - Update a pull request branch with the latest changes from the base branch
213213

214214
- `owner`: Repository owner (string, required)
215215
- `repo`: Repository name (string, required)
216-
- `pull_number`: Pull request number (number, required)
217-
- `expected_head_sha`: The expected SHA of the pull request's HEAD ref (string, optional)
216+
- `pullNumber`: Pull request number (number, required)
217+
- `expectedHeadSha`: The expected SHA of the pull request's HEAD ref (string, optional)
218218

219219
- **get_pull_request_comments** - Get the review comments on a pull request
220220

221221
- `owner`: Repository owner (string, required)
222222
- `repo`: Repository name (string, required)
223-
- `pull_number`: Pull request number (number, required)
223+
- `pullNumber`: Pull request number (number, required)
224224

225225
- **get_pull_request_reviews** - Get the reviews on a pull request
226226

227227
- `owner`: Repository owner (string, required)
228228
- `repo`: Repository name (string, required)
229-
- `pull_number`: Pull request number (number, required)
229+
- `pullNumber`: Pull request number (number, required)
230230

231231
- **create_pull_request_review** - Create a review on a pull request review
232232

233233
- `owner`: Repository owner (string, required)
234234
- `repo`: Repository name (string, required)
235-
- `pull_number`: Pull request number (number, required)
235+
- `pullNumber`: Pull request number (number, required)
236236
- `body`: Review comment text (string, optional)
237237
- `event`: Review action ('APPROVE', 'REQUEST_CHANGES', 'COMMENT') (string, required)
238-
- `commit_id`: SHA of commit to review (string, optional)
238+
- `commitId`: SHA of commit to review (string, optional)
239239
- `comments`: Line-specific comments array of objects, each object with path (string), position (number), and body (string) (array, optional)
240240

241241
- **create_pull_request** - Create a new pull request
@@ -275,14 +275,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
275275
- `sort`: Sort field (string, optional)
276276
- `order`: Sort order (string, optional)
277277
- `page`: Page number (number, optional)
278-
- `per_page`: Results per page (number, optional)
278+
- `perPage`: Results per page (number, optional)
279279

280280
- **create_repository** - Create a new GitHub repository
281281

282282
- `name`: Repository name (string, required)
283283
- `description`: Repository description (string, optional)
284284
- `private`: Whether the repository is private (boolean, optional)
285-
- `auto_init`: Auto-initialize with README (boolean, optional)
285+
- `autoInit`: Auto-initialize with README (boolean, optional)
286286

287287
- **get_file_contents** - Get contents of a file or directory
288288

@@ -310,7 +310,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
310310
- `sha`: Branch name, tag, or commit SHA (string, optional)
311311
- `path`: Only commits containing this file path (string, optional)
312312
- `page`: Page number (number, optional)
313-
- `per_page`: Results per page (number, optional)
313+
- `perPage`: Results per page (number, optional)
314314

315315
### Search
316316

@@ -320,22 +320,22 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
320320
- `sort`: Sort field (string, optional)
321321
- `order`: Sort order (string, optional)
322322
- `page`: Page number (number, optional)
323-
- `per_page`: Results per page (number, optional)
323+
- `perPage`: Results per page (number, optional)
324324

325325
- **search_users** - Search for GitHub users
326326
- `query`: Search query (string, required)
327327
- `sort`: Sort field (string, optional)
328328
- `order`: Sort order (string, optional)
329329
- `page`: Page number (number, optional)
330-
- `per_page`: Results per page (number, optional)
330+
- `perPage`: Results per page (number, optional)
331331

332332
### Code Scanning
333333

334334
- **get_code_scanning_alert** - Get a code scanning alert
335335

336336
- `owner`: Repository owner (string, required)
337337
- `repo`: Repository name (string, required)
338-
- `alert_number`: Alert number (number, required)
338+
- `alertNumber`: Alert number (number, required)
339339

340340
- **list_code_scanning_alerts** - List code scanning alerts for a repository
341341
- `owner`: Repository owner (string, required)
@@ -390,11 +390,11 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
390390
- **Get Repository Content for a Specific Pull Request**
391391
Retrieves the content of a repository at a specific path for a given pull request.
392392

393-
- **Template**: `repo://{owner}/{repo}/refs/pull/{pr_number}/head/contents{/path*}`
393+
- **Template**: `repo://{owner}/{repo}/refs/pull/{prNumber}/head/contents{/path*}`
394394
- **Parameters**:
395395
- `owner`: Repository owner (string, required)
396396
- `repo`: Repository name (string, required)
397-
- `pr_number`: Pull request number (string, required)
397+
- `prNumber`: Pull request number (string, required)
398398
- `path`: File or directory path (string, optional)
399399

400400
## License

cmd/mcpcurl/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Use "mcpcurl tools [command] --help" for more information about a command.
7272
Get help for a specific tool:
7373

7474
```bash
75-
% ./mcpcurl --stdio-server-cmd "docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN mcp/github" tools get_issue --help
75+
% ./mcpcurl --stdio-server-cmd "docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN mcp/github" tools get_issue --help
7676
Get details of a specific issue in a GitHub repository.
7777

7878
Usage:

conformance/conformance_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"bufio"
77
"context"
88
"encoding/json"
9+
"errors"
910
"fmt"
1011
"io"
1112
"os"
@@ -17,6 +18,8 @@ import (
1718
"github.com/docker/docker/api/types/network"
1819
"github.com/docker/docker/client"
1920
"github.com/docker/docker/pkg/stdcopy"
21+
"github.com/google/go-cmp/cmp"
22+
"github.com/google/go-cmp/cmp/cmpopts"
2023
"github.com/stretchr/testify/require"
2124
)
2225

@@ -230,6 +233,69 @@ func diffNonNilFields(a, b interface{}, path string) string {
230233
return sb.String()
231234
}
232235

236+
func TestListTools(t *testing.T) {
237+
anthropicServer := start(t, anthropic)
238+
githubServer := start(t, github)
239+
240+
req := listToolsRequest{
241+
JSONRPC: "2.0",
242+
ID: 1,
243+
Method: "tools/list",
244+
}
245+
246+
require.NoError(t, anthropicServer.send(req))
247+
248+
var anthropicListToolsResponse listToolsResponse
249+
require.NoError(t, anthropicServer.receive(&anthropicListToolsResponse))
250+
251+
require.NoError(t, githubServer.send(req))
252+
253+
var ghListToolsResponse listToolsResponse
254+
require.NoError(t, githubServer.receive(&ghListToolsResponse))
255+
256+
require.NoError(t, isToolListSubset(anthropicListToolsResponse.Result, ghListToolsResponse.Result), "expected the github list tools response to be a subset of the anthropic list tools response")
257+
}
258+
259+
func isToolListSubset(subset, superset listToolsResult) error {
260+
// Build a map from tool name to Tool from the superset
261+
supersetMap := make(map[string]tool)
262+
for _, tool := range superset.Tools {
263+
supersetMap[tool.Name] = tool
264+
}
265+
266+
var err error
267+
for _, tool := range subset.Tools {
268+
sup, ok := supersetMap[tool.Name]
269+
if !ok {
270+
return fmt.Errorf("tool %q not found in superset", tool.Name)
271+
}
272+
273+
// Intentionally ignore the description fields because there are lots of slight differences.
274+
// if tool.Description != sup.Description {
275+
// return fmt.Errorf("description mismatch for tool %q, got %q expected %q", tool.Name, tool.Description, sup.Description)
276+
// }
277+
278+
// Ignore any description fields within the input schema properties for the same reason
279+
ignoreDescOpt := cmp.FilterPath(func(p cmp.Path) bool {
280+
// Look for a field named "Properties" somewhere in the path
281+
for _, ps := range p {
282+
if sf, ok := ps.(cmp.StructField); ok && sf.Name() == "Properties" {
283+
return true
284+
}
285+
}
286+
return false
287+
}, cmpopts.IgnoreMapEntries(func(k string, _ any) bool {
288+
return k == "description"
289+
}))
290+
291+
if diff := cmp.Diff(tool.InputSchema, sup.InputSchema, ignoreDescOpt); diff != "" {
292+
err = errors.Join(err, fmt.Errorf("inputSchema mismatch for tool %q:\n%s", tool.Name, diff))
293+
}
294+
}
295+
296+
return err
297+
}
298+
233299
type serverStartResult struct {
234300
server server
235301
err error
@@ -348,3 +414,22 @@ type serverInfo struct {
348414
Name string `json:"name"`
349415
Version string `json:"version"`
350416
}
417+
418+
type listToolsRequest = jsonRPRCRequest[struct{}]
419+
420+
type listToolsResponse = jsonRPRCResponse[listToolsResult]
421+
422+
type listToolsResult struct {
423+
Tools []tool `json:"tools"`
424+
}
425+
type tool struct {
426+
Name string `json:"name"`
427+
Description string `json:"description,omitempty"`
428+
InputSchema inputSchema `json:"inputSchema"`
429+
}
430+
431+
type inputSchema struct {
432+
Type string `json:"type"`
433+
Properties map[string]any `json:"properties,omitempty"`
434+
Required []string `json:"required,omitempty"`
435+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.23.7
55
require (
66
github.com/aws/smithy-go v1.22.3
77
github.com/docker/docker v28.0.4+incompatible
8+
github.com/google/go-cmp v0.7.0
89
github.com/google/go-github/v69 v69.2.0
910
github.com/mark3labs/mcp-go v0.14.1
1011
github.com/migueleliasweb/go-github-mock v1.1.0

pkg/github/code_scanning.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func getCodeScanningAlert(client *github.Client, t translations.TranslationHelpe
2424
mcp.Required(),
2525
mcp.Description("The name of the repository."),
2626
),
27-
mcp.WithNumber("alert_number",
27+
mcp.WithNumber("alertNumber",
2828
mcp.Required(),
2929
mcp.Description("The number of the alert."),
3030
),
@@ -38,7 +38,7 @@ func getCodeScanningAlert(client *github.Client, t translations.TranslationHelpe
3838
if err != nil {
3939
return mcp.NewToolResultError(err.Error()), nil
4040
}
41-
alertNumber, err := requiredInt(request, "alert_number")
41+
alertNumber, err := requiredInt(request, "alertNumber")
4242
if err != nil {
4343
return mcp.NewToolResultError(err.Error()), nil
4444
}

pkg/github/code_scanning_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ func Test_GetCodeScanningAlert(t *testing.T) {
2222
assert.NotEmpty(t, tool.Description)
2323
assert.Contains(t, tool.InputSchema.Properties, "owner")
2424
assert.Contains(t, tool.InputSchema.Properties, "repo")
25-
assert.Contains(t, tool.InputSchema.Properties, "alert_number")
26-
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alert_number"})
25+
assert.Contains(t, tool.InputSchema.Properties, "alertNumber")
26+
assert.ElementsMatch(t, tool.InputSchema.Required, []string{"owner", "repo", "alertNumber"})
2727

2828
// Setup mock alert for success case
2929
mockAlert := &github.Alert{
@@ -50,9 +50,9 @@ func Test_GetCodeScanningAlert(t *testing.T) {
5050
),
5151
),
5252
requestArgs: map[string]interface{}{
53-
"owner": "owner",
54-
"repo": "repo",
55-
"alert_number": float64(42),
53+
"owner": "owner",
54+
"repo": "repo",
55+
"alertNumber": float64(42),
5656
},
5757
expectError: false,
5858
expectedAlert: mockAlert,
@@ -69,9 +69,9 @@ func Test_GetCodeScanningAlert(t *testing.T) {
6969
),
7070
),
7171
requestArgs: map[string]interface{}{
72-
"owner": "owner",
73-
"repo": "repo",
74-
"alert_number": float64(9999),
72+
"owner": "owner",
73+
"repo": "repo",
74+
"alertNumber": float64(9999),
7575
},
7676
expectError: true,
7777
expectedErrMsg: "failed to get alert",

0 commit comments

Comments
 (0)
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