mirror of
https://github.com/github/awesome-copilot.git
synced 2026-06-22 23:47:36 +00:00
dfecafec8c
Add MCP tools (list_issue_fields, set_issue_fields, issue_write with issue_fields param, list_issues with field_filters) as the preferred approach for managing issue fields. REST and GraphQL APIs remain as fallback when MCP is unavailable. Key changes: - SKILL.md: Add new MCP tools to Available Tools table, update workflow - references/issue-fields.md: Restructure to lead with MCP, demote REST to fallback section, add examples for all MCP tool variants Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
344 lines
11 KiB
Markdown
344 lines
11 KiB
Markdown
# Issue Fields
|
|
|
|
Issue fields are custom metadata (dates, text, numbers, single-select) defined at the organization level and set per-issue. They are separate from labels, milestones, and assignees. Common examples: Start Date, Target Date, Priority, Impact, Effort.
|
|
|
|
**Prefer issue fields over project fields.** When you need to set metadata like dates, priority, or status on an issue, use issue fields (which live on the issue itself) rather than project fields (which live on a project item). Issue fields travel with the issue across projects and views, while project fields are scoped to a single project. Only use project fields when issue fields are not available or when the field is project-specific (e.g., sprint iterations).
|
|
|
|
## MCP Tools (preferred)
|
|
|
|
When the GitHub MCP server is available, use MCP tools for all issue field operations. They handle ID resolution internally, so you work with human-readable names.
|
|
|
|
### Discovering available fields
|
|
|
|
Use `list_issue_fields` to get field definitions and valid options:
|
|
|
|
```
|
|
Tool: mcp__github__list_issue_fields
|
|
Parameters:
|
|
owner: "ORG"
|
|
repo: "REPO" # optional; omit for org-level fields
|
|
```
|
|
|
|
Returns field names, types (text, number, date, single_select), and for single-select fields, the list of valid option names.
|
|
|
|
### Reading field values on an issue
|
|
|
|
Use `issue_read` with method `get`. Field values are included in the response.
|
|
|
|
```
|
|
Tool: mcp__github__issue_read
|
|
Parameters:
|
|
method: "get"
|
|
owner: "OWNER"
|
|
repo: "REPO"
|
|
issue_number: 123
|
|
```
|
|
|
|
### Setting fields via issue_write (simplest)
|
|
|
|
When creating or updating an issue, pass `issue_fields` inline. Uses field names and option names directly (no ID lookups needed):
|
|
|
|
```
|
|
Tool: mcp__github__issue_write
|
|
Parameters:
|
|
method: "update"
|
|
owner: "OWNER"
|
|
repo: "REPO"
|
|
issue_number: 123
|
|
show_ui: false
|
|
issue_fields:
|
|
- field_name: "Priority"
|
|
field_option_name: "P1"
|
|
- field_name: "Target Date"
|
|
value: "2026-07-01"
|
|
- field_name: "Effort"
|
|
value: 5
|
|
```
|
|
|
|
Each entry takes `field_name` (case-insensitive) plus one of:
|
|
- `field_option_name` - for single-select fields (validated against options)
|
|
- `value` - for text, number, or date fields (date as YYYY-MM-DD)
|
|
- `delete: true` - to clear the field value
|
|
|
|
### Setting fields via set_issue_fields (advanced)
|
|
|
|
Use the dedicated `set_issue_fields` tool when you need confidence scoring, rationale, or suggestion mode. Requires GraphQL node IDs (get them from `list_issue_fields` response):
|
|
|
|
```
|
|
Tool: mcp__github__set_issue_fields
|
|
Parameters:
|
|
owner: "OWNER"
|
|
repo: "REPO"
|
|
issue_number: 123
|
|
fields:
|
|
- field_id: "IFD_abc123"
|
|
date_value: "2026-07-01"
|
|
confidence: "HIGH"
|
|
rationale: "Deadline stated in issue description"
|
|
- field_id: "IFSS_def456"
|
|
single_select_option_id: "OPT_xyz789"
|
|
confidence: "MEDIUM"
|
|
rationale: "Reports a crash when saving, likely high priority"
|
|
is_suggestion: true
|
|
```
|
|
|
|
Each entry takes `field_id` plus one value parameter:
|
|
|
|
| Field type | Value parameter | Format |
|
|
|-----------|----------------|--------|
|
|
| Date | `date_value` | ISO 8601 date string |
|
|
| Text | `text_value` | String |
|
|
| Number | `number_value` | Number |
|
|
| Single select | `single_select_option_id` | GraphQL node ID of the option |
|
|
|
|
Additional parameters per field:
|
|
- `confidence` (LOW/MEDIUM/HIGH) - how certain you are of this value
|
|
- `rationale` (max 280 chars) - one sentence explaining what led to this choice
|
|
- `is_suggestion` (boolean) - if true, sent as a suggestion rather than applied value
|
|
- `delete` (boolean) - set true to clear the field value
|
|
|
|
### Filtering issues by field values
|
|
|
|
Use `list_issues` with `field_filters` to find issues matching specific field values:
|
|
|
|
```
|
|
Tool: mcp__github__list_issues
|
|
Parameters:
|
|
owner: "OWNER"
|
|
repo: "REPO"
|
|
state: "OPEN"
|
|
field_filters:
|
|
- field_name: "Priority"
|
|
value: "P1"
|
|
```
|
|
|
|
### Workflow (MCP)
|
|
|
|
1. **Discover fields** - `list_issue_fields` to see available fields and options
|
|
2. **Set values** - use `issue_write` with `issue_fields` for simple cases, or `set_issue_fields` for confidence/rationale
|
|
3. **Query by fields** - use `list_issues` with `field_filters`
|
|
|
|
## REST API (fallback)
|
|
|
|
Use the REST API when MCP tools are not available.
|
|
|
|
### Discovering available fields
|
|
|
|
```bash
|
|
gh api orgs/{org}/issue-fields --jq '.[] | {id, name, options: [.options[]? | {id, name}]}'
|
|
```
|
|
|
|
### Reading field values on an issue
|
|
|
|
```bash
|
|
gh api repos/{owner}/{repo}/issues/{number}/issue-field-values
|
|
```
|
|
|
|
### Setting field values
|
|
|
|
```bash
|
|
gh api repos/{owner}/{repo}/issues/{number}/issue-field-values \
|
|
-X POST \
|
|
--input - <<'EOF'
|
|
{"issue_field_values": [{"field_id": 1, "value": "P1"}]}
|
|
EOF
|
|
```
|
|
|
|
**Important:** The payload must be a JSON object with an `issue_field_values` array. Each entry has:
|
|
- `field_id` (integer): the field's numeric ID from the org fields list
|
|
- `value` (string): the **option name** for single-select fields (e.g., `"P1"`, `"High"`), or the literal value for text/number/date fields
|
|
|
|
Common mistakes to avoid:
|
|
- Passing the option ID instead of the option name as `value` (the API expects the display name)
|
|
- Sending `field_id` and `value` as top-level keys without wrapping in `issue_field_values` array
|
|
- Using `-f` flags instead of `--input` with JSON body
|
|
|
|
### Example: Set priority to P1
|
|
|
|
```bash
|
|
# 1. Find the Priority field ID and option names
|
|
gh api orgs/{org}/issue-fields --jq '.[] | select(.name == "Priority")'
|
|
|
|
# 2. Set it (use the option NAME, not ID)
|
|
gh api repos/{owner}/{repo}/issues/{number}/issue-field-values \
|
|
-X POST \
|
|
--input - <<'EOF'
|
|
{"issue_field_values": [{"field_id": 1, "value": "P1"}]}
|
|
EOF
|
|
```
|
|
|
|
### Example: Set multiple fields at once
|
|
|
|
```bash
|
|
gh api repos/{owner}/{repo}/issues/{number}/issue-field-values \
|
|
-X POST \
|
|
--input - <<'EOF'
|
|
{"issue_field_values": [
|
|
{"field_id": 1, "value": "P1"},
|
|
{"field_id": 5, "value": "2026-06-01"},
|
|
{"field_id": 7, "value": "High"}
|
|
]}
|
|
EOF
|
|
```
|
|
|
|
### Workflow for setting fields (REST)
|
|
|
|
1. **Discover fields** - `gh api orgs/{org}/issue-fields` to get field IDs and option names
|
|
2. **Set values** - POST to `repos/{owner}/{repo}/issues/{number}/issue-field-values` with JSON body
|
|
3. **Batch when possible** - multiple fields can be set in a single request
|
|
|
|
## GraphQL API (alternative)
|
|
|
|
The GraphQL API requires the `GraphQL-Features: issue_fields` HTTP header. Without it, the fields are not visible in the schema.
|
|
|
|
### Discovering available fields (GraphQL)
|
|
|
|
```graphql
|
|
# Header: GraphQL-Features: issue_fields
|
|
{
|
|
organization(login: "OWNER") {
|
|
issueFields(first: 30) {
|
|
nodes {
|
|
__typename
|
|
... on IssueFieldDate { id name }
|
|
... on IssueFieldText { id name }
|
|
... on IssueFieldNumber { id name }
|
|
... on IssueFieldSingleSelect { id name options { id name color } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Field types: `IssueFieldDate`, `IssueFieldText`, `IssueFieldNumber`, `IssueFieldSingleSelect`.
|
|
|
|
### Reading field values (GraphQL)
|
|
|
|
```graphql
|
|
# Header: GraphQL-Features: issue_fields
|
|
{
|
|
repository(owner: "OWNER", name: "REPO") {
|
|
issue(number: 123) {
|
|
issueFieldValues(first: 20) {
|
|
nodes {
|
|
__typename
|
|
... on IssueFieldDateValue {
|
|
value
|
|
field { ... on IssueFieldDate { id name } }
|
|
}
|
|
... on IssueFieldTextValue {
|
|
value
|
|
field { ... on IssueFieldText { id name } }
|
|
}
|
|
... on IssueFieldNumberValue {
|
|
value
|
|
field { ... on IssueFieldNumber { id name } }
|
|
}
|
|
... on IssueFieldSingleSelectValue {
|
|
name
|
|
color
|
|
field { ... on IssueFieldSingleSelect { id name } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Setting field values (GraphQL)
|
|
|
|
Use `setIssueFieldValue` to set one or more fields at once. You need the issue's node ID and the field IDs from the discovery query above.
|
|
|
|
```graphql
|
|
# Header: GraphQL-Features: issue_fields
|
|
mutation {
|
|
setIssueFieldValue(input: {
|
|
issueId: "ISSUE_NODE_ID"
|
|
issueFields: [
|
|
{ fieldId: "IFD_xxx", dateValue: "2026-04-15" }
|
|
{ fieldId: "IFT_xxx", textValue: "some text" }
|
|
{ fieldId: "IFN_xxx", numberValue: 3.0 }
|
|
{ fieldId: "IFSS_xxx", singleSelectOptionId: "OPTION_ID" }
|
|
]
|
|
}) {
|
|
issue { id title }
|
|
}
|
|
}
|
|
```
|
|
|
|
Each entry in `issueFields` takes a `fieldId` plus exactly one value parameter:
|
|
|
|
| Field type | Value parameter | Format |
|
|
|-----------|----------------|--------|
|
|
| Date | `dateValue` | ISO 8601 date string, e.g. `"2026-04-15"` |
|
|
| Text | `textValue` | String |
|
|
| Number | `numberValue` | Float |
|
|
| Single select | `singleSelectOptionId` | Node ID from the field's `options` list |
|
|
|
|
To clear a field value, set `delete: true` instead of a value parameter.
|
|
|
|
## Searching by field values
|
|
|
|
### GraphQL bulk query (recommended)
|
|
|
|
The most reliable way to find issues by field value is to fetch issues via GraphQL and filter by `issueFieldValues`. The search qualifier syntax (`field.name:value`) is not yet reliable across all environments.
|
|
|
|
```bash
|
|
# Find all open P1 issues in a repo
|
|
gh api graphql -H "GraphQL-Features: issue_fields" -f query='
|
|
{
|
|
repository(owner: "OWNER", name: "REPO") {
|
|
issues(first: 100, states: OPEN) {
|
|
nodes {
|
|
number
|
|
title
|
|
updatedAt
|
|
assignees(first: 3) { nodes { login } }
|
|
issueFieldValues(first: 10) {
|
|
nodes {
|
|
__typename
|
|
... on IssueFieldSingleSelectValue {
|
|
name
|
|
field { ... on IssueFieldSingleSelect { name } }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}' --jq '
|
|
[.data.repository.issues.nodes[] |
|
|
select(.issueFieldValues.nodes[] |
|
|
select(.field.name == "Priority" and .name == "P1")
|
|
) |
|
|
{number, title, updatedAt, assignees: [.assignees.nodes[].login]}
|
|
]'
|
|
```
|
|
|
|
**Schema notes for `IssueFieldSingleSelectValue`:**
|
|
- The selected option's display text is in `.name` (not `.value`)
|
|
- Also available: `.color`, `.description`, `.id`
|
|
- The parent field reference is in `.field` (use inline fragment to get the field name)
|
|
|
|
### Search qualifier syntax (experimental)
|
|
|
|
Issue fields may also be searchable using dot notation in search queries. This requires `advanced_search=true` on REST or `ISSUE_ADVANCED` search type on GraphQL, but results are inconsistent and may return 0 results even when matching issues exist.
|
|
|
|
```
|
|
field.priority:P0 # Single-select equals value
|
|
field.target-date:>=2026-04-01 # Date comparison
|
|
has:field.priority # Has any value set
|
|
no:field.priority # Has no value set
|
|
```
|
|
|
|
Field names use the **slug** (lowercase, hyphens for spaces). For example, "Target Date" becomes `target-date`.
|
|
|
|
```bash
|
|
# REST API (may not return results in all environments)
|
|
gh api "search/issues?q=repo:owner/repo+field.priority:P0+is:open&advanced_search=true" \
|
|
--jq '.items[] | "#\(.number): \(.title)"'
|
|
```
|
|
|
|
> **Warning:** The colon notation (`field:Priority:P1`) is silently ignored. If using search qualifiers, always use dot notation (`field.priority:P1`). However, the GraphQL bulk query approach above is more reliable. See [search.md](search.md) for the full search guide.
|