Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
42 changes: 29 additions & 13 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,21 @@ on:
branches: ["main", "next"]
workflow_dispatch:
inputs:
description:
required: false
description: "Description of the run."
type: string
default: "Manual run"
ref:
description: "Git ref to build (branch, tag, or SHA). Leave empty for default branch."
required: false
type: string
default: ""
tag:
description: "Custom image tag (e.g., 'test-oauth', 'pr-1836'). Required for manual runs."
required: false
type: string
default: ""
push:
description: "Push to registry"
required: false
type: boolean
default: true

env:
# Use docker.io for Docker Hub if empty
Expand All @@ -41,6 +51,8 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
ref: ${{ inputs.ref || github.ref }}

# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
Expand Down Expand Up @@ -76,15 +88,17 @@ jobs:
tags: |
type=schedule
type=ref,event=branch
type=ref,event=tag
type=ref,event=tag,enable=${{ github.event_name != 'workflow_dispatch' }}
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=semver,pattern={{version}},enable=${{ github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{major}}.{{minor}},enable=${{ github.event_name != 'workflow_dispatch' }}
type=semver,pattern={{major}},enable=${{ github.event_name != 'workflow_dispatch' }}
type=sha
type=edge
type=edge,enable=${{ github.event_name != 'workflow_dispatch' }}
# Custom tag for manual workflow dispatch
type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != '' }}
# Custom rule to prevent pre-releases from getting latest tag
type=raw,value=latest,enable=${{ github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-') }}
type=raw,value=latest,enable=${{ github.event_name != 'workflow_dispatch' && github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, '-') }}

- name: Go Build Cache for Docker
uses: actions/cache@v5
Expand All @@ -104,14 +118,16 @@ jobs:
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
push: ${{ github.event_name != 'pull_request' && (github.event_name != 'workflow_dispatch' || inputs.push) }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ github.ref_name }}
VERSION=${{ inputs.ref || github.ref_name }}
OAUTH_CLIENT_ID=${{ secrets.OAUTH_CLIENT_ID }}
OAUTH_CLIENT_SECRET=${{ secrets.OAUTH_CLIENT_SECRET }}

# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ jobs:
workdir: .
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OAUTH_CLIENT_ID: ${{ secrets.OAUTH_CLIENT_ID }}
OAUTH_CLIENT_SECRET: ${{ secrets.OAUTH_CLIENT_SECRET }}

- name: Generate signed build provenance attestations for workflow artifacts
uses: actions/attest-build-provenance@v3
Expand Down
2 changes: 1 addition & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ builds:
- env:
- CGO_ENABLED=0
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}}
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientID={{ .Env.OAUTH_CLIENT_ID }} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientSecret={{ .Env.OAUTH_CLIENT_SECRET }}
goos:
- linux
- windows
Expand Down
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
FROM golang:1.25.4-alpine AS build
ARG VERSION="dev"
ARG OAUTH_CLIENT_ID=""
ARG OAUTH_CLIENT_SECRET=""

# Set the working directory
WORKDIR /build
Expand All @@ -13,7 +15,7 @@ RUN --mount=type=cache,target=/var/cache/apk \
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)" \
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) -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientID=${OAUTH_CLIENT_ID} -X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientSecret=${OAUTH_CLIENT_SECRET}" \
-o /bin/github-mcp-server cmd/github-mcp-server/main.go

# Make a stage to run the app
Expand Down
31 changes: 31 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,37 @@ To keep your GitHub PAT secure and reusable across different MCP hosts:

</details>

### OAuth Authentication (stdio mode)

For stdio mode, you can use OAuth 2.1 instead of a Personal Access Token. The server automatically selects the appropriate flow:

| Environment | Flow | Setup |
|-------------|------|-------|
| Native binary | PKCE (browser auto-opens) | Just set `GITHUB_OAUTH_CLIENT_ID` |
| Docker | Device flow (enter code at github.com/login/device) | Just set `GITHUB_OAUTH_CLIENT_ID` |
| Docker with port | PKCE (browser auto-opens) | Set `GITHUB_OAUTH_CALLBACK_PORT` and bind port |

**Example MCP configuration (Docker with device flow):**
```json
{
"mcpServers": {
"github": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "GITHUB_OAUTH_CLIENT_ID",
"-e", "GITHUB_OAUTH_CLIENT_SECRET",
"ghcr.io/github/github-mcp-server"],
"env": {
"GITHUB_OAUTH_CLIENT_ID": "your_client_id",
"GITHUB_OAUTH_CLIENT_SECRET": "your_client_secret"
}
}
}
}
```

See [docs/oauth-authentication.md](docs/oauth-authentication.md) for full setup instructions, including how to create a GitHub OAuth App.

### GitHub Enterprise Server and Enterprise Cloud with data residency (ghe.com)

The flag `--gh-host` and the environment variable `GITHUB_HOST` can be used to set
Expand Down
31 changes: 16 additions & 15 deletions cmd/github-mcp-server/list_scopes.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,27 +101,28 @@ func runListScopes() error {
}
}

// Get enabled features (similar to toolsets)
var enabledFeatures []string
if viper.IsSet("features") {
if err := viper.UnmarshalKey("features", &enabledFeatures); err != nil {
return fmt.Errorf("failed to unmarshal features: %w", err)
}
}

readOnly := viper.GetBool("read-only")
outputFormat := viper.GetString("list-scopes-output")

// Create translation helper
t, _ := translations.TranslationHelper()

// Build inventory using the same logic as the stdio server
inventoryBuilder := github.NewInventory(t).
WithReadOnly(readOnly)

// Configure toolsets (same as stdio)
if enabledToolsets != nil {
inventoryBuilder = inventoryBuilder.WithToolsets(enabledToolsets)
}

// Configure specific tools
if len(enabledTools) > 0 {
inventoryBuilder = inventoryBuilder.WithTools(enabledTools)
}

inv, err := inventoryBuilder.Build()
// Build inventory using the shared builder for consistency
inv, err := github.NewStandardBuilder(github.InventoryConfig{
Translator: t,
ReadOnly: readOnly,
Toolsets: enabledToolsets,
Tools: enabledTools,
EnabledFeatures: enabledFeatures,
}).Build()
if err != nil {
return fmt.Errorf("failed to build inventory: %w", err)
}
Expand Down
Loading