feat(mcp): log JSON-RPC method and tool name on per-request slog line#86
Merged
Merged
Conversation
added 4 commits
May 12, 2026 21:26
- Add MCPCall struct and WithMCPCall/MCPCallFromContext helpers to ctxlog - observe middleware injects *MCPCall into context for /mcp requests and appends mcp_method/mcp_tool fields after ServeHTTP returns - mcpRequestInfoMiddleware in mcp/server.go reads+restores body, parses the JSON-RPC envelope, and populates the MCPCall pointer - Wire mcpRequestInfoMiddleware between clearWriteDeadlineForStreaming and the SDK handler inside NewHandler - Add TestWithMCPCall_roundtrip and TestMCPCallFromContext_missing to ctxlog - Add TestMCPRequestInfoMiddleware table test covering tools/call, other methods, malformed JSON, GET no-op, and nil-context defensive path
…pace - Replace require.NoError with assert.NoError inside httptest handler closures so testifylint go-require passes (require.NoError can call t.FailNow which is unsafe outside the test goroutine) - Apply whitespace-linter (wsl) formatting in observe middleware
- Add gotcha entry explaining the two new slog fields emitted on POST /mcp requests (mcp_method, mcp_tool), the body-peeking middleware that extracts them, and best-effort semantics (errors swallowed, fields omitted when absent) - Update ctxlog component description in architecture.md to mention MCPCall context value and how observe middleware surfaces it on the log line
- Add truncateLogField helper and maxLogFieldLen constant in mcp/server.go - Truncate extracted JSON-RPC method and tool name before storing on the shared MCPCall so an authenticated client cannot inflate per-request slog lines with a multi-megabyte JSON-RPC payload (the body is already bounded at 5 MB by the outer bodyLimit middleware, but the extracted strings would otherwise be logged verbatim) - Add TestMCPRequestInfoMiddleware_truncatesLongFields covering both the long method-name and long tool-name paths
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
POST /mcprequest log line previously contained onlypath=/mcp status=200 duration_ms=x, with no indication of which MCP tool was invoked. This adds two new slog fields,mcp_methodandmcp_tool, surfaced from a minimal JSON-RPC body peek.MCPCallcontext value (inctxlog) is attached by theobservemiddleware on/mcprequests; a smallmcpRequestInfoMiddlewarein the MCP handler chain reads the body, parses the JSON-RPC envelope, restores the body viaio.NopCloser(bytes.NewReader(buf)), and writes the extracted values back into the shared*MCPCall. AfterServeHTTPreturns,observeappendsmcp_method(andmcp_toolfortools/call) to the existing per-request log line.Test plan
go test ./...— all internal packages passmake lint(golangci-lint) — 0 issuesWithMCPCall/MCPCallFromContextround-trip and missing-context cases ininternal/ctxlog/ctxlog_test.gointernal/mcp/logging_test.go) coveringtools/call, non-tools/call, malformed JSON, GET no-op, nil-context defense, and field-length truncation/mcptools/callrequest now emitsmcp_method=tools/call mcp_tool=<tool_name>on the request log line