@@ -1789,10 +1789,8 @@ func CreateLabel(getGQLClient GetGQLClientFn, t translations.TranslationHelperFu
17891789 var mutation struct {
17901790 CreateLabel struct {
17911791 Label struct {
1792- ID githubv4.ID
1793- Name githubv4.String
1794- Color githubv4.String
1795- Description githubv4.String
1792+ Name githubv4.String
1793+ ID githubv4.ID
17961794 }
17971795 } `graphql:"createLabel(input: $input)"`
17981796 }
@@ -1801,29 +1799,298 @@ func CreateLabel(getGQLClient GetGQLClientFn, t translations.TranslationHelperFu
18011799 return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to create label" , err ), nil
18021800 }
18031801
1804- out := map [string ]any {
1805- "id" : fmt .Sprintf ("%v" , mutation .CreateLabel .Label .ID ),
1806- "name" : string (mutation .CreateLabel .Label .Name ),
1807- "color" : string (mutation .CreateLabel .Label .Color ),
1808- "description" : string (mutation .CreateLabel .Label .Description ),
1802+ return mcp .NewToolResultText (fmt .Sprintf ("label %s created successfully" , mutation .CreateLabel .Label .Name )), nil
1803+ }
1804+ }
1805+
1806+ // Get label
1807+ func GetLabel (getGQLClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
1808+ return mcp .NewTool ("get_label" ,
1809+ mcp .WithDescription (t ("TOOL_GET_LABEL_DESCRIPTION" , "Get a label in a GitHub repository." )),
1810+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
1811+ Title : t ("TOOL_GET_LABEL_TITLE" , "Get label" ),
1812+ ReadOnlyHint : ToBoolPtr (true ),
1813+ }),
1814+ mcp .WithString ("owner" ,
1815+ mcp .Required (),
1816+ mcp .Description ("Repository owner" ),
1817+ ),
1818+ mcp .WithString ("repo" ,
1819+ mcp .Required (),
1820+ mcp .Description ("Repository name" ),
1821+ ),
1822+ mcp .WithString ("name" ,
1823+ mcp .Required (),
1824+ mcp .Description ("Name of the label to retrieve" ),
1825+ ),
1826+ ),
1827+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
1828+ owner , err := RequiredParam [string ](request , "owner" )
1829+ if err != nil {
1830+ return mcp .NewToolResultError (err .Error ()), nil
1831+ }
1832+ repo , err := RequiredParam [string ](request , "repo" )
1833+ if err != nil {
1834+ return mcp .NewToolResultError (err .Error ()), nil
1835+ }
1836+ name , err := RequiredParam [string ](request , "name" )
1837+ if err != nil {
1838+ return mcp .NewToolResultError (err .Error ()), nil
18091839 }
18101840
1811- r , err := json . Marshal ( out )
1841+ client , err := getGQLClient ( ctx )
18121842 if err != nil {
1813- return nil , fmt .Errorf ("failed to marshal response : %w" , err )
1843+ return nil , fmt .Errorf ("failed to get GitHub client : %w" , err )
18141844 }
18151845
1816- return mcp .NewToolResultText (string (r )), nil
1846+ var query struct {
1847+ Repository struct {
1848+ Label struct {
1849+ ID githubv4.ID
1850+ Name githubv4.String
1851+ Color githubv4.String
1852+ Description githubv4.String
1853+ } `graphql:"label(name: $name)"`
1854+ } `graphql:"repository(owner: $owner, name: $repo)"`
1855+ }
1856+
1857+ vars := map [string ]any {
1858+ "owner" : githubv4 .String (owner ),
1859+ "repo" : githubv4 .String (repo ),
1860+ "name" : githubv4 .String (name ),
1861+ }
1862+
1863+ if err := client .Query (ctx , & query , vars ); err != nil {
1864+ return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to find label" , err ), nil
1865+ }
1866+
1867+ // If label wasn't found, return a helpful error
1868+ if query .Repository .Label .Name == "" {
1869+ return mcp .NewToolResultError (fmt .Sprintf ("label '%s' not found in %s/%s" , name , owner , repo )), nil
1870+ }
1871+
1872+ label := map [string ]interface {}{
1873+ "id" : fmt .Sprintf ("%v" , query .Repository .Label .ID ),
1874+ "name" : string (query .Repository .Label .Name ),
1875+ "color" : string (query .Repository .Label .Color ),
1876+ "description" : string (query .Repository .Label .Description ),
1877+ }
1878+
1879+ out , err := json .Marshal (label )
1880+ if err != nil {
1881+ return nil , fmt .Errorf ("failed to marshal label: %w" , err )
1882+ }
1883+
1884+ return mcp .NewToolResultText (string (out )), nil
18171885 }
18181886}
18191887
1820- // Get label
1821- //func GetLabel(getGQLClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, server.ToolHandlerFunc) {}
18221888// Update label
1823- //func UpdateLabel(getGQLClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, server.ToolHandlerFunc) {}
1889+ func UpdateLabel (getGQLClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
1890+ return mcp .NewTool ("update_label" ,
1891+ mcp .WithDescription (t ("TOOL_UPDATE_LABEL_DESCRIPTION" , "Update an existing label in a GitHub repository." )),
1892+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
1893+ Title : t ("TOOL_UPDATE_LABEL_TITLE" , "Update label" ),
1894+ ReadOnlyHint : ToBoolPtr (false ),
1895+ }),
1896+ mcp .WithString ("owner" ,
1897+ mcp .Required (),
1898+ mcp .Description ("Repository owner" ),
1899+ ),
1900+ mcp .WithString ("repo" ,
1901+ mcp .Required (),
1902+ mcp .Description ("Repository name" ),
1903+ ),
1904+ mcp .WithString ("name" ,
1905+ mcp .Required (),
1906+ mcp .Description ("Name of the existing label to update" ),
1907+ ),
1908+ mcp .WithString ("new_name" ,
1909+ mcp .Description ("New name for the label" ),
1910+ ),
1911+ mcp .WithString ("color" ,
1912+ mcp .Description ("New label color as a 6-character hex code without '#', e.g. 'f29513'" ),
1913+ ),
1914+ mcp .WithString ("description" ,
1915+ mcp .Description ("New label description" ),
1916+ ),
1917+ ),
1918+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
1919+ owner , err := RequiredParam [string ](request , "owner" )
1920+ if err != nil {
1921+ return mcp .NewToolResultError (err .Error ()), nil
1922+ }
1923+ repo , err := RequiredParam [string ](request , "repo" )
1924+ if err != nil {
1925+ return mcp .NewToolResultError (err .Error ()), nil
1926+ }
1927+ name , err := RequiredParam [string ](request , "name" )
1928+ if err != nil {
1929+ return mcp .NewToolResultError (err .Error ()), nil
1930+ }
1931+
1932+ newName , err := OptionalParam [string ](request , "new_name" )
1933+ if err != nil {
1934+ return mcp .NewToolResultError (err .Error ()), nil
1935+ }
1936+ color , err := OptionalParam [string ](request , "color" )
1937+ if err != nil {
1938+ return mcp .NewToolResultError (err .Error ()), nil
1939+ }
1940+ description , err := OptionalParam [string ](request , "description" )
1941+ if err != nil {
1942+ return mcp .NewToolResultError (err .Error ()), nil
1943+ }
1944+
1945+ client , err := getGQLClient (ctx )
1946+ if err != nil {
1947+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
1948+ }
1949+
1950+ // Fetch the label to get its GQL ID
1951+ var query struct {
1952+ Repository struct {
1953+ Label struct {
1954+ ID githubv4.ID
1955+ Name githubv4.String
1956+ } `graphql:"label(name: $name)"`
1957+ } `graphql:"repository(owner: $owner, name: $repo)"`
1958+ }
1959+
1960+ vars := map [string ]any {
1961+ "owner" : githubv4 .String (owner ),
1962+ "repo" : githubv4 .String (repo ),
1963+ "name" : githubv4 .String (name ),
1964+ }
1965+
1966+ if err := client .Query (ctx , & query , vars ); err != nil {
1967+ return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to find label" , err ), nil
1968+ }
1969+
1970+ // If label wasn't found, return a helpful error
1971+ if query .Repository .Label .Name == "" {
1972+ return mcp .NewToolResultError (fmt .Sprintf ("label '%s' not found in %s/%s" , name , owner , repo )), nil
1973+ }
1974+
1975+ // Build the update input, only set fields that were provided
1976+ input := githubv4.UpdateLabelInput {
1977+ ID : query .Repository .Label .ID ,
1978+ }
1979+ if newName != "" {
1980+ n := githubv4 .String (newName )
1981+ input .Name = & n
1982+ }
1983+ if color != "" {
1984+ c := githubv4 .String (color )
1985+ input .Color = & c
1986+ }
1987+ if description != "" {
1988+ d := githubv4 .String (description )
1989+ input .Description = & d
1990+ }
1991+
1992+ var mutation struct {
1993+ UpdateLabel struct {
1994+ Label struct {
1995+ Name githubv4.String
1996+ ID githubv4.ID
1997+ }
1998+ } `graphql:"updateLabel(input: $input)"`
1999+ }
2000+
2001+ if err := client .Mutate (ctx , & mutation , input , nil ); err != nil {
2002+ return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to update label" , err ), nil
2003+ }
2004+
2005+ return mcp .NewToolResultText (fmt .Sprintf ("label %s updated successfully" , mutation .UpdateLabel .Label .Name )), nil
2006+ }
2007+ }
2008+
18242009// Delete label
1825- //func DeleteLabel(getGQLClient GetGQLClientFn, t translations.TranslationHelperFunc) (mcp.Tool, server.ToolHandlerFunc) {}
2010+ func DeleteLabel (getGQLClient GetGQLClientFn , t translations.TranslationHelperFunc ) (mcp.Tool , server.ToolHandlerFunc ) {
2011+ return mcp .NewTool ("delete_label" ,
2012+ mcp .WithDescription (t ("TOOL_DELETE_LABEL_DESCRIPTION" , "Delete an existing label from a GitHub repository." )),
2013+ mcp .WithToolAnnotation (mcp.ToolAnnotation {
2014+ Title : t ("TOOL_DELETE_LABEL_TITLE" , "Delete label" ),
2015+ ReadOnlyHint : ToBoolPtr (false ),
2016+ }),
2017+ mcp .WithString ("owner" ,
2018+ mcp .Required (),
2019+ mcp .Description ("Repository owner" ),
2020+ ),
2021+ mcp .WithString ("repo" ,
2022+ mcp .Required (),
2023+ mcp .Description ("Repository name" ),
2024+ ),
2025+ mcp .WithString ("name" ,
2026+ mcp .Required (),
2027+ mcp .Description ("Name of the label to delete" ),
2028+ ),
2029+ ),
2030+ func (ctx context.Context , request mcp.CallToolRequest ) (* mcp.CallToolResult , error ) {
2031+ owner , err := RequiredParam [string ](request , "owner" )
2032+ if err != nil {
2033+ return mcp .NewToolResultError (err .Error ()), nil
2034+ }
2035+ repo , err := RequiredParam [string ](request , "repo" )
2036+ if err != nil {
2037+ return mcp .NewToolResultError (err .Error ()), nil
2038+ }
2039+ name , err := RequiredParam [string ](request , "name" )
2040+ if err != nil {
2041+ return mcp .NewToolResultError (err .Error ()), nil
2042+ }
18262043
2044+ client , err := getGQLClient (ctx )
2045+ if err != nil {
2046+ return nil , fmt .Errorf ("failed to get GitHub client: %w" , err )
2047+ }
2048+
2049+ // Fetch the label to get its GQL ID
2050+ var query struct {
2051+ Repository struct {
2052+ Label struct {
2053+ ID githubv4.ID
2054+ Name githubv4.String
2055+ } `graphql:"label(name: $name)"`
2056+ } `graphql:"repository(owner: $owner, name: $repo)"`
2057+ }
2058+
2059+ vars := map [string ]any {
2060+ "owner" : githubv4 .String (owner ),
2061+ "repo" : githubv4 .String (repo ),
2062+ "name" : githubv4 .String (name ),
2063+ }
2064+
2065+ if err := client .Query (ctx , & query , vars ); err != nil {
2066+ return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to find label" , err ), nil
2067+ }
2068+
2069+ // If label wasn't found, return a helpful error
2070+ if query .Repository .Label .Name == "" {
2071+ return mcp .NewToolResultError (fmt .Sprintf ("label '%s' not found in %s/%s" , name , owner , repo )), nil
2072+ }
2073+
2074+ input := githubv4.DeleteLabelInput {
2075+ ID : query .Repository .Label .ID ,
2076+ }
2077+
2078+ var mutation struct {
2079+ DeleteLabel struct {
2080+ Typename githubv4.String `graphql:"__typename"`
2081+ } `graphql:"deleteLabel(input: $input)"`
2082+ }
2083+
2084+ if err := client .Mutate (ctx , & mutation , input , nil ); err != nil {
2085+ return ghErrors .NewGitHubGraphQLErrorResponse (ctx , "Failed to delete label" , err ), nil
2086+ }
2087+
2088+ return mcp .NewToolResultText (fmt .Sprintf ("label %s deleted successfully" , name )), nil
2089+ }
2090+ }
2091+
2092+ // ReplaceActorsForAssignableInput represents the input for replacing actors for an assignable entity.
2093+ // Used in the AssignCopilotToIssue tool to assign Copilot to an issue.
18272094type ReplaceActorsForAssignableInput struct {
18282095 AssignableID githubv4.ID `json:"assignableId"`
18292096 ActorIDs []githubv4.ID `json:"actorIds"`
@@ -1852,42 +2119,3 @@ func parseISOTimestamp(timestamp string) (time.Time, error) {
18522119 // Return error with supported formats
18532120 return time.Time {}, fmt .Errorf ("invalid ISO 8601 timestamp: %s (supported formats: YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DD)" , timestamp )
18542121}
1855-
1856- func AssignCodingAgentPrompt (t translations.TranslationHelperFunc ) (tool mcp.Prompt , handler server.PromptHandlerFunc ) {
1857- return mcp .NewPrompt ("AssignCodingAgent" ,
1858- mcp .WithPromptDescription (t ("PROMPT_ASSIGN_CODING_AGENT_DESCRIPTION" , "Assign GitHub Coding Agent to multiple tasks in a GitHub repository." )),
1859- mcp .WithArgument ("repo" , mcp .ArgumentDescription ("The repository to assign tasks in (owner/repo)." ), mcp .RequiredArgument ()),
1860- ), func (_ context.Context , request mcp.GetPromptRequest ) (* mcp.GetPromptResult , error ) {
1861- repo := request .Params .Arguments ["repo" ]
1862-
1863- messages := []mcp.PromptMessage {
1864- {
1865- Role : "user" ,
1866- Content : mcp .NewTextContent ("You are a personal assistant for GitHub the Copilot GitHub Coding Agent. Your task is to help the user assign tasks to the Coding Agent based on their open GitHub issues. You can use `assign_copilot_to_issue` tool to assign the Coding Agent to issues that are suitable for autonomous work, and `search_issues` tool to find issues that match the user's criteria. You can also use `list_issues` to get a list of issues in the repository." ),
1867- },
1868- {
1869- Role : "user" ,
1870- Content : mcp .NewTextContent (fmt .Sprintf ("Please go and get a list of the most recent 10 issues from the %s GitHub repository" , repo )),
1871- },
1872- {
1873- Role : "assistant" ,
1874- Content : mcp .NewTextContent (fmt .Sprintf ("Sure! I will get a list of the 10 most recent issues for the repo %s." , repo )),
1875- },
1876- {
1877- Role : "user" ,
1878- Content : mcp .NewTextContent ("For each issue, please check if it is a clearly defined coding task with acceptance criteria and a low to medium complexity to identify issues that are suitable for an AI Coding Agent to work on. Then assign each of the identified issues to Copilot." ),
1879- },
1880- {
1881- Role : "assistant" ,
1882- Content : mcp .NewTextContent ("Certainly! Let me carefully check which ones are clearly scoped issues that are good to assign to the coding agent, and I will summarize and assign them now." ),
1883- },
1884- {
1885- Role : "user" ,
1886- Content : mcp .NewTextContent ("Great, if you are unsure if an issue is good to assign, ask me first, rather than assigning copilot. If you are certain the issue is clear and suitable you can assign it to Copilot without asking." ),
1887- },
1888- }
1889- return & mcp.GetPromptResult {
1890- Messages : messages ,
1891- }, nil
1892- }
1893- }
0 commit comments