Skip to content

Reject roots listing before sending unsupported client requests - #1160

Open
karthiksenv wants to merge 1 commit into
modelcontextprotocol:mainfrom
karthiksenv:codex/fix-list-roots-capability
Open

karthiksenv wants to merge 1 commit into
modelcontextprotocol:mainfrom
karthiksenv:codex/fix-list-roots-capability

Conversation

@karthiksenv

@karthiksenv karthiksenv commented Oct 3, 2026 •

Copy link
Copy Markdown

A server calling listRoots against an uninitialized client or one without the roots capability currently sends an unsupported roots/list request. Add the same fail-fast checks used by sampling and elicitation, returning an IllegalStateException before contacting the session.

Fixes #1067.

Both listRoots overloads are covered by regression tests that assert no session interaction before or after subscription. Roots support with listChanged=false remains valid. The shared client/server integration test now asserts the local exception and a successful tool response instead of allowing an unasserted call to pass.

Validation on Windows with Temurin 17.0.19 and embedded Tomcat 11.0.2:

  • Before the production fix: 41 exchange tests ran; the four new rejection cases failed because sendRequest was called.
  • After the fix: mvnw.cmd -pl mcp-core -am clean test passed all 457 core tests.
  • Streamable HTTP and SSE testRootsWithoutCapability passed with both Jackson 3 and Jackson 2 (two tests per backend).
  • Formatting validation and git diff --check passed.
  • Full mvnw.cmd verify: core and both Jackson modules passed; mcp-test ran 822 tests with 0 assertion failures and 12 errors caused by unavailable Docker / dependent class initialization. Conformance modules were skipped after that failure. This is not a fully green local CI run.
  • A fork CI dispatch was attempted but GitHub returned workflow ci.yml not found on the default branch; the Ubuntu/Docker CI environment remains unverified.

This is an AI-assisted contribution requiring human review. The repository's AI submission threshold is not met; the exact required disclosure is included in disclosure.txt.

@karthiksenv
karthiksenv marked this pull request as ready for review October 3, 2026 16:14

@soyeladice-svg soyeladice-svg left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

AI-assisted review: the new integration assertion appears to check the wrong failure mode. listRoots() returns a Mono<ListRootsResult>, and the new guards return Mono.error(...); they do not throw synchronously when exchange.listRoots() is called. assertThatThrownBy(exchange::listRoots) only invokes the method reference and receives the Mono, so it should not observe the IllegalStateException unless the publisher is subscribed/blocked. Could this assertion consume the publisher (for example assertThatThrownBy(() -> exchange.listRoots().block())...) or use StepVerifier as the unit tests do? Otherwise the integration test does not actually pin the new fail-fast behavior.

This branch has not been deployed

No deployments
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.

Reject listRoots if not supported by client, without sending any request

2 participants