Skip to content

Commit 6f7458a

Browse files
committed
Conform list tools
1 parent 989c43f commit 6f7458a

14 files changed

+239
-153
lines changed

README.md

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

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

@@ -177,7 +177,7 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
177177

178178
- `owner`: Repository owner (string, required)
179179
- `repo`: Repository name (string, required)
180-
- `pull_number`: Pull request number (number, required)
180+
- `pullNumber`: Pull request number (number, required)
181181

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

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

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

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

203203
- `owner`: Repository owner (string, required)
204204
- `repo`: Repository name (string, required)
205-
- `pull_number`: Pull request number (number, required)
205+
- `pullNumber`: Pull request number (number, required)
206206

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

209209
- `owner`: Repository owner (string, required)
210210
- `repo`: Repository name (string, required)
211-
- `pull_number`: Pull request number (number, required)
211+
- `pullNumber`: Pull request number (number, required)
212212

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

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

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

222222
- `owner`: Repository owner (string, required)
223223
- `repo`: Repository name (string, required)
224-
- `pull_number`: Pull request number (number, required)
224+
- `pullNumber`: Pull request number (number, required)
225225

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

228228
- `owner`: Repository owner (string, required)
229229
- `repo`: Repository name (string, required)
230-
- `pull_number`: Pull request number (number, required)
230+
- `pullNumber`: Pull request number (number, required)
231231

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

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

242242
- **create_pull_request** - Create a new pull request
@@ -276,14 +276,14 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
276276
- `sort`: Sort field (string, optional)
277277
- `order`: Sort order (string, optional)
278278
- `page`: Page number (number, optional)
279-
- `per_page`: Results per page (number, optional)
279+
- `perPage`: Results per page (number, optional)
280280

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

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

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

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

316316
### Search
317317

@@ -321,22 +321,22 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
321321
- `sort`: Sort field (string, optional)
322322
- `order`: Sort order (string, optional)
323323
- `page`: Page number (number, optional)
324-
- `per_page`: Results per page (number, optional)
324+
- `perPage`: Results per page (number, optional)
325325

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

333333
### Code Scanning
334334

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

337337
- `owner`: Repository owner (string, required)
338338
- `repo`: Repository name (string, required)
339-
- `alert_number`: Alert number (number, required)
339+
- `alertNumber`: Alert number (number, required)
340340

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

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

401401
## 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.18.0
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