* PoC full flow (hello world example)
* add avatar resource domain
* add postmessage logic and richer UI
* add create issue ui
* update ui for issue creatioon
* fix
* ignore banner
* update docs after rebase
* update toolsnap for get_me
* new UI changes
* update docs
* update workflows that need ui build
* add UI diff
* fix build ui step for windows runners to use git bash
* fix UI diff
* refactor issue creation UI
* add AvatarWithFallback component and update UserCard to use it; enhance CreateIssueApp to manage existing issue data
* fix formatting of button labels
* add create pull request functionality with UI support and insiders
* update docs
* add test for insiders mode handling in ServerTool schema
* remove `show_ui` param for now
* make insiders mode metadata stripping generic
* remove ui diff
* fix CI
* remove redundant mention of old app name
* add node types to fix ide issues for ts code
* remove unused TriangleDownIcon import
* update @primer/behaviors and electron-to-chromium versions in package-lock.json
* add check to ensure base and head are not the same when creating a new PR
* remove old show_ui
* fix gitignore for dist so builds dont break
* add tests for insiders mode handling and metadata stripping in ServerTool
* remove unused state and components from CreatePRApp
* fix ui build
* update docker build to fix npm issue
* remove reference to show_ui
* allow insiders to work for non-ui features
* formalise insiders inventory support
* update docs
* fix overflow issues and replace pull request dropdown with matching UI from dotcom
* fix createpullrequest test
* consolidate fetching tools under `ui_get` tool to remove toolset deps
* fix issue data prefill in issue_write form
* fix link component when updating issue
* fix avatar URL
* fix broken issue update logic
* remove dbg
* fix for new GetFlags
* revert to original required fields for create_pull_request
* fix for UI form submission
* Simplify MCP App UIs for basic branch
Remove advanced features to be kept in mcp-ui-apps-advanced:
- Strip labels, assignees, milestones, issue types, repo picker from issue-write
- Strip repo picker, branch selectors from pr-write
- Delete ui_get tool (ui_tools.go, ui_tools_test.go, ui_get.snap)
- Remove UIGet registration from tools.go
Basic forms retain: title, body, submit with _ui_submitted,
draft/regular split button (PR), MarkdownEditor, and SuccessView.
* Fix header spacing in issue-write and pr-write UIs
Add proper spacing between icon, title text, and repo name in the
header bar for both issue-write and create-pull-request forms.
* fix UI spacing
* Revert "Simplify MCP App UIs for basic branch"
This reverts commit 24174b91e222e45b47913ff6b760db809f48660b.
* Undo dependency downgrades in ui/package-lock.json
* Update ui/src/apps/pr-write/App.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Update ui/src/apps/issue-write/App.tsx
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Implement pagination for uiGetBranches (#2012)
* Initial plan
* Implement pagination for uiGetBranches function
Co-authored-by: mattdholloway <918573+mattdholloway@users.noreply.github.com>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: mattdholloway <918573+mattdholloway@users.noreply.github.com>
* update to new insiders feature flag func
* ensure transient state is reset on successive tool calls
* Mark ui_get as app-only visibility
ui_get backs only the MCP App views and has no business in the agent's
tool list. Per the MCP Apps 2026-01-26 spec, omitting _meta.ui.visibility
defaults to ["model","app"], which exposes the tool to the model. Declare
visibility ["app"] so the host hides it from tools/list while the views can
still invoke it via tools/call.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Update ui_get toolsnap for app-only visibility
Regenerated via UPDATE_TOOLSNAPS to capture the new _meta.ui.visibility.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Assert ui_get declares app-only visibility
Locks in the _meta.ui.visibility ["app"] contract so a future edit can't
silently re-expose the UI data tool to the model.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add ui_get to insiders feature docs
Regenerated docs/feature-flags.md and docs/insiders-features.md to include
the ui_get tool entry.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address ui_get review feedback
- Paginate the labels GraphQL query (cursor-based) so repos with more than
100 labels return a complete list instead of silently truncating.
- Emit an empty due_on for milestones without a due date instead of
formatting the zero time as "0001-01-01".
- Use NewGitHubAPIErrorResponse in uiGetIssueTypes to preserve GitHub
response context, matching the other REST-backed methods.
- Extend tests to cover the labels (GraphQL), milestones (including the
no-due-date case) and issue_types methods, plus the issue_types error path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix repo reset and stale base-branch in MCP App views
- Re-initialize selectedRepo from toolInput inside the reset-on-invocation
effect instead of a separate effect. The two effects both depended on
toolInput and ran in declaration order, so the reset wiped the just-
initialized repo and the picker never reflected the invocation's owner/repo.
- Set the default base branch with a functional update in pr-write so a base
prefilled from toolInput.base (or chosen by the user) isn't overwritten by
a stale baseBranch value captured before the branches request resolved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Fix issue-write repo owner mapping and clear stale UI state on reset
- issue-write: derive owner/name from full_name since search_repositories
minimal output omits the owner object (mirrors pr-write)
- pr-write/issue-write: clear available branch/label/assignee/milestone/type
lists and filters in the toolInput reset effect so prefill effects can't
match against the previous repo's stale data
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Merge remote-tracking branch 'origin/main' into mcp-ui-apps-advanced
* feat: add pull request editing functionality with reviewers support
* feat: implement interactive form handling for issue and pull request creation and updates
* Close response body per page in ui_get pagination loops
Avoids leaking HTTP connections when paging through assignees,
milestones, branches, collaborators, and teams.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Cache pr-edit.html in build-ui action
The build-ui cache only saved get-me/issue-write/pr-write HTML, so once a
cache entry was stored it restored an incomplete ui_dist on later runs and
skipped the rebuild, leaving pr-edit.html absent and panicking the tests.
Add pr-edit.html to the cached paths and bump the cache key to v2 to evict
the incomplete entries.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: tommaso-moro <tommaso-moro@github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The mcp-server-diff action checks the baseline ref out into a separate
working directory and runs install_command there. Without prebuilt UI
artifacts, pkg/github/ui_dist/ is empty on the baseline side and
UIAssetsAvailable() returns false, producing a false-positive diff that
"adds" _meta.ui to MCP Apps tools on every PR.
Stash the artifacts to RUNNER_TEMP after the workflow's build-ui step,
then restore them from install_command so both the baseline and PR
checkouts register identical MCP Apps UI metadata.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add CSV output for list tools under insiders mode
* fix: resolve rebase feature flag conflicts
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Simplify feature-flag handling: collapse CSV dual-variant + skip filtering when no checker (#2516)
* refactor: generic toolset+name sort, clarify feature flag intent
Address review feedback on #2450:
- Collapse the three near-identical sort helpers in pkg/inventory/filters.go
into a generic sortByToolsetThenName so adding new inventory item types
doesn't require copying the comparator.
- Expand the doc comments on the three *WithoutFeatureFiltering helpers to
spell out why they exist: HTTP mode builds a static (process-wide)
inventory as an upper bound, but per-request feature flags from headers
(X-MCP-Features, X-MCP-Insiders) are evaluated later, so feature-flagged
variants must be preserved here.
- Strengthen the doc comment on ResolveFeatureFlags to make the contract
explicit: user-supplied flags are validated against AllowedFeatureFlags,
but insiders expansion deliberately is not — InsidersFeatureFlags may
include server-controlled flags that are not user-toggleable.
CORS comments are intentionally left for the PR author.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(feature-flags): clarify allowed and insiders sets are independent
Also add tests covering:
- a user-toggleable flag (FeatureFlagIssuesGranular) that insiders does
not turn on automatically
- insiders mode not turning on user-only allowed flags
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(inventory): collapse three *WithoutFeatureFiltering helpers into StaticUpperBound
The three parallel methods (AvailableToolsWithoutFeatureFiltering,
AvailableResourceTemplatesWithoutFeatureFiltering,
AvailablePromptsWithoutFeatureFiltering) were always called as a triple
in exactly two places: HTTP buildStaticInventory and its test mirror.
They exist because the dual-variant pattern (sibling tools with mirrored
FeatureFlagEnable / FeatureFlagDisable on the same name, e.g. CSV output)
makes feature filtering at static-build time impossible — both variants
must be kept and resolved per-request.
Replace the three with one method, Inventory.StaticUpperBound(ctx), that
returns (tools, resources, prompts) and carries the rationale in its
doc comment. Reduces API surface, eliminates the triplication, and makes
the single "skip feature filtering" concept obvious to readers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor: simplify feature-flag handling
Two related simplifications, both about treating insiders as a meta flag
that expands once at startup and then stops mattering:
- Collapse CSV's dual-variant pattern into a single tool whose handler
performs a runtime feature-flag check via deps.IsFeatureEnabled. CSV
is a pure response-format toggle, not a schema change, so it does not
need the dual-name pattern that genuine schema variants (granular
issues/PRs) still use.
- When no feature checker is installed, skip feature-flag filtering and
return the full upper bound. The static HTTP inventory now uses plain
AvailableTools/Resources/Prompts; the per-request inventory always
installs a checker, so MCP registration (which serves a tool name once)
always sees a deduplicated set. The bespoke StaticUpperBound helper and
the isToolEnabledWithFeatureFlags split go away.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* ci(mcp-diff): add insiders + per-feature configs
The mcp-diff matrix now includes:
- --insiders (and --insiders --read-only)
- one config per github.AllowedFeatureFlags entry, generated by
script/print-mcp-diff-configs so new user-controllable flags get
diffed automatically without editing the workflow
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs(insiders): explain feature-flag resolution for contributors
Adds a 'How feature flags are resolved' section covering:
- Insiders is a meta flag, like 'all'/'default' for toolsets
- User input -> allowlist filter -> insiders expansion ->
server-side fallback (remote only)
- AllowedFeatureFlags vs InsidersFeatureFlags are independent
- How to add a new feature flag, including the
TestGitHubPackageDoesNotReadInsidersMode guard
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* refactor(inventory): make feature-flag gating a regular ToolFilter
Move tool feature-flag evaluation out of isToolEnabled and into a
ToolFilter installed at the head of the pipeline by Build() when
WithFeatureChecker received a non-nil checker. The 'no checker = no
filtering' contract is now expressed structurally (the filter isn't
installed) instead of by a runtime nil check inside the helper.
Resources and prompts have no filter pipeline, so they call the now-pure
featureFlagAllowed helper behind an explicit r.featureChecker != nil
guard at the iteration site.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* perf(inventory): cache extracted toolset IDs in sort comparator
Avoid evaluating the extractor closures up to three times per comparison.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: correct MCP features header in cors
* docs: regenerate README for CSV output toolset
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* fix: remove duplicate MCPFeaturesHeader from CORS headers
* ci(mcp-diff): add streamable-http job with header-based configs
Adds a sibling mcp-diff-http job that exercises the streamable-http
transport against a shared HTTP server, with per-config settings supplied
via X-MCP-* request headers — mirroring how the remote server is invoked
in production (server-side defaults + per-user header overrides).
The config generator gains a -transport flag:
- stdio (default, unchanged behaviour)
- http-headers (emits headers-only configs targeting a shared server)
Two new combined entries layer multiple headers together as a smoke test
for header-merging regressions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: regenerate after merging main
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Sam Morrow <info@sam-morrow.com>
Co-authored-by: sammorrowdrums <sammorrowdrums@github.com>
Dynamic toolset discovery (the meta-tools enable_toolset, list_available_toolsets,
get_toolset_tools and the --dynamic-toolsets / GITHUB_DYNAMIC_TOOLSETS switch)
was a local-only feature never offered by the remote server. Removing it
deletes a meaningful chunk of branching, configuration surface and tests
for a path no longer in active use.
The deprecated closure-based NewServerToolWithDeps generic constructor was
only kept around for the dynamic tool registration path and is removed
together with it. Going forward there are exactly two constructors:
- NewServerTool — raw mcp.ToolHandler, no closure, no unmarshalling
- NewServerToolWithContextHandler[In, Out] — typed handler, deps via context
Inventory methods that only existed for the dynamic path
(ToolsForToolset, IsToolsetEnabled, EnableToolset, EnabledToolsetIDs)
are removed. ResolvedEnabledToolsets loses its dynamic flag.
Also strips dynamic references from the README, server configuration
docs, copilot-instructions, mcp-diff workflow, and conformance-test
script.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore(ui): migrate vite 6 -> 8 and plugin-react 4 -> 6
Supersedes the auto-generated bump in #2496, which only updated vite and
left @vitejs/plugin-react on a peer range that excludes vite 8, breaking
the UI build (and every Go job that embeds the UI assets) with ERESOLVE.
- vite ^6.0.0 -> ^8.0.13
- @vitejs/plugin-react ^4.3.0 -> ^6.0.2 (peers vite ^8.0.0 only)
- vite-plugin-singlefile ^2.0.0 -> ^2.3.3 (peers already allowed v8)
- engines.node >=20 -> ^20.19.0 || >=22.12.0 (Vite 7+ requirement)
Vite 8 ships Rolldown instead of Rollup, which rejects bundle mutation in
generateBundle. The rename-output plugin was doing exactly that to flatten
the singlefile-inlined HTML from src/apps/<app>/index.html down to
<app>.html. Refactored it to hoist the file in closeBundle (post-write)
and renamed it to flatten-output to reflect what it actually does.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* chore(ui): give flatten-output a clearer error when the HTML is missing
Addresses Copilot review feedback on #2501: if the singlefile-inlined HTML
isn't where we expect it (e.g. because a future Vite/Rolldown change alters
the output path), throw with the app name and expected path instead of
letting renameSync surface a bare ENOENT.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* perf(ui+ci): cache build artifacts and run vite in single process
Introduce a content-addressable cache for the embedded UI HTML and refactor
the build script to invoke vite once per Node process instead of three
times.
* New ui/scripts/build.mjs runs vite build() in a loop within one process,
removing the cross-env dev dependency and avoiding redundant plugin/JIT
warm-up. Local build time drops from ~2.4s to ~1.5s.
* New .github/actions/build-ui composite action restores
pkg/github/ui_dist/{get-me,issue-write,pr-write}.html from cache keyed on
hashes of ui/ sources and the lockfile. On cache hit it skips Node setup
and the build entirely; on miss it sets up Node and runs script/build-ui
as before. Saves ~6s per workflow on Go-only PRs, which is the common
case across seven workflows.
* Replace the duplicated setup-node + Build UI pair in seven workflows
(go, lint, docs-check, license-check, goreleaser, mcp-diff, code-scanning)
with a single uses: ./.github/actions/build-ui line. code-scanning keeps
a dedicated setup-node for the JavaScript CodeQL path.
Output files are byte-identical to the pre-refactor build.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* perf(ci): share UI artifact cache across runner OSes
The cached HTML output is platform-independent, so set
enableCrossOsArchive on the cache step. With this any OS can restore
the cache populated by any other OS — one shared cache instead of three.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add explicit detection of unmodified template text and placeholders
- Add detection of meaningless/spam-like titles
- Add 'Invalid' assessment category for spam/test issues
- Add label recommendations (waiting-for-reply, invalid)
- Strengthen 'Missing Details' criteria with specific examples
- Add guidance to be specific about which sections need actual content
This addresses issues like #2029 where template text was not replaced
with actual information but was not flagged as missing details.
* PoC full flow (hello world example)
* add avatar resource domain
* add postmessage logic and richer UI
* add create issue ui
* update ui for issue creatioon
* fix
* ignore banner
* update docs after rebase
* update toolsnap for get_me
* new UI changes
* update docs
* update workflows that need ui build
* add UI diff
* fix build ui step for windows runners to use git bash
* fix UI diff
* refactor issue creation UI
* add AvatarWithFallback component and update UserCard to use it; enhance CreateIssueApp to manage existing issue data
* fix formatting of button labels
* add create pull request functionality with UI support and insiders
* update docs
* add test for insiders mode handling in ServerTool schema
* remove `show_ui` param for now
* make insiders mode metadata stripping generic
* remove ui diff
* fix CI
* remove redundant mention of old app name
* add node types to fix ide issues for ts code
* remove unused TriangleDownIcon import
* update @primer/behaviors and electron-to-chromium versions in package-lock.json
* add check to ensure base and head are not the same when creating a new PR
* remove old show_ui
* fix gitignore for dist so builds dont break
* add tests for insiders mode handling and metadata stripping in ServerTool
* remove unused state and components from CreatePRApp
* fix ui build
* update docker build to fix npm issue
* remove reference to show_ui
* allow insiders to work for non-ui features
* formalise insiders inventory support
* update docs
* fix overflow issues and replace pull request dropdown with matching UI from dotcom
* fix createpullrequest test
* consolidate fetching tools under `ui_get` tool to remove toolset deps
* fix issue data prefill in issue_write form
* fix link component when updating issue
* fix avatar URL
* fix broken issue update logic
* remove dbg
* fix for new GetFlags
* revert to original required fields for create_pull_request
* fix for UI form submission
* Simplify MCP App UIs for basic branch
Remove advanced features to be kept in mcp-ui-apps-advanced:
- Strip labels, assignees, milestones, issue types, repo picker from issue-write
- Strip repo picker, branch selectors from pr-write
- Delete ui_get tool (ui_tools.go, ui_tools_test.go, ui_get.snap)
- Remove UIGet registration from tools.go
Basic forms retain: title, body, submit with _ui_submitted,
draft/regular split button (PR), MarkdownEditor, and SuccessView.
* Fix header spacing in issue-write and pr-write UIs
Add proper spacing between icon, title text, and repo name in the
header bar for both issue-write and create-pull-request forms.
* fix UI spacing
* Add insiders flag to User-Agent header
When InsidersMode is enabled, append '(insiders)' to the User-Agent
string sent with GitHub API requests, enabling server-side adoption
tracking.
* address ui feedback
* added ui/no-ui support
* improve active state UI for write and preview button. make padding consistent in textarea
* return to prev non ui check
* use hardcoded client name check for ui support
* linter fixes
* merge fix
* linter fix 2
---------
Co-authored-by: tommaso-moro <tommaso-moro@github.com>
Add toolsets-context and toolsets-issues,context configurations to
improve test coverage for instruction generation with different
toolset combinations.
Add push triggers to run on:
- Pushes to main branch (catches merges)
- Tag pushes (v*) for release comparisons against previous tags
The pull_request trigger alone doesn't run when commits are pushed
to PR branches via merge or direct push. Adding push triggers ensures
the diff runs in all expected scenarios.