* 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>
* Add explicit show_ui parameter to UI-enabled write tools
Today the server decides whether to route issue_write and create_pull_request
through the MCP App form using two implicit signals: _ui_submitted (set by
the form on submit) and a heuristic that bypasses the form when the call
carries any parameter the form cannot represent (labels, assignees,
issue_fields, state, reviewers, etc.). The model had no first-class,
documented way to say "execute directly, do not show a form".
Add a show_ui boolean parameter to the input schema of IssueWrite,
LegacyIssueWrite, and CreatePullRequest. It defaults to true and is
visible only to clients that advertise MCP App UI support: the strip
happens per-request in inventory.ToolsForRegistration via a new
stripUIOnlySchemaProperties helper, gated by the same predicate that
already strips _meta.ui (shouldStripMCPAppsMetadata). The two strips share
one decision so the schema and metadata stay in lock-step.
Form-routing predicate becomes:
MCPApps FF on && client supports UI &&
!_ui_submitted && show_ui && !hasNonFormParams
show_ui=false is a new explicit way for the model to opt out. The existing
non-form-param auto-bypass stays as a safety net, and the React forms keep
sending _ui_submitted=true on submit unchanged. get_me is out of scope
because its UI is pure client-side card rendering with no server-side
gating to replace.
The current strip gate ("strip when FF is off OR capability explicitly
absent") mirrors today's _meta.ui behavior exactly, including the
"capability unknown" case. For stdio that means UI-capable schemas are
exposed to any FF-enabled client. The handler-side clientSupportsUI check
still gates form execution at call time, so it is functionally a no-op for
non-UI stdio clients. A separate follow-up will tighten the gate to
"strip on unknown too" and wire an InitializedHandler in stdio to
re-register the un-stripped surface only after a UI-capable client has
advertised; the two changes must ship together to avoid breaking stdio.
docs/feature-flags.md and docs/insiders-features.md include an unrelated
"reviewers" description update picked up by script/generate-docs from
commit 2bd162ac ("fix: support team pull request reviewers"), which
updated the source schema but did not regenerate docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify where show_ui appears in generated docs
The code comments next to the show_ui schema entries (and the
uiOnlySchemaProperties allowlist) said the property is documented in
"toolsnaps / README". README is generated from the stripped (non-UI)
schema, so show_ui is not actually in it — it only appears in toolsnaps
and the feature-flag / insiders docs. Reword the comments to match
reality.
Comment-only change; no behavior or test impact.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Guard issue_write/create_pull_request schemas against UI-gating desync
The form-routing logic depends on a hand-maintained classification of
each schema property into form-resendable vs known-non-form. A new
property added without updating the classification would silently shift
UI gating behavior (e.g. a form-incompatible param wouldn't trigger the
safety-net bypass).
Add Test_issueWriteSchemaClassification and Test_createPullRequestSchemaClassification
that enumerate each tool's InputSchema.Properties and require every
property to be classified as exactly one of:
- form-resendable (member of issueWriteFormParams / pullRequestWriteFormParams)
- known-non-form (test-local allowlist)
A future schema addition without classification fails the test with a
message pointing at the exact set the contributor needs to update.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Mark conditional schema parameters in generated docs
Previously `show_ui` was listed in docs/feature-flags.md and
docs/insiders-features.md alongside ordinary parameters with no
indication that it is hidden from clients without MCP App UI support.
A reader scanning the parameter list would assume it is always available.
Add a programmatic conditional-property mechanism:
- `inventory.ConditionalSchemaPropertyDescriptions()` exposes a
map[propertyName]conditionDescription derived from the same
uiOnlySchemaProperties allowlist that drives the per-request strip
in ToolsForRegistration. Single source of truth.
- The doc generator (writeToolDoc) consults this map and appends
"conditional — <description>" to the parameter's parenthesised
type/required suffix.
Example rendered output:
- `show_ui`: Whether to render the MCP App form... (boolean, optional,
conditional — only visible to clients that advertise MCP App UI support)
A small test (TestConditionalSchemaPropertyDescriptions) ensures every
entry in uiOnlySchemaProperties has a description, so a future stripped
property addition can't silently lose its doc marker.
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>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
Previously, omitting the `private` parameter on create_repository
defaulted the new repository to public, an insecure default that could
unintentionally expose code, configuration, and history. Omission now
defaults to a private repository; public repositories are only created
when `private` is explicitly set to false.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build and Test Go Project / build (macos-latest) (push) Has been cancelled
Build and Test Go Project / build (ubuntu-latest) (push) Has been cancelled
Build and Test Go Project / build (windows-latest) (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
GoReleaser Release / release (push) Has been cancelled
MCP Server Diff / mcp-diff (push) Has been cancelled
MCP Server Diff / mcp-diff-http (push) Has been cancelled
Publish to MCP Registry / publish (push) Has been cancelled
Add one-click install badges for Visual Studio alongside the existing
VS Code and VS Code Insiders badges in both the Remote and Local server
sections. Uses the aka.ms/mcpinstall redirect URL with the vsweb+mcp
protocol handler, matching the badge styling from the Visual Studio blog.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
* feat: add get_file_blame tool
* feat: implement cursor-based pagination for get_file_blame tool
* resolve annotated tags to their target commit in get_file_blame
* Regenerate get_file_blame toolsnap and docs after merge with main
The cursor-pagination parameter description changed on main; regenerate the
toolsnap and README so docs-check and toolsnap tests pass.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: gate get_file_blame behind file_blame feature flag
The git blame tool adds a new tool to the inventory, which carries a
context-footprint cost for every client. Gate it behind a new
file_blame feature flag (user opt-in via --features / X-MCP-Features)
that is also auto-enabled in insiders mode, so it is not advertised by
default.
Regenerated README, feature-flags.md and insiders-features.md docs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* feat: Add get_commits method to pull_request_read
* Add nil check and additional test case
---------
Co-authored-by: Sam Morrow <info@sam-morrow.com>
* errors: improve rate limit error messages for AI agents
When the GitHub API returns a rate limit error, replace the raw Go HTTP
error string with a clean, actionable message so agents know exactly
how long to wait before retrying.
Before:
search code: GET https://api.github.com/search/code: 403 API rate
limit exceeded for user ID 12345. [rate reset in 2m59s]
After:
search code: GitHub API rate limit exceeded. Retry after 2m59s.
create issue: GitHub secondary rate limit exceeded. Retry after 47s.
create issue: GitHub secondary rate limit exceeded. Wait before retrying.
Edge cases: expired/zero reset time, nil RetryAfter, and errors
wrapped with errors.As all produce "Wait before retrying." rather
than a negative or confusing duration.
The original error is stored in context via addGitHubAPIErrorToContext
before the rate-limit check, so middleware is unaffected.
Fixes#2385.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* errors: fix flaky rate limit tests
Compute expectedRetryIn before calling the function under test,
and use larger reset time offsets (20-30 min), so a 1s boundary
during time.Duration.Round cannot cause spurious mismatches.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* errors: extract requireErrorText and assertContextHasError test helpers
Reduces repetition in TestNewGitHubAPIErrorResponse_RateLimits subtests.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix edge cases: sub-second rate limit durations and UTF-8 BOM
- Primary rate limit: compute time.Until(resetTime) once and check the
rounded result is >0 before showing 'Retry after X'. This avoids a
TOCTOU race between the After(time.Now()) guard and the subsequent
time.Until call, and prevents showing 'Retry after 0s.' when the
reset time is imminent.
- Secondary rate limit: round RetryAfter first, then check >0.
Previously, a RetryAfter of e.g. 200ms would pass the >0 guard
but format as 'Retry after 0s.' after rounding.
- Add tests for both sub-second edge cases.
- Remove UTF-8 BOM accidentally introduced in error_test.go by
.NET WriteAllText with the default UTF8 encoding.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Annotate read tools with ifc labels
* Dont automatically enable IFCLabels in insiders mode
* ifc: don't label unpublished repo advisories as public
Repository security advisory listings can include draft/triage/closed
advisories (via the state filter), which are not world-readable even on a
public repository. Deriving confidentiality from repo visibility alone
under-classified those results as public.
LabelRepositorySecurityAdvisory now takes an allPublished flag and only
returns a public label when the repo is public AND every returned advisory
is published; otherwise it is private. list_repository_security_advisories
computes allPublished from the response state; the org-wide listing stays
private-untrusted. Adds unit + handler regression tests covering the
draft-advisory-on-public-repo case.
Addresses PR review feedback.
* ifc: fix confidentiality under-classification in releases, collaborators, get_me
Audit for the same bug class as the repo-advisory fix (confidentiality
derived from a coarse signal that misses access-restricted items) found
three more under-classifications:
- Releases (list_releases, get_latest_release, get_release_by_tag): draft
releases are visible only to push-access users and are not world-readable
even on a public repo. New LabelRelease(isPrivate, hasDraft) returns public
only for a non-draft release on a public repo; handlers compute hasDraft
from the response (Draft flag / per-item scan).
- list_repository_collaborators: a collaborator roster requires push access
to list, so it is never world-readable, not even on a public repo. New
LabelCollaboratorRoster() is always PrivateTrusted (mirrors LabelTeam),
replacing the repo-visibility-derived label.
- get_me: the result includes private_gists / total_private_repos /
owned_private_repos, which are not part of the public profile. LabelGetMe
is now PrivateTrusted instead of PublicTrusted.
Verified the remaining public-capable labels are sound: Actions logs are
world-readable on public repos; branches/tags are public metadata; gist,
project, search, and starred-repo labels read per-item visibility and join.
Adds ifc unit tests for the new/changed labels and a get_release_by_tag
handler regression test (draft on public repo -> private); updates the
get_me handler test to assert private.
* ifc: document why list results use one joined label, not per-item
Explain on LabelSearchIssues (and cross-ref from LabelGistList) that a tool
result is delivered as one opaque payload and the IFC engine makes one
allow/deny decision per flow at egress, so the only sound bound for a list is
the meet of every item's label. Per-item labels would only be load-bearing if
the engine could partition a result and route items to different sinks; until
then they would invite unsafe declassification of a public item that arrived
alongside private data. Doc-only change.
* Using issues suggestions feature flag
* Gate set_issue_fields confidence behind update_issue_confidence flag
The GitHub GraphQL API does not yet accept the per-field confidence input
on setIssueFieldValue mutations. Hide it from the user-facing schema and
drop it from the mutation payload unless the new update_issue_confidence
feature flag is enabled so users do not try to use it before the API
supports it.
* adding back confidence
* Update set_issue_fields confidence schema and toolsnap
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
Build and Test Go Project / build (macos-latest) (push) Has been cancelled
Build and Test Go Project / build (ubuntu-latest) (push) Has been cancelled
Build and Test Go Project / build (windows-latest) (push) Has been cancelled
GoReleaser Release / release (push) Has been cancelled
MCP Server Diff / mcp-diff (push) Has been cancelled
MCP Server Diff / mcp-diff-http (push) Has been cancelled
Publish to MCP Registry / publish (push) Has been cancelled
Add an optional confidence integer parameter (0–100) to update_issue_type,
update_issue_labels, and set_issue_fields MCP tools. The confidence score
is passed through to the REST/GraphQL API on mutation calls.
- Rename structs to WithIntent (labelWithIntent, issueTypeWithIntent)
- Add confidence schema property (integer, min 0, max 100) with prompt
guidance describing what different confidence levels represent
- Update tool descriptions to encourage including confidence scores
- Pass confidence in the API request body alongside rationale/suggest
Closesgithub/plan-track-agentic-toolkit#219
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Open created issue/PR link via host open-link capability
The success views for issue-write and pr-write rendered a plain anchor
to the created/updated issue or PR. MCP Apps run in a sandboxed iframe
where target="_blank" navigation may be blocked, so clicking the link
did nothing in some hosts.
Route the click through the host's ui/open-link capability (already
exposed by useMcpApp as openLink), which asks the host to open the URL
in the user's browser. The hook now also falls back to window.open when
the host denies the request, in addition to the existing no-app
fallback. The href is retained so right-click/copy and native fallback
still work.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Prevent default anchor navigation before URL check
When the success-view link URL was unavailable ("#"), the click handler
returned before calling e.preventDefault(), so the anchor's default
target="_blank" navigation still ran and could open a stray blank tab.
Call preventDefault() first, then no-op when the URL is unavailable.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the get_commit tool's two boolean flags (include_diff,
include_patch) with a single detail enum: none / stats / full_patch.
Why:
- The two-boolean shape had an awkward dependency
("include_patch only applies when include_diff is true") and an
impossible state (include_patch=true, include_diff=false) that was
silently ignored.
- A single discriminator collapses three meaningful response shapes
into one orthogonal choice, makes the most expensive option
("full_patch") self-describing, and eliminates the "diff vs patch"
naming confusion.
Behavior:
- Default ("stats") matches the previous default
(include_diff=true, include_patch=false): per-file metadata with no
patch text. Existing callers using defaults are unaffected.
- "none" omits Stats and Files entirely (was include_diff=false).
- "full_patch" is the new opt-in level that adds the unified diff to
each MinimalCommitFile.
Breaking change: callers that previously passed include_diff or
include_patch must switch to detail. Callers using the defaults are
unaffected.
Changes:
- Added Patch field to MinimalCommitFile.
- Added commitDetail type, parseCommitDetail, and migrated
convertToMinimalCommit to take a commitDetail.
- Updated get_commit schema, list_commits caller (commitDetailNone),
unit tests, toolsnap, and README.
Co-authored-by: Sam Morrow <sammorrowdrums@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Skip MCP App form when issue/PR write carries non-form params
When MCP Apps are enabled and the client supports UI, issue_write and
create_pull_request route the call to an interactive form. The form only
collects a subset of fields and rebuilds the submit payload from scratch,
so any parameter it cannot represent was silently dropped — e.g. labels,
assignees, milestone, type, state and issue_fields (priority) for
issue_write.
Skip the form and execute directly whenever the call carries a parameter
outside the set the form collects and re-sends. This generalizes the
previous state-only guard and is robust to future parameter additions
(an unrecognized param now bypasses the form rather than being lost).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Forward original tool params on MCP App form submit
The issue-write and pr-write forms rebuilt their submit payload from
scratch, so any parameter the form does not render was dropped on submit.
Spread the original toolInput first and override only the edited fields,
so unsupported params (e.g. issue_fields, labels, state) are preserved
when the user submits the form.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per @SamMorrowDrums review — replace the manual cleanup() calls before
each error return with a single defer right after cmd.Start(). Same
behaviour, less code.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mcpcurl was sending tools/list and tools/call requests without first
performing the MCP initialize handshake, causing the server to silently
reject all requests and discover zero tools.
Before:
$ mcpcurl --stdio-server-cmd "github-mcp-server stdio" tools --help
(no tools listed)
After:
$ mcpcurl --stdio-server-cmd "github-mcp-server stdio" tools --help
Available Commands:
add_comment_to_pending_review ...
add_issue_comment ...
create_branch ...
The default toolset row covers /mcp/ but /x/all is still a real, useful
meta toolset that enables every toolset at once. Render both as special
rows above the per-toolset list.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Linux/macOS: actually set GITHUB_PAT instead of inlining via subshell, matching the heading.
- PowerShell: use Select-Object -First 1, split with max 2 parts, and trim quotes/whitespace so common .env formats work.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix README.md: Remove non-existent 'Claude Web' from description
- Add Windows PowerShell environment variable example for loading PAT from .env file
The previous documentation only showed bash syntax for loading environment
variables from .env files, which doesn't work on Windows PowerShell. This
adds a PowerShell equivalent to help Windows users set up the GitHub MCP
Server correctly.
Adds two new installation guides under docs/installation-guides/ covering MCP host applications that are not yet documented:
- install-zed.md: covers Zed's 'context_servers' settings key (command + args shape), the official GitHub MCP extension as an easier alternative, remote/local setup, the 'mcp:<server>:<tool>' permission key format introduced in Zed v0.224.0, and OAuth-vs-PAT trade-offs.
- install-opencode.md: covers OpenCode's 'mcp' config block (type-discriminated local/remote, command-as-array, 'environment' instead of 'env'), the 'oauth: false' opt-out needed when using a PAT, the '{env:VAR}' interpolation pattern, and the per-agent tool-gating pattern recommended for token-heavy servers like GitHub.
Also adds both hosts to:
- docs/installation-guides/README.md installation-guides index and the support-by-host-application table.
- README.md 'Install in other MCP hosts' and 'Install in Other MCP Hosts' lists.
Closes#2531.
Adds two new methods to the consolidated projects_write tool:
- create_project: creates a new GitHub ProjectsV2 for a user or org
- create_iteration_field: adds an iteration field to an existing project
Changes addressing review feedback:
- Validate owner_type is exactly 'user' or 'org' in create_project
- Use resolveProjectNodeID (GraphQL) instead of getProjectNodeID (REST)
to avoid HTTP response body leaks
- Add omitempty to Iterations JSON tag
- Rename iterations item field startDate to start_date for consistency
- Validate iteration elements instead of silently skipping invalid ones
- Use explicit response structs with snake_case JSON tags
- Add test for auto-detected owner_type in create_iteration_field
- Use stubExporters() in test deps for nil-safety
Co-authored-by: João Doria de Souza <jdoria@github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Declare appCapabilities.availableDisplayModes (defaults to ["inline"])
during initialization, as required by the new spec.
* Track McpUiHostContext (and its updates via onhostcontextchanged) and
thread it into AppProvider, which now picks up host-supplied
theme + CSS style variables and projects them onto the root element so
Primer components inherit host theming.
* Add setModelContext and openLink helpers to useMcpApp. issue-write and
pr-write call setModelContext on a successful submission so the agent
has the new entity in its next-turn context; get-me uses openLink for
the profile's external blog link.
The pinned @modelcontextprotocol/ext-apps ^1.7.2 was already resolved to
1.7.2 in the lockfile, so no dependency bump is required for the new
HostContext / openLink / updateModelContext APIs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Explicitly set prefersBorder on every UI resource — false for the
get_me profile card, true for the issue/PR write forms — since
hosts' defaults vary.
* Declare an empty csp on issue_write_ui and pr_write_ui to document
that they need no external origins.
* Point spec link comment at the stable 2026-01-26 location.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Per the MCP Apps 2026-01-26 spec, servers SHOULD check client capabilities
before advertising UI-enabled tools. Extend the inventory strip gate to
remove _meta.ui not only when the feature flag is off, but also when the
request context explicitly reports the client lacks UI support
(HasUISupport returns supported=false, ok=true).
When the capability is unknown (ok=false, e.g. stdio paths), fall through
to the existing feature-flag gate so existing behaviour is preserved.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Build and Test Go Project / build (macos-latest) (push) Has been cancelled
Build and Test Go Project / build (ubuntu-latest) (push) Has been cancelled
Build and Test Go Project / build (windows-latest) (push) Has been cancelled
CodeQL / Analyze (go) (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript) (push) Has been cancelled
Docker / build (push) Has been cancelled
GoReleaser Release / release (push) Has been cancelled
MCP Server Diff / mcp-diff (push) Has been cancelled
MCP Server Diff / mcp-diff-http (push) Has been cancelled
Publish to MCP Registry / publish (push) Has been cancelled
The remote/HTTP server never called RegisterUIResources, so when the
remote_mcp_ui_apps feature flag was enabled per-request, tools like
issue_write and create_pull_request would advertise a ui:// resource URI
in their _meta.ui block but the resource itself was not registered. The
client's follow-up resources/read call then failed with -32002 'Resource
not found' (the error surfaced as 'Error loading MCP App: MPC -32002:
Resource not found' in VS Code).
The stdio bootstrap also gated registration on featureChecker called
with context.Background(), which can't see per-request flag overrides.
Move RegisterUIResources into pkg/github.NewMCPServer (the shared
constructor used by both stdio and HTTP), gated only on
UIAssetsAvailable(). The resources are inert static HTML; the inventory
still strips _meta.ui from tools per-request via stripMCPAppsMetadata,
so the URI is only advertised to clients when the flag is on for that
request.
Fixes#2467
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move the AST-based ReadOnlyHint scan introduced in #2486 out of
pkg/github's test file and into a new exported package, pkg/toolvalidation,
so downstream consumers (notably github/github-mcp-server-remote, which
uses this repo as a library) can apply the same guardrail to their own
tool registrations with a one-line test:
violations, err := toolvalidation.ScanReadOnlyHint(pkgDir)
Changes:
- New pkg/toolvalidation/readonlyhint.go with ScanReadOnlyHint,
FormatReadOnlyHintViolations, and the ReadOnlyHintViolation type.
- Dedicated unit tests for the scanner using in-memory fixtures
(compliant, missing-hint, missing-annotations, non-literal,
aliased import, positional fields, file without mcp import).
- pkg/github/tools_static_validation_test.go shrunk to a thin wrapper
that calls ScanReadOnlyHint against its own package directory; the
existing behavior for pkg/github is preserved.
No production-code, schema, or toolsnap changes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Resolve each file's local alias for github.com/modelcontextprotocol/go-sdk/mcp
via file.Imports rather than hard-coding the "mcp" qualifier, so the check
also covers files that import the SDK under a non-default alias.
- Detect positional (unkeyed) composite literals and report a dedicated
diagnostic instead of producing misleading "missing field" violations.
- Drop the brittle 'expected to discover at least one mcp.Tool literal'
assertion: if registrations move behind constructors/factories the AST
walker legitimately finds nothing.
- Use strconv.Unquote to decode tool-name string literals (handles escapes
in interpreted strings); fall back to the raw lexeme on parse error.
Adds a source-level (AST) validation test that walks every non-test Go file in pkg/github and fails if any mcp.Tool composite literal omits Annotations.ReadOnlyHint.
The existing TestAllToolsHaveRequiredMetadata can only assert that Annotations is non-nil at runtime: Go cannot distinguish an unset bool field from one explicitly set to false. The new test closes that gap so future read-intent tools cannot silently default to ReadOnlyHint=false, which has caused downstream agents to prompt for human approval on safe read operations.
All 97 current mcp.Tool registrations pass. Fault-injected by removing ReadOnlyHint from issue_read and confirmed the test reports the exact file, line, tool name, and reason.
Refs github/github-mcp-server#2483