Fix HTTP 400 on tools/list for HTTP backends with custom auth headers (Atlassian MCP)#2608
Merged
Fix HTTP 400 on tools/list for HTTP backends with custom auth headers (Atlassian MCP)#2608
Conversation
Contributor
There was a problem hiding this comment.
Copilot wasn't able to review any files in this pull request.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ia RoundTripper in SDK transports Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/aa49466a-a33a-4fcc-b3f9-6b8d24d91a06 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix HTTP 400 error on tools/list for Atlassian MCP backend
Fix HTTP 400 on tools/list for HTTP backends with custom auth headers (Atlassian MCP)
Mar 26, 2026
lpcox
added a commit
that referenced
this pull request
Mar 26, 2026
PR #2608 removed the 'headers → skip SDK transports' shortcut so SDK transports now always attempt first. The mock servers were hardcoding JSON-RPC response id=1, which caused mismatched request IDs when the SDK assigned sequential IDs — tools/list responses never matched their Await calls, hanging the tests. Fixes: - Echo back the request ID from the JSON-RPC body in mock responses - Handle notifications/initialized with 202 Accepted - Handle empty/probe requests (GET/DELETE) with 405 - Update session ID propagation assertions to account for SDK transport behavior (SDK manages sessions internally, no Mcp-Session-Id header) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
lpcox
added a commit
that referenced
this pull request
Mar 26, 2026
PR #2608 removed the 'headers → skip SDK transports' shortcut, so SDK transports now always attempt first. This caused 3 tests in `unified_http_backend_test.go` to hang because: 1. Mock servers hardcoded `"id": 1` in all JSON-RPC responses, but the SDK assigns sequential IDs — `tools/list` responses never matched their `Await` calls 2. Mocks didn't handle `notifications/initialized` (SDK sends this after initialize) 3. Session ID propagation assertions assumed plain JSON-RPC behavior **Fixes:** - Echo back the request ID from the JSON-RPC body - Handle `notifications/initialized` with 202 Accepted - Handle empty/probe requests with 405 - Update session ID assertions to account for SDK streamable transport `make agent-finished` passes ✅
lpcox
added a commit
that referenced
this pull request
Mar 27, 2026
Fixes hanging `TestConnection_SendRequest` in `internal/mcp` caused by SDK streamable transport changes from #2608. **Root cause:** After #2608 removed the headers shortcut, `NewHTTPConnection` always tries SDK streamable transport first. Two mock server issues caused hangs: 1. `newPlainJSONTestServer` didn't handle `notifications/initialized` (SDK sends this after `initialize`) 2. `TestConnection_SendRequest` hardcoded `"id": 1` — SDK assigns sequential IDs, so the response never matched the `Await` call **Fix:** - Added `notifications/initialized` handler (202 Accepted) to `newPlainJSONTestServer` - Echo back `req["id"]` instead of hardcoding `1` in the test handler
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.
When an HTTP MCP backend was configured with custom headers (e.g.
Authorization: Basic …),NewHTTPConnectionskipped the SDK-managed Streamable HTTP and SSE transports entirely and jumped straight to a plain JSON-RPC-over-POST fallback. That fallback violates the MCP 2025-03-26 spec in several ways (missing initialize handshake ordering,params: nullvsparams: {}), causing Atlassian's server to return HTTP 400 ontools/list.Core fix
internal/mcp/http_transport.goheaderInjectingRoundTripper: anhttp.RoundTripperwrapper that injects a fixed header map into every outgoing request.buildHTTPClientWithHeaders(base, headers): returns a shallow-cloned*http.Clientwhose transport is the injecting round-tripper; returnsbaseunchanged whenheadersis empty.internal/mcp/connection.goif len(headers) > 0 { → tryPlainJSONTransport }bypass. All backends now always attempt Streamable HTTP → SSE → plain JSON-RPC, passing a header-injecting client to the SDK transports.reconnectSDKTransportlikewise rebuilds the header-injecting client on reconnect so auth headers survive session expiry.Test updates
Several tests assumed "custom headers → plain JSON-RPC". Changes:
tryPlainJSONTransportdirectly via anewPlainJSONConnhelper, insulating them from transport selection changes.t.FailNow()/require.NoErroron empty-body requests (GET/DELETE probe requests from the Streamable transport) now return405 Method Not Allowedgracefully so they fail-fast and fall back to plain JSON-RPC as intended.Mcp-Session-Id, while still asserting theAuthorizationheader is present on every request and that the final plain JSON-RPC initialization succeeds with the correct session ID pattern.Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
example.com/tmp/go-build171139688/b334/launcher.test /tmp/go-build171139688/b334/launcher.test -test.testlogfile=/tmp/go-build171139688/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s -W aw-mcpg/internal/tmp/go-build303593668/b241/symabis aw-mcpg/internal-c=4 x_amd64/link . --gdwarf2 --64 x_amd64/link -I 372667/b001/_pkg_.a -I(dns block)invalid-host-that-does-not-exist-12345.com/tmp/go-build171139688/b319/config.test /tmp/go-build171139688/b319/config.test -test.testlogfile=/tmp/go-build171139688/b319/testlog.txt -test.paniconexit0 -test.timeout=10m0s -uns�� Fj0d/1ybRA9tQ-C_xvKXEFj0d /tmp/go-build3955865240/b041/vet.cfg x_amd64/compile -D GOAMD64_v1 -o x_amd64/compile -I ache/go/1.25.8/x64/src/net/addrselect.go ache/go/1.25.8/x64/src/net/cgo_unix.go ache/Python/3.12.13/x64/bin/bash --gdwarf-5 --64 -o /opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linuconntrack(dns block)/tmp/go-build3065041637/b319/config.test /tmp/go-build3065041637/b319/config.test -test.testlogfile=/tmp/go-build3065041637/b319/testlog.txt -test.paniconexit0 -test.timeout=10m0s -o fa3e4140c55d28ab -trimpath docker-compose by/abae9c8c0ced3bash github.com/githu/usr/bin/runc -lang=go1.25 docker-compose �� d68cedb73cad4caf/run/containerd/io.containerd.runtime.v2.task/moby/aecbb305fa8c8fe12aec9eb4a2fb2/opt/hostedtoolcache/go/1.25.8/x64/pkg/tool/linux_amd64/vet -goversion /usr/bin/docker -c=4 -nolocalimports 802/log.json docker(dns block)nonexistent.local/tmp/go-build171139688/b334/launcher.test /tmp/go-build171139688/b334/launcher.test -test.testlogfile=/tmp/go-build171139688/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s -W aw-mcpg/internal/tmp/go-build303593668/b241/symabis aw-mcpg/internal-c=4 x_amd64/link . --gdwarf2 --64 x_amd64/link -I 372667/b001/_pkg_.a -I(dns block)slow.example.com/tmp/go-build171139688/b334/launcher.test /tmp/go-build171139688/b334/launcher.test -test.testlogfile=/tmp/go-build171139688/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s -W aw-mcpg/internal/tmp/go-build303593668/b241/symabis aw-mcpg/internal-c=4 x_amd64/link . --gdwarf2 --64 x_amd64/link -I 372667/b001/_pkg_.a -I(dns block)this-host-does-not-exist-12345.com/tmp/go-build3955865240/b001/mcp.test /tmp/go-build3955865240/b001/mcp.test -test.testlogfile=/tmp/go-build3955865240/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.run=TestNewHTTPConnection 1.4.1/internal/x. ypto.go x_amd64/compile credential.usernas(dns block)/tmp/go-build399372667/b001/mcp.test /tmp/go-build399372667/b001/mcp.test -test.testlogfile=/tmp/go-build399372667/b001/testlog.txt -test.paniconexit0 -test.run=TestNewHTTPConnection|TestTryPlain -test.v=true -test.timeout=1m0s S2YQJddBm 64/pkg/tool/linu-o gpg.program(dns block)/tmp/go-build3428895484/b001/mcp.test /tmp/go-build3428895484/b001/mcp.test -test.testlogfile=/tmp/go-build3428895484/b001/testlog.txt -test.paniconexit0 -test.timeout=2m0s -goversion go1.25.8 -c=4 -nolocalimports -importcfg /tmp/go-build399372667/b001/importcfg -pack /tmp/go-build399372667/b001/_testmain.go ortc�� g_.a 64/src/crypto/internal/impl/impl--gdwarf2 ache/go/1.25.8/x64/pkg/tool/linu--64 commit.gpgsign abis(dns block)If you need me to access, download, or install something from one of these locations, you can either:
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.