Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ jobs:
platforms: linux/amd64,linux/arm64
build-args: |
VERSION=${{ github.ref_name }}
secrets: |
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 @@ -38,6 +38,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@v4
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
7 changes: 6 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,14 @@ COPY . .
COPY --from=ui-build /app/pkg/github/ui_dist/* ./pkg/github/ui_dist/

# Build the server
# OAuth credentials are injected via build secrets so they are not baked into image history; the values are public in practice but kept out of layers.
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
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)" \
--mount=type=secret,id=oauth_client_id \
--mount=type=secret,id=oauth_client_secret \
export OAUTH_CLIENT_ID="$(cat /run/secrets/oauth_client_id 2>/dev/null || echo '')" && \
export OAUTH_CLIENT_SECRET="$(cat /run/secrets/oauth_client_secret 2>/dev/null || echo '')" && \
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}" \
Comment on lines +30 to +34
-o /bin/github-mcp-server ./cmd/github-mcp-server

# Make a stage to run the app
Expand Down
15 changes: 14 additions & 1 deletion cmd/github-mcp-server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"
"time"

"github.com/github/github-mcp-server/internal/buildinfo"
"github.com/github/github-mcp-server/internal/ghmcp"
"github.com/github/github-mcp-server/internal/oauth"
"github.com/github/github-mcp-server/pkg/github"
Expand Down Expand Up @@ -37,6 +38,18 @@ var (
RunE: func(_ *cobra.Command, _ []string) error {
token := viper.GetString("personal_access_token")
oauthClientID := viper.GetString("oauth-client-id")
oauthClientSecret := viper.GetString("oauth-client-secret")
// Fall back to the build-time baked-in client (official releases) when none is
// configured explicitly. The baked-in app is registered on github.com, so it is
// only applied to the default host; GHES/ghe.com users must bring their own
// --oauth-client-id. Recognizing the host via NormalizeHost means an explicit
// GITHUB_HOST=github.com (or api.github.com) still counts as the default and keeps
// zero-config login working. The secret tracks the id, so an explicitly provided
// id with no secret never picks up the baked-in secret.
if oauthClientID == "" && oauth.NormalizeHost(viper.GetString("host")) == "https://github.com" {
oauthClientID = buildinfo.OAuthClientID
oauthClientSecret = buildinfo.OAuthClientSecret
}
if token == "" && oauthClientID == "" {
return errors.New("authentication required: set GITHUB_PERSONAL_ACCESS_TOKEN, or pass --oauth-client-id to log in via OAuth")
}
Expand Down Expand Up @@ -112,7 +125,7 @@ var (
}
oauthConfig := oauth.NewGitHubConfig(
oauthClientID,
viper.GetString("oauth-client-secret"),
oauthClientSecret,
scopes,
viper.GetString("host"),
viper.GetInt("oauth-callback-port"),
Expand Down
19 changes: 19 additions & 0 deletions internal/buildinfo/buildinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Package buildinfo contains variables that are set at build time via ldflags.
// These allow official releases to ship default OAuth credentials so users can
// log in without configuring their own OAuth app. The values are public in
// practice (security relies on PKCE, not on the client secret), but are kept out
// of source and injected at build time.
//
// Example:
//
// go build -ldflags="-X github.com/github/github-mcp-server/internal/buildinfo.OAuthClientID=xxx"
package buildinfo

// OAuthClientID is the default OAuth client ID, set at build time. Empty in
// local/dev builds.
var OAuthClientID string

// OAuthClientSecret is the default OAuth client secret, set at build time. For
// public OAuth clients it is not truly secret per OAuth 2.1 — PKCE provides the
// security — but it is still injected at build time rather than committed.
var OAuthClientSecret string