Skip to content

Commit ad7a49a

Browse files
committed
fix some linter errors, make port configurable
1 parent 61db07d commit ad7a49a

File tree

7 files changed

+54
-40
lines changed

7 files changed

+54
-40
lines changed

cmd/github-mcp-server/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ var (
9898
httpConfig := ghhttp.HTTPServerConfig{
9999
Version: version,
100100
Host: viper.GetString("host"),
101+
Port: viper.GetInt("port"),
101102
ExportTranslations: viper.GetBool("export-translations"),
102103
EnableCommandLogging: viper.GetBool("enable-command-logging"),
103104
LogFilePath: viper.GetString("log-file"),
@@ -128,6 +129,7 @@ func init() {
128129
rootCmd.PersistentFlags().Int("content-window-size", 5000, "Specify the content window size")
129130
rootCmd.PersistentFlags().Bool("lockdown-mode", false, "Enable lockdown mode")
130131
rootCmd.PersistentFlags().Duration("repo-access-cache-ttl", 5*time.Minute, "Override the repo access cache TTL (e.g. 1m, 0s to disable)")
132+
rootCmd.PersistentFlags().Int("port", 8082, "HTTP server port")
131133

132134
// Bind flag to viper
133135
_ = viper.BindPFlag("toolsets", rootCmd.PersistentFlags().Lookup("toolsets"))
@@ -142,6 +144,7 @@ func init() {
142144
_ = viper.BindPFlag("content-window-size", rootCmd.PersistentFlags().Lookup("content-window-size"))
143145
_ = viper.BindPFlag("lockdown-mode", rootCmd.PersistentFlags().Lookup("lockdown-mode"))
144146
_ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl"))
147+
_ = viper.BindPFlag("port", rootCmd.PersistentFlags().Lookup("port"))
145148

146149
// Add subcommands
147150
rootCmd.AddCommand(stdioCmd)

internal/ghmcp/server.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ type githubClients struct {
3636
}
3737

3838
// createGitHubClients creates all the GitHub API clients needed by the server.
39-
func createGitHubClients(cfg github.MCPServerConfig, apiHost utils.ApiHost) (*githubClients, error) {
39+
func createGitHubClients(cfg github.MCPServerConfig, apiHost utils.APIHost) (*githubClients, error) {
4040
// Construct REST client
4141
restClient := gogithub.NewClient(nil).WithAuthToken(cfg.Token)
4242
restClient.UserAgent = fmt.Sprintf("github-mcp-server/%s", cfg.Version)

pkg/github/dependencies.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ type RequestDeps struct {
213213
RepoAccessCache *lockdown.RepoAccessCache
214214

215215
// Static dependencies
216-
apiHosts *utils.ApiHost
216+
apiHosts *utils.APIHost
217217
version string
218218
lockdownMode bool
219219
RepoAccessOpts []lockdown.RepoAccessOption
@@ -224,7 +224,7 @@ type RequestDeps struct {
224224

225225
// NewRequestDeps creates a RequestDeps with the provided clients and configuration.
226226
func NewRequestDeps(
227-
apiHosts *utils.ApiHost,
227+
apiHosts *utils.APIHost,
228228
version string,
229229
lockdownMode bool,
230230
repoAccessOpts []lockdown.RepoAccessOption,

pkg/github/server_test.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,14 @@ func TestNewMCPServer_CreatesSuccessfully(t *testing.T) {
123123

124124
deps := stubDeps{}
125125

126+
// Build inventory
127+
inv := NewInventory(cfg.Translator).
128+
WithDeprecatedAliases(DeprecatedToolAliases).
129+
WithToolsets(cfg.EnabledToolsets).
130+
Build()
131+
126132
// Create the server
127-
server, err := NewMCPServer(&cfg, deps)
133+
server, err := NewMCPServer(&cfg, deps, inv)
128134
require.NoError(t, err, "expected server creation to succeed")
129135
require.NotNil(t, server, "expected server to be non-nil")
130136

pkg/http/handler.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,22 @@ import (
1616

1717
type InventoryFactoryFunc func(r *http.Request) *inventory.Inventory
1818

19-
type HttpMcpHandler struct {
19+
type HTTPMcpHandler struct {
2020
config *HTTPServerConfig
21-
apiHosts utils.ApiHost
21+
apiHosts utils.APIHost
2222
logger *slog.Logger
2323
t translations.TranslationHelperFunc
2424
repoAccessOpts []lockdown.RepoAccessOption
2525
inventoryFactoryFunc InventoryFactoryFunc
2626
}
2727

28-
func NewHttpMcpHandler(cfg *HTTPServerConfig,
28+
func NewHTTPMcpHandler(cfg *HTTPServerConfig,
2929
t translations.TranslationHelperFunc,
30-
apiHosts *utils.ApiHost,
30+
apiHosts *utils.APIHost,
3131
repoAccessOptions []lockdown.RepoAccessOption,
3232
logger *slog.Logger,
33-
inventoryFactory InventoryFactoryFunc) *HttpMcpHandler {
34-
return &HttpMcpHandler{
33+
inventoryFactory InventoryFactoryFunc) *HTTPMcpHandler {
34+
return &HTTPMcpHandler{
3535
config: cfg,
3636
apiHosts: *apiHosts,
3737
logger: logger,
@@ -41,7 +41,7 @@ func NewHttpMcpHandler(cfg *HTTPServerConfig,
4141
}
4242
}
4343

44-
func (s *HttpMcpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
44+
func (s *HTTPMcpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
4545
// Set up repo access cache for lockdown mode
4646
deps := github.NewRequestDeps(
4747
&s.apiHosts,

pkg/http/server.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ type HTTPServerConfig struct {
2424
// GitHub Host to target for API requests (e.g. github.com or github.enterprise.com)
2525
Host string
2626

27+
// Port to listen on (default: 8082)
28+
Port int
29+
2730
// ExportTranslations indicates if we should export translations
2831
// See: https://github.com/github/github-mcp-server?tab=readme-ov-file#i18n--overriding-descriptions
2932
ExportTranslations bool
@@ -79,14 +82,16 @@ func RunHTTPServer(cfg HTTPServerConfig) error {
7982
repoAccessOpts = append(repoAccessOpts, lockdown.WithTTL(*cfg.RepoAccessCacheTTL))
8083
}
8184

82-
handler := NewHttpMcpHandler(&cfg, t, &apiHost, repoAccessOpts, logger, DefaultInventoryFactory(&cfg, t))
85+
handler := NewHTTPMcpHandler(&cfg, t, &apiHost, repoAccessOpts, logger, DefaultInventoryFactory(&cfg, t))
8386

8487
r := chi.NewRouter()
8588
r.Mount("/", handler)
8689

90+
addr := fmt.Sprintf(":%d", cfg.Port)
8791
httpSvr := http.Server{
88-
Addr: ":8082",
89-
Handler: r,
92+
Addr: addr,
93+
Handler: r,
94+
ReadHeaderTimeout: 60 * time.Second,
9095
}
9196

9297
go func() {
@@ -104,7 +109,7 @@ func RunHTTPServer(cfg HTTPServerConfig) error {
104109
dumpTranslations()
105110
}
106111

107-
logger.Info("HTTP server listening on :8082")
112+
logger.Info("HTTP server listening", "addr", addr)
108113
if err := httpSvr.ListenAndServe(); err != nil && err != http.ErrServerClosed {
109114
return fmt.Errorf("HTTP server error: %w", err)
110115
}

pkg/utils/api.go

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,95 +8,95 @@ import (
88
"time"
99
)
1010

11-
type ApiHost struct {
11+
type APIHost struct {
1212
BaseRESTURL *url.URL
1313
GraphqlURL *url.URL
1414
UploadURL *url.URL
1515
RawURL *url.URL
1616
}
1717

18-
func newDotcomHost() (ApiHost, error) {
18+
func newDotcomHost() (APIHost, error) {
1919
baseRestURL, err := url.Parse("https://api.github.com/")
2020
if err != nil {
21-
return ApiHost{}, fmt.Errorf("failed to parse dotcom REST URL: %w", err)
21+
return APIHost{}, fmt.Errorf("failed to parse dotcom REST URL: %w", err)
2222
}
2323

2424
gqlURL, err := url.Parse("https://api.github.com/graphql")
2525
if err != nil {
26-
return ApiHost{}, fmt.Errorf("failed to parse dotcom GraphQL URL: %w", err)
26+
return APIHost{}, fmt.Errorf("failed to parse dotcom GraphQL URL: %w", err)
2727
}
2828

2929
uploadURL, err := url.Parse("https://uploads.github.com")
3030
if err != nil {
31-
return ApiHost{}, fmt.Errorf("failed to parse dotcom Upload URL: %w", err)
31+
return APIHost{}, fmt.Errorf("failed to parse dotcom Upload URL: %w", err)
3232
}
3333

3434
rawURL, err := url.Parse("https://raw.githubusercontent.com/")
3535
if err != nil {
36-
return ApiHost{}, fmt.Errorf("failed to parse dotcom Raw URL: %w", err)
36+
return APIHost{}, fmt.Errorf("failed to parse dotcom Raw URL: %w", err)
3737
}
3838

39-
return ApiHost{
39+
return APIHost{
4040
BaseRESTURL: baseRestURL,
4141
GraphqlURL: gqlURL,
4242
UploadURL: uploadURL,
4343
RawURL: rawURL,
4444
}, nil
4545
}
4646

47-
func newGHECHost(hostname string) (ApiHost, error) {
47+
func newGHECHost(hostname string) (APIHost, error) {
4848
u, err := url.Parse(hostname)
4949
if err != nil {
50-
return ApiHost{}, fmt.Errorf("failed to parse GHEC URL: %w", err)
50+
return APIHost{}, fmt.Errorf("failed to parse GHEC URL: %w", err)
5151
}
5252

5353
// Unsecured GHEC would be an error
5454
if u.Scheme == "http" {
55-
return ApiHost{}, fmt.Errorf("GHEC URL must be HTTPS")
55+
return APIHost{}, fmt.Errorf("GHEC URL must be HTTPS")
5656
}
5757

5858
restURL, err := url.Parse(fmt.Sprintf("https://api.%s/", u.Hostname()))
5959
if err != nil {
60-
return ApiHost{}, fmt.Errorf("failed to parse GHEC REST URL: %w", err)
60+
return APIHost{}, fmt.Errorf("failed to parse GHEC REST URL: %w", err)
6161
}
6262

6363
gqlURL, err := url.Parse(fmt.Sprintf("https://api.%s/graphql", u.Hostname()))
6464
if err != nil {
65-
return ApiHost{}, fmt.Errorf("failed to parse GHEC GraphQL URL: %w", err)
65+
return APIHost{}, fmt.Errorf("failed to parse GHEC GraphQL URL: %w", err)
6666
}
6767

6868
uploadURL, err := url.Parse(fmt.Sprintf("https://uploads.%s", u.Hostname()))
6969
if err != nil {
70-
return ApiHost{}, fmt.Errorf("failed to parse GHEC Upload URL: %w", err)
70+
return APIHost{}, fmt.Errorf("failed to parse GHEC Upload URL: %w", err)
7171
}
7272

7373
rawURL, err := url.Parse(fmt.Sprintf("https://raw.%s/", u.Hostname()))
7474
if err != nil {
75-
return ApiHost{}, fmt.Errorf("failed to parse GHEC Raw URL: %w", err)
75+
return APIHost{}, fmt.Errorf("failed to parse GHEC Raw URL: %w", err)
7676
}
7777

78-
return ApiHost{
78+
return APIHost{
7979
BaseRESTURL: restURL,
8080
GraphqlURL: gqlURL,
8181
UploadURL: uploadURL,
8282
RawURL: rawURL,
8383
}, nil
8484
}
8585

86-
func newGHESHost(hostname string) (ApiHost, error) {
86+
func newGHESHost(hostname string) (APIHost, error) {
8787
u, err := url.Parse(hostname)
8888
if err != nil {
89-
return ApiHost{}, fmt.Errorf("failed to parse GHES URL: %w", err)
89+
return APIHost{}, fmt.Errorf("failed to parse GHES URL: %w", err)
9090
}
9191

9292
restURL, err := url.Parse(fmt.Sprintf("%s://%s/api/v3/", u.Scheme, u.Hostname()))
9393
if err != nil {
94-
return ApiHost{}, fmt.Errorf("failed to parse GHES REST URL: %w", err)
94+
return APIHost{}, fmt.Errorf("failed to parse GHES REST URL: %w", err)
9595
}
9696

9797
gqlURL, err := url.Parse(fmt.Sprintf("%s://%s/api/graphql", u.Scheme, u.Hostname()))
9898
if err != nil {
99-
return ApiHost{}, fmt.Errorf("failed to parse GHES GraphQL URL: %w", err)
99+
return APIHost{}, fmt.Errorf("failed to parse GHES GraphQL URL: %w", err)
100100
}
101101

102102
// Check if subdomain isolation is enabled
@@ -112,7 +112,7 @@ func newGHESHost(hostname string) (ApiHost, error) {
112112
uploadURL, err = url.Parse(fmt.Sprintf("%s://%s/api/uploads/", u.Scheme, u.Hostname()))
113113
}
114114
if err != nil {
115-
return ApiHost{}, fmt.Errorf("failed to parse GHES Upload URL: %w", err)
115+
return APIHost{}, fmt.Errorf("failed to parse GHES Upload URL: %w", err)
116116
}
117117

118118
var rawURL *url.URL
@@ -124,10 +124,10 @@ func newGHESHost(hostname string) (ApiHost, error) {
124124
rawURL, err = url.Parse(fmt.Sprintf("%s://%s/raw/", u.Scheme, u.Hostname()))
125125
}
126126
if err != nil {
127-
return ApiHost{}, fmt.Errorf("failed to parse GHES Raw URL: %w", err)
127+
return APIHost{}, fmt.Errorf("failed to parse GHES Raw URL: %w", err)
128128
}
129129

130-
return ApiHost{
130+
return APIHost{
131131
BaseRESTURL: restURL,
132132
GraphqlURL: gqlURL,
133133
UploadURL: uploadURL,
@@ -159,18 +159,18 @@ func checkSubdomainIsolation(scheme, hostname string) bool {
159159
}
160160

161161
// Note that this does not handle ports yet, so development environments are out.
162-
func ParseAPIHost(s string) (ApiHost, error) {
162+
func ParseAPIHost(s string) (APIHost, error) {
163163
if s == "" {
164164
return newDotcomHost()
165165
}
166166

167167
u, err := url.Parse(s)
168168
if err != nil {
169-
return ApiHost{}, fmt.Errorf("could not parse host as URL: %s", s)
169+
return APIHost{}, fmt.Errorf("could not parse host as URL: %s", s)
170170
}
171171

172172
if u.Scheme == "" {
173-
return ApiHost{}, fmt.Errorf("host must have a scheme (http or https): %s", s)
173+
return APIHost{}, fmt.Errorf("host must have a scheme (http or https): %s", s)
174174
}
175175

176176
if strings.HasSuffix(u.Hostname(), "github.com") {

0 commit comments

Comments
 (0)