Skip to content

fix(mcp): invalidate cached sessions when DynamicHeaders change#27

Merged
ysyneu merged 3 commits intomainfrom
fix/mcp-session-header-invalidation
Apr 8, 2026
Merged

fix(mcp): invalidate cached sessions when DynamicHeaders change#27
ysyneu merged 3 commits intomainfrom
fix/mcp-session-header-invalidation

Conversation

@ysyneu
Copy link
Copy Markdown
Collaborator

@ysyneu ysyneu commented Apr 8, 2026

Summary

  • Fix session caching bug where ClientManager.GetSession reused stale sessions even when DynamicHeaders (auth credentials) changed, causing 401 Unauthorized on MCP tool calls
  • Hash both static and dynamic headers at session creation; invalidate and recreate session when headers differ
  • Add masked auth_key (first 6 chars) to session lifecycle logs for debugging without leaking secrets

Test plan

  • Set SAFARI_FLASHDUTY_MCP_APP_KEY on Safari, verify runner logs show mcp headers changed, invalidating cached session on first call after restart
  • Verify auth_key=<first6>*** appears in runner logs for session creation
  • Confirm Flashduty MCP tool calls (e.g. query_incidents) succeed with production key

🤖 Generated with Claude Code

ysyneu and others added 3 commits April 8, 2026 09:49
The ClientManager cached MCP sessions by server name but never checked
if the authentication headers had changed. When Safari restarts with
different credentials (e.g. SAFARI_FLASHDUTY_MCP_APP_KEY override), the
runner kept reusing the stale session with old headers, causing 401
Unauthorized errors on tool calls.

Now we hash both static and dynamic headers at session creation time and
compare on reuse. If headers differ, the stale session is closed and a
new one is created with the current credentials.

Also adds masked auth_key (first 6 chars) to session lifecycle logs for
easier debugging without leaking secrets.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- 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>
- G706 (log injection): exclude globally — slog structured logging is
  inherently safe against injection
- G204 (subprocess with variable): add nolint for intentional exec calls
  (MCP stdio, bash workspace, rg grep)
- G118 (context cancel): nolint — cancel is stored in runningTask map
- S1017: use strings.TrimPrefix instead of if+slice
- QF1012: use fmt.Fprintf instead of WriteString(fmt.Sprintf(...))
- noctx: use exec.CommandContext for system info commands
- prealloc: preallocate grep cmdArgs slice

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@ysyneu ysyneu merged commit 232a6c5 into main Apr 8, 2026
9 of 10 checks passed
@ysyneu ysyneu deleted the fix/mcp-session-header-invalidation branch April 8, 2026 02:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant