Skip to content

feat(mcp): log JSON-RPC method and tool name on per-request slog line#86

Merged
mhersson merged 4 commits into
mainfrom
ctxmax-488/log-which-mcp-tool-is-being-used
May 12, 2026
Merged

feat(mcp): log JSON-RPC method and tool name on per-request slog line#86
mhersson merged 4 commits into
mainfrom
ctxmax-488/log-which-mcp-tool-is-being-used

Conversation

@contextmatrix-runner
Copy link
Copy Markdown
Contributor

Summary

  • The POST /mcp request log line previously contained only path=/mcp status=200 duration_ms=x, with no indication of which MCP tool was invoked. This adds two new slog fields, mcp_method and mcp_tool, surfaced from a minimal JSON-RPC body peek.
  • A new MCPCall context value (in ctxlog) is attached by the observe middleware on /mcp requests; a small mcpRequestInfoMiddleware in the MCP handler chain reads the body, parses the JSON-RPC envelope, restores the body via io.NopCloser(bytes.NewReader(buf)), and writes the extracted values back into the shared *MCPCall. After ServeHTTP returns, observe appends mcp_method (and mcp_tool for tools/call) to the existing per-request log line.
  • Both fields are capped at 64 chars (matching the project's request-id ceiling) so an authenticated client cannot use a multi-megabyte JSON-RPC payload to bloat per-request log output.

Test plan

  • go test ./... — all internal packages pass
  • make lint (golangci-lint) — 0 issues
  • Unit coverage: WithMCPCall / MCPCallFromContext round-trip and missing-context cases in internal/ctxlog/ctxlog_test.go
  • Middleware table test (internal/mcp/logging_test.go) covering tools/call, non-tools/call, malformed JSON, GET no-op, nil-context defense, and field-length truncation
  • Verify in a running server that a POST /mcp tools/call request now emits mcp_method=tools/call mcp_tool=<tool_name> on the request log line

ContextMatrix Runner 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
@mhersson mhersson merged commit b0cb22f into main May 12, 2026
2 checks passed
@mhersson mhersson deleted the ctxmax-488/log-which-mcp-tool-is-being-used branch May 12, 2026 21:38
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