feat: log which MCP client connected, fix capability-read race - #253
Open
mattpodwysocki wants to merge 2 commits into
Open
feat: log which MCP client connected, fix capability-read race#253mattpodwysocki wants to merge 2 commits into
mattpodwysocki wants to merge 2 commits into
Conversation
server.server.getClientVersion()/getClientCapabilities() are only populated once the client's initialize request has been processed -- reading them synchronously right after server.connect() races that request, since connect() only waits for the transport to start, not for the handshake to finish. Confirmed live: reading capabilities immediately after connect() reliably returned undefined even for a client that declared them. Moved both reads into a server.server.oninitialized callback, which fires only once the handshake is fully done. This also fixes the same-shaped bug in the existing capability-gated elicitation-tool registration (currently dormant since ELICITATION_TOOLS is empty, but was silently broken for whenever a tool is added there), and adds client identification as a byproduct: the client's name/version from its initialize request is now logged on connect. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
setClientInfo (tracing.ts) stores the connected client's clientInfo as module-level state -- there's exactly one client per stdio server process -- and createToolSpan now reads it into mcp.client.name/mcp.client.version attributes on every tool span. index.ts calls setClientInfo from the same oninitialized callback that already logs the client identity, so OTel traces can be filtered/grouped by which client made each call. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
zmofei
approved these changes
Aug 26, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
server.server.getClientVersion()(populated from theclientInfosent in the client'sinitializerequest) is now logged on connect, e.g.Client identified as: claude-ai v1.0.0— useful for support/debugging when behavior differs across Claude Desktop, Cursor, VS Code, etc. Also recorded asmcp.client.name/mcp.client.versionon every subsequent tool-execution trace span, so OTel-backed traces can be filtered or grouped by client.getClientVersion()/getClientCapabilities()are only populated once the client'sinitializerequest has been processed. Reading them synchronously right afterawait server.connect(transport)races that request, sinceconnect()only waits for the transport to start, not for the handshake to complete. Confirmed live — even with a client that explicitly declaredelicitationsupport, the existing "Client capabilities detected" debug log always printedundefined.server.server.oninitializedcallback (registered beforeconnect()), which only fires once the initialize handshake is fully done. This also fixes the same-shaped bug in the existing capability-gated elicitation-tool registration path — currently dormant sinceELICITATION_TOOLSis empty, but would have silently never worked for the first tool added there.Test plan
npx vitest run— all 937 tests pass, including new coverage intest/utils/tracing.test.tsfor the client-info trace attributesnpm run buildsucceedselicitationcapability: server now logsClient identified as: pretend-cursor-client v9.9.9andClient capabilities detected: { "elicitation": { "form": {} } }(previouslyundefined)🤖 Generated with Claude Code