Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
67a4793
PoC full flow (hello world example)
tommaso-moro Jan 7, 2026
7d2b463
add avatar resource domain
tommaso-moro Jan 7, 2026
7606aec
add postmessage logic and richer UI
tommaso-moro Jan 7, 2026
02ce9bf
add create issue ui
tommaso-moro Jan 15, 2026
d53ff41
update ui for issue creatioon
tommaso-moro Jan 15, 2026
e3d5db7
fix
tommaso-moro Jan 15, 2026
b149642
ignore banner
tommaso-moro Jan 15, 2026
92aabf2
update docs after rebase
mattdholloway Feb 2, 2026
8b55d08
update toolsnap for get_me
mattdholloway Feb 2, 2026
06270c7
new UI changes
mattdholloway Feb 2, 2026
a770719
update docs
mattdholloway Feb 2, 2026
23de0bc
update workflows that need ui build
mattdholloway Feb 2, 2026
e2a8582
add UI diff
mattdholloway Feb 2, 2026
5bb6228
fix build ui step for windows runners to use git bash
mattdholloway Feb 2, 2026
157ba4d
fix UI diff
mattdholloway Feb 2, 2026
c927390
refactor issue creation UI
mattdholloway Feb 3, 2026
6d0eda6
add AvatarWithFallback component and update UserCard to use it; enhan…
mattdholloway Feb 3, 2026
2b0d8cc
fix formatting of button labels
mattdholloway Feb 3, 2026
b8dc0d5
add create pull request functionality with UI support and insiders
mattdholloway Feb 3, 2026
2d186da
update docs
mattdholloway Feb 3, 2026
072f5c4
add test for insiders mode handling in ServerTool schema
mattdholloway Feb 3, 2026
adc1053
remove `show_ui` param for now
mattdholloway Feb 4, 2026
ee0a440
make insiders mode metadata stripping generic
mattdholloway Feb 4, 2026
2b8f062
remove ui diff
mattdholloway Feb 4, 2026
6070471
Merge branch 'main' into mcp-ui-apps-3
mattdholloway Feb 4, 2026
d0f0334
Merge branch 'mcp-ui-apps-3' of https://github.com/github/github-mcp-…
mattdholloway Feb 4, 2026
37da563
fix CI
mattdholloway Feb 4, 2026
8b23e49
remove redundant mention of old app name
mattdholloway Feb 4, 2026
12af958
add node types to fix ide issues for ts code
mattdholloway Feb 4, 2026
e61c2d2
remove unused TriangleDownIcon import
mattdholloway Feb 4, 2026
54ce61d
update @primer/behaviors and electron-to-chromium versions in package…
mattdholloway Feb 4, 2026
03aad7f
add check to ensure base and head are not the same when creating a ne…
mattdholloway Feb 4, 2026
ad09947
remove old show_ui
mattdholloway Feb 4, 2026
d5e263e
fix gitignore for dist so builds dont break
mattdholloway Feb 4, 2026
dca4d52
add tests for insiders mode handling and metadata stripping in Server…
mattdholloway Feb 4, 2026
932750c
remove unused state and components from CreatePRApp
mattdholloway Feb 4, 2026
16469f8
fix ui build
mattdholloway Feb 4, 2026
d0085a7
update docker build to fix npm issue
mattdholloway Feb 4, 2026
7ce5e08
remove reference to show_ui
mattdholloway Feb 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/code-scanning.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ jobs:
go-version: ${{ fromJSON(steps.resolve-environment.outputs.environment).configuration.go.version }}
cache: false

- name: Set up Node.js
if: matrix.language == 'go'
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Build UI
if: matrix.language == 'go'
run: script/build-ui

- name: Autobuild
uses: github/codeql-action/autobuild@v4

Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/docs-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ jobs:
- name: Checkout code
uses: actions/checkout@v6

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Build UI
run: script/build-ui

- name: Set up Go
uses: actions/setup-go@v6
with:
Expand Down
12 changes: 12 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ jobs:
- name: Check out code
uses: actions/checkout@v6

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Build UI
shell: bash
run: script/build-ui

- name: Set up Go
uses: actions/setup-go@v6
with:
Expand All @@ -34,6 +45,7 @@ jobs:
run: go mod tidy -diff

- name: Run unit tests
shell: bash
run: script/test

- name: Build
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@ jobs:
- name: Check out code
uses: actions/checkout@v6

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Build UI
run: script/build-ui

- name: Set up Go
uses: actions/setup-go@v6
with:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/license-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: gh pr checkout ${{ github.event.pull_request.number }}

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json

- name: Build UI
run: script/build-ui

- name: Set up Go
uses: actions/setup-go@v6
with:
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: ui/package-lock.json
- name: Build UI
run: script/build-ui
- uses: actions/setup-go@v6
with:
go-version: stable
Expand Down
8 changes: 8 additions & 0 deletions .github/workflows/mcp-diff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ jobs:
with:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Build UI
run: script/build-ui

- name: Run MCP Server Diff
uses: SamMorrowDrums/mcp-server-diff@v2.3.5
with:
Expand Down
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,12 @@ e2e.test

.history
conformance-report/

# UI build artifacts
ui/dist/
ui/node_modules/

# Embedded UI assets (built from ui/)
pkg/github/ui_dist/*
!pkg/github/ui_dist/.gitkeep
!pkg/github/ui_dist/.placeholder.html
17 changes: 15 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
FROM node:20-alpine AS ui-build
WORKDIR /app
COPY ui/package*.json ./ui/
RUN cd ui && npm ci
COPY ui/ ./ui/
# Create output directory and build - vite outputs directly to pkg/github/ui_dist/
RUN mkdir -p ./pkg/github/ui_dist && \
cd ui && npm run build

FROM golang:1.25.6-alpine AS build
ARG VERSION="dev"

Expand All @@ -8,11 +17,15 @@ WORKDIR /build
RUN --mount=type=cache,target=/var/cache/apk \
apk add git

# Copy source code (including ui_dist placeholder)
COPY . .

# Copy built UI assets over the placeholder
COPY --from=ui-build /app/pkg/github/ui_dist/* ./pkg/github/ui_dist/

# Build the server
# go build automatically download required module dependencies to /go/pkg/mod
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
--mount=type=bind,target=. \
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=${VERSION} -X main.commit=$(git rev-parse HEAD) -X main.date=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
-o /bin/github-mcp-server ./cmd/github-mcp-server

Expand Down
17 changes: 14 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,11 @@ The following sets of tools are available:
- `title`: Issue title (string, optional)
- `type`: Type of this issue. Only use if the repository has issue types configured. Use list_issue_types tool to get valid type values for the organization. If the repository doesn't support issue types, omit this parameter. (string, optional)

- **list_assignees** - List assignable users
- **Required OAuth Scopes**: `repo`
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)

- **list_issue_types** - List available issue types
- **Required OAuth Scopes**: `read:org`
- **Accepted OAuth Scopes**: `admin:org`, `read:org`, `write:org`
Expand All @@ -860,6 +865,12 @@ The following sets of tools are available:
- `since`: Filter by date (ISO 8601 timestamp) (string, optional)
- `state`: Filter by state, by default both open and closed issues are returned when not provided (string, optional)

- **list_milestones** - List milestones
- **Required OAuth Scopes**: `repo`
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `state`: Filter by state (open, closed, all). Default: open (string, optional)

- **search_issues** - Search issues
- **Required OAuth Scopes**: `repo`
- `order`: Sort order (string, optional)
Expand Down Expand Up @@ -1035,14 +1046,14 @@ The following sets of tools are available:

- **create_pull_request** - Open new pull request
- **Required OAuth Scopes**: `repo`
- `base`: Branch to merge into (string, required)
- `base`: Branch to merge into (string, optional)
- `body`: PR description (string, optional)
- `draft`: Create as draft PR (boolean, optional)
- `head`: Branch containing changes (string, required)
- `head`: Branch containing changes (string, optional)
- `maintainer_can_modify`: Allow maintainer edits (boolean, optional)
- `owner`: Repository owner (string, required)
- `repo`: Repository name (string, required)
- `title`: PR title (string, required)
- `title`: PR title (string, optional)

- **list_pull_requests** - List pull requests
- **Required OAuth Scopes**: `repo`
Expand Down
6 changes: 6 additions & 0 deletions internal/ghmcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
WithToolsets(enabledToolsets).
WithTools(cfg.EnabledTools).
WithFeatureChecker(featureChecker).
WithInsidersMode(cfg.InsidersMode).
WithServerInstructions()

// Apply token scope filtering if scopes are known (for PAT filtering)
Expand Down Expand Up @@ -250,6 +251,11 @@ func NewMCPServer(cfg MCPServerConfig) (*mcp.Server, error) {
// enable toolsets or tools explicitly that do need registration).
inventory.RegisterAll(context.Background(), ghServer, deps)

// Register MCP App UI resources (static resources for tool UI) - insiders only
if cfg.InsidersMode {
github.RegisterUIResources(ghServer)
}

// Register dynamic toolset management tools (enable/disable) - these are separate
// meta-tools that control the inventory, not part of the inventory itself
if cfg.DynamicToolsets {
Expand Down
14 changes: 10 additions & 4 deletions pkg/github/__toolsnaps__/create_pull_request.snap
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"_meta": {
"ui": {
"resourceUri": "ui://github-mcp-server/pr-write",
"visibility": [
"model",
"app"
]
}
},
"annotations": {
"title": "Open new pull request"
},
Expand Down Expand Up @@ -40,10 +49,7 @@
},
"required": [
"owner",
"repo",
"title",
"head",
"base"
"repo"
],
"type": "object"
},
Expand Down
5 changes: 5 additions & 0 deletions pkg/github/__toolsnaps__/get_me.snap
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"_meta": {
"ui": {
"resourceUri": "ui://github-mcp-server/get-me"
}
},
"annotations": {
"readOnlyHint": true,
"title": "Get my user profile"
Expand Down
9 changes: 9 additions & 0 deletions pkg/github/__toolsnaps__/issue_write.snap
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"_meta": {
"ui": {
"resourceUri": "ui://github-mcp-server/issue-write",
"visibility": [
"model",
"app"
]
}
},
"annotations": {
"title": "Create or update issue."
},
Expand Down
25 changes: 25 additions & 0 deletions pkg/github/__toolsnaps__/list_assignees.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"annotations": {
"readOnlyHint": true,
"title": "List assignable users"
},
"description": "List available assignees for a repository. Returns users who can be assigned to issues.",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
}
},
"required": [
"owner",
"repo"
],
"type": "object"
},
"name": "list_assignees"
}
34 changes: 34 additions & 0 deletions pkg/github/__toolsnaps__/list_milestones.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"annotations": {
"readOnlyHint": true,
"title": "List milestones"
},
"description": "List milestones for a repository.",
"inputSchema": {
"properties": {
"owner": {
"description": "Repository owner",
"type": "string"
},
"repo": {
"description": "Repository name",
"type": "string"
},
"state": {
"description": "Filter by state (open, closed, all). Default: open",
"enum": [
"open",
"closed",
"all"
],
"type": "string"
}
},
"required": [
"owner",
"repo"
],
"type": "object"
},
"name": "list_milestones"
}
8 changes: 8 additions & 0 deletions pkg/github/context_tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import (
"github.com/shurcooL/githubv4"
)

// GetMeUIResourceURI is the URI for the get_me tool's MCP App UI resource.
const GetMeUIResourceURI = "ui://github-mcp-server/get-me"

// UserDetails contains additional fields about a GitHub user not already
// present in MinimalUser. Used by get_me context tool but omitted from search_users.
type UserDetails struct {
Expand Down Expand Up @@ -51,6 +54,11 @@ func GetMe(t translations.TranslationHelperFunc) inventory.ServerTool {
// Use json.RawMessage to ensure "properties" is included even when empty.
// OpenAI strict mode requires the properties field to be present.
InputSchema: json.RawMessage(`{"type":"object","properties":{}}`),
Meta: mcp.Meta{
"ui": map[string]any{
"resourceUri": GetMeUIResourceURI,
},
},
},
nil,
func(ctx context.Context, deps ToolDependencies, _ *mcp.CallToolRequest, _ map[string]any) (*mcp.CallToolResult, any, error) {
Expand Down
Loading