spring-projects/spring-ai · warning

Found MCP Clients. The MCP Client tools will not be exposed

Error message

Found MCP Clients. The MCP Client tools will not be exposed by the MCP Server. If you would like to expose the tools, set spring.ai.mcp.server.expose-mcp-client-tools=true.

What it means

ToolCallbackUtils.aggregateToolCallbacks collects tool callbacks from providers and beans, but by default it excludes tools coming from MCP clients so an MCP server does not re-expose its own clients' tools. When such excluded tools are detected, it logs this warning explaining how to opt in via the expose-mcp-client-tools property.

Source

Thrown at auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackUtils.java:67

		var allCallbackProviders = Stream.concat(tcbProviderList.stream().flatMap(List::stream), tcbProviders.stream());
		AtomicBoolean hasExcludedToolProvider = new AtomicBoolean(false);
		var filteredProviders = allCallbackProviders.filter(provider -> {
			var includeProvider = includeMcpTools || !isMcpToolProvider(provider);
			if (!includeProvider) {
				hasExcludedToolProvider.set(true);
			}
			return includeProvider;
		}).distinct();
		var toolCallbacksFromProviders = filteredProviders.map(pr -> List.of(pr.getToolCallbacks()))
			.flatMap(List::stream)
			.filter(Objects::nonNull);

		var toolCallbacks = Stream.concat(allToolCallbacks, toolCallbacksFromProviders).toList();

		// After consuming all the streams, log if we have excluded MCP tools
		if (log.isWarnEnabled() && hasExcludedToolProvider.get()) {
			log.warn(
					"Found MCP Clients. The MCP Client tools will not be exposed by the MCP Server. If you would like to expose the tools, set "
							+ McpServerProperties.CONFIG_PREFIX + ".expose-mcp-client-tools=true.");
		}
		return toolCallbacks;
	}

	static boolean isMcpToolCallback(ToolCallback toolCallback) {
		return (toolCallback instanceof SyncMcpToolCallback) || (toolCallback instanceof AsyncMcpToolCallback);
	}

	static boolean isMcpToolProvider(ToolCallbackProvider tcbp) {
		return (tcbp instanceof org.springframework.ai.mcp.SyncMcpToolCallbackProvider)
				|| (tcbp instanceof org.springframework.ai.mcp.AsyncMcpToolCallbackProvider);
	}

}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Set spring.ai.mcp.server.expose-mcp-client-tools=true to expose MCP client tools through the server.
  2. If re-exposure is undesired, accept the default and ignore the warning.
  3. Split client and server roles into separate applications if the mixing is unintentional.

Example fix

// before (application.yml)
spring:
  ai:
    mcp:
      server:
        enabled: true
// after
spring:
  ai:
    mcp:
      server:
        enabled: true
        expose-mcp-client-tools: true
Defensive patterns

Strategy: validation

Validate before calling

boolean exposingClientTools = env.getProperty(
    "spring.ai.mcp.server.expose-mcp-client-tools", Boolean.class, false);
boolean hasMcpClients = mcpClients != null && !mcpClients.isEmpty();
if (hasMcpClients && !exposingClientTools) {
    // client tools will be hidden; set the property if that's unintended
}

Prevention

When it happens

Trigger: Running the MCP server auto-configuration in an application that itself holds MCP client connections (SyncMcpToolCallbackProvider/McpToolUtils sourced callbacks), with spring.ai.mcp.server.expose-mcp-client-tools left at its default (false).

Common situations: Apps acting as both MCP client and MCP server (gateway/proxy setups); after adding MCP client starter dependencies alongside the server starter; forgetting to enable exposure when building an aggregating MCP server.

Related errors


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/e03fe8d471a4a5de. Report an issue: GitHub.