This is an automated email from the ASF dual-hosted git repository.
Croway pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
The following commit(s) were added to refs/heads/main by this push:
new 7610a717ffd CAMEL-24507: camel-mcp-server-starter - correct the
authentication claim in the docs
7610a717ffd is described below
commit 7610a717ffd5d579ffafdb04b8cb74e1ff8d23d9
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Aug 28 09:57:42 2026 +0200
CAMEL-24507: camel-mcp-server-starter - correct the authentication claim in
the docs
The starter's javadoc and intro documentation listed authentication among
the
serving concerns owned by the Spring AI MCP server and configured via
spring.ai.mcp.server.*. That namespace has no authentication property, so a
reader following the sentence would look for a knob that does not exist and
may
conclude the endpoint is covered when it is not.
The claim is removed from McpServerConfigurationProperties,
SpringAiMcpServerEngine
and intro.adoc, and intro.adoc gains a "Securing the MCP endpoint" section
with a
Spring Security filter chain example.
The default posture is unchanged and remains sound: tags default to null
and the
untagged pool is never served, so nothing is exposed until an operator opts
in.
When they do, one INFO line at startup now says so and points at securing
the
endpoint - not WARN, which would fire on every legitimate deployment.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Signed-off-by: Andrea Cosentino <[email protected]>
---
.../src/main/doc/intro.adoc | 34 ++++++++++++++++++++--
.../server/CamelMcpServerAutoConfiguration.java | 12 ++++++++
.../server/McpServerConfigurationProperties.java | 8 +++--
.../mcp/server/SpringAiMcpServerEngine.java | 3 +-
.../modules/ROOT/pages/starters/mcp-server.adoc | 34 ++++++++++++++++++++--
5 files changed, 84 insertions(+), 7 deletions(-)
diff --git
a/components-starter/camel-mcp-server-starter/src/main/doc/intro.adoc
b/components-starter/camel-mcp-server-starter/src/main/doc/intro.adoc
index 4af6d66884c..1c94a3143f4 100644
--- a/components-starter/camel-mcp-server-starter/src/main/doc/intro.adoc
+++ b/components-starter/camel-mcp-server-starter/src/main/doc/intro.adoc
@@ -9,6 +9,36 @@ Tool semantics — tag-based opt-in (the untagged default pool
is never
exposed), flat-namespace collision refusal, per-call timeout and error
sanitization — are owned by the runtime-agnostic `camel-mcp-server-api`
bridge and are identical on every Camel runtime. Serving concerns (endpoint
-path, protocol, server identity, authentication) are owned by the Spring AI
-MCP server and configured via `spring.ai.mcp.server.*`; use
+path, protocol, server identity) are owned by the Spring AI MCP server and
+configured via `spring.ai.mcp.server.*`; use
`spring.ai.mcp.server.protocol=STREAMABLE` for the streamable HTTP transport.
+
+== Securing the MCP endpoint
+
+`spring.ai.mcp.server.*` provides **no authentication**. The MCP endpoint is
+served on the application's own HTTP port, and anything that can reach it can
+list and call every exposed tool. Protecting it is the application's
+responsibility.
+
+Nothing is exposed until `camel.mcp-server.tags` is set — the untagged default
+pool is never served — so the surface is opt-in. Once tags are configured,
+secure the endpoint path, for example with a Spring Security filter chain:
+
+[source,java]
+----
+@Bean
+SecurityFilterChain mcpSecurity(HttpSecurity http) throws Exception {
+ return http.securityMatcher("/mcp/**")
+ .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
+ .oauth2ResourceServer(oauth2 ->
oauth2.jwt(Customizer.withDefaults()))
+ .build();
+}
+----
+
+Adjust the matcher to whatever `spring.ai.mcp.server` is configured to serve
on.
+A network policy that keeps the port off untrusted networks is an alternative
+where the deployment allows it.
+
+See the camel-mcp-server component documentation for the trust boundary this
+sits in: external MCP clients are untrusted senders under the Camel security
+model.
diff --git
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/CamelMcpServerAutoConfiguration.java
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/CamelMcpServerAutoConfiguration.java
index 4c9c1bac7f2..f2f3b3c00f9 100644
---
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/CamelMcpServerAutoConfiguration.java
+++
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/CamelMcpServerAutoConfiguration.java
@@ -22,6 +22,8 @@ import org.apache.camel.component.mcp.server.McpServerBridge;
import org.apache.camel.component.mcp.server.McpServerConfiguration;
import org.apache.camel.component.mcp.server.McpServerEngine;
import org.apache.camel.spring.boot.CamelAutoConfiguration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
@@ -40,6 +42,8 @@ import org.springframework.context.annotation.Bean;
@EnableConfigurationProperties(McpServerConfigurationProperties.class)
public class CamelMcpServerAutoConfiguration {
+ private static final Logger LOG =
LoggerFactory.getLogger(CamelMcpServerAutoConfiguration.class);
+
@Bean(initMethod = "", destroyMethod = "")
// Camel handles the lifecycle of this bean
@ConditionalOnMissingBean(McpServerEngine.class)
@@ -58,6 +62,14 @@ public class CamelMcpServerAutoConfiguration {
configuration.setToolTimeout(properties.getToolTimeout());
McpServerBridge bridge = new McpServerBridge(configuration);
camelContext.addService(bridge);
+ if (properties.getTags() != null && !properties.getTags().isBlank()) {
+ // exposing tools is opt-in, but once opted in the endpoint is
reachable by anything that can reach
+ // the application HTTP port - spring.ai.mcp.server.* has no
authentication of its own
+ LOG.info("Exposing ai-tool routes tagged [{}] as MCP tools. The
MCP endpoint is served on the"
+ + " application HTTP port and is not authenticated by the
Spring AI MCP server; secure it in"
+ + " the application, for example with a Spring Security
filter chain on its path.",
+ properties.getTags());
+ }
return bridge;
}
}
diff --git
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/McpServerConfigurationProperties.java
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/McpServerConfigurationProperties.java
index b5023fe62b4..2a35b7e6472 100644
---
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/McpServerConfigurationProperties.java
+++
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/McpServerConfigurationProperties.java
@@ -19,8 +19,12 @@ package org.apache.camel.springboot.mcp.server;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
- * Bridge-owned configuration of the Camel MCP server. Serving concerns
(endpoint path, protocol, server identity,
- * authentication) are owned by the Spring AI MCP server and configured via
{@code spring.ai.mcp.server.*}.
+ * Bridge-owned configuration of the Camel MCP server. Serving concerns
(endpoint path, protocol, server identity)
+ * are owned by the Spring AI MCP server and configured via {@code
spring.ai.mcp.server.*}.
+ * <p/>
+ * Note that {@code spring.ai.mcp.server.*} provides no authentication: the
MCP endpoint is served on the
+ * application's own HTTP port and must be protected by the application, for
example with a Spring Security filter
+ * chain matching the endpoint path.
*/
@ConfigurationProperties(prefix = "camel.mcp-server")
public class McpServerConfigurationProperties {
diff --git
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/SpringAiMcpServerEngine.java
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/SpringAiMcpServerEngine.java
index 1728fd4fd9a..1f8939af346 100644
---
a/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/SpringAiMcpServerEngine.java
+++
b/components-starter/camel-mcp-server-starter/src/main/java/org/apache/camel/springboot/mcp/server/SpringAiMcpServerEngine.java
@@ -37,7 +37,8 @@ import org.slf4j.LoggerFactory;
* {@link McpServerEngine} publishing tools into the Spring AI MCP server:
{@code toolAdded}/{@code toolRemoved} map to
* the auto-configured {@link McpSyncServer}'s {@code addTool}/{@code
removeTool}, which emit
* {@code notifications/tools/list_changed} to connected clients. Serving
concerns (endpoint path, protocol, server
- * identity, authentication) are owned by the Spring AI MCP server
configuration ({@code spring.ai.mcp.server.*}).
+ * identity) are owned by the Spring AI MCP server configuration ({@code
spring.ai.mcp.server.*}), which provides
+ * no authentication - the endpoint must be protected by the application.
*/
public class SpringAiMcpServerEngine extends ServiceSupport implements
McpServerEngine {
diff --git a/docs/spring-boot/modules/ROOT/pages/starters/mcp-server.adoc
b/docs/spring-boot/modules/ROOT/pages/starters/mcp-server.adoc
index bd465cb2b0b..73f5c698eb2 100644
--- a/docs/spring-boot/modules/ROOT/pages/starters/mcp-server.adoc
+++ b/docs/spring-boot/modules/ROOT/pages/starters/mcp-server.adoc
@@ -14,10 +14,40 @@ Tool semantics — tag-based opt-in (the untagged default
pool is never
exposed), flat-namespace collision refusal, per-call timeout and error
sanitization — are owned by the runtime-agnostic `camel-mcp-server-api`
bridge and are identical on every Camel runtime. Serving concerns (endpoint
-path, protocol, server identity, authentication) are owned by the Spring AI
-MCP server and configured via `spring.ai.mcp.server.*`; use
+path, protocol, server identity) are owned by the Spring AI MCP server and
+configured via `spring.ai.mcp.server.*`; use
`spring.ai.mcp.server.protocol=STREAMABLE` for the streamable HTTP transport.
+== Securing the MCP endpoint
+
+`spring.ai.mcp.server.*` provides **no authentication**. The MCP endpoint is
+served on the application's own HTTP port, and anything that can reach it can
+list and call every exposed tool. Protecting it is the application's
+responsibility.
+
+Nothing is exposed until `camel.mcp-server.tags` is set — the untagged default
+pool is never served — so the surface is opt-in. Once tags are configured,
+secure the endpoint path, for example with a Spring Security filter chain:
+
+[source,java]
+----
+@Bean
+SecurityFilterChain mcpSecurity(HttpSecurity http) throws Exception {
+ return http.securityMatcher("/mcp/**")
+ .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
+ .oauth2ResourceServer(oauth2 ->
oauth2.jwt(Customizer.withDefaults()))
+ .build();
+}
+----
+
+Adjust the matcher to whatever `spring.ai.mcp.server` is configured to serve
on.
+A network policy that keeps the port off untrusted networks is an alternative
+where the deployment allows it.
+
+See the camel-mcp-server component documentation for the trust boundary this
+sits in: external MCP clients are untrusted senders under the Camel security
+model.
+
== Maven coordinates
[source,xml]