Skip to content

Commit 4425d0a

Browse files
authored
Merge branch 'main' into reneexeener/promote-issue-write-with-issue-fields
2 parents f7ddf66 + 6586b84 commit 4425d0a

6 files changed

Lines changed: 263 additions & 197 deletions

File tree

Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node:26-alpine@sha256:144769ec3f32e8ee36b3cfde91e82bee25d9367b20f31a151f3f7eea3a2a8541 AS ui-build
1+
FROM node:26-alpine@sha256:3ad34ca6292aec4a91d8ddeb9229e29d9c2f689efd0dd242860889ac71842eba AS ui-build
22
WORKDIR /app
33
COPY ui/package*.json ./ui/
44
RUN cd ui && npm ci
@@ -7,7 +7,7 @@ COPY ui/ ./ui/
77
RUN mkdir -p ./pkg/github/ui_dist && \
88
cd ui && npm run build
99

10-
FROM golang:1.25.11-alpine@sha256:cd2fb3559df6e13bc93b7f0734a4eabe1d21e7b64eec211ed90784f00a17a56a AS build
10+
FROM golang:1.25.11-alpine@sha256:8d95af53d0d58e1759ddb4028285d9b1239067e4fbf4f544618cad0f60fbc354 AS build
1111
ARG VERSION="dev"
1212

1313
# Set the working directory
@@ -30,7 +30,7 @@ RUN --mount=type=cache,target=/go/pkg/mod \
3030
-o /bin/github-mcp-server ./cmd/github-mcp-server
3131

3232
# Make a stage to run the app
33-
FROM gcr.io/distroless/base-debian12@sha256:58695f439f772a00009c8f6be4c183f824c1f556d74b313c30900f167e4772f8
33+
FROM gcr.io/distroless/base-debian12@sha256:e7e678c88c59e70e105a46549bb3fbfb3d732ee3b4afd3a19fdab2e15afaa6b3
3434

3535
# Add required MCP server annotation
3636
LABEL io.modelcontextprotocol.server.name="io.github.github/github-mcp-server"

cmd/github-mcp-server/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ var (
138138
Version: version,
139139
Host: viper.GetString("host"),
140140
Port: viper.GetInt("port"),
141+
ListenHost: viper.GetString("listen-host"),
141142
BaseURL: viper.GetString("base-url"),
142143
ResourcePath: viper.GetString("base-path"),
143144
ExportTranslations: viper.GetBool("export-translations"),
@@ -184,6 +185,7 @@ func init() {
184185

185186
// HTTP-specific flags
186187
httpCmd.Flags().Int("port", 8082, "HTTP server port")
188+
httpCmd.Flags().String("listen-host", "", "Host the HTTP server binds to (e.g. 127.0.0.1). Empty binds to all interfaces.")
187189
httpCmd.Flags().String("base-url", "", "Base URL where this server is publicly accessible (for OAuth resource metadata)")
188190
httpCmd.Flags().String("base-path", "", "Externally visible base path for the HTTP server (for OAuth resource metadata)")
189191
httpCmd.Flags().Bool("scope-challenge", false, "Enable OAuth scope challenge responses")
@@ -204,6 +206,7 @@ func init() {
204206
_ = viper.BindPFlag("insiders", rootCmd.PersistentFlags().Lookup("insiders"))
205207
_ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl"))
206208
_ = viper.BindPFlag("port", httpCmd.Flags().Lookup("port"))
209+
_ = viper.BindPFlag("listen-host", httpCmd.Flags().Lookup("listen-host"))
207210
_ = viper.BindPFlag("base-url", httpCmd.Flags().Lookup("base-url"))
208211
_ = viper.BindPFlag("base-path", httpCmd.Flags().Lookup("base-path"))
209212
_ = viper.BindPFlag("scope-challenge", httpCmd.Flags().Lookup("scope-challenge"))

pkg/http/server.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import (
55
"fmt"
66
"io"
77
"log/slog"
8+
"net"
89
"net/http"
910
"os"
1011
"os/signal"
12+
"strconv"
1113
"syscall"
1214
"time"
1315

@@ -32,9 +34,13 @@ type ServerConfig struct {
3234
// GitHub Host to target for API requests (e.g. github.com or github.enterprise.com)
3335
Host string
3436

35-
// Port to listen on (default: 8082)
37+
// Port to listen on (default: 8082).
3638
Port int
3739

40+
// ListenHost is the host the HTTP server binds to (e.g. "127.0.0.1").
41+
// When empty, the server binds to all interfaces. Combined with Port.
42+
ListenHost string
43+
3844
// BaseURL is the publicly accessible URL of this server for OAuth resource metadata.
3945
// If not set, the server will derive the URL from incoming request headers.
4046
BaseURL string
@@ -192,7 +198,7 @@ func RunHTTPServer(cfg ServerConfig) error {
192198
})
193199
logger.Info("OAuth protected resource endpoints registered", "baseURL", cfg.BaseURL)
194200

195-
addr := fmt.Sprintf(":%d", cfg.Port)
201+
addr := resolveListenAddress(cfg.ListenHost, cfg.Port)
196202
httpSvr := http.Server{
197203
Addr: addr,
198204
Handler: r,
@@ -223,6 +229,16 @@ func RunHTTPServer(cfg ServerConfig) error {
223229
return nil
224230
}
225231

232+
// resolveListenAddress returns the address string passed to http.Server.
233+
// When host is empty the server binds to all interfaces on the given port;
234+
// otherwise host and port are joined into a single address.
235+
func resolveListenAddress(host string, port int) string {
236+
if host == "" {
237+
return fmt.Sprintf(":%d", port)
238+
}
239+
return net.JoinHostPort(host, strconv.Itoa(port))
240+
}
241+
226242
func initGlobalToolScopeMap(t translations.TranslationHelperFunc) error {
227243
// Build inventory with all tools to extract scope information
228244
inv, err := inventory.NewBuilder().

pkg/http/server_test.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,47 @@ func TestCreateHTTPFeatureChecker(t *testing.T) {
125125
}
126126
}
127127

128+
func TestResolveListenAddress(t *testing.T) {
129+
tests := []struct {
130+
name string
131+
host string
132+
port int
133+
want string
134+
}{
135+
{
136+
name: "empty host falls back to :port",
137+
host: "",
138+
port: 8082,
139+
want: ":8082",
140+
},
141+
{
142+
name: "ipv4 host is joined with port",
143+
host: "127.0.0.1",
144+
port: 9090,
145+
want: "127.0.0.1:9090",
146+
},
147+
{
148+
name: "ipv6 host is bracketed and joined with port",
149+
host: "::1",
150+
port: 9090,
151+
want: "[::1]:9090",
152+
},
153+
{
154+
name: "hostname is joined with port",
155+
host: "localhost",
156+
port: 8082,
157+
want: "localhost:8082",
158+
},
159+
}
160+
161+
for _, tt := range tests {
162+
t.Run(tt.name, func(t *testing.T) {
163+
got := resolveListenAddress(tt.host, tt.port)
164+
assert.Equal(t, tt.want, got)
165+
})
166+
}
167+
}
168+
128169
func TestHeaderAllowedFeatureFlagsMatchesAllowed(t *testing.T) {
129170
// Ensure HeaderAllowedFeatureFlags delegates to AllowedFeatureFlags
130171
allowed := github.HeaderAllowedFeatureFlags()

0 commit comments

Comments
 (0)