ListIssueFields creates a tool to list issue field definitions for a repository or organization.
(t translations.TranslationHelperFunc)
| 105 | |
| 106 | // ListIssueFields creates a tool to list issue field definitions for a repository or organization. |
| 107 | func ListIssueFields(t translations.TranslationHelperFunc) inventory.ServerTool { |
| 108 | st := NewTool( |
| 109 | ToolsetMetadataIssues, |
| 110 | mcp.Tool{ |
| 111 | Name: "list_issue_fields", |
| 112 | Description: t("TOOL_LIST_ISSUE_FIELDS_DESCRIPTION", "List issue fields for a repository or organization. Returns field definitions including name, type (text, number, date, single_select), and for single_select fields the list of valid option names. When repo is omitted, returns org-level fields directly."), |
| 113 | Annotations: &mcp.ToolAnnotations{ |
| 114 | Title: t("TOOL_LIST_ISSUE_FIELDS_USER_TITLE", "List issue fields"), |
| 115 | ReadOnlyHint: true, |
| 116 | }, |
| 117 | InputSchema: &jsonschema.Schema{ |
| 118 | Type: "object", |
| 119 | Properties: map[string]*jsonschema.Schema{ |
| 120 | "owner": { |
| 121 | Type: "string", |
| 122 | Description: "The account owner of the repository or organization. The name is not case sensitive.", |
| 123 | }, |
| 124 | "repo": { |
| 125 | Type: "string", |
| 126 | Description: "The name of the repository. When provided, returns fields for this specific repository (inherited from its organization). When omitted, returns org-level fields directly.", |
| 127 | }, |
| 128 | }, |
| 129 | Required: []string{"owner"}, |
| 130 | }, |
| 131 | }, |
| 132 | []scopes.Scope{scopes.Repo, scopes.ReadOrg}, |
| 133 | func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, args map[string]any) (*mcp.CallToolResult, any, error) { |
| 134 | owner, err := RequiredParam[string](args, "owner") |
| 135 | if err != nil { |
| 136 | return utils.NewToolResultError(err.Error()), nil, nil |
| 137 | } |
| 138 | repo, err := OptionalParam[string](args, "repo") |
| 139 | if err != nil { |
| 140 | return utils.NewToolResultError(err.Error()), nil, nil |
| 141 | } |
| 142 | |
| 143 | gqlClient, err := deps.GetGQLClient(ctx) |
| 144 | if err != nil { |
| 145 | return utils.NewToolResultErrorFromErr("failed to get GitHub GraphQL client", err), nil, nil |
| 146 | } |
| 147 | |
| 148 | fields, err := fetchIssueFields(ctx, gqlClient, owner, repo) |
| 149 | if err != nil { |
| 150 | return ghErrors.NewGitHubGraphQLErrorResponse(ctx, "failed to list issue fields", err), nil, nil |
| 151 | } |
| 152 | |
| 153 | r, err := json.Marshal(fields) |
| 154 | if err != nil { |
| 155 | return utils.NewToolResultErrorFromErr("failed to marshal issue fields", err), nil, nil |
| 156 | } |
| 157 | |
| 158 | result := utils.NewToolResultText(string(r)) |
| 159 | // Issue field definitions are repo/org structural metadata |
| 160 | // (trusted). When scoped to a specific repo, confidentiality |
| 161 | // follows that repo's visibility; for an org-level lookup (no |
| 162 | // repo) it is conservatively treated as private. |
| 163 | if repo == "" { |
| 164 | result = attachStaticIFCLabel(ctx, deps, result, ifc.LabelRepoMetadata(true)) |