Skip to content
Merged
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
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,9 @@ The following sets of tools are available:
(string, required)
- `milestone`: Milestone number (number, optional)
- `owner`: Repository owner (string, required)
- `parent_issue_number`: Issue number of the parent issue. Only used when method is 'create' and cannot be combined with issue_fields. The new issue is created and attached to this parent in the same operation. (number, optional)
- `parent_owner`: Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `parent_repo`: Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `repo`: Repository name (string, required)
- `state`: New state (string, optional)
- `state_reason`: Reason for the state change. Ignored unless state is changed. (string, optional)
Expand Down
6 changes: 6 additions & 0 deletions docs/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ runtime behavior (such as output formatting) won't appear here.
(string, required)
- `milestone`: Milestone number (number, optional)
- `owner`: Repository owner (string, required)
- `parent_issue_number`: Issue number of the parent issue. Only used when method is 'create' and cannot be combined with issue_fields. The new issue is created and attached to this parent in the same operation. (number, optional)
- `parent_owner`: Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `parent_repo`: Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `repo`: Repository name (string, required)
- `state`: New state (string, optional)
- `state_reason`: Reason for the state change. Ignored unless state is changed. (string, optional)
Expand Down Expand Up @@ -122,6 +125,9 @@ runtime behavior (such as output formatting) won't appear here.
- **Required OAuth Scopes**: `repo`
- `body`: Issue body content (optional) (string, optional)
- `owner`: Repository owner (username or organization) (string, required)
- `parent_issue_number`: Issue number of the parent issue. The new issue is created and attached to this parent in the same operation. (number, optional)
- `parent_owner`: Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when parent_issue_number is provided. (string, optional)
- `parent_repo`: Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when parent_issue_number is provided. (string, optional)
- `repo`: Repository name (string, required)
- `title`: Issue title (string, required)

Expand Down
3 changes: 3 additions & 0 deletions docs/insiders-features.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ The list below is generated from the Go source. It covers tool **inventory and s
(string, required)
- `milestone`: Milestone number (number, optional)
- `owner`: Repository owner (string, required)
- `parent_issue_number`: Issue number of the parent issue. Only used when method is 'create' and cannot be combined with issue_fields. The new issue is created and attached to this parent in the same operation. (number, optional)
- `parent_owner`: Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `parent_repo`: Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided. (string, optional)
- `repo`: Repository name (string, required)
- `state`: New state (string, optional)
- `state_reason`: Reason for the state change. Ignored unless state is changed. (string, optional)
Expand Down
80 changes: 80 additions & 0 deletions e2e/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,86 @@ func TestToolsets(t *testing.T) {
require.False(t, toolsContains("pull_request_read"), "expected not to find 'pull_request_read' tool")
}

func TestCreateIssueWithParent(t *testing.T) {
t.Parallel()

mcpClient := setupMCPClient(t)
ctx := context.Background()

t.Log("Getting current user...")
resp, err := mcpClient.CallTool(ctx, &mcp.CallToolParams{Name: "get_me"})
require.NoError(t, err, "expected to call 'get_me' tool successfully")
require.False(t, resp.IsError, fmt.Sprintf("expected result not to be an error: %+v", resp))
require.Len(t, resp.Content, 1, "expected content to have one item")

textContent, ok := resp.Content[0].(*mcp.TextContent)
require.True(t, ok, "expected content to be of type TextContent")

var trimmedGetMeText struct {
Login string `json:"login"`
}
err = json.Unmarshal([]byte(textContent.Text), &trimmedGetMeText)
require.NoError(t, err, "expected to unmarshal text content successfully")
currentOwner := trimmedGetMeText.Login

repoName := fmt.Sprintf("github-mcp-server-e2e-%s-%d", t.Name(), time.Now().UnixMilli())
t.Logf("Creating repository %s/%s...", currentOwner, repoName)
resp, err = mcpClient.CallTool(ctx, &mcp.CallToolParams{
Name: "create_repository",
Arguments: map[string]any{
"name": repoName,
"private": true,
"autoInit": true,
},
})
require.NoError(t, err, "expected to call 'create_repository' tool successfully")
require.False(t, resp.IsError, fmt.Sprintf("expected result not to be an error: %+v", resp))

t.Cleanup(func() {
ghClient := getRESTClient(t)
t.Logf("Deleting repository %s/%s...", currentOwner, repoName)
_, err := ghClient.Repositories.Delete(context.Background(), currentOwner, repoName)
require.NoError(t, err, "expected to delete repository successfully")
})

t.Logf("Creating parent issue in %s/%s...", currentOwner, repoName)
resp, err = mcpClient.CallTool(ctx, &mcp.CallToolParams{
Name: "issue_write",
Arguments: map[string]any{
"method": "create",
"owner": currentOwner,
"repo": repoName,
"title": "Parent issue",
},
})
require.NoError(t, err, "expected to call 'issue_write' tool successfully")
require.False(t, resp.IsError, fmt.Sprintf("expected result not to be an error: %+v", resp))

t.Logf("Creating child issue under %s/%s#1...", currentOwner, repoName)
resp, err = mcpClient.CallTool(ctx, &mcp.CallToolParams{
Name: "issue_write",
Arguments: map[string]any{
"method": "create",
"owner": currentOwner,
"repo": repoName,
"title": "Child issue",
"parent_issue_number": 1,
},
})
require.NoError(t, err, "expected to call 'issue_write' tool successfully")
require.False(t, resp.IsError, fmt.Sprintf("expected result not to be an error: %+v", resp))

ghClient := getRESTClient(t)
parentIssue, parentResponse, err := ghClient.Issues.Get(ctx, currentOwner, repoName, 1)
require.NoError(t, err, "expected to get parent issue successfully")
require.Equal(t, http.StatusOK, parentResponse.StatusCode, "expected to get parent issue successfully")

childIssue, childResponse, err := ghClient.Issues.Get(ctx, currentOwner, repoName, 2)
require.NoError(t, err, "expected to get child issue successfully")
require.Equal(t, http.StatusOK, childResponse.StatusCode, "expected to get child issue successfully")
require.Equal(t, parentIssue.GetURL(), childIssue.GetParentIssueURL(), "expected child issue to reference its parent")
}

func TestTags(t *testing.T) {
t.Parallel()

Expand Down
13 changes: 13 additions & 0 deletions pkg/github/__toolsnaps__/create_issue.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@
"description": "Repository owner (username or organization)",
"type": "string"
},
"parent_issue_number": {
"description": "Issue number of the parent issue. The new issue is created and attached to this parent in the same operation.",
"minimum": 1,
"type": "number"
},
"parent_owner": {
"description": "Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when parent_issue_number is provided.",
"type": "string"
},
"parent_repo": {
"description": "Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when parent_issue_number is provided.",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
Expand Down
13 changes: 13 additions & 0 deletions pkg/github/__toolsnaps__/issue_write.snap
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,19 @@
"description": "Repository owner",
"type": "string"
},
"parent_issue_number": {
"description": "Issue number of the parent issue. Only used when method is 'create' and cannot be combined with issue_fields. The new issue is created and attached to this parent in the same operation.",
"minimum": 1,
"type": "number"
},
"parent_owner": {
"description": "Repository owner of the parent issue. Must be provided with parent_repo. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided.",
"type": "string"
},
"parent_repo": {
"description": "Repository name of the parent issue. Must be provided with parent_owner. Omit both to use owner and repo. Only used when method is 'create' and parent_issue_number is provided.",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
Expand Down
Loading
Loading