Files
Matt Holloway 4e8eb81dac MCP Apps with extra functionality (#1974)
* 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>
2026-06-16 16:45:16 +01:00

138 lines
3.7 KiB
Go

package github
import (
"context"
"github.com/modelcontextprotocol/go-sdk/mcp"
)
// RegisterUIResources registers MCP App UI resources with the server.
// These are static resources (not templates) that serve HTML content for
// MCP App-enabled tools. The HTML is built from React/Primer components
// in the ui/ directory using `script/build-ui`.
//
// Resource metadata follows the stable 2026-01-26 MCP Apps spec:
// https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/2026-01-26/apps.mdx
func RegisterUIResources(s *mcp.Server, readOnly bool) {
// Register the get_me UI resource
s.AddResource(
&mcp.Resource{
URI: GetMeUIResourceURI,
Name: "get_me_ui",
Description: "MCP App UI for the get_me tool",
MIMEType: MCPAppMIMEType,
},
func(_ context.Context, _ *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
html := MustGetUIAsset("get-me.html")
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{
{
URI: GetMeUIResourceURI,
MIMEType: MCPAppMIMEType,
Text: html,
Meta: mcp.Meta{
"ui": map[string]any{
// Allow loading images from GitHub's avatar CDN.
"csp": map[string]any{
"resourceDomains": []string{"https://avatars.githubusercontent.com"},
},
// Profile card renders inline within chat without a host border.
"prefersBorder": false,
},
},
},
},
}, nil
},
)
if readOnly {
return
}
// Register the issue_write UI resource
s.AddResource(
&mcp.Resource{
URI: IssueWriteUIResourceURI,
Name: "issue_write_ui",
Description: "MCP App UI for creating and updating GitHub issues",
MIMEType: MCPAppMIMEType,
},
func(_ context.Context, _ *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
html := MustGetUIAsset("issue-write.html")
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{
{
URI: IssueWriteUIResourceURI,
MIMEType: MCPAppMIMEType,
Text: html,
Meta: mcp.Meta{
"ui": map[string]any{
// No external origins required; documents the secure default.
"csp": map[string]any{},
// Form surface benefits from a host-provided border.
"prefersBorder": true,
},
},
},
},
}, nil
},
)
// Register the create_pull_request UI resource
s.AddResource(
&mcp.Resource{
URI: PullRequestWriteUIResourceURI,
Name: "pr_write_ui",
Description: "MCP App UI for creating GitHub pull requests",
MIMEType: MCPAppMIMEType,
},
func(_ context.Context, _ *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
html := MustGetUIAsset("pr-write.html")
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{
{
URI: PullRequestWriteUIResourceURI,
MIMEType: MCPAppMIMEType,
Text: html,
Meta: mcp.Meta{
"ui": map[string]any{
"csp": map[string]any{},
"prefersBorder": true,
},
},
},
},
}, nil
},
)
s.AddResource(
&mcp.Resource{
URI: PullRequestEditUIResourceURI,
Name: "pr_edit_ui",
Description: "MCP App UI for editing GitHub pull requests",
MIMEType: MCPAppMIMEType,
},
func(_ context.Context, _ *mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
html := MustGetUIAsset("pr-edit.html")
return &mcp.ReadResourceResult{
Contents: []*mcp.ResourceContents{
{
URI: PullRequestEditUIResourceURI,
MIMEType: MCPAppMIMEType,
Text: html,
Meta: mcp.Meta{
"ui": map[string]any{
"csp": map[string]any{},
"prefersBorder": true,
},
},
},
},
}, nil
},
)
}