🌐 AI搜索 & 代理 主页
Skip to content

Commit d0e8fd9

Browse files
Merge branch 'main' into add-logging-stack
2 parents 9af271a + adaa6a1 commit d0e8fd9

File tree

17 files changed

+475
-73
lines changed

17 files changed

+475
-73
lines changed

README.md

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -726,12 +726,12 @@ The following sets of tools are available:
726726
- **issue_read** - Get issue details
727727
- `issue_number`: The number of the issue (number, required)
728728
- `method`: The read operation to perform on a single issue.
729-
Options are:
730-
1. get - Get details of a specific issue.
731-
2. get_comments - Get issue comments.
732-
3. get_sub_issues - Get sub-issues of the issue.
733-
4. get_labels - Get labels assigned to the issue.
734-
(string, required)
729+
Options are:
730+
1. get - Get details of a specific issue.
731+
2. get_comments - Get issue comments.
732+
3. get_sub_issues - Get sub-issues of the issue.
733+
4. get_labels - Get labels assigned to the issue.
734+
(string, required)
735735
- `owner`: The owner of the repository (string, required)
736736
- `page`: Page number for pagination (min 1) (number, optional)
737737
- `perPage`: Results per page for pagination (min 1, max 100) (number, optional)
@@ -744,10 +744,10 @@ Options are:
744744
- `issue_number`: Issue number to update (number, optional)
745745
- `labels`: Labels to apply to this issue (string[], optional)
746746
- `method`: Write operation to perform on a single issue.
747-
Options are:
748-
- 'create' - creates a new issue.
749-
- 'update' - updates an existing issue.
750-
(string, required)
747+
Options are:
748+
- 'create' - creates a new issue.
749+
- 'update' - updates an existing issue.
750+
(string, required)
751751
- `milestone`: Milestone number (number, optional)
752752
- `owner`: Repository owner (string, required)
753753
- `repo`: Repository name (string, required)
@@ -784,11 +784,11 @@ Options are:
784784
- `before_id`: The ID of the sub-issue to be prioritized before (either after_id OR before_id should be specified) (number, optional)
785785
- `issue_number`: The number of the parent issue (number, required)
786786
- `method`: The action to perform on a single sub-issue
787-
Options are:
788-
- 'add' - add a sub-issue to a parent issue in a GitHub repository.
789-
- 'remove' - remove a sub-issue from a parent issue in a GitHub repository.
790-
- 'reprioritize' - change the order of sub-issues within a parent issue in a GitHub repository. Use either 'after_id' or 'before_id' to specify the new position.
791-
(string, required)
787+
Options are:
788+
- 'add' - add a sub-issue to a parent issue in a GitHub repository.
789+
- 'remove' - remove a sub-issue from a parent issue in a GitHub repository.
790+
- 'reprioritize' - change the order of sub-issues within a parent issue in a GitHub repository. Use either 'after_id' or 'before_id' to specify the new position.
791+
(string, required)
792792
- `owner`: Repository owner (string, required)
793793
- `replace_parent`: When true, replaces the sub-issue's current parent issue. Use with 'add' method only. (boolean, optional)
794794
- `repo`: Repository name (string, required)
@@ -986,15 +986,15 @@ Options are:
986986

987987
- **pull_request_read** - Get details for a single pull request
988988
- `method`: Action to specify what pull request data needs to be retrieved from GitHub.
989-
Possible options:
990-
1. get - Get details of a specific pull request.
991-
2. get_diff - Get the diff of a pull request.
992-
3. get_status - Get status of a head commit in a pull request. This reflects status of builds and checks.
993-
4. get_files - Get the list of files changed in a pull request. Use with pagination parameters to control the number of results returned.
994-
5. get_review_comments - Get the review comments on a pull request. They are comments made on a portion of the unified diff during a pull request review. Use with pagination parameters to control the number of results returned.
995-
6. get_reviews - Get the reviews on a pull request. When asked for review comments, use get_review_comments method.
996-
7. get_comments - Get comments on a pull request. Use this if user doesn't specifically want review comments. Use with pagination parameters to control the number of results returned.
997-
(string, required)
989+
Possible options:
990+
1. get - Get details of a specific pull request.
991+
2. get_diff - Get the diff of a pull request.
992+
3. get_status - Get status of a head commit in a pull request. This reflects status of builds and checks.
993+
4. get_files - Get the list of files changed in a pull request. Use with pagination parameters to control the number of results returned.
994+
5. get_review_comments - Get the review comments on a pull request. They are comments made on a portion of the unified diff during a pull request review. Use with pagination parameters to control the number of results returned.
995+
6. get_reviews - Get the reviews on a pull request. When asked for review comments, use get_review_comments method.
996+
7. get_comments - Get comments on a pull request. Use this if user doesn't specifically want review comments. Use with pagination parameters to control the number of results returned.
997+
(string, required)
998998
- `owner`: Repository owner (string, required)
999999
- `page`: Page number for pagination (min 1) (number, optional)
10001000
- `perPage`: Results per page for pagination (min 1, max 100) (number, optional)

cmd/github-mcp-server/generate_docs.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,9 @@ func generateToolDoc(tool mcp.Tool) string {
273273

274274
description = prop.Description
275275

276+
// Indent any continuation lines in the description to maintain markdown formatting
277+
description = indentMultilineDescription(description, " ")
278+
276279
paramLine := fmt.Sprintf(" - `%s`: %s (%s, %s)", propName, description, typeStr, requiredStr)
277280
lines = append(lines, paramLine)
278281
}
@@ -292,6 +295,19 @@ func contains(slice []string, item string) bool {
292295
return false
293296
}
294297

298+
// indentMultilineDescription adds the specified indent to all lines after the first line.
299+
// This ensures that multi-line descriptions maintain proper markdown list formatting.
300+
func indentMultilineDescription(description, indent string) string {
301+
lines := strings.Split(description, "\n")
302+
if len(lines) <= 1 {
303+
return description
304+
}
305+
for i := 1; i < len(lines); i++ {
306+
lines[i] = indent + lines[i]
307+
}
308+
return strings.Join(lines, "\n")
309+
}
310+
295311
func replaceSection(content, startMarker, endMarker, newContent string) string {
296312
startPattern := fmt.Sprintf(`<!-- %s -->`, regexp.QuoteMeta(startMarker))
297313
endPattern := fmt.Sprintf(`<!-- %s -->`, regexp.QuoteMeta(endMarker))

docs/remote-server.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Below is a table of available toolsets for the remote GitHub MCP Server. Each to
1919
<!-- START AUTOMATED TOOLSETS -->
2020
| Name | Description | API URL | 1-Click Install (VS Code) | Read-only Link | 1-Click Read-only Install (VS Code) |
2121
|----------------|--------------------------------------------------|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
22-
| Default | ["Default" toolset](../README.md#default-toolset) | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2F%22%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Freadonly%22%7D) |
22+
| all | All available GitHub MCP tools | https://api.githubcopilot.com/mcp/ | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2F%22%7D) | [read-only](https://api.githubcopilot.com/mcp/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=github&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Freadonly%22%7D) |
2323
| Actions | GitHub Actions workflows and CI/CD operations | https://api.githubcopilot.com/mcp/x/actions | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/actions/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-actions&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Factions%2Freadonly%22%7D) |
2424
| Code Security | Code security related tools, such as GitHub Code Scanning | https://api.githubcopilot.com/mcp/x/code_security | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/code_security/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-code_security&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fcode_security%2Freadonly%22%7D) |
2525
| Dependabot | Dependabot tools | https://api.githubcopilot.com/mcp/x/dependabot | [Install](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%22%7D) | [read-only](https://api.githubcopilot.com/mcp/x/dependabot/readonly) | [Install read-only](https://insiders.vscode.dev/redirect/mcp/install?name=gh-dependabot&config=%7B%22type%22%3A%20%22http%22%2C%22url%22%3A%20%22https%3A%2F%2Fapi.githubcopilot.com%2Fmcp%2Fx%2Fdependabot%2Freadonly%22%7D) |

internal/ghmcp/server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
102102

103103
enabledToolsets := cfg.EnabledToolsets
104104

105-
// If dynamic toolsets are enabled, remove "all" from the enabled toolsets
105+
// If dynamic toolsets are enabled, remove "all" and "default" from the enabled toolsets
106106
if cfg.DynamicToolsets {
107107
enabledToolsets = github.RemoveToolset(enabledToolsets, github.ToolsetMetadataAll.ID)
108+
enabledToolsets = github.RemoveToolset(enabledToolsets, github.ToolsetMetadataDefault.ID)
108109
}
109110

110111
// Clean up the passed toolsets
@@ -182,8 +183,8 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
182183

183184
// Register specific tools if configured
184185
if len(cfg.EnabledTools) > 0 {
185-
// Clean and validate tool names
186186
enabledTools := github.CleanTools(cfg.EnabledTools)
187+
enabledTools, _ = tsg.ResolveToolAliases(enabledTools)
187188

188189
// Register the specified tools (additive to any toolsets already enabled)
189190
err = tsg.RegisterSpecificTools(ghServer, enabledTools, cfg.ReadOnly)
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// deprecated_tool_aliases.go
2+
package github
3+
4+
// DeprecatedToolAliases maps old tool names to their new canonical names.
5+
// When tools are renamed, add an entry here to maintain backward compatibility.
6+
// Users referencing the old name will receive the new tool with a deprecation warning.
7+
//
8+
// Example:
9+
//
10+
// "get_issue": "issue_read",
11+
// "create_pr": "pull_request_create",
12+
var DeprecatedToolAliases = map[string]string{
13+
// Add entries as tools are renamed
14+
}

pkg/github/issues.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,11 +1385,14 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
13851385
return utils.NewToolResultError(err.Error()), nil, nil
13861386
}
13871387

1388-
// If the state has a value, cast into an array of strings
1388+
// Normalize and filter by state
1389+
state = strings.ToUpper(state)
13891390
var states []githubv4.IssueState
1390-
if state != "" {
1391-
states = append(states, githubv4.IssueState(state))
1392-
} else {
1391+
1392+
switch state {
1393+
case "OPEN", "CLOSED":
1394+
states = []githubv4.IssueState{githubv4.IssueState(state)}
1395+
default:
13931396
states = []githubv4.IssueState{githubv4.IssueStateOpen, githubv4.IssueStateClosed}
13941397
}
13951398

@@ -1409,13 +1412,21 @@ func ListIssues(getGQLClient GetGQLClientFn, t translations.TranslationHelperFun
14091412
return utils.NewToolResultError(err.Error()), nil, nil
14101413
}
14111414

1412-
// These variables are required for the GraphQL query to be set by default
1413-
// If orderBy is empty, default to CREATED_AT
1414-
if orderBy == "" {
1415+
// Normalize and validate orderBy
1416+
orderBy = strings.ToUpper(orderBy)
1417+
switch orderBy {
1418+
case "CREATED_AT", "UPDATED_AT", "COMMENTS":
1419+
// Valid, keep as is
1420+
default:
14151421
orderBy = "CREATED_AT"
14161422
}
1417-
// If direction is empty, default to DESC
1418-
if direction == "" {
1423+
1424+
// Normalize and validate direction
1425+
direction = strings.ToUpper(direction)
1426+
switch direction {
1427+
case "ASC", "DESC":
1428+
// Valid, keep as is
1429+
default:
14191430
direction = "DESC"
14201431
}
14211432

pkg/github/issues_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,6 +1187,16 @@ func Test_ListIssues(t *testing.T) {
11871187
expectError: false,
11881188
expectedCount: 2,
11891189
},
1190+
{
1191+
name: "filter by open state - lc",
1192+
reqParams: map[string]interface{}{
1193+
"owner": "owner",
1194+
"repo": "repo",
1195+
"state": "open",
1196+
},
1197+
expectError: false,
1198+
expectedCount: 2,
1199+
},
11901200
{
11911201
name: "filter by closed state",
11921202
reqParams: map[string]interface{}{
@@ -1233,6 +1243,9 @@ func Test_ListIssues(t *testing.T) {
12331243
case "filter by open state":
12341244
matcher := githubv4mock.NewQueryMatcher(qBasicNoLabels, varsOpenOnly, mockResponseOpenOnly)
12351245
httpClient = githubv4mock.NewMockedHTTPClient(matcher)
1246+
case "filter by open state - lc":
1247+
matcher := githubv4mock.NewQueryMatcher(qBasicNoLabels, varsOpenOnly, mockResponseOpenOnly)
1248+
httpClient = githubv4mock.NewMockedHTTPClient(matcher)
12361249
case "filter by closed state":
12371250
matcher := githubv4mock.NewQueryMatcher(qBasicNoLabels, varsClosedOnly, mockResponseClosedOnly)
12381251
httpClient = githubv4mock.NewMockedHTTPClient(matcher)

pkg/github/repositories.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,8 @@ func CreateOrUpdateFile(getClient GetClientFn, t translations.TranslationHelperF
402402
if err != nil {
403403
return nil, nil, fmt.Errorf("failed to get GitHub client: %w", err)
404404
}
405+
406+
path = strings.TrimPrefix(path, "/")
405407
fileContent, resp, err := client.Repositories.CreateFile(ctx, owner, repo, path, opts)
406408
if err != nil {
407409
return ghErrors.NewGitHubAPIErrorResponse(ctx,

pkg/github/tools.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,8 @@ func DefaultToolsetGroup(readOnly bool,
388388
tsg.AddToolset(stargazers)
389389
tsg.AddToolset(labels)
390390

391+
tsg.AddDeprecatedToolAliases(DeprecatedToolAliases)
392+
391393
return tsg
392394
}
393395

pkg/toolsets/toolsets.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,16 +192,24 @@ func (t *Toolset) AddReadTools(tools ...ServerTool) *Toolset {
192192
}
193193

194194
type ToolsetGroup struct {
195-
Toolsets map[string]*Toolset
196-
everythingOn bool
197-
readOnly bool
195+
Toolsets map[string]*Toolset
196+
deprecatedAliases map[string]string
197+
everythingOn bool
198+
readOnly bool
198199
}
199200

200201
func NewToolsetGroup(readOnly bool) *ToolsetGroup {
201202
return &ToolsetGroup{
202-
Toolsets: make(map[string]*Toolset),
203-
everythingOn: false,
204-
readOnly: readOnly,
203+
Toolsets: make(map[string]*Toolset),
204+
deprecatedAliases: make(map[string]string),
205+
everythingOn: false,
206+
readOnly: readOnly,
207+
}
208+
}
209+
210+
func (tg *ToolsetGroup) AddDeprecatedToolAliases(aliases map[string]string) {
211+
for oldName, newName := range aliases {
212+
tg.deprecatedAliases[oldName] = newName
205213
}
206214
}
207215

@@ -307,6 +315,26 @@ func NewToolDoesNotExistError(name string) *ToolDoesNotExistError {
307315
return &ToolDoesNotExistError{Name: name}
308316
}
309317

318+
// ResolveToolAliases resolves deprecated tool aliases to their canonical names.
319+
// It logs a warning to stderr for each deprecated alias that is resolved.
320+
// Returns:
321+
// - resolved: tool names with aliases replaced by canonical names
322+
// - aliasesUsed: map of oldName → newName for each alias that was resolved
323+
func (tg *ToolsetGroup) ResolveToolAliases(toolNames []string) (resolved []string, aliasesUsed map[string]string) {
324+
resolved = make([]string, 0, len(toolNames))
325+
aliasesUsed = make(map[string]string)
326+
for _, toolName := range toolNames {
327+
if canonicalName, isAlias := tg.deprecatedAliases[toolName]; isAlias {
328+
fmt.Fprintf(os.Stderr, "Warning: tool %q is deprecated, use %q instead\n", toolName, canonicalName)
329+
aliasesUsed[toolName] = canonicalName
330+
resolved = append(resolved, canonicalName)
331+
} else {
332+
resolved = append(resolved, toolName)
333+
}
334+
}
335+
return resolved, aliasesUsed
336+
}
337+
310338
// FindToolByName searches all toolsets (enabled or disabled) for a tool by name.
311339
// Returns the tool, its parent toolset name, and an error if not found.
312340
func (tg *ToolsetGroup) FindToolByName(toolName string) (*ServerTool, string, error) {

0 commit comments

Comments
 (0)