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
Bumps github.com/modelcontextprotocol/go-sdk from v1.6.0 to v1.6.1 and
removes the CrossOriginProtection bypass we previously installed on the
StreamableHTTP handler.
As of go-sdk v1.6.0 the cross-origin check is opt-in: a nil
CrossOriginProtection on StreamableHTTPOptions means no check is run.
v1.6.1 also marks the field itself as deprecated (the SDK recommends
wrapping the handler with middleware instead, and the field will be
removed in v1.8.0).
This server authenticates via bearer tokens, not cookies, so the
Sec-Fetch-Site CSRF check is unnecessary and would block browser-based
MCP clients. Leaving CrossOriginProtection unset preserves that
behavior without depending on a deprecated API.
Supersedes #2541.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The generic map decoding path for project field values treated 'name'
(ProjectV2FieldOption) and 'title' (ProjectV2FieldIteration) as plain
strings, but the GitHub API returns them as ProjectV2TextContent objects
with raw/html fields. As a result, single-select option names and
iteration titles could be returned empty when values reached the
minimal converter as map[string]any instead of typed structs.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Return compact project item content and field values from project item tools to avoid verbose issue and pull request payloads.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
mergeIssueFieldValues built the merged slice by iterating a Go map,
which produces non-deterministic ordering and caused a flake in
Test_UpdateIssue/partial_update_with_issue_fields_reconciled_by_names
(introduced in #2551). Switch to an order-preserving merge: emit
incoming entries first in their original order, then any existing
entries (in their original order) whose field IDs weren't seen in
incoming. Semantics (incoming wins, existing preserved) unchanged.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Companion to Test_GetIssue_FieldValues: when remote_mcp_issue_fields is
enabled, the GraphQL nodes() round-trip populates the enriched
field_values while the raw REST issue_field_values stays cleared.
Addresses the Copilot review suggestion on #2558.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the shared buildIssueWrite(includeIssueFields) helper with two
fully duplicated tool definitions. When the FeatureFlagIssueFields flag
is retired, LegacyIssueWrite can be deleted as a single function with no
merge thinking required.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ports the gating from PR #2553 onto main (the original merge landed on a
stack base that did not make it to main).
Changes:
- pkg/inventory: FeatureFlagDisable becomes []string (any-listed-on → hide).
FeatureFlagEnable stays as a single string. This avoids the AND-of-enable
semantics from the earlier proposal, which encoded dependencies rather
than rollout knobs and had no real call site. Disable-OR is the case
that does need the slice (LegacyIssueWrite below).
- pkg/github/issues.go: split IssueWrite into IssueWrite (flag-enabled,
exposes issue_fields) and LegacyIssueWrite (flag-disabled, omits it).
Both register as 'issue_write'; mutually exclusive flag annotations
pick exactly one at runtime. Refactored into a shared buildIssueWrite
helper instead of duplicating the ~250-line tool definition.
- pkg/github/issues.go: GetIssue field_values enrichment now requires
the flag at runtime. The verbose REST IssueFieldValues is always
cleared from the response.
- Existing single-flag Disable call sites converted to slices.
- New toolsnap variant issue_write_ff_remote_mcp_issue_fields.snap; the
canonical issue_write.snap is owned by LegacyIssueWrite.
- README + flag docs regenerated.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>