Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitaa9623c

Browse files
committed
Add HTTP+SSE server command with graceful shutdown and logging middleware
I'm not sure we want to merge this, but this allowed me to try dotcom chat action as an MCP host, using `mark3labs/mcp-go` in copilot-api, connecting to a localhost version of github-mcp-server via HTTP/SSE.```export GITHUB_PERSONAL_ACCESS_TOKEN=<TOKEN_FROM_DEV_ENVIRONMENT>go run cmd/github-mcp-server/main.go http --gh-hosthttp://api.github.localhost --port 4567```
1 parent5eb969e commitaa9623c

File tree

2 files changed

+160
-7
lines changed

2 files changed

+160
-7
lines changed

‎README.md

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
237237

238238
###Repository Content
239239

240-
-**Get Repository Content**
240+
-**Get Repository Content**
241241
Retrieves the content of a repository at a specific path.
242242

243243
-**Template**:`repo://{owner}/{repo}/contents{/path*}`
@@ -246,7 +246,7 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
246246
-`repo`: Repository name (string, required)
247247
-`path`: File or directory path (string, optional)
248248

249-
-**Get Repository Content for a Specific Branch**
249+
-**Get Repository Content for a Specific Branch**
250250
Retrieves the content of a repository at a specific path for a given branch.
251251

252252
-**Template**:`repo://{owner}/{repo}/refs/heads/{branch}/contents{/path*}`
@@ -256,7 +256,7 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
256256
-`branch`: Branch name (string, required)
257257
-`path`: File or directory path (string, optional)
258258

259-
-**Get Repository Content for a Specific Commit**
259+
-**Get Repository Content for a Specific Commit**
260260
Retrieves the content of a repository at a specific path for a given commit.
261261

262262
-**Template**:`repo://{owner}/{repo}/sha/{sha}/contents{/path*}`
@@ -266,7 +266,7 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
266266
-`sha`: Commit SHA (string, required)
267267
-`path`: File or directory path (string, optional)
268268

269-
-**Get Repository Content for a Specific Tag**
269+
-**Get Repository Content for a Specific Tag**
270270
Retrieves the content of a repository at a specific path for a given tag.
271271

272272
-**Template**:`repo://{owner}/{repo}/refs/tags/{tag}/contents{/path*}`
@@ -276,7 +276,7 @@ and set it as the GITHUB_PERSONAL_ACCESS_TOKEN environment variable.
276276
-`tag`: Tag name (string, required)
277277
-`path`: File or directory path (string, optional)
278278

279-
-**Get Repository Content for a Specific Pull Request**
279+
-**Get Repository Content for a Specific Pull Request**
280280
Retrieves the content of a repository at a specific path for a given pull request.
281281

282282
-**Template**:`repo://{owner}/{repo}/refs/pull/{pr_number}/head/contents{/path*}`
@@ -319,6 +319,35 @@ GitHub MCP Server running on stdio
319319
320320
```
321321
322+
## HTTP+SSE server
323+
324+
> [!WARNING]
325+
> This version of the server works with the [2024-11-05 MCP Spec](https://spec.modelcontextprotocol.io/specification/2024-11-05/), which requires a stateful connectionforSSE. We plan to add support for a stateless modein the future, as allowed by the [2025-03-26 MCP Spec](https://spec.modelcontextprotocol.io/specification/2025-03-26/changelog).
326+
327+
Run the serverin HTTP mode with Server-Sent Events (SSE):
328+
329+
```sh
330+
go run cmd/github-mcp-server/main.go http
331+
```
332+
333+
The server will start on port 8080 by default. You can specify a different port using the`--port` flag:
334+
335+
```sh
336+
go run cmd/github-mcp-server/main.go http --port 3000
337+
```
338+
339+
The server accepts connections at`http://localhost:<port>` and communicates using Server-Sent Events (SSE).
340+
341+
Like the stdio server, ensure your GitHub Personal Access Token issetin the`GITHUB_PERSONAL_ACCESS_TOKEN` environment variable before starting the server.
342+
343+
You can use the same flags as the stdio server:
344+
345+
-`--read-only`: Restrict the server to read-only operations
346+
-`--log-file`: Path to log file
347+
-`--enable-command-logging`: Enable logging of allcommand requests and responses
348+
-`--export-translations`: Save translations to a JSON file
349+
-`--gh-host`: Specify the GitHub hostname (for GitHub Enterprise, localhost etc.)
350+
322351
## i18n / Overriding descriptions
323352
324353
The descriptions of the tools can be overridden by creating a github-mcp-server.json filein the same directory as the binary.
@@ -376,7 +405,7 @@ Run **Preferences: Open User Settings (JSON)**, and create or append to the `mcp
376405
"args": ["stdio"],
377406
"env": {
378407
"GITHUB_PERSONAL_ACCESS_TOKEN":"${input:githubpat}"
379-
},
408+
}
380409
}
381410
}
382411
}

‎cmd/github-mcp-server/main.go

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"io"
77
stdlog"log"
8+
"net/http"
89
"os"
910
"os/signal"
1011
"syscall"
@@ -44,6 +45,26 @@ var (
4445
}
4546
},
4647
}
48+
49+
httpCmd=&cobra.Command{
50+
Use:"http",
51+
Short:"Start HTTP server",
52+
Long:`Start a server that communicates via HTTP using Server-Sent Events (SSE).`,
53+
Run:func(cmd*cobra.Command,args []string) {
54+
logFile:=viper.GetString("log-file")
55+
readOnly:=viper.GetBool("read-only")
56+
exportTranslations:=viper.GetBool("export-translations")
57+
port:=viper.GetString("port")
58+
logger,err:=initLogger(logFile)
59+
iferr!=nil {
60+
stdlog.Fatal("Failed to initialize logger:",err)
61+
}
62+
logCommands:=viper.GetBool("enable-command-logging")
63+
iferr:=runHTTPServer(readOnly,logger,logCommands,exportTranslations,port);err!=nil {
64+
stdlog.Fatal("failed to run http server:",err)
65+
}
66+
},
67+
}
4768
)
4869

4970
funcinit() {
@@ -56,15 +77,20 @@ func init() {
5677
rootCmd.PersistentFlags().Bool("export-translations",false,"Save translations to a JSON file")
5778
rootCmd.PersistentFlags().String("gh-host","","Specify the GitHub hostname (for GitHub Enterprise etc.)")
5879

59-
// Bind flag to viper
80+
// Add HTTP specific flags
81+
httpCmd.Flags().String("port","8080","Port for the HTTP server")
82+
83+
// Bind flags to viper
6084
viper.BindPFlag("read-only",rootCmd.PersistentFlags().Lookup("read-only"))
6185
viper.BindPFlag("log-file",rootCmd.PersistentFlags().Lookup("log-file"))
6286
viper.BindPFlag("enable-command-logging",rootCmd.PersistentFlags().Lookup("enable-command-logging"))
6387
viper.BindPFlag("export-translations",rootCmd.PersistentFlags().Lookup("export-translations"))
6488
viper.BindPFlag("gh-host",rootCmd.PersistentFlags().Lookup("gh-host"))
89+
viper.BindPFlag("port",httpCmd.Flags().Lookup("port"))
6590

6691
// Add subcommands
6792
rootCmd.AddCommand(stdioCmd)
93+
rootCmd.AddCommand(httpCmd)
6894
}
6995

7096
funcinitConfig() {
@@ -159,6 +185,104 @@ func runStdioServer(readOnly bool, logger *log.Logger, logCommands bool, exportT
159185
returnnil
160186
}
161187

188+
funcrunHTTPServer(readOnlybool,logger*log.Logger,logCommandsbool,exportTranslationsbool,portstring)error {
189+
// Create app context
190+
ctx,stop:=signal.NotifyContext(context.Background(),os.Interrupt,syscall.SIGTERM)
191+
deferstop()
192+
193+
// Create GH client
194+
token:=os.Getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
195+
iftoken=="" {
196+
logger.Fatal("GITHUB_PERSONAL_ACCESS_TOKEN not set")
197+
}
198+
ghClient:=gogithub.NewClient(nil).WithAuthToken(token)
199+
200+
// Check GH_HOST env var first, then fall back to viper config
201+
host:=os.Getenv("GH_HOST")
202+
ifhost=="" {
203+
host=viper.GetString("gh-host")
204+
}
205+
206+
ifhost!="" {
207+
varerrerror
208+
ghClient,err=ghClient.WithEnterpriseURLs(host,host)
209+
iferr!=nil {
210+
returnfmt.Errorf("failed to create GitHub client with host: %w",err)
211+
}
212+
}
213+
214+
t,dumpTranslations:=translations.TranslationHelper()
215+
216+
// Create GitHub server
217+
ghServer:=github.NewServer(ghClient,readOnly,t)
218+
219+
ifexportTranslations {
220+
// Once server is initialized, all translations are loaded
221+
dumpTranslations()
222+
}
223+
224+
// Create SSE server
225+
sseServer:=server.NewSSEServer(ghServer)
226+
227+
// Start listening for messages
228+
errC:=make(chanerror,1)
229+
gofunc() {
230+
// Configure and start HTTP server
231+
mux:=http.NewServeMux()
232+
233+
// Add SSE handler with logging middleware if enabled
234+
varhandler http.Handler=sseServer
235+
iflogCommands {
236+
handler=loggingMiddleware(handler,logger)
237+
}
238+
mux.Handle("/",handler)
239+
240+
srv:=&http.Server{
241+
Addr:":"+port,
242+
Handler:mux,
243+
}
244+
245+
// Graceful shutdown
246+
gofunc() {
247+
<-ctx.Done()
248+
iferr:=srv.Shutdown(context.Background());err!=nil {
249+
logger.Errorf("HTTP server shutdown error: %v",err)
250+
}
251+
}()
252+
253+
iferr:=srv.ListenAndServe();err!=http.ErrServerClosed {
254+
errC<-err
255+
}
256+
}()
257+
258+
// Output github-mcp-server string
259+
_,_=fmt.Fprintf(os.Stderr,"GitHub MCP Server running on http://localhost:%s\n",port)
260+
261+
// Wait for shutdown signal
262+
select {
263+
case<-ctx.Done():
264+
logger.Infof("shutting down server...")
265+
caseerr:=<-errC:
266+
iferr!=nil {
267+
returnfmt.Errorf("error running server: %w",err)
268+
}
269+
}
270+
271+
returnnil
272+
}
273+
274+
// loggingMiddleware wraps an http.Handler and logs requests
275+
funcloggingMiddleware(next http.Handler,logger*log.Logger) http.Handler {
276+
returnhttp.HandlerFunc(func(w http.ResponseWriter,r*http.Request) {
277+
logger.WithFields(log.Fields{
278+
"method":r.Method,
279+
"path":r.URL.Path,
280+
}).Info("Received request")
281+
282+
next.ServeHTTP(w,r)
283+
})
284+
}
285+
162286
funcmain() {
163287
iferr:=rootCmd.Execute();err!=nil {
164288
fmt.Println(err)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp