Add initial support for MCP Apps for select tools under Insiders#1957
Add initial support for MCP Apps for select tools under Insiders#1957mattdholloway wants to merge 51 commits intomainfrom
Conversation
…ce CreateIssueApp to manage existing issue data
…server into mcp-ui-apps-3
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 40 out of 43 changed files in this pull request and generated 7 comments.
Comments suppressed due to low confidence (2)
ui/src/apps/pr-write/App.tsx:415
- The pr-write UI collects reviewers, labels, and milestones from the user (state variables on lines 184-196), but these values are not sent to the
create_pull_requesttool in the handleSubmit function (lines 406-415). The GitHub API's create PR endpoint doesn't support setting these fields directly - they would need to be set via separate API calls after PR creation. Either: 1) Remove these UI elements since they're not functional, 2) Make follow-up API calls to set these after PR creation, or 3) Document that these fields are for future implementation.
pkg/inventory/builder.go:365 - The function
stripInsidersMetaFromToolreturnsnilwhen no insiders keys are found, but the caller instripInsidersFeaturesuses this to decide whether to use the stripped tool or the original. This creates an unnecessary copy of all tools even when no changes are made. Consider returning a boolean indicating whether stripping was needed, or only modifying tools that actually need it to avoid unnecessary allocations.
// stripInsidersFeatures removes insiders-only features from tools.
// This includes Meta keys listed in insidersOnlyMetaKeys.
func stripInsidersFeatures(tools []ServerTool) []ServerTool {
result := make([]ServerTool, len(tools))
for i, tool := range tools {
if stripped := stripInsidersMetaFromTool(tool); stripped != nil {
result[i] = *stripped
} else {
result[i] = tool
}
}
return result
}
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>Create GitHub Issue</title> | ||
| </head> | ||
| <body> | ||
| <div id="root"></div> | ||
| <script type="module" src="./App.tsx"></script> | ||
| </body> | ||
| </html> |
There was a problem hiding this comment.
The issue-write and pr-write HTML files don't have Content-Security-Policy headers like get-me does. For consistency and security, all three apps should have CSP headers. The get-me app needs to load images from GitHub's avatar CDN, but the other apps may have similar requirements (e.g., loading user avatars in the assignee picker). Consider adding appropriate CSP headers to these files as well.
| setToolInput(args); | ||
| onToolInput?.(args); | ||
| }; | ||
| app.onerror = console.error; |
There was a problem hiding this comment.
The console.error is called directly on line 42 without proper error handling or context. Consider using a more robust error handling approach that logs context about what failed, or allows the parent component to handle errors through the onError callback pattern.
bddf923 to
7ce5e08
Compare
tommaso-moro
left a comment
There was a problem hiding this comment.
Great work on this, and it's really cool to see the Primer design system in action here! 🚀
A few comments:
I see you added two tools (list_milestones and list_assignees) that are meant to be used only by the Apps in the iframes. My concerns are:
- I am worried about how this will this play out if users are configuring specific tools in their server config. From my understanding, we'd be introducing a dependency of some tools on other tools (suddenly,
issue_writerelies onlist_assigneesfor example). This is a problem because users are not aware of these dependencies (and shouldn't be) when configuring their server. So if they don't enable bothissue_writeandlist_assigneesat the same time, things would break I assume. I wonder if there is another way of doing this. Wdyt? - (Less important for these 2 tools but relevant if we build more) These tools appear in
tools/listand consume context. Now it's only 2 additional tools, but if we follow this pattern when building more UIs we can easily end up having a lot of tools which can be expensive context-wise
Does the input schema change from Required: []string{"owner", "repo", "title", "head", "base"} to Required: []string{"owner", "repo"} affect non-insiders users ?
I noticed some issues with the UI/UX when trying this out locally. Some related to general spacing and layout (probs easy to fix) but other seem like core markdown functionality that is broken, this is a blocker even for an Insiders ship. Here are some of the main ones:
1- The 'Add a quote' functionality in the markdown editor is broken
2- The repository selection dropdown is too wide and overflows outside the app's window.
Demo:
Screen.Recording.2026-02-05.at.16.23.56.mov
3- Missing spacing between the bottom dropdowns. Also, can't scroll horizontally to reveal the ones past "Milestone"
4- The top part of the PR creation UI overflows
5- Lists (both numbered and bullet points) don't fully work, as pressing "enter" doesn't create a new list item, it just creates a new line. This is not super high priority but should ideally be fixed.
Demo:
Screen.Recording.2026-02-05.at.16.22.56.mov
6- Missing spacing here between "create as draft" and "allow maintainer edits"
At first glance, it seems that a lot of the markdown issues are due to the fact that MarkdownEditor.tsx is using a simple textarea instead of a markdown editor. There may be an official markdown editor from the Primer lib or similar that could be used?
(nit: I think the React code can be improved but haven't reviewed it because I assume the priority in this PR is just to make it work for experimental testing)
| Description: "Allow maintainer edits", | ||
| }, | ||
| }, | ||
| Required: []string{"owner", "repo"}, |
There was a problem hiding this comment.
Why did Required change from Required: []string{"owner", "repo", "title", "head", "base"} to Required: []string{"owner", "repo"} ?
There was a problem hiding this comment.
This changed so that the model doesn't need to provide these fields upfront, they can be filled by the user in the UI
|
A few issues I noticed while testing: get_me: Avatar is not being downloaded/displayed. I think this we want to fix. create_issue: Fields like Type, Assignee, Labels, and Milestones are not populated with suggestions. The Title field looks like a link, but it doesn’t open or navigate anywhere If suggesting predefined fields (like labels, milestones, etc.) is complex to implement at this stage, we can consider moving that out of scope for the Insiders launch. |



Summary
Based on initial work by @tommaso-moro
This PR adds support for MCP Apps, enabling rich interactive UIs for MCP tools.
New MCP App UIs
get_me- User profile display with avatar and statsissue_write- Create/update issues with pickers for labels, assignees, milestones, and issue typescreate_pull_request- Create PRs with branch selection, reviewers, labels, and milestonesImplementation
ui/): React + Primer design system, built to single HTML files viascript/build-uiui_getfor fetching picker data (labels, assignees, milestones, issue types, branches)Insiders Mode
All MCP Apps functionality gated behind Insiders
insidersOnlyMetaKeysmechanism for future experimental featuresThese new UIs require a new React app that exists under the
uifolder with components made available in iframes for clients that support the feature. This has been extensively tested under VSCode-Insiders.This will require additional support in Remote MCP to ensure Insiders and resources support works correctly.
Why
As part of https://github.com/github/copilot-mcp-core/issues/1125
What changed
ui/directory with React + Primer design system apps forget_me,issue_write, andcreate_pull_requestscript/build-uito compile React apps into single HTML filespkg/github/ui_embed.goto embed built HTML assets into binarypkg/github/ui_resources.goto register UI resources with the MCP serverui_gettool for fetching UI picker data (labels, assignees, milestones, issue types, branches)Meta.ui.resourceUri) toget_me,issue_write, andcreate_pull_requesttoolsget_meresourceissue_writeandcreate_pull_requestto proceed with operations when form data is submittedWithInsidersMode()to inventory builder to gate experimental featuresinsidersOnlyMetaKeysmechanism to strip insiders-only metadata when disabledMCP impact
Prompts tested (tool changes only)
Security / limits
Tool renaming
deprecated_tool_aliases.goNote: if you're renaming tools, you must add the tool aliases. For more information on how to do so, please refer to the official docs.
Lint & tests
./script/lint./script/testDocs