Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
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;
Expand All @@ -40,6 +42,8 @@
@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)
Expand All @@ -58,6 +62,14 @@ McpServerBridge camelMcpServerBridge(
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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@
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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
* {@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 {

Expand Down
34 changes: 32 additions & 2 deletions docs/spring-boot/modules/ROOT/pages/starters/mcp-server.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
Loading