Skip to content

Commit 270bbf7

Browse files
authored
pretty print json (github#114)
1 parent 86b0dcd commit 270bbf7

File tree

1 file changed

+45
-9
lines changed

1 file changed

+45
-9
lines changed

cmd/github-mcp-server/main.go

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package main
22

33
import (
4+
"bytes"
45
"context"
6+
"encoding/json"
57
"fmt"
68
"io"
79
stdlog "log"
@@ -39,12 +41,20 @@ var (
3941
logFile := viper.GetString("log-file")
4042
readOnly := viper.GetBool("read-only")
4143
exportTranslations := viper.GetBool("export-translations")
44+
prettyPrintJSON := viper.GetBool("pretty-print-json")
4245
logger, err := initLogger(logFile)
4346
if err != nil {
4447
stdlog.Fatal("Failed to initialize logger:", err)
4548
}
4649
logCommands := viper.GetBool("enable-command-logging")
47-
if err := runStdioServer(readOnly, logger, logCommands, exportTranslations); err != nil {
50+
cfg := runConfig{
51+
readOnly: readOnly,
52+
logger: logger,
53+
logCommands: logCommands,
54+
exportTranslations: exportTranslations,
55+
prettyPrintJSON: prettyPrintJSON,
56+
}
57+
if err := runStdioServer(cfg); err != nil {
4858
stdlog.Fatal("failed to run stdio server:", err)
4959
}
5060
},
@@ -60,13 +70,15 @@ func init() {
6070
rootCmd.PersistentFlags().Bool("enable-command-logging", false, "When enabled, the server will log all command requests and responses to the log file")
6171
rootCmd.PersistentFlags().Bool("export-translations", false, "Save translations to a JSON file")
6272
rootCmd.PersistentFlags().String("gh-host", "", "Specify the GitHub hostname (for GitHub Enterprise etc.)")
73+
rootCmd.PersistentFlags().Bool("pretty-print-json", false, "Pretty print JSON output")
6374

6475
// Bind flag to viper
6576
_ = viper.BindPFlag("read-only", rootCmd.PersistentFlags().Lookup("read-only"))
6677
_ = viper.BindPFlag("log-file", rootCmd.PersistentFlags().Lookup("log-file"))
6778
_ = viper.BindPFlag("enable-command-logging", rootCmd.PersistentFlags().Lookup("enable-command-logging"))
6879
_ = viper.BindPFlag("export-translations", rootCmd.PersistentFlags().Lookup("export-translations"))
6980
_ = viper.BindPFlag("gh-host", rootCmd.PersistentFlags().Lookup("gh-host"))
81+
_ = viper.BindPFlag("pretty-print-json", rootCmd.PersistentFlags().Lookup("pretty-print-json"))
7082

7183
// Add subcommands
7284
rootCmd.AddCommand(stdioCmd)
@@ -95,15 +107,36 @@ func initLogger(outPath string) (*log.Logger, error) {
95107
return logger, nil
96108
}
97109

98-
func runStdioServer(readOnly bool, logger *log.Logger, logCommands bool, exportTranslations bool) error {
110+
type runConfig struct {
111+
readOnly bool
112+
logger *log.Logger
113+
logCommands bool
114+
exportTranslations bool
115+
prettyPrintJSON bool
116+
}
117+
118+
// JSONPrettyPrintWriter is a Writer that pretty prints input to indented JSON
119+
type JSONPrettyPrintWriter struct {
120+
writer io.Writer
121+
}
122+
123+
func (j JSONPrettyPrintWriter) Write(p []byte) (n int, err error) {
124+
var prettyJSON bytes.Buffer
125+
if err := json.Indent(&prettyJSON, p, "", "\t"); err != nil {
126+
return 0, err
127+
}
128+
return j.writer.Write(prettyJSON.Bytes())
129+
}
130+
131+
func runStdioServer(cfg runConfig) error {
99132
// Create app context
100133
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
101134
defer stop()
102135

103136
// Create GH client
104137
token := os.Getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
105138
if token == "" {
106-
logger.Fatal("GITHUB_PERSONAL_ACCESS_TOKEN not set")
139+
cfg.logger.Fatal("GITHUB_PERSONAL_ACCESS_TOKEN not set")
107140
}
108141
ghClient := gogithub.NewClient(nil).WithAuthToken(token)
109142
ghClient.UserAgent = fmt.Sprintf("github-mcp-server/%s", version)
@@ -125,13 +158,13 @@ func runStdioServer(readOnly bool, logger *log.Logger, logCommands bool, exportT
125158
t, dumpTranslations := translations.TranslationHelper()
126159

127160
// Create
128-
ghServer := github.NewServer(ghClient, readOnly, t)
161+
ghServer := github.NewServer(ghClient, cfg.readOnly, t)
129162
stdioServer := server.NewStdioServer(ghServer)
130163

131-
stdLogger := stdlog.New(logger.Writer(), "stdioserver", 0)
164+
stdLogger := stdlog.New(cfg.logger.Writer(), "stdioserver", 0)
132165
stdioServer.SetErrorLogger(stdLogger)
133166

134-
if exportTranslations {
167+
if cfg.exportTranslations {
135168
// Once server is initialized, all translations are loaded
136169
dumpTranslations()
137170
}
@@ -141,11 +174,14 @@ func runStdioServer(readOnly bool, logger *log.Logger, logCommands bool, exportT
141174
go func() {
142175
in, out := io.Reader(os.Stdin), io.Writer(os.Stdout)
143176

144-
if logCommands {
145-
loggedIO := iolog.NewIOLogger(in, out, logger)
177+
if cfg.logCommands {
178+
loggedIO := iolog.NewIOLogger(in, out, cfg.logger)
146179
in, out = loggedIO, loggedIO
147180
}
148181

182+
if cfg.prettyPrintJSON {
183+
out = JSONPrettyPrintWriter{writer: out}
184+
}
149185
errC <- stdioServer.Listen(ctx, in, out)
150186
}()
151187

@@ -155,7 +191,7 @@ func runStdioServer(readOnly bool, logger *log.Logger, logCommands bool, exportT
155191
// Wait for shutdown signal
156192
select {
157193
case <-ctx.Done():
158-
logger.Infof("shutting down server...")
194+
cfg.logger.Infof("shutting down server...")
159195
case err := <-errC:
160196
if err != nil {
161197
return fmt.Errorf("error running server: %w", err)

0 commit comments

Comments
 (0)