stacklok / stacklok/toolhive

OTEL: Session-related telemetry and code quality issues

Open
#3,764 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

api bug go telemetry
Dominant language
Go
Stars
2.2k
Forks
300
Avg merge
1d 15h
Merged PRs (30d)
184

Description

Context

These issues were identified during the OTEL MCP semantic conventions review (parent issue: #3399). They are all related to session management code that is expected to undergo significant redesign. Tracking them here so we can check which ones get resolved by the session refactor and which need separate fixes.

Issues

StreamableSession.Disconnect() has a data race (High)

File: pkg/transport/session/streamable_session.go:46-77

The disconnected field is read and written without any synchronization. Concurrent calls to Disconnect() and SendMessage()/SendResponse() can race, potentially causing a double-close panic on channels. Compare with SSESession which correctly uses a mutex.

Fix: Add mutex synchronization matching the SSESession pattern.

"terminated" magic string used across packages (Low)

Files: pkg/transport/session/manager.go:286,308, pkg/vmcp/server/session_adapter.go:105,144

The string "terminated" is used as a metadata key across two packages. A typo would cause silent bugs.

Fix: Define MetadataKeyTerminated constant in the session package.

Potential double-callback race in cleanupExpiredOnce (Low)

File: pkg/transport/session/manager.go

cleanupExpiredOnce and concurrent TerminateSession can fire a session's end callback twice. The safeCallback panic recovery prevents crashes but duplicate metric recordings can occur.

Fix: Use an atomic flag per session to ensure the callback fires at most once.

mcp.server.session.duration metric not implemented (Medium)

Files: pkg/vmcp/server/server.go, pkg/transport/session/manager.go

The OTEL MCP semconv defines mcp.server.session.duration as a recommended histogram metric. The session manager already tracks creation timestamps, so computing duration at termination/expiry is straightforward.

Fix: Add a Float64Histogram metric in the session end callback, recording time.Since(session.CreatedAt()).

Expired-session callbacks silently skip non-LocalStorage backends (Medium)

File: pkg/transport/session/manager.go:299-314

The cleanupExpiredOnce type-asserts *LocalStorage to iterate. Non-local backends silently skip callbacks. Document the limitation or add ListExpired to the Storage interface.

Validate touches terminated sessions, extending TTL (Low)

File: pkg/vmcp/server/session_adapter.go:92

Get() extends the session TTL even for terminated sessions, preventing cleanup. Terminated sessions should expire quickly rather than being kept alive by validation probes.

Notes

  • These should be revisited after the session management redesign
  • Some may be resolved as part of the refactor; others may need separate fixes
  • The StreamableSession.Disconnect() data race is the highest severity item (potential panic)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with pkg/transport/session/streamable_session.go:46-77 and compare its synchronization with SSESession. Then review the listed manager.go, session_adapter.go, and server.go locations, including callback, metadata, metric, storage, and TTL behavior. Done means each issue is fixed or explicitly documented after the planned session redesign.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
backend, observability-sre
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.