From c1118d255c667292b1d4db90da997e25c6816f92 Mon Sep 17 00:00:00 2001 From: Manuel Odendahl Date: Tue, 21 Jan 2025 11:20:41 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=A8=20improve=20logger=20output=20with?= =?UTF-8?q?=20terminal=20detection?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TODO.md | 3 ++- changelog.md | 10 +++++++++- cmd/mcp-client/main.go | 16 +++++++++++++--- cmd/mcp-server/main.go | 16 +++++++++++++--- go.mod | 3 ++- go.sum | 12 ++++++++++++ pkg/server/stdio.go | 15 --------------- 7 files changed, 51 insertions(+), 24 deletions(-) diff --git a/TODO.md b/TODO.md index fe728d1..1fa3d8a 100644 --- a/TODO.md +++ b/TODO.md @@ -18,6 +18,7 @@ ### Bugs - [x] BUG: figure out why closing the client seems to hang +- [ ] Still using the wrong loggers in server (one with terminal, the other, for example) ## MCP server @@ -30,4 +31,4 @@ - [X] Allow debug logging - [x] Implement missing SSE methods -- [ ] BUG: killing server doesn't seem to kill hanging connections (when using inspector, for example) \ No newline at end of file +- [x] BUG: killing server doesn't seem to kill hanging connections (when using inspector, for example) \ No newline at end of file diff --git a/changelog.md b/changelog.md index e04c623..8299e3c 100644 --- a/changelog.md +++ b/changelog.md @@ -308,4 +308,12 @@ Consolidated list operation response types into a shared location: - Moved ListPromptsResult, ListResourcesResult, and ListToolsResult to responses.go - Updated both SSE and stdio servers to use the shared types -- Ensured consistent response structure across all server implementations \ No newline at end of file +- Ensured consistent response structure across all server implementations + +# Improved Logger Output + +Added conditional logger output based on terminal detection. When output is not going to a terminal, the logger will not use color escape codes, making the output more readable in log files and non-terminal environments. + +- Updated both client and server to detect terminal output +- Added golang.org/x/term dependency for terminal detection +- Logger now uses NoColor mode when output is not going to a terminal \ No newline at end of file diff --git a/cmd/mcp-client/main.go b/cmd/mcp-client/main.go index 0a58bac..9331a9d 100644 --- a/cmd/mcp-client/main.go +++ b/cmd/mcp-client/main.go @@ -12,6 +12,7 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "golang.org/x/term" ) var ( @@ -46,9 +47,18 @@ Supports both stdio and SSE transports for client-server communication.`, level = zerolog.InfoLevel } - // Set up console writer for colored output - consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339} - logger := zerolog.New(consoleWriter).With().Timestamp() + var writer zerolog.ConsoleWriter + if term.IsTerminal(int(os.Stderr.Fd())) { + writer = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339} + } else { + writer = zerolog.ConsoleWriter{ + Out: os.Stderr, + TimeFormat: time.RFC3339, + NoColor: true, + } + } + + logger := zerolog.New(writer).With().Timestamp() if withCaller { logger = logger.Caller() } diff --git a/cmd/mcp-server/main.go b/cmd/mcp-server/main.go index 8369efc..37df073 100644 --- a/cmd/mcp-server/main.go +++ b/cmd/mcp-server/main.go @@ -18,6 +18,7 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/spf13/cobra" + "golang.org/x/term" ) var ( @@ -50,9 +51,18 @@ providing a framework for building MCP servers and clients.`, level = zerolog.InfoLevel } - // Set up console writer for colored output - consoleWriter := zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339} - logger := zerolog.New(consoleWriter).With().Timestamp() + var writer zerolog.ConsoleWriter + if term.IsTerminal(int(os.Stderr.Fd())) { + writer = zerolog.ConsoleWriter{Out: os.Stderr, TimeFormat: time.RFC3339} + } else { + writer = zerolog.ConsoleWriter{ + Out: os.Stderr, + TimeFormat: time.RFC3339, + NoColor: true, + } + } + + logger := zerolog.New(writer).With().Timestamp() if withCaller { logger = logger.Caller() } diff --git a/go.mod b/go.mod index a3e4854..f36eed5 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/gorilla/mux v1.8.1 github.com/r3labs/sse/v2 v2.10.0 github.com/rs/zerolog v1.33.0 + golang.org/x/term v0.28.0 ) require ( @@ -23,5 +24,5 @@ require ( github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/spf13/cobra v1.8.1 - golang.org/x/sys v0.28.0 // indirect + golang.org/x/sys v0.29.0 // indirect ) diff --git a/go.sum b/go.sum index 6a4d66c..71516c6 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= @@ -14,9 +15,11 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/r3labs/sse/v2 v2.10.0 h1:hFEkLLFY4LDifoHdiCN/LlGBAdVJYsANaLqNYa1l/v0= github.com/r3labs/sse/v2 v2.10.0/go.mod h1:Igau6Whc+F17QUgML1fYe1VPZzTV6EMCnYktEmkNJ7I= github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg= @@ -30,14 +33,23 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/net v0.0.0-20191116160921-f9c825593386/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I= +golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= +golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= +golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= +golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y= gopkg.in/cenkalti/backoff.v1 v1.1.0/go.mod h1:J6Vskwqd+OMVJl8C33mmtxTBs2gyzfv7UDAkHu8BrjI= diff --git a/pkg/server/stdio.go b/pkg/server/stdio.go index 5f8585a..c45d9f1 100644 --- a/pkg/server/stdio.go +++ b/pkg/server/stdio.go @@ -306,18 +306,3 @@ func (s *StdioServer) sendError(id *json.RawMessage, code int, message string, d s.logger.Debug().Interface("response", response).Msg("Sending error response") return s.writer.Encode(response) } - -type ListPromptsResult struct { - Prompts []protocol.Prompt `json:"prompts"` - NextCursor string `json:"nextCursor"` -} - -type ListResourcesResult struct { - Resources []protocol.Resource `json:"resources"` - NextCursor string `json:"nextCursor"` -} - -type ListToolsResult struct { - Tools []protocol.Tool `json:"tools"` - NextCursor string `json:"nextCursor"` -}