fix(interceptors): serialize tool call protocol payloads by kyletser · Pull Request #577 · docker/mcp-gateway · GitHub
Skip to content

fix(interceptors): serialize tool call protocol payloads - #577

Open
kyletser wants to merge 1 commit into
docker:mainfrom
kyletser:fix/interceptor-request-payload
Open

kyletser wants to merge 1 commit into
docker:mainfrom
kyletser:fix/interceptor-request-payload

Conversation

@kyletser

Copy link
Copy Markdown

What I did

Before interceptors currently marshal the entire Go SDK request. On Streamable HTTP, RequestExtra contains a CloseSSEStream function field, which makes encoding/json reject the request before the interceptor or tool can run. Even an empty non-nil RequestExtra triggers this error.

Serialize only { "method": "tools/call", "params": ... }, retaining tool arguments and request _meta while excluding SDK session objects and transport state. This applies to all three interceptor runners because serialization happens before runner dispatch. After-interceptor behavior is unchanged.

The lowercase params key matches the existing jq examples. This intentionally replaces the SDK-shaped uppercase Params key; the example README now documents that migration and the payload boundary.

Regression coverage uses a real HTTP interceptor for passthrough and short-circuit results, with nil, empty and callback-bearing transport extras. A separate end-to-end test initializes a real MCP Streamable HTTP client/server pair and calls a tool through the interceptor. It verifies the tool result and the intercepted payload without Docker or a model provider.

Related issue

Fixes #358. The earlier #360 is closed and unmerged; this change includes transport-level regression coverage and does not depend on that PR.

Verification

  • Linux, Go 1.25.12: full-repository golangci-lint 2.8.0 (run ./...) reported 0 issues, and the CLI build passed.
  • Linux: interceptor package passed 10 consecutive runs. Modified Go files pass the repository's formatter checks.
  • Linux full short suite: 34 packages passed; TestReset, TestResetEmptyCatalogs, and TestDockerCatalogProtection failed while downloading https://desktop.docker.com/mcp/catalog/v2/catalog.yaml (connection reset by peer). No tests were excluded or weakened. This is not a full-suite pass.
  • Windows, Go 1.26.7: interceptor package tests passed.
  • TDD: all six payload cases failed before the fix and passed after it.
  • Mutation check: restoring json.Marshal(req) makes the real Streamable HTTP regression fail with the reported serialization error; restoring the fix makes the package pass again.
  • Docker-backed integration tests were not run: the local Docker daemon is unavailable.
  • A Windows full short-suite attempt encountered catalog/path/environment failures and was stopped; it is not reported as passing.

Signed-off-by: Xiaoping Liao <106010272+kyletser@users.noreply.github.com>
@kyletser
kyletser requested a review from a team as a code owner September 12, 2026 13:17
Copilot AI lite review requested due to automatic review settings September 12, 2026 13:17

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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.

before interceptors fail to marshal request: json: unsupported type func(mcp.CloseSSEStreamArgs)

2 participants