mcp: use rand.Text and slog.DiscardHandler over internal implementation (#773)

Address TODOs in code requiring go 1.24 as minimum version

mcp/logging.go: use slog.DiscardHandler, over local implementation
mcp/util.go: use rand.Text, over local implementation

Fixes #772
This commit is contained in:
Suraj Bobade 2026-02-03 18:53:59 +05:30 • committed by GitHub
commit df4f0d56a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 10 additions and 44 deletions

View file

@ -234,7 +234,7 @@ func deepCopyThoughts(thoughts []*Thought) []*Thought {
func StartThinking(ctx context.Context, _ *mcp.CallToolRequest, args StartThinkingArgs) (*mcp.CallToolResult, any, error) {
sessionID := args.SessionID
if sessionID == "" {
sessionID = randText()
sessionID = rand.Text()
}
estimatedSteps := args.EstimatedSteps
@ -480,20 +480,6 @@ func ThinkingHistory(ctx context.Context, req *mcp.ReadResourceRequest) (*mcp.Re
}, nil
}
// Copied from crypto/rand.
// TODO: once 1.24 is assured, just use crypto/rand.
const base32alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
func randText() string {
// ⌈log₃₂ 2¹²⁸⌉ = 26 chars
src := make([]byte, 26)
rand.Read(src)
for i := range src {
src[i] = base32alphabet[src[i]%32]
}
return string(src)
}
func main() {
flag.Parse()

View file

@ -6,6 +6,7 @@ package mcp
import (
"context"
"crypto/rand"
"fmt"
"slices"
"strings"
@ -281,7 +282,7 @@ func BenchmarkMemoryEventStore(b *testing.B) {
for i := range sessionIDs {
sessionIDs[i] = fmt.Sprint(i)
for j := range 3 {
streamIDs[i][j] = randText()
streamIDs[i][j] = rand.Text()
}
}
payload := make([]byte, test.datasize)

View file

@ -89,21 +89,12 @@ type LoggingHandler struct {
handler slog.Handler
}
// discardHandler is a slog.Handler that drops all logs.
// TODO: use slog.DiscardHandler when we require Go 1.24+.
type discardHandler struct{}
func (discardHandler) Enabled(context.Context, slog.Level) bool { return false }
func (discardHandler) Handle(context.Context, slog.Record) error { return nil }
func (discardHandler) WithAttrs([]slog.Attr) slog.Handler { return discardHandler{} }
func (discardHandler) WithGroup(string) slog.Handler { return discardHandler{} }
// ensureLogger returns l if non-nil, otherwise a discard logger.
func ensureLogger(l *slog.Logger) *slog.Logger {
if l != nil {
return l
}
return slog.New(discardHandler{})
return slog.New(slog.DiscardHandler)
}
// NewLoggingHandler creates a [LoggingHandler] that logs to the given [ServerSession] using a

View file

@ -7,6 +7,7 @@ package mcp
import (
"bytes"
"context"
"crypto/rand"
"encoding/base64"
"encoding/gob"
"encoding/json"
@ -175,7 +176,7 @@ func NewServer(impl *Implementation, options *ServerOptions) *Server {
}
if opts.GetSessionID == nil {
opts.GetSessionID = randText
opts.GetSessionID = rand.Text
}
if opts.Logger == nil { // ensure we have a logger

View file

@ -7,6 +7,7 @@ package mcp
import (
"bytes"
"context"
"crypto/rand"
"fmt"
"io"
"net/http"
@ -216,7 +217,7 @@ func (h *SSEHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
sessionID = randText()
sessionID = rand.Text()
endpoint, err := req.URL.Parse("?sessionid=" + sessionID)
if err != nil {
http.Error(w, "internal error: failed to create endpoint", http.StatusInternalServerError)

View file

@ -11,6 +11,7 @@ package mcp
import (
"bytes"
"context"
crand "crypto/rand"
"encoding/json"
"errors"
"fmt"
@ -1140,7 +1141,7 @@ func (c *streamableServerConn) servePOST(w http.ResponseWriter, req *http.Reques
// Important: don't publish the incoming messages until the stream is
// registered, as the server may attempt to respond to imcoming messages as
// soon as they're published.
stream, err := c.newStream(req.Context(), calls, randText())
stream, err := c.newStream(req.Context(), calls, crand.Text())
if err != nil {
http.Error(w, fmt.Sprintf("storing stream: %v", err), http.StatusInternalServerError)
return

View file

@ -5,7 +5,6 @@
package mcp
import (
"crypto/rand"
"encoding/json"
)
@ -15,20 +14,6 @@ func assert(cond bool, msg string) {
}
}
// Copied from crypto/rand.
// TODO: once 1.24 is assured, just use crypto/rand.
const base32alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
func randText() string {
// ⌈log₃₂ 2¹²⁸⌉ = 26 chars
src := make([]byte, 26)
rand.Read(src)
for i := range src {
src[i] = base32alphabet[src[i]%32]
}
return string(src)
}
// remarshal marshals from to JSON, and then unmarshals into to, which must be
// a pointer type.
func remarshal(from, to any) error {