{"record":{"id":"e03fe8d471a4a5de","repo":"spring-projects/spring-ai","slug":"found-mcp-clients-the-mcp-client-tools-will-not-b","errorCode":null,"errorMessage":"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.","messagePattern":"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\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackUtils.java","lineNumber":67,"sourceCode":"\n\t\tvar allCallbackProviders = Stream.concat(tcbProviderList.stream().flatMap(List::stream), tcbProviders.stream());\n\t\tAtomicBoolean hasExcludedToolProvider = new AtomicBoolean(false);\n\t\tvar filteredProviders = allCallbackProviders.filter(provider -> {\n\t\t\tvar includeProvider = includeMcpTools || !isMcpToolProvider(provider);\n\t\t\tif (!includeProvider) {\n\t\t\t\thasExcludedToolProvider.set(true);\n\t\t\t}\n\t\t\treturn includeProvider;\n\t\t}).distinct();\n\t\tvar toolCallbacksFromProviders = filteredProviders.map(pr -> List.of(pr.getToolCallbacks()))\n\t\t\t.flatMap(List::stream)\n\t\t\t.filter(Objects::nonNull);\n\n\t\tvar toolCallbacks = Stream.concat(allToolCallbacks, toolCallbacksFromProviders).toList();\n\n\t\t// After consuming all the streams, log if we have excluded MCP tools\n\t\tif (log.isWarnEnabled() && hasExcludedToolProvider.get()) {\n\t\t\tlog.warn(\n\t\t\t\t\t\"Found MCP Clients. The MCP Client tools will not be exposed by the MCP Server. If you would like to expose the tools, set \"\n\t\t\t\t\t\t\t+ McpServerProperties.CONFIG_PREFIX + \".expose-mcp-client-tools=true.\");\n\t\t}\n\t\treturn toolCallbacks;\n\t}\n\n\tstatic boolean isMcpToolCallback(ToolCallback toolCallback) {\n\t\treturn (toolCallback instanceof SyncMcpToolCallback) || (toolCallback instanceof AsyncMcpToolCallback);\n\t}\n\n\tstatic boolean isMcpToolProvider(ToolCallbackProvider tcbp) {\n\t\treturn (tcbp instanceof org.springframework.ai.mcp.SyncMcpToolCallbackProvider)\n\t\t\t\t|| (tcbp instanceof org.springframework.ai.mcp.AsyncMcpToolCallbackProvider);\n\t}\n\n}\n","sourceCodeStart":49,"sourceCodeEnd":84,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/auto-configurations/mcp/spring-ai-autoconfigure-mcp-server-common/src/main/java/org/springframework/ai/mcp/server/common/autoconfigure/ToolCallbackUtils.java#L49-L84","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Set spring.ai.mcp.server.expose-mcp-client-tools=true to expose MCP client tools through the server.","If re-exposure is undesired, accept the default and ignore the warning.","Split client and server roles into separate applications if the mixing is unintentional."],"exampleFix":"// before (application.yml)\nspring:\n  ai:\n    mcp:\n      server:\n        enabled: true\n// after\nspring:\n  ai:\n    mcp:\n      server:\n        enabled: true\n        expose-mcp-client-tools: true","handlingStrategy":"validation","validationCode":"boolean exposingClientTools = env.getProperty(\n    \"spring.ai.mcp.server.expose-mcp-client-tools\", Boolean.class, false);\nboolean hasMcpClients = mcpClients != null && !mcpClients.isEmpty();\nif (hasMcpClients && !exposingClientTools) {\n    // client tools will be hidden; set the property if that's unintended\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set expose-mcp-client-tools explicitly whenever the app has both MCP client and server starters.","Document the intended client/server topology per service.","Check startup logs for this warning in integration tests."],"tags":["mcp","spring-boot","auto-configuration","tools"],"backgroundTag":"feature-not-enabled","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}