NUAAwqy opened a new pull request, #6947:
URL: https://github.com/apache/rocketmq-dashboard/pull/6947
### What this PR does
The rmqctl stdio-MCP bridge re-encodes JSON-RPC messages through mcp-go SDK
types. The SDK decodes numeric ids (mcp.RequestId and notification params)
through float64, so integers beyond 2^53 are silently rounded:
- a request id like `9007199254740993` is sent as `9007199254740992` (int64
max becomes `9223372036854776000`),
- the id returned to the stdio client is the rounded one,
- a response carrying the rounded neighbour of the request id is accepted as
matching,
- `notifications/cancelled` forwards `params.requestId` rounded.
Reproduced on `rocketmq-studio` at `a92c231` with the production
`MCPClientSession` against a local httptest peer; no live Studio/Broker
required.
Fixes #6904
### How it is fixed
Bridge-side, no SDK change:
- `decodeMCPMessage` keeps the exact textual token for numeric request ids
(`json.Number` re-marshals verbatim) and for a numeric `params.requestId` in
notifications.
- `mcpStatusRoundTripper` compares the raw id token of the outgoing JSON-RPC
request against the response frame before the SDK decodes it: JSON bodies
eagerly, POST SSE streams as the response frame is consumed (non-response SSE
events keep streaming unblocked). Numeric tokens are compared by value (`1`
matches `1.0`), a numeric and a string token never match, and a mismatch fails
the exchange.
- `sendRequest` returns the exact outgoing identity in the response payload
once the raw tokens matched.
### Tests
New `rmqctl/internal/studio/mcp_id_precision_test.go`: the four defect
scenarios from the issue (the adjacent-id one over both the JSON and the SSE
response channel) plus six passing controls.
RED against the unmodified code:
```
--- FAIL: TestLargeNumericRequestIDIsPreserved (0.00s)
--- FAIL: TestInt64MaxRequestIDIsPreserved (0.00s)
--- FAIL: TestAdjacentResponseIDIsRejected (0.00s)
--- FAIL: TestLargeCancellationRequestIDIsPreserved (0.00s)
--- FAIL: TestAdjacentResponseIDIsRejectedOverSSE (0.00s)
--- PASS: TestSmallNumericRequestIDIsPreserved (0.00s)
--- PASS: TestStringRequestIDIsPreserved (0.00s)
--- PASS: TestStringResponseIDForNumericRequestIsRejected (0.00s)
--- PASS: TestNumericResponseIDForStringRequestIsRejected (0.00s)
--- PASS: TestSmallCancellationRequestIDIsPreserved (0.00s)
--- PASS: TestStringCancellationRequestIDIsPreserved (0.00s)
FAIL
FAIL github.com/apache/rocketmq-dashboard/rmqctl/internal/studio 0.035s
FAIL
mcp_id_precision_test.go:134: wire request id was changed, body =
{"jsonrpc":"2.0","id":9007199254740992,"method":"tools/list","params":{}}
mcp_id_precision_test.go:134: returned response id was changed, payload
= {"jsonrpc":"2.0","id":9007199254740992,"result":{"tools":[]}}
mcp_id_precision_test.go:144: wire request id was changed, body =
{"jsonrpc":"2.0","id":9223372036854776000,"method":"tools/list","params":{}}
mcp_id_precision_test.go:144: returned response id was changed, payload
= {"jsonrpc":"2.0","id":9223372036854776000,"result":{"tools":[]}}
mcp_id_precision_test.go:157: adjacent response id was accepted: ok:true
err:<nil>
mcp_id_precision_test.go:174: cancellation requestId was changed, body =
{"jsonrpc":"2.0","method":"notifications/cancelled","params":{"_meta":{},"requestId":9007199254740992}}
mcp_id_precision_test.go:189: adjacent SSE response id was accepted:
ok:true err:<nil>
```
GREEN with the fix:
```
--- PASS: TestLargeNumericRequestIDIsPreserved (0.00s)
--- PASS: TestInt64MaxRequestIDIsPreserved (0.00s)
--- PASS: TestAdjacentResponseIDIsRejected (0.00s)
--- PASS: TestLargeCancellationRequestIDIsPreserved (0.00s)
--- PASS: TestAdjacentResponseIDIsRejectedOverSSE (0.00s)
--- PASS: TestSmallNumericRequestIDIsPreserved (0.00s)
--- PASS: TestStringRequestIDIsPreserved (0.00s)
--- PASS: TestStringResponseIDForNumericRequestIsRejected (0.00s)
--- PASS: TestNumericResponseIDForStringRequestIsRejected (0.00s)
--- PASS: TestSmallCancellationRequestIDIsPreserved (0.00s)
--- PASS: TestStringCancellationRequestIDIsPreserved (0.00s)
PASS
ok github.com/apache/rocketmq-dashboard/rmqctl/internal/studio 0.034s
```
Full-module `go test ./... -count=1`, `go test -race ./internal/studio/
./cmd/`, `go vet ./...` and `gofmt -l` are clean, including the existing stdio
saturation tests.
AI assistance used for discovery; changes were verified by running the test
suite locally.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]