Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions docs/feature-flags.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@ end users. Insiders-only flags are not user-toggleable.

## Declaring tool availability

### Issue artifacts

Enable `--features=issue_artifacts` (or `GITHUB_FEATURES=issue_artifacts`) to
expose `issue_artifact_read` (`method: list | get`) and `issue_artifact_write`
(`method: create | update | delete`) in the `issues` toolset.
This flag is **off by default**, including in Insiders mode. Read-only mode
exposes only `issue_artifact_read`.

The MCP flag only exposes tools; it does not grant API access. The tools
use the configured authenticated GitHub client and base URL without an
endpoint-specific preview header. They declare `repo` in their OAuth challenge
metadata; API access also depends on the token's permissions and repository
access. API failures are returned explicitly; writes are not retried.

Artifact numbers are scoped to their owning issue, not global IDs. Updates
preserve omitted fields, allow `body: ""` to clear the body, and cannot change
type. Lists return one explicit `page`/`perPage` with bodies; request successive
pages until fewer than `perPage` artifacts are returned (there are no `Link`
headers). Artifact names and bodies are sanitized as user-authored content.
Both tools fail closed in lockdown mode because the reference artifact
response does not identify authors for content-trust checks.

All methods require `owner`, `repo`, and `issue_number`. Get, update, and delete
also require `artifact_number`. Create requires `type`, `name`, and `body`;
an empty body is allowed. Update requires `name`, `body`, or both. Method-specific
fields are rejected when used with another method.

Get, create, and update return an `artifact` object. List returns a `list` object
containing `artifacts`, `page`, and `perPage`; delete returns a `deleted` object
containing `issue_number`, `artifact_number`, and a confirmation message.

Tools, resources, and prompts use `inventory.NewFeatureRule` when feature flags
change whether they are available. Each rule declares the flags it references
and evaluates them with a fail-closed `FeatureResolver`, so normal Go boolean
Expand Down Expand Up @@ -395,6 +426,30 @@ as output formatting) won't appear here.
- 'blocked_by' - the subject issue is blocked by the related issue.
- 'blocking' - the subject issue blocks the related issue. (string, required)

### `issue_artifacts`

- **issue_artifact_read** - Read issue artifacts
- **OAuth Challenge Scopes**: `repo`
- `artifact_number`: Required for get: positive issue-scoped artifact number, not its global ID (integer, optional)
- `issue_number`: Positive issue number (integer, required)
- `method`: (string, required)
- `owner`: Repository owner (string, required)
- `page`: For list only: page number, starting at 1 (default 1) (integer, optional)
- `perPage`: For list only: results per page, from 1 to 100 (default 30) (integer, optional)
- `repo`: Repository name (string, required)
- `type`: (string, optional)

- **issue_artifact_write** - Write issue artifacts
- **OAuth Challenge Scopes**: `repo`
- `artifact_number`: Required for update and delete: positive issue-scoped artifact number, not its global ID (integer, optional)
- `body`: Required for create, optional for update: Markdown body; an empty string clears it (string, optional)
- `issue_number`: Positive issue number (integer, required)
- `method`: (string, required)
- `name`: Required for create, optional for update: nonempty artifact name (string, optional)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `type`: (string, optional)

### `duplicate_detection`

- **find_duplicate** - Find duplicate issues
Expand Down
182 changes: 182 additions & 0 deletions pkg/github/__toolsnaps__/issue_artifact_read_ff_issue_artifacts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
{
"annotations": {
"destructiveHint": false,
"idempotentHint": false,
"readOnlyHint": true,
"title": "Read issue artifacts"
},
"description": "List or get GitHub issue artifacts including their bodies. Get requires artifact_number (issue-scoped, not its global ID). List accepts an optional type filter and page/perPage; request successive pages until a page is shorter than perPage because no Link headers are provided.",
"icons": [
{
"mimeType": "image/png",
"src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAAC2UlEQVRIicWVMUyTaRjHf/+vVUpOJOdilOYoUvVreq2CDmLOwdlAS5xMbrrhBifjYG7QjYuJw108nZx1huLgYlw0QshxChUK2koxHHcuCmgsFfieG0or3kGPSoz/8X3f5/97nvfN8z7wmaVqm9FodFfR/EnMugy5giCAwYwgI9Ff9Hl9L9Lp1zUBgsGO+rqGwnlhF4CdwBSyAUwvS1G220zHBSFgHtmVxYWvfp2ZGSj8LyAcjgfZphTQZtAr7OdsZvSP9RIJR+LtQhcNusF+d1aUfPp05M8NAavmg8AOk3cmN56+s1Hpa7U/cviUYbcw3jgex9ZCKoBgsKM+0PDuAdBq2He5zOiTzZiXtc+NxRw598GeLRcWTuTz+UUAp3ygrqFwHmgzeWdqNQd4PpFOy/gedNQfaDz3UQXRaHRX0fNPGdzNZUZO12q+VuHIoV7g5Hu/1/IinX7tABTNnwR2SvRsxRzAzOsBGuuWfAkoX5FZFzCVHR95tFVAbiI9DEwj6wLwl5YVMTRYLTDsxjuRrgGYYz/kxkbvbXRWMOBB24cKYI9ks1X8hXQDaAaa5XG9WjImZgV71wI+m8qAv8y0t1pSmP0ITANTmHO2qqvRZDALlTdgHKyjWkx2YvQ2cHtTacMxYBhWK5DoF4TCkXj7Jg02VKsbOwI0Y+qvALZrOQXMC13cKkDSJWBuJUCqAhgbG3uF7IpBcn/k8KlPNQ+78U5QQuhy/vHjuQoAYPndwi9gw4bd2ufGYrWatxz8No50ExhaKsz9Vl6vAPL5/KKzoiTGG0fOg1oqCbvxTp/juw/M+zynu/yTwjoD58CBQ02ez/pAR4E+M69ntf3/o1Y3dqR050oAQz7P6Z6cfPRRw647MkOhUMAfaDyH+AloBKYNPRT292rQHoMOSp09J3TZlt5ezWazxX97VR3638RiX9ct+RImSyBcrDT0ETMyMp4ptRIgVX7QL6J/ALSUEwJ5rdg2AAAAAElFTkSuQmCC",
"theme": "light"
},
{
"mimeType": "image/png",
"src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABmJLR0QA/wD/AP+gvaeTAAABxElEQVRIibWVvW4TURCFv0vlNEDcIHAkKAERJOIKSjoUArwBPwUFFaKIIngAJARCPIgdh4cgRBYt6ZIAEYEqdhpEw0fhCbkKa68dxyNtsfNzzpnZu3NhwpYGBdUqcA+4A1wEZiK0DawD74FWSml3JAJ1CngGLAIngU1gFfgZKWeAG8AFoAu8At6mlH6VtqTOqJ/UP2pDnRuQO6c27VlbrQ0Dvq121Fulag7q5qPmW18SdSqUd9Qrw4Jn9bNR21YrRQkvYixDKy/AuB3jWjocqKpdtXFU8AxrOTqZzp2PgvnaMRDUA+tB7mypG+OCZ3hbahPgRPguAR9LihaicEu9WcKxClzOi/fU1wPAk7rjgX0uEfNG3cs7mJjtE+wA5/olpZQEHgNf6K2NJyW4NeD7v7c4WptjSc0svlMjdzyM2fbdOyOA7x/T+7mzGj9H8xgIWuquevpw4HmsivkxwBdC/WJRsBKLqqPOHgH8aqybtcJlF0m1WLndUToJ5V31q9r3NOYk7Wh1Wa0PyK3HzA3l/4H3uzIrwFNgCThF7/x/AH5EylngOnAe6AAvgXcppd9DEWRE08DdeIou/RVgJaXUGYQzUfsL+zmwV7BtIq0AAAAASUVORK5CYII=",
"theme": "dark"
}
],
"inputSchema": {
"additionalProperties": false,
"properties": {
"artifact_number": {
"description": "Required for get: positive issue-scoped artifact number, not its global ID",
"minimum": 1,
"type": "integer"
},
"issue_number": {
"description": "Positive issue number",
"minimum": 1,
"type": "integer"
},
"method": {
"enum": [
"list",
"get"
],
"type": "string"
},
"owner": {
"description": "Repository owner",
"minLength": 1,
"type": "string",
"x-mcp-header": "owner"
},
"page": {
"description": "For list only: page number, starting at 1 (default 1)",
"minimum": 1,
"type": "integer"
},
"perPage": {
"description": "For list only: results per page, from 1 to 100 (default 30)",
"maximum": 100,
"minimum": 1,
"type": "integer"
},
"repo": {
"description": "Repository name",
"minLength": 1,
"type": "string",
"x-mcp-header": "repo"
},
"type": {
"enum": [
"plan",
"generic",
"link",
"instruction",
"skill",
"mcp_config",
"reference"
],
"type": "string"
}
},
"required": [
"owner",
"repo",
"issue_number",
"method"
],
"type": "object"
},
"name": "issue_artifact_read",
"outputSchema": {
"additionalProperties": false,
"properties": {
"artifact": {
"additionalProperties": false,
"description": "Artifact returned by get",
"properties": {
"body": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"number": {
"type": "integer"
},
"type": {
"type": "string"
}
},
"required": [
"id",
"number",
"type",
"name",
"body"
],
"type": [
"null",
"object"
]
},
"list": {
"additionalProperties": false,
"description": "Page of artifacts returned by list",
"properties": {
"artifacts": {
"items": {
"additionalProperties": false,
"properties": {
"body": {
"type": "string"
},
"id": {
"type": "integer"
},
"name": {
"type": "string"
},
"number": {
"type": "integer"
},
"type": {
"type": "string"
}
},
"required": [
"id",
"number",
"type",
"name",
"body"
],
"type": "object"
},
"type": [
"null",
"array"
]
},
"page": {
"type": "integer"
},
"perPage": {
"type": "integer"
}
},
"required": [
"artifacts",
"page",
"perPage"
],
"type": [
"null",
"object"
]
}
},
"type": [
"null",
"object"
]
}
}
Loading
Loading