apache/shenyu · error · IllegalArgumentException

ToolContext is required

Error message

ToolContext is required

What it means

IllegalArgumentException from McpSessionHelper.getMcpSyncServerExchange when the ToolContext argument is null. Spring AI passes a ToolContext to tool callbacks during MCP tool execution; the helper needs it to retrieve the McpSyncServerExchange under the 'exchange' key. A null context means the tool was invoked without the MCP-provided context.

Solutions

  1. Invoke the tool through the MCP server path (or pass a ToolContext built with the 'exchange' key) rather than calling call(args) directly
  2. Upgrade Spring AI to the tested version (1.1.2) so ToolContext is populated automatically for MCP tool calls
  3. In custom wrappers, always forward the ToolContext argument to the underlying callback
  4. Guard in your code: reject tool invocations where ToolContext is null before reaching the plugin

Example fix

// before
toolCallback.call(toolArgs);
// after
toolCallback.call(toolArgs, new ToolContext(Map.of("exchange", mcpSyncServerExchange)));
Defensive patterns

Strategy: type-guard

Validate before calling

if (toolContext == null) {
    throw new IllegalArgumentException("tool call requires a ToolContext from the MCP pipeline");
}

Type guard

boolean hasToolContext(Object ctx) { return ctx instanceof ToolContext; }

Try / catch

try {
    result = toolCallback.call(args, toolContext);
} catch (IllegalArgumentException e) {
    if ("ToolContext is required".equals(e.getMessage())) {
        LOG.error("Tool invoked without MCP ToolContext; use the MCP execution path", e);
    } else throw e;
}

Prevention

When it happens

Trigger: getMcpSyncServerExchange(null) is called — i.e. a ShenyuToolCallback is executed with a null ToolContext (e.g. calling call()/apply() directly without context, or a Spring AI version not passing context).

Common situations: Directly invoking ShenyuToolCallback in tests or custom code without a ToolContext; an older Spring AI runtime that doesn't propagate ToolContext into tool calls; a custom tool-execution wrapper dropping the context argument.

Related errors


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

Appendix: source

Thrown at shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/session/McpSessionHelper.java:132

                    + "(tested: {}). Error: {}", SUPPORTED_SDK_VERSION, e.getMessage(), e);
        }
    }

    private static void clearReflectionFieldCache() {
        asyncExchangeFieldCache = null;
        sessionFieldCache = null;
        fieldsResolved = false;
    }

    /**
     * Get McpSyncServerExchange from ToolContext.
     *
     * @param toolContext the tool context
     * @return the McpSyncServerExchange instance
     */
    public static McpSyncServerExchange getMcpSyncServerExchange(final ToolContext toolContext) {
        if (Objects.isNull(toolContext)) {
            throw new IllegalArgumentException("ToolContext is required");
        }
        Map<String, Object> contextMap = toolContext.getContext();
        if (Objects.isNull(contextMap) || contextMap.isEmpty()) {
            throw new IllegalArgumentException("ToolContext is required");
        }
        McpSyncServerExchange mcpSyncServerExchange = (McpSyncServerExchange) contextMap.get("exchange");
        if (Objects.isNull(mcpSyncServerExchange)) {
            throw new IllegalArgumentException("McpSyncServerExchange is required in ToolContext");
        }
        return mcpSyncServerExchange;
    }

    /**
     * Get sessionId from McpSyncServerExchange.
     *
     * <p>Uses reflection to access internal SDK fields. If reflection fails,
     * an IllegalStateException is thrown with SDK compatibility information.
     *

View on GitHub (pinned to 567142e072)