aws / aws/amazon-q-developer-cli

bug: Q CLI fails to connect to MCP servers that don't support SSE (returns 405) - violates MCP specification

Open
#3,182 3 comments 0 reactions 1 assignee Claimed by @dingfeli View on GitHub
MCP
Dominant language
Rust
Stars
2k
Forks
439
PR merge metrics
No merged PRs in 30d

Description

### Checks

- [x] I have searched [github.com/aws/amazon-q-developer-cli/issues](https://github.com/aws/amazon-q-developer-cli/issues?q=) and there are no duplicates of my issue
- [x] I have run `q doctor` in the affected terminal session
- [x] I have run `q restart` and replicated the issue again

### Operating system

Linux

### Expected behaviour

**TLDR:** Q CLI incorrectly handles MCP servers that don't support Server-Sent Events (SSE), failing to establish connections even though these servers correctly follow the MCP specification by returning HTTP 405 for SSE requests.

According to the MCP specification (2025-03-26 / 2025-06-18, Streamable HTTP transport section on "Sending Messages to the Server"):
> "The client MUST include an Accept header, listing both application/json and text/event-stream as supported content types. The server MUST either return Content-Type: text/event-stream in response to this HTTP GET, or else return HTTP 405 Method Not Allowed, indicating that the server does not offer an SSE stream at this endpoint" - [Specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#sending-messages-to-the-server).

Q CLI should:
1. Receive the 405 response to the initial probe.
2. Specifically detect the 405 status as an indicator of no SSE support (per spec).
3. Retry the connection with `Accept: application/json` only, allowing successful JSON-based communication.
4. Only fallback to legacy SSE transport for non-405 errors (e.g., authentication issues).
5. Successfully connect using JSON-only mode for spec-compliant non-SSE servers.

### Actual behaviour

When connecting to an MCP server that doesn't support SSE:
1. Q CLI sends a POST request with: `Accept: application/json, text/event-stream` (as seen in `crates/chat-cli/src/mcp_client/oauth_util.rs#L258-L262`):
```rust
let probe_resp = reqwest_client
.post(url.clone())
.header("Accept", "application/json, text/event-stream")
.send()
.await;
```
2. Server returns: `405 Method Not Allowed` (as per MCP spec).
3. Q CLI treats this as a generic transport failure and incorrectly transitions the state machine to attempt legacy SSE mode, without retrying in JSON-only mode. This is evident in the error handling for unauthenticated connections (`crates/chat-cli/src/mcp_client/oauth_util.rs#L273-L285`):
```rust
match service.clone().into_dyn().serve(transport).await {
Ok(service) => return Ok((service, None)),
Err(e) => {
// BUG: Treats any error (including 405) as reason to switch to SSE transport
// No specific check for 405 to retry JSON-only
error!("## mcp: open http handshake attempted failed for {server_name}: {:?}. Attempting sse", e);
state = HttpServiceBuilderState::AttemptConnection(TransportType::Sse, false);
},
}
```
For authenticated connections, a similar flawed transition occurs (`crates/chat-cli/src/mcp_client/oauth_util.rs#L220-L233`), first attempting a token refresh on failure, then falling back to SSE if that also fails—still without handling 405 specifically.
4. The SSE fallback also fails (since the server doesn't support it), leading to a complete connection abandonment.
5. Error message: `Mcp error: -32002: Client error: Client error: HTTP status client error (405 Method Not Allowed)`

### Steps to reproduce

1. Create an MCP server that only supports JSON responses (no SSE).
2. Configure server to return 405 for requests with `Accept: text/event-stream`.
3. Add server to Q CLI configuration.
4. Run `q chat`.
5. Observe connection failure.

### Environment

```yaml

```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.