Skip to content

Commit 8dcd049

Browse files
authored
Merge branch 'main' into add-issue-dependencies
2 parents fb758ed + 121d50a commit 8dcd049

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+5561
-1420
lines changed

.vscode/launch.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
"program": "cmd/github-mcp-server/main.go",
2424
"args": ["stdio", "--read-only"],
2525
"console": "integratedTerminal",
26+
},
27+
{
28+
"name": "Launch http server",
29+
"type": "go",
30+
"request": "launch",
31+
"mode": "auto",
32+
"cwd": "${workspaceFolder}",
33+
"program": "cmd/github-mcp-server/main.go",
34+
"args": ["http", "--port", "8082"],
35+
"console": "integratedTerminal",
2636
}
2737
]
2838
}

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ LABEL io.modelcontextprotocol.server.name="io.github.github/github-mcp-server"
2626
WORKDIR /server
2727
# Copy the binary from the build stage
2828
COPY --from=build /bin/github-mcp-server .
29+
# Expose the default port
30+
EXPOSE 8082
2931
# Set the entrypoint to the server binary
3032
ENTRYPOINT ["/server/github-mcp-server"]
3133
# Default arguments for ENTRYPOINT

cmd/github-mcp-server/main.go

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/github/github-mcp-server/internal/ghmcp"
1111
"github.com/github/github-mcp-server/pkg/github"
12+
ghhttp "github.com/github/github-mcp-server/pkg/http"
1213
"github.com/spf13/cobra"
1314
"github.com/spf13/pflag"
1415
"github.com/spf13/viper"
@@ -89,6 +90,31 @@ var (
8990
return ghmcp.RunStdioServer(stdioServerConfig)
9091
},
9192
}
93+
94+
httpCmd = &cobra.Command{
95+
Use: "http",
96+
Short: "Start HTTP server",
97+
Long: `Start an HTTP server that listens for MCP requests over HTTP.`,
98+
RunE: func(_ *cobra.Command, _ []string) error {
99+
ttl := viper.GetDuration("repo-access-cache-ttl")
100+
httpConfig := ghhttp.ServerConfig{
101+
Version: version,
102+
Host: viper.GetString("host"),
103+
Port: viper.GetInt("port"),
104+
BaseURL: viper.GetString("base-url"),
105+
ResourcePath: viper.GetString("base-path"),
106+
ExportTranslations: viper.GetBool("export-translations"),
107+
EnableCommandLogging: viper.GetBool("enable-command-logging"),
108+
LogFilePath: viper.GetString("log-file"),
109+
ContentWindowSize: viper.GetInt("content-window-size"),
110+
LockdownMode: viper.GetBool("lockdown-mode"),
111+
RepoAccessCacheTTL: &ttl,
112+
ScopeChallenge: viper.GetBool("scope-challenge"),
113+
}
114+
115+
return ghhttp.RunHTTPServer(httpConfig)
116+
},
117+
}
92118
)
93119

94120
func init() {
@@ -112,6 +138,12 @@ func init() {
112138
rootCmd.PersistentFlags().Bool("insiders", false, "Enable insiders features")
113139
rootCmd.PersistentFlags().Duration("repo-access-cache-ttl", 5*time.Minute, "Override the repo access cache TTL (e.g. 1m, 0s to disable)")
114140

141+
// HTTP-specific flags
142+
httpCmd.Flags().Int("port", 8082, "HTTP server port")
143+
httpCmd.Flags().String("base-url", "", "Base URL where this server is publicly accessible (for OAuth resource metadata)")
144+
httpCmd.Flags().String("base-path", "", "Externally visible base path for the HTTP server (for OAuth resource metadata)")
145+
httpCmd.Flags().Bool("scope-challenge", false, "Enable OAuth scope challenge responses")
146+
115147
// Bind flag to viper
116148
_ = viper.BindPFlag("toolsets", rootCmd.PersistentFlags().Lookup("toolsets"))
117149
_ = viper.BindPFlag("tools", rootCmd.PersistentFlags().Lookup("tools"))
@@ -126,9 +158,13 @@ func init() {
126158
_ = viper.BindPFlag("lockdown-mode", rootCmd.PersistentFlags().Lookup("lockdown-mode"))
127159
_ = viper.BindPFlag("insiders", rootCmd.PersistentFlags().Lookup("insiders"))
128160
_ = viper.BindPFlag("repo-access-cache-ttl", rootCmd.PersistentFlags().Lookup("repo-access-cache-ttl"))
129-
161+
_ = viper.BindPFlag("port", httpCmd.Flags().Lookup("port"))
162+
_ = viper.BindPFlag("base-url", httpCmd.Flags().Lookup("base-url"))
163+
_ = viper.BindPFlag("base-path", httpCmd.Flags().Lookup("base-path"))
164+
_ = viper.BindPFlag("scope-challenge", httpCmd.Flags().Lookup("scope-challenge"))
130165
// Add subcommands
131166
rootCmd.AddCommand(stdioCmd)
167+
rootCmd.AddCommand(httpCmd)
132168
}
133169

134170
func initConfig() {

docs/remote-server.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,13 +121,15 @@ The Remote GitHub MCP server supports the following URL path patterns:
121121
- `/` - Default toolset (see ["default" toolset](../README.md#default-toolset))
122122
- `/readonly` - Default toolset in read-only mode
123123
- `/insiders` - Default toolset with insiders mode enabled
124-
- `/insiders/readonly` - Default toolset with insiders mode in read-only mode
124+
- `/readonly/insiders` - Default toolset in read-only mode with insiders mode enabled
125125
- `/x/all` - All available toolsets
126126
- `/x/all/readonly` - All available toolsets in read-only mode
127127
- `/x/all/insiders` - All available toolsets with insiders mode enabled
128+
- `/x/all/readonly/insiders` - All available toolsets in read-only mode with insiders mode enabled
128129
- `/x/{toolset}` - Single specific toolset
129130
- `/x/{toolset}/readonly` - Single specific toolset in read-only mode
130131
- `/x/{toolset}/insiders` - Single specific toolset with insiders mode enabled
132+
- `/x/{toolset}/readonly/insiders` - Single specific toolset in read-only mode with insiders mode enabled
131133

132134
Note: `{toolset}` can only be a single toolset, not a comma-separated list. To combine multiple toolsets, use the `X-MCP-Toolsets` header instead. Path modifiers like `/readonly` and `/insiders` can be combined with the `X-MCP-Insiders` or `X-MCP-Readonly` headers.
133135

docs/streamable-http.md

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Streamable HTTP Server
2+
3+
The Streamable HTTP mode enables the GitHub MCP Server to run as an HTTP service, allowing clients to connect via standard HTTP protocols. This mode is ideal for deployment scenarios where stdio transport isn't suitable, such as reverse proxy setups, containerized environments, or distributed architectures.
4+
5+
## Features
6+
7+
- **Streamable HTTP Transport** — Full HTTP server with streaming support for real-time tool responses
8+
- **OAuth Metadata Endpoints** — Standard `.well-known/oauth-protected-resource` discovery for OAuth clients
9+
- **Scope Challenge Support** — Automatic scope validation with proper HTTP 403 responses and `WWW-Authenticate` headers
10+
- **Scope Filtering** — Restrict available tools based on authenticated credentials and permissions
11+
- **Custom Base Paths** — Support for reverse proxy deployments with customizable base URLs
12+
13+
## Running the Server
14+
15+
### Basic HTTP Server
16+
17+
Start the server on the default port (8082):
18+
19+
```bash
20+
github-mcp-server http
21+
```
22+
23+
The server will be available at `http://localhost:8082`.
24+
25+
### With Scope Challenge
26+
27+
Enable scope validation to enforce GitHub permission checks:
28+
29+
```bash
30+
github-mcp-server http --scope-challenge
31+
```
32+
33+
When `--scope-challenge` is enabled, requests with insufficient scopes receive a `403 Forbidden` response with a `WWW-Authenticate` header indicating the required scopes.
34+
35+
### With OAuth Metadata Discovery
36+
37+
For use behind reverse proxies or with custom domains, expose OAuth metadata endpoints:
38+
39+
```bash
40+
github-mcp-server http --scope-challenge --base-url https://myserver.com --base-path /mcp
41+
```
42+
43+
The OAuth protected resource metadata's `resource` attribute will be populated with the full URL to the server's protected resource endpoint:
44+
45+
```json
46+
{
47+
"resource_name": "GitHub MCP Server",
48+
"resource": "https://myserver.com/mcp",
49+
"authorization_servers": [
50+
"https://github.com/login/oauth"
51+
],
52+
"scopes_supported": [
53+
"repo",
54+
...
55+
],
56+
...
57+
}
58+
```
59+
60+
This allows OAuth clients to discover authentication requirements and endpoint information automatically.
61+
62+
## Client Configuration
63+
64+
### Using OAuth Authentication
65+
66+
If your IDE or client has GitHub credentials configured (i.e. VS Code), simply reference the HTTP server:
67+
68+
```json
69+
{
70+
"type": "http",
71+
"url": "http://localhost:8082"
72+
}
73+
```
74+
75+
The server will use the client's existing GitHub authentication.
76+
77+
### Using Bearer Tokens or Custom Headers
78+
79+
To provide PAT credentials, or to customize server behavior preferences, you can include additional headers in the client configuration:
80+
81+
```json
82+
{
83+
"type": "http",
84+
"url": "http://localhost:8082",
85+
"headers": {
86+
"Authorization": "Bearer ghp_yourtokenhere",
87+
"X-MCP-Toolsets": "default",
88+
"X-MCP-Readonly": "true"
89+
}
90+
}
91+
```
92+
93+
See [Remote Server](./remote-server.md) documentation for more details on client configuration options.

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ require (
1717
github.com/aymerick/douceur v0.2.0 // indirect
1818
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
1919
github.com/fsnotify/fsnotify v1.9.0 // indirect
20+
github.com/go-chi/chi/v5 v5.2.3
2021
github.com/go-openapi/jsonpointer v0.19.5 // indirect
2122
github.com/go-openapi/swag v0.21.1 // indirect
2223
github.com/go-viper/mapstructure/v2 v2.5.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
1010
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
1111
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
1212
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
13+
github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE=
14+
github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops=
1315
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
1416
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
1517
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=

0 commit comments

Comments
 (0)