apache/shenyu · error · IllegalStateException

Failed to retrieve MCP sync server exchange from context

Error message

Failed to retrieve MCP sync server exchange from context

What it means

extractMcpExchange fetches the McpSyncServerExchange from the ToolContext via McpSessionHelper and throws IllegalStateException when it is absent. The ShenYu MCP bridge needs the current MCP exchange to build the decorated ServerWebExchange; its absence means the callback was invoked outside a proper MCP session context.

Solutions

  1. Ensure the tool is invoked through the MCP server flow that populates the exchange into the ToolContext/session holder first.
  2. In tests, register a mock McpSyncServerExchange via McpSessionHelper/McpSessionHelper-equivalent setup before calling.
  3. Check session lifetime configuration — if sessions expire quickly, increase the timeout or reuse a persistent session.
  4. Confirm the MCP client maintains the same sessionId across initialization and tool calls.

Example fix

// before (test)
callback.call(args, new ToolContext(Map.of()));
// after
ToolContext ctx = McpTestSupport.contextWithExchange(mockMcpSyncServerExchange);
callback.call(args, ctx);
Defensive patterns

Strategy: type-guard

Validate before calling

if (McpSessionHelper.getMcpSyncServerExchange(toolContext) == null) {
    throw new IllegalStateException("No MCP exchange in ToolContext; invoke via MCP server flow");
}

Type guard

boolean hasMcpExchange(ToolContext ctx) {
    return McpSessionHelper.getMcpSyncServerExchange(ctx) != null;
}

Try / catch

try {
    return callback.call(args, ctx);
} catch (IllegalStateException e) {
    if (e.getMessage().contains("MCP sync server exchange")) {
        // reinitialize the MCP session and retry once, or report session expired
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling the tool callback with a ToolContext that has no McpSyncServerExchange stored (McpSessionHelper returns null) — e.g. the callback invoked directly in tests, or by a non-MCP caller, or the session state was cleared before the call.

Common situations: Unit-testing ShenyuToolCallback with a synthetic ToolContext; MCP client disconnecting/timing out so the session was removed before tool execution; invoking the callback through a path that bypasses ShenyuMcpExchangeHolder session setup.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/shenyu@567142e072 (2026-09-12). Data as JSON: /api/errors/581339ded2c87eb1. Report an issue: GitHub.

Appendix: source

Thrown at shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/callback/ShenyuToolCallback.java:759

     * @return true if the method supports request body
     */
    private boolean isRequestBodyMethod(final String method) {
        return "POST".equalsIgnoreCase(method)
                || "PUT".equalsIgnoreCase(method)
                || "PATCH".equalsIgnoreCase(method);
    }

    /**
     * Extracts the MCP sync server exchange from the tool context.
     *
     * @param toolContext the tool context containing MCP session information
     * @return the MCP sync server exchange
     * @throws IllegalStateException if exchange cannot be retrieved
     */
    private McpSyncServerExchange extractMcpExchange(final ToolContext toolContext) {
        final McpSyncServerExchange exchange = McpSessionHelper.getMcpSyncServerExchange(toolContext);
        if (Objects.isNull(exchange)) {
            throw new IllegalStateException("Failed to retrieve MCP sync server exchange from context");
        }
        return exchange;
    }

    /**
     * Extracts the session ID from the MCP sync server exchange.
     *
     * @param mcpExchange the MCP sync server exchange
     * @return the session ID
     * @throws IllegalStateException if the session ID is blank or an SDK compatibility issue blocks extraction
     * @throws IllegalArgumentException if the exchange is missing required session state
     */
    private String extractSessionId(final McpSyncServerExchange mcpExchange) {
        try {
            final String sessionId = McpSessionHelper.getSessionId(mcpExchange);
            if (StringUtils.hasText(sessionId)) {
                LOG.debug("Extracted session ID: {}", sessionId);
                return sessionId;

View on GitHub (pinned to 567142e072)