Skip to content

feat: expose resumableStreams and openConnectionOnStartup on McpClientBuilder#2004

Closed
wkflash wants to merge 2 commits into
agentscope-ai:mainfrom
wkflash:feat/mcp-streamable-http-disable-sse
Closed

feat: expose resumableStreams and openConnectionOnStartup on McpClientBuilder#2004
wkflash wants to merge 2 commits into
agentscope-ai:mainfrom
wkflash:feat/mcp-streamable-http-disable-sse

Conversation

@wkflash

@wkflash wkflash commented Jul 3, 2026

Copy link
Copy Markdown

Summary

Expose resumableStreams and openConnectionOnStartup on McpClientBuilder for Streamable HTTP transport, with
bidirectional call-order safety.

Closes #2003.

Problem

When connecting to a Streamable HTTP MCP server that disables SSE and only accepts POST, tool calls hang indefinitely. The
underlying MCP Java SDK (HttpClientStreamableHttpTransport.Builder) already supports these options, but AgentScope's
builder did not expose them.

Solution

Two new fluent methods + tools.json config support:

Java API

McpClientBuilder.create("example")
    .streamableHttpTransport("https://sse-disabled.example.com/mcp")
    .resumableStreams(false)
    .openConnectionOnStartup(false)
    .buildSync();

tools.json

{
  "mcpServers": {
    "my-server": {
      "transport": "http",
      "url": "https://example.com/mcp",
      "resumableStreams": false,
      "openConnectionOnStartup": false
    }
  }
}

Bidirectional safety

Unlike the approach that only writes to the config object, this PR stores values in both a builder-level field AND syncs to
the config if already present. Both call orders work:

// order 1: transport first → instanceOf check writes to config

// order 2: options first → builder field stored, applied when transport is created
.resumableStreams(false).streamableHttpTransport(url)

Tests

- resumableStreams / openConnectionOnStartup after streamableHttpTransportstored correctly
- resumableStreams / openConnectionOnStartup before streamableHttpTransportstored correctly
- Called on SSE transportsilently ignored, type unchanged
- Called before any transportno NPE
- Both options combined
- JSON deserialization of resumableStreams / openConnectionOnStartup

…tBuilder

Adds two new methods to McpClientBuilder for StreamableHTTP transport:
- resumableStreams(boolean) — disable SSE streams for POST-only servers
- openConnectionOnStartup(boolean) — skip persistent connection probe

Both default to null (SDK built-in default), fully backward compatible.

Fixes: tool calls hanging on Streamable HTTP MCP servers that disable SSE.
@wkflash wkflash requested a review from a team July 3, 2026 15:10
@CLAassistant

CLAassistant commented Jul 3, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 76.47059% with 8 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
.../io/agentscope/core/tool/mcp/McpClientBuilder.java 83.33% 2 Missing and 2 partials ⚠️
...tscope/harness/agent/tools/McpServerRegistrar.java 0.00% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

Comment on lines 193 to +201
public McpClientBuilder streamableHttpTransport(String url) {
this.transportConfig = new StreamableHttpTransportConfig(url);
StreamableHttpTransportConfig config = new StreamableHttpTransportConfig(url);
if (resumableStreams != null) {
config.resumableStreams = resumableStreams;
}
if (openConnectionOnStartup != null) {
config.openConnectionOnStartup = openConnectionOnStartup;
}
this.transportConfig = config;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

McpClientBuilder.create("mcp")
.streamableHttpTransport(url)
.resumableStreams(false)
.openConnectionOnStartup(false)

In this order, resumableStreams(false) and openConnectionOnStartup(false) are ignored because they update only the builder-level fields, not the already-created StreamableHttpTransportConfig, leaving the config fields null and thus falling back to SDK defaults.
Recommend the following:

public McpClientBuilder resumableStreams(boolean value) {
    this.resumableStreams = value;
    if (transportConfig instanceof StreamableHttpTransportConfig config) {
        config.resumableStreams = value;
    }
    return this;
}

public McpClientBuilder openConnectionOnStartup(boolean value) {
    this.openConnectionOnStartup = value;
    if (transportConfig instanceof StreamableHttpTransportConfig config) {
        config.openConnectionOnStartup = value;
    }
    return this;
}

@jujn

jujn commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Additionally, it is recommended to supplement corresponding tests

@wkflash wkflash closed this Jul 4, 2026
@wkflash wkflash deleted the feat/mcp-streamable-http-disable-sse branch July 4, 2026 16:41
@wkflash wkflash restored the feat/mcp-streamable-http-disable-sse branch July 5, 2026 00:11
…eamable HTTP transport

- Add resumableStreams(boolean) and openConnectionOnStartup(boolean) to McpClientBuilder
  with bidirectional safety: builder field + instanceof check covers both call orders
- Wire options through to HttpClientStreamableHttpTransport.Builder
- Add resumableStreams and openConnectionOnStartup to tools.json McpServerConfig
- Wire JSON config through McpServerRegistrar
- Add tests covering both call orders, SSE ignore, no-transport safety, and JSON parsing
@wkflash wkflash reopened this Jul 5, 2026
@wkflash wkflash closed this Jul 6, 2026
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.

[Bug]:McpClientBuilder.streamableHttpTransport does not expose resumableStreams option — hangs on SSE-disabled MCP servers

3 participants