What happened?
I use Fastmail's MCP server (see their blogpost) in other LLM interfaces and coding agents, and wanted to set it up in qwen.
The authentication works in qwen, but then getting tools times out, and never successfully completes.
What did you expect to happen?
I expected requesting tool/resource/prompt lists all succeed in a short time.
Client information
Client Information
Run qwen to enter the interactive CLI, then run the /about command.
Warning: MCP server(s) failed to start: fastmail. Continuing with built-in tools and any servers that did connect. Re-run with QWEN_CODE_DEBUG=1 to see per-server reasons.
Qwen Code v0.19.11
Model: qwen3.6-35b-a3b-mtp
Fast Model: openai:lfm2-2.6b
Auth: openai
Platform: linux x64 (7.1.3-arch2-1)
Node.js: v26.4.0
Session: f65b4b65-f1cd-4218-a7e6-272e76501c81
Git commit: a0f373c1c
LSP: disabled
Login information
API Config
Anything else we need to know?
The same Fastmail MCP server works just fine in LMStudio and in Claude Code.
Also context7 (also oAuth) and kagi (bearer token, remoete) MCP servers work just fine in qwen.
While trying to hunt down the issue, I replicated similar calls to the MCP server as qwen does it, with curl, and all of those worked as expected.
Some further debug seems to be suggesting something around qwen's handling of the long loved GET SSE streams seems funky, that something hangs there.
The logs show something like:
269:2026-07-18T01:26:53.843Z [DEBUG] [MCP_OAUTH] Starting OAuth for MCP server "fastmail"…
279:2026-07-18T01:27:14.418Z [DEBUG] [MCP_OAUTH] Getting valid token for server: fastmail
280:2026-07-18T01:27:14.419Z [DEBUG] [MCP_OAUTH] Found token for server: fastmail, expired: false
281:2026-07-18T01:27:14.419Z [DEBUG] [MCP_OAUTH] Returning valid token for server: fastmail
282:2026-07-18T01:27:14.419Z [DEBUG] [MCP] Found stored OAuth token for server 'fastmail'
303:2026-07-18T01:28:14.872Z [ERROR] [MCP] Error discovering prompts from fastmail: MCP error -32001: Request timed out
304:2026-07-18T01:28:14.872Z [ERROR] [MCP] Error discovering resources from fastmail: MCP error -32001: Request timed out
305:2026-07-18T01:28:14.873Z [ERROR] [MCP] Error discovering tools from fastmail: MCP error -32001: Request timed out
306:2026-07-18T01:28:14.873Z [ERROR] [MCP] Error during discovery for server 'fastmail': No prompts, tools, or resources found on the server.
308:2026-07-18T01:28:44.874Z [WARN] [MCP] Health check failed for server 'fastmail' (1/3)
310:2026-07-18T01:29:14.875Z [WARN] [MCP] Health check failed for server 'fastmail' (2/3)
312:2026-07-18T01:29:44.876Z [WARN] [MCP] Health check failed for server 'fastmail' (3/3)
313:2026-07-18T01:29:44.877Z [INFO] [MCP] Attempting to reconnect to server 'fastmail'...
here's a hacked-up patch that seems to work for the feature but produces some test failures that need checking
diff --git a/packages/core/src/tools/mcp-client.ts b/packages/core/src/tools/mcp-client.ts
index ea7ead8fe..250de3b1f 100644
--- a/packages/core/src/tools/mcp-client.ts
+++ b/packages/core/src/tools/mcp-client.ts
@@ -26,6 +26,7 @@ import {
ReadResourceResultSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { parse } from 'shell-quote';
+import { Agent, fetch as undiciFetch } from 'undici';
import type { Config, MCPServerConfig } from '../config/config.js';
import { AuthProviderType, isSdkMcpServerConfig } from '../config/config.js';
import { GoogleCredentialProvider } from '../mcp/google-auth-provider.js';
@@ -57,6 +58,7 @@ import type { PromptRegistry } from '../prompts/prompt-registry.js';
import type { ResourceRegistry } from '../resources/resource-registry.js';
import { getErrorMessage, getErrorStatus } from '../utils/errors.js';
import { createDebugLogger } from '../utils/debugLogger.js';
+import { isTlsVerificationDisabled } from '../utils/runtimeFetchOptions.js';
import { retryWithBackoff } from './mcp-retry.js';
import { normalizePathEnvForWindows } from '../utils/windowsPath.js';
import type {
@@ -250,13 +252,48 @@ export function createStreamableHttpCompatibilityFetch(
};
}
+// Streamable HTTP servers may hold a long-lived GET SSE stream open for the
+// lifetime of the connection (the transport opens it automatically after
+// `notifications/initialized`, per the MCP spec). Node's default global
+// fetch dispatcher stalls subsequent requests to the same origin while that
+// stream is open, until the MCP SDK's own request timeout fires. A
+// dedicated undici Agent does not have this problem, regardless of its
+// connection cap. `headersTimeout`/`bodyTimeout` are disabled because the
+// GET stream is expected to sit idle between server-sent events.
+let mcpFetchDispatcher: Agent | undefined;
+function getMcpFetchDispatcher(): Agent {
+ if (!mcpFetchDispatcher) {
+ mcpFetchDispatcher = new Agent({
+ headersTimeout: 0,
+ bodyTimeout: 0,
+ keepAliveTimeout: 60_000,
+ ...(isTlsVerificationDisabled()
+ ? { connect: { rejectUnauthorized: false } }
+ : {}),
+ });
+ }
+ return mcpFetchDispatcher;
+}
+
+// Bound to undici's own fetch (not Node's global fetch) so the dispatcher
+// and fetch implementation always come from the same undici version — Node's
+// bundled undici can be a different major version than the `undici` package
+// installed here, and mixing dispatcher/fetch across versions throws
+// "invalid onError method".
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+const mcpGlobalFetch: any = (input: unknown, init?: unknown) =>
+ undiciFetch(input as string, {
+ ...(init as object),
+ dispatcher: getMcpFetchDispatcher(),
+ });
+
function createMcpStreamableHttpFetch(
mcpServerName: string,
mcpServerConfig: MCPServerConfig,
): typeof fetch {
return createStreamableHttpCompatibilityFetch(
mcpServerName,
- globalThis.fetch.bind(globalThis),
+ mcpGlobalFetch,
mcpServerConfig,
);
}
What happened?
I use Fastmail's MCP server (see their blogpost) in other LLM interfaces and coding agents, and wanted to set it up in qwen.
The authentication works in qwen, but then getting tools times out, and never successfully completes.
What did you expect to happen?
I expected requesting tool/resource/prompt lists all succeed in a short time.
Client information
Client Information
Run
qwento enter the interactive CLI, then run the/aboutcommand.Login information
API Config
Anything else we need to know?
The same Fastmail MCP server works just fine in LMStudio and in Claude Code.
Also
context7(also oAuth) andkagi(bearer token, remoete) MCP servers work just fine in qwen.While trying to hunt down the issue, I replicated similar calls to the MCP server as qwen does it, with
curl, and all of those worked as expected.Some further debug seems to be suggesting something around qwen's handling of the long loved GET SSE streams seems funky, that something hangs there.
The logs show something like:
here's a hacked-up patch that seems to work for the feature but produces some test failures that need checking