Skip to content

Commit f2d79f9

Browse files
committed
Added get_issue_events , get_issue_timeline and get_issue_event tools
1 parent 3134b09 commit f2d79f9

File tree

5 files changed

+604
-0
lines changed

5 files changed

+604
-0
lines changed

README.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,27 @@ export GITHUB_MCP_TOOL_ADD_ISSUE_COMMENT_DESCRIPTION="an alternative description
283283
- `repo`: Repository name (string, required)
284284
- `issue_number`: Issue number (number, required)
285285

286+
- **get_issue_events** - Get events for a GitHub issue
287+
- `owner`: Repository owner (string, required)
288+
- `repo`: Repository name (string, required)
289+
- `issue_number`: Issue number (number, required)
290+
- `page`: Page number (number, optional)
291+
- `perPage`: Results per page (number, optional)
292+
293+
- **get_issue_timeline** - Get the timeline of events for a GitHub issue
294+
295+
- `owner`: Repository owner (string, required)
296+
- `repo`: Repository name (string, required)
297+
- `issue_number`: Issue number (number, required)
298+
- `page`: Page number (number, optional)
299+
- `perPage`: Results per page (number, optional)
300+
301+
- **get_issue_event** - Get a specific event for a GitHub issue
302+
303+
- `owner`: Repository owner (string, required)
304+
- `repo`: Repository name (string, required)
305+
- `event_id`: Event ID (number, required)
306+
286307
- **create_issue** - Create a new issue in a GitHub repository
287308

288309
- `owner`: Repository owner (string, required)

pkg/github/issues.go

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,218 @@ func GetIssueComments(getClient GetClientFn, t translations.TranslationHelperFun
711711
}
712712
}
713713

714+
// GetIssueTimeline creates a tool to get timeline for a GitHub issue.
715+
func GetIssueTimeline(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
716+
return mcp.NewTool("get_issue_timeline",
717+
mcp.WithDescription(t("TOOL_GET_ISSUE_TIMELINE_DESCRIPTION", "Get timeline for a GitHub issue")),
718+
mcp.WithString("owner",
719+
mcp.Required(),
720+
mcp.Description("Repository owner"),
721+
),
722+
mcp.WithString("repo",
723+
mcp.Required(),
724+
mcp.Description("Repository name"),
725+
),
726+
mcp.WithNumber("issue_number",
727+
mcp.Required(),
728+
mcp.Description("Issue number"),
729+
),
730+
mcp.WithNumber("page",
731+
mcp.Description("Page number"),
732+
),
733+
mcp.WithNumber("per_page",
734+
mcp.Description("Number of records per page"),
735+
),
736+
),
737+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
738+
owner, err := requiredParam[string](request, "owner")
739+
if err != nil {
740+
return mcp.NewToolResultError(err.Error()), nil
741+
}
742+
repo, err := requiredParam[string](request, "repo")
743+
if err != nil {
744+
return mcp.NewToolResultError(err.Error()), nil
745+
}
746+
issueNumber, err := RequiredInt(request, "issue_number")
747+
if err != nil {
748+
return mcp.NewToolResultError(err.Error()), nil
749+
}
750+
page, err := OptionalIntParamWithDefault(request, "page", 1)
751+
if err != nil {
752+
return mcp.NewToolResultError(err.Error()), nil
753+
}
754+
perPage, err := OptionalIntParamWithDefault(request, "per_page", 30)
755+
if err != nil {
756+
return mcp.NewToolResultError(err.Error()), nil
757+
}
758+
759+
opts := &github.ListOptions{
760+
Page: page,
761+
PerPage: perPage,
762+
}
763+
764+
client, err := getClient(ctx)
765+
if err != nil {
766+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
767+
}
768+
events, resp, err := client.Issues.ListIssueTimeline(ctx, owner, repo, issueNumber, opts)
769+
if err != nil {
770+
return nil, fmt.Errorf("failed to get issue timeline: %w", err)
771+
}
772+
defer func() { _ = resp.Body.Close() }()
773+
774+
if resp.StatusCode != http.StatusOK {
775+
body, err := io.ReadAll(resp.Body)
776+
if err != nil {
777+
return nil, fmt.Errorf("failed to read response body: %w", err)
778+
}
779+
return mcp.NewToolResultError(fmt.Sprintf("failed to get issue timeline: %s", string(body))), nil
780+
}
781+
782+
r, err := json.Marshal(events)
783+
if err != nil {
784+
return nil, fmt.Errorf("failed to marshal response: %w", err)
785+
}
786+
787+
return mcp.NewToolResultText(string(r)), nil
788+
}
789+
}
790+
791+
// GetIssueEvents creates a tool to get events for a GitHub issue.
792+
func GetIssueEvents(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
793+
return mcp.NewTool("get_issue_events",
794+
mcp.WithDescription(t("TOOL_GET_ISSUE_EVENTS_DESCRIPTION", "Get list of events for a GitHub issue")),
795+
mcp.WithString("owner",
796+
mcp.Required(),
797+
mcp.Description("Repository owner"),
798+
),
799+
mcp.WithString("repo",
800+
mcp.Required(),
801+
mcp.Description("Repository name"),
802+
),
803+
mcp.WithNumber("issue_number",
804+
mcp.Required(),
805+
mcp.Description("Issue number"),
806+
),
807+
mcp.WithNumber("page",
808+
mcp.Description("Page number"),
809+
),
810+
mcp.WithNumber("per_page",
811+
mcp.Description("Number of records per page"),
812+
),
813+
),
814+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
815+
owner, err := requiredParam[string](request, "owner")
816+
if err != nil {
817+
return mcp.NewToolResultError(err.Error()), nil
818+
}
819+
repo, err := requiredParam[string](request, "repo")
820+
if err != nil {
821+
return mcp.NewToolResultError(err.Error()), nil
822+
}
823+
issueNumber, err := RequiredInt(request, "issue_number")
824+
if err != nil {
825+
return mcp.NewToolResultError(err.Error()), nil
826+
}
827+
page, err := OptionalIntParamWithDefault(request, "page", 1)
828+
if err != nil {
829+
return mcp.NewToolResultError(err.Error()), nil
830+
}
831+
perPage, err := OptionalIntParamWithDefault(request, "per_page", 30)
832+
if err != nil {
833+
return mcp.NewToolResultError(err.Error()), nil
834+
}
835+
836+
opts := &github.ListOptions{
837+
Page: page,
838+
PerPage: perPage,
839+
}
840+
841+
client, err := getClient(ctx)
842+
if err != nil {
843+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
844+
}
845+
events, resp, err := client.Issues.ListIssueEvents(ctx, owner, repo, issueNumber, opts)
846+
if err != nil {
847+
return nil, fmt.Errorf("failed to get issue events: %w", err)
848+
}
849+
defer func() { _ = resp.Body.Close() }()
850+
851+
if resp.StatusCode != http.StatusOK {
852+
body, err := io.ReadAll(resp.Body)
853+
if err != nil {
854+
return nil, fmt.Errorf("failed to read response body: %w", err)
855+
}
856+
return mcp.NewToolResultError(fmt.Sprintf("failed to get issue events: %s", string(body))), nil
857+
}
858+
859+
r, err := json.Marshal(events)
860+
if err != nil {
861+
return nil, fmt.Errorf("failed to marshal response: %w", err)
862+
}
863+
864+
return mcp.NewToolResultText(string(r)), nil
865+
}
866+
}
867+
868+
// GetIssueEvent creates a tool to get an event for a GitHub issue.
869+
func GetIssueEvent(getClient GetClientFn, t translations.TranslationHelperFunc) (tool mcp.Tool, handler server.ToolHandlerFunc) {
870+
return mcp.NewTool("get_issue_event",
871+
mcp.WithDescription(t("TOOL_GET_ISSUE_EVENT_DESCRIPTION", "Get single event for a GitHub issue")),
872+
mcp.WithString("owner",
873+
mcp.Required(),
874+
mcp.Description("Repository owner"),
875+
),
876+
mcp.WithString("repo",
877+
mcp.Required(),
878+
mcp.Description("Repository name"),
879+
),
880+
mcp.WithNumber("event_id",
881+
mcp.Required(),
882+
mcp.Description("Event ID"),
883+
),
884+
),
885+
func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
886+
owner, err := requiredParam[string](request, "owner")
887+
if err != nil {
888+
return mcp.NewToolResultError(err.Error()), nil
889+
}
890+
repo, err := requiredParam[string](request, "repo")
891+
if err != nil {
892+
return mcp.NewToolResultError(err.Error()), nil
893+
}
894+
eventID, err := RequiredInt64(request, "event_id")
895+
if err != nil {
896+
return mcp.NewToolResultError(err.Error()), nil
897+
}
898+
899+
client, err := getClient(ctx)
900+
if err != nil {
901+
return nil, fmt.Errorf("failed to get GitHub client: %w", err)
902+
}
903+
event, resp, err := client.Issues.GetEvent(ctx, owner, repo, eventID)
904+
if err != nil {
905+
return nil, fmt.Errorf("failed to get issue event: %w", err)
906+
}
907+
defer func() { _ = resp.Body.Close() }()
908+
909+
if resp.StatusCode != http.StatusOK {
910+
body, err := io.ReadAll(resp.Body)
911+
if err != nil {
912+
return nil, fmt.Errorf("failed to read response body: %w", err)
913+
}
914+
return mcp.NewToolResultError(fmt.Sprintf("failed to get issue event: %s", string(body))), nil
915+
}
916+
917+
r, err := json.Marshal(event)
918+
if err != nil {
919+
return nil, fmt.Errorf("failed to marshal response: %w", err)
920+
}
921+
922+
return mcp.NewToolResultText(string(r)), nil
923+
}
924+
}
925+
714926
// parseISOTimestamp parses an ISO 8601 timestamp string into a time.Time object.
715927
// Returns the parsed time or an error if parsing fails.
716928
// Example formats supported: "2023-01-15T14:30:00Z", "2023-01-15"

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