Skip to content

Commit f22ba4f

Browse files
ysyneuclaude
andcommitted
refactor(mcp): simplify header cache key and minimize critical section
- Replace SHA-256 hash with sorted key=value concatenation for header comparison — simpler, debuggable, and avoids ambiguous boundaries - Move cache key computation outside mutex to minimize critical section - Remove redundant comments on self-documenting functions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6005b9a commit f22ba4f

1 file changed

Lines changed: 10 additions & 20 deletions

File tree

mcp/client.go

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package mcp
33

44
import (
55
"context"
6-
"crypto/sha256"
76
"fmt"
87
"log/slog"
98
"sort"
@@ -55,12 +54,12 @@ func (m *ClientManager) GetSession(ctx context.Context, server *protocol.MCPServ
5554
logger = slog.With("server", server.Name)
5655
}
5756

57+
serverName := server.Name
58+
currentHash := headersCacheKey(server.Headers, server.DynamicHeaders)
59+
5860
m.mu.Lock()
5961
defer m.mu.Unlock()
6062

61-
serverName := server.Name
62-
currentHash := hashHeaders(server.Headers, server.DynamicHeaders)
63-
6463
logger.Debug("mcp resolving session",
6564
"transport", server.Transport,
6665
"url", server.URL,
@@ -198,31 +197,22 @@ func (m *ClientManager) invalidateSession(serverName string) {
198197
m.mu.Unlock()
199198
}
200199

201-
// hashHeaders computes a stable hash of both static and dynamic headers.
202-
// Used to detect when credentials change so stale sessions are invalidated.
203-
func hashHeaders(headers, dynamicHeaders map[string]string) string {
204-
h := sha256.New()
205-
// Sort keys for deterministic hashing
206-
writeMap := func(m map[string]string) {
200+
func headersCacheKey(headers, dynamicHeaders map[string]string) string {
201+
encode := func(m map[string]string) string {
207202
keys := make([]string, 0, len(m))
208203
for k := range m {
209204
keys = append(keys, k)
210205
}
211206
sort.Strings(keys)
212-
for _, k := range keys {
213-
h.Write([]byte(k))
214-
h.Write([]byte(m[k]))
207+
parts := make([]string, len(keys))
208+
for i, k := range keys {
209+
parts[i] = k + "=" + m[k]
215210
}
211+
return strings.Join(parts, "\x00")
216212
}
217-
h.Write([]byte("static:"))
218-
writeMap(headers)
219-
h.Write([]byte("dynamic:"))
220-
writeMap(dynamicHeaders)
221-
return fmt.Sprintf("%x", h.Sum(nil))
213+
return "s:" + encode(headers) + "\x01d:" + encode(dynamicHeaders)
222214
}
223215

224-
// maskKey returns the first 6 characters of a key for safe logging.
225-
// Returns empty string for empty/short keys.
226216
func maskKey(key string) string {
227217
// Strip "Bearer " prefix if present
228218
if strings.HasPrefix(key, "Bearer ") {

0 commit comments

Comments
 (0)