Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,13 @@ The following sets of tools are available:

<summary>Discussions</summary>

- **create_discussion** - Create discussion
- `body`: Discussion body text in markdown format (string, required)
- `categoryId`: Category ID where the discussion should be created (obtainable via list_discussion_categories) (string, required)
- `owner`: Repository owner (string, required)
- `repo`: Repository name. If not provided, the discussion will be created at the organisation level. (string, optional)
- `title`: Discussion title (string, required)

- **get_discussion** - Get discussion
- `discussionNumber`: Discussion Number (number, required)
- `owner`: Repository owner (string, required)
Expand Down
2 changes: 1 addition & 1 deletion docs/remote-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Below is a table of available toolsets for the remote GitHub MCP Server. Each to
<!-- START AUTOMATED TOOLSETS -->
| Name | Description | API URL | 1-Click Install (VS Code) | Read-only Link | 1-Click Read-only Install (VS Code) |
|----------------|--------------------------------------------------|-------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 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) |
| 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) |
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change from "Default" to "all" appears to be unrelated to adding the create_discussion tool. If this is an intentional update to the remote server documentation, it should be in a separate commit or PR. Otherwise, this line should remain as "Default" to match line 91 which still references "Default toolset".

Suggested change
| 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) |
| Default | 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) |

Copilot uses AI. Check for mistakes.
| 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) |
| 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) |
| 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) |
Expand Down
38 changes: 38 additions & 0 deletions pkg/github/__toolsnaps__/create_discussion.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"annotations": {
"title": "Create discussion"
},
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toolsnap is missing the readOnlyHint field that should be set to false for write operations. This needs to be regenerated after adding ReadOnlyHint: false to the tool annotations in discussions.go. Run UPDATE_TOOLSNAPS=true go test ./... to update the snapshot after fixing the code.

Suggested change
},
},
"readOnlyHint": false,

Copilot uses AI. Check for mistakes.
"description": "Create a new discussion in a repository or organisation.",
"inputSchema": {
"type": "object",
"required": [
"owner",
"categoryId",
"title",
"body"
],
"properties": {
"body": {
"type": "string",
"description": "Discussion body text in markdown format"
},
"categoryId": {
"type": "string",
"description": "Category ID where the discussion should be created (obtainable via list_discussion_categories)"
},
"owner": {
"type": "string",
"description": "Repository owner"
},
"repo": {
"type": "string",
"description": "Repository name. If not provided, the discussion will be created at the organisation level."
},
"title": {
"type": "string",
"description": "Discussion title"
}
}
},
"name": "create_discussion"
}
113 changes: 113 additions & 0 deletions pkg/github/discussions.go
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,119 @@ func GetDiscussionComments(getGQLClient GetGQLClientFn, t translations.Translati
}
}

func CreateDiscussion(getGQLClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
return mcp.Tool{
Name: "create_discussion",
Description: t("TOOL_CREATE_DISCUSSION_DESCRIPTION", "Create a new discussion in a repository or organisation."),
Annotations: &mcp.ToolAnnotations{
Title: t("TOOL_CREATE_DISCUSSION_USER_TITLE", "Create discussion"),
Copy link

Copilot AI Dec 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing ReadOnlyHint: false annotation. Write operations like create_discussion should explicitly set ReadOnlyHint: false to indicate they perform mutations. This is consistent with other write tools in the codebase (see create_gist, label_write, create_issue, etc.).

Suggested change
Title: t("TOOL_CREATE_DISCUSSION_USER_TITLE", "Create discussion"),
Title: t("TOOL_CREATE_DISCUSSION_USER_TITLE", "Create discussion"),
ReadOnlyHint: mcp.BoolPtr(false),

Copilot uses AI. Check for mistakes.
},
InputSchema: &jsonschema.Schema{
Type: "object",
Properties: map[string]*jsonschema.Schema{
"owner": {
Type: "string",
Description: "Repository owner",
},
"repo": {
Type: "string",
Description: "Repository name. If not provided, the discussion will be created at the organisation level.",
},
"categoryId": {
Type: "string",
Description: "Category ID where the discussion should be created (obtainable via list_discussion_categories)",
},
"title": {
Type: "string",
Description: "Discussion title",
},
"body": {
Type: "string",
Description: "Discussion body text in markdown format",
},
},
Required: []string{"owner", "categoryId", "title", "body"},
},
},
func(ctx context.Context, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) {
owner, err := RequiredParam[string](args, "owner")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
repo, err := OptionalParam[string](args, "repo")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}
// when not provided, default to the .github repository
// this will create the discussion at the organisation level
if repo == "" {
repo = ".github"
}

categoryID, err := RequiredParam[string](args, "categoryId")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}

title, err := RequiredParam[string](args, "title")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}

body, err := RequiredParam[string](args, "body")
if err != nil {
return utils.NewToolResultError(err.Error()), nil, nil
}

client, err := getGQLClient(ctx)
if err != nil {
return utils.NewToolResultError(fmt.Sprintf("failed to get GitHub GQL client: %v", err)), nil, nil
}

// Get repository ID first
repoID, err := getRepositoryID(ctx, client, owner, repo)
if err != nil {
return utils.NewToolResultError(fmt.Sprintf("failed to get repository ID: %v", err)), nil, nil
}

// Define the mutation
var mutation struct {
CreateDiscussion struct {
Discussion struct {
ID githubv4.ID
Number githubv4.Int
URL githubv4.String
}
} `graphql:"createDiscussion(input: $input)"`
}

input := githubv4.CreateDiscussionInput{
RepositoryID: repoID,
CategoryID: githubv4.ID(categoryID),
Title: githubv4.String(title),
Body: githubv4.String(body),
}

if err := client.Mutate(ctx, &mutation, input, nil); err != nil {
return utils.NewToolResultError(fmt.Sprintf("failed to create discussion: %v", err)), nil, nil
}

// Build response
response := map[string]interface{}{
"id": fmt.Sprint(mutation.CreateDiscussion.Discussion.ID),
"number": int(mutation.CreateDiscussion.Discussion.Number),
"url": string(mutation.CreateDiscussion.Discussion.URL),
}

out, err := json.Marshal(response)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal discussion: %w", err)
}

return utils.NewToolResultText(string(out)), nil, nil
}
}

func ListDiscussionCategories(getGQLClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, mcp.ToolHandlerFor[map[string]any, any]) {
return mcp.Tool{
Name: "list_discussion_categories",
Expand Down
Loading