feat(resources): return issue resource as single markdown document#2031
feat(resources): return issue resource as single markdown document#2031SamMorrowDrums wants to merge 1 commit intomainfrom
Conversation
Consolidate the issue resource into a single ResourceContents item containing the issue body, frontmatter metadata, and all comments separated by --- delimiters. - Return one markdown file instead of multiple content items - Use .md extension in URI template for editor preview support - Convert HTML <img> tags to markdown image syntax - Keep original image URLs (private images won't render in preview) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
Comments suppressed due to low confidence (1)
pkg/github/issue_resource.go:261
- The response body from
client.Search.Issuesis not being closed, which can lead to resource leaks. The response should be captured and its body should be closed with a defer statement.
Similar to the pattern used in other parts of the codebase, the response body should be closed:
issues, resp, err := client.Search.Issues(ctx, fmt.Sprintf("repo:%s/%s is:issue", owner, repo), &github.SearchOptions{
ListOptions: github.ListOptions{PerPage: 100},
})
if err != nil {
return nil, err
}
defer func() { _ = resp.Body.Close() }()Note: This same issue exists in completePRNumber in repository_resource_completions.go line 218, but that's outside the scope of this PR.
issues, _, err := client.Search.Issues(ctx, fmt.Sprintf("repo:%s/%s is:issue", owner, repo), &github.SearchOptions{
| issue, _, err := client.Issues.Get(ctx, owner, repo, issueNumber) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("failed to get issue: %w", err) | ||
| } |
There was a problem hiding this comment.
The response body from client.Issues.Get is not being closed, which can lead to resource leaks. The response should be captured and its body should be closed with a defer statement, similar to the pattern used in GetIssue function in issues.go.
The response body should be closed even when the blank identifier is used for the response variable, following the pattern:
issue, resp, err := client.Issues.Get(ctx, owner, repo, issueNumber)
if err != nil {
return nil, fmt.Errorf("failed to get issue: %w", err)
}
defer func() { _ = resp.Body.Close() }()This issue also appears on line 261 of the same file.
| issue, _, err := client.Issues.Get(ctx, owner, repo, issueNumber) | |
| if err != nil { | |
| return nil, fmt.Errorf("failed to get issue: %w", err) | |
| } | |
| issue, resp, err := client.Issues.Get(ctx, owner, repo, issueNumber) | |
| if err != nil { | |
| return nil, fmt.Errorf("failed to get issue: %w", err) | |
| } | |
| defer func() { _ = resp.Body.Close() }() |
| b.WriteString(fmt.Sprintf("state: %s\n", issue.GetState())) | ||
| if user := issue.GetUser(); user != nil { | ||
| b.WriteString(fmt.Sprintf("author: %s\n", user.GetLogin())) | ||
| } | ||
| if issue.CreatedAt != nil { | ||
| b.WriteString(fmt.Sprintf("created_at: %s\n", issue.CreatedAt.Format("2006-01-02T15:04:05Z"))) | ||
| } | ||
| if len(issue.Labels) > 0 { | ||
| b.WriteString("labels:\n") | ||
| for _, label := range issue.Labels { | ||
| if label != nil { | ||
| b.WriteString(fmt.Sprintf(" - %s\n", label.GetName())) | ||
| } | ||
| } | ||
| } | ||
| if issue.GetMilestone() != nil { | ||
| b.WriteString(fmt.Sprintf("milestone: %s\n", issue.GetMilestone().GetTitle())) | ||
| } | ||
| b.WriteString("---\n\n") | ||
| return b.String() | ||
| } | ||
|
|
||
| func buildCommentFrontmatter(comment *github.IssueComment) string { | ||
| var b strings.Builder | ||
| b.WriteString("---\n") | ||
| if user := comment.GetUser(); user != nil { | ||
| b.WriteString(fmt.Sprintf("author: %s\n", user.GetLogin())) | ||
| } | ||
| b.WriteString(fmt.Sprintf("author_association: %s\n", comment.GetAuthorAssociation())) |
There was a problem hiding this comment.
Several frontmatter fields are not quoted or escaped, which could potentially cause YAML parsing issues if they contain special characters like colons, quotes, or hash symbols. While unlikely in practice (GitHub usernames are alphanumeric, states are enums, etc.), consider quoting these values for robustness:
author(lines 129, 153)state(line 127)milestone(line 143)author_association(line 155)labelsarray items (line 138)
For example:
b.WriteString(fmt.Sprintf("author: %q\n", user.GetLogin()))
b.WriteString(fmt.Sprintf(" - %s\n", label.GetName())) // Labels can be handled with %q as wellThis would make the YAML more robust against edge cases and align with how the title field is handled.
Summary
Prototype of issues as an MCP resource. Consolidates the issue resource into a single
ResourceContentsitem — one markdown file with the issue body, frontmatter metadata, and all comments separated by---delimiters.Changes
.mdextension in URI template for editor preview support<img>tags to markdown image syntaxCaveats
Testing
script/lintandscript/testpass