Skip to content

Commit 60a27a8

Browse files
eddumelendezilayaperumalg
authored andcommitted
Add docker/mcp-gateway docker compose service connection
Signed-off-by: Eddú Meléndez <eddu.melendez@gmail.com>
1 parent f9d87fd commit 60a27a8

File tree

10 files changed

+227
-6
lines changed

10 files changed

+227
-6
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.mcp.client.common.autoconfigure;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties;
22+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
23+
24+
/**
25+
* Connection details for an MCP client.
26+
*
27+
* @author Eddú Meléndez
28+
*/
29+
public interface McpSseClientConnectionDetails extends ConnectionDetails {
30+
31+
Map<String, McpSseClientProperties.SseParameters> getConnections();
32+
33+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2025-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.mcp.client.common.autoconfigure;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties;
22+
23+
public class PropertiesMcpSseClientConnectionDetails implements McpSseClientConnectionDetails {
24+
25+
private final McpSseClientProperties properties;
26+
27+
public PropertiesMcpSseClientConnectionDetails(McpSseClientProperties properties) {
28+
this.properties = properties;
29+
}
30+
31+
@Override
32+
public Map<String, McpSseClientProperties.SseParameters> getConnections() {
33+
return this.properties.getConnections();
34+
}
35+
36+
}

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-httpclient/src/main/java/org/springframework/ai/mcp/client/httpclient/autoconfigure/SseHttpClientTransportAutoConfiguration.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import io.modelcontextprotocol.client.transport.customizer.McpSyncHttpClientRequestCustomizer;
2929
import io.modelcontextprotocol.spec.McpSchema;
3030

31+
import org.springframework.ai.mcp.client.common.autoconfigure.McpSseClientConnectionDetails;
3132
import org.springframework.ai.mcp.client.common.autoconfigure.NamedClientMcpTransport;
33+
import org.springframework.ai.mcp.client.common.autoconfigure.PropertiesMcpSseClientConnectionDetails;
3234
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
3335
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties;
3436
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties.SseParameters;
@@ -73,6 +75,11 @@ public class SseHttpClientTransportAutoConfiguration {
7375

7476
private static final LogAccessor logger = new LogAccessor(SseHttpClientTransportAutoConfiguration.class);
7577

78+
@Bean
79+
PropertiesMcpSseClientConnectionDetails mcpSseClientConnectionDetails(McpSseClientProperties sseProperties) {
80+
return new PropertiesMcpSseClientConnectionDetails(sseProperties);
81+
}
82+
7683
/**
7784
* Creates a list of HTTP client-based SSE transports for MCP communication.
7885
*
@@ -84,7 +91,8 @@ public class SseHttpClientTransportAutoConfiguration {
8491
* <li>ObjectMapper for JSON processing
8592
* <li>A sync or async HTTP request customizer. Sync takes precedence.
8693
* </ul>
87-
* @param sseProperties the SSE client properties containing server configurations
94+
* @param connectionDetails the SSE client connection details containing server
95+
* configurations
8896
* @param objectMapperProvider the provider for ObjectMapper or a new instance if not
8997
* available
9098
* @param syncHttpRequestCustomizer provider for
@@ -94,7 +102,7 @@ public class SseHttpClientTransportAutoConfiguration {
94102
* @return list of named MCP transports
95103
*/
96104
@Bean
97-
public List<NamedClientMcpTransport> sseHttpClientTransports(McpSseClientProperties sseProperties,
105+
public List<NamedClientMcpTransport> sseHttpClientTransports(McpSseClientConnectionDetails connectionDetails,
98106
ObjectProvider<ObjectMapper> objectMapperProvider,
99107
ObjectProvider<McpSyncHttpClientRequestCustomizer> syncHttpRequestCustomizer,
100108
ObjectProvider<McpAsyncHttpClientRequestCustomizer> asyncHttpRequestCustomizer) {
@@ -103,7 +111,7 @@ public List<NamedClientMcpTransport> sseHttpClientTransports(McpSseClientPropert
103111

104112
List<NamedClientMcpTransport> sseTransports = new ArrayList<>();
105113

106-
for (Map.Entry<String, SseParameters> serverParameters : sseProperties.getConnections().entrySet()) {
114+
for (Map.Entry<String, SseParameters> serverParameters : connectionDetails.getConnections().entrySet()) {
107115

108116
String baseUrl = serverParameters.getValue().url();
109117
String sseEndpoint = serverParameters.getValue().sseEndpoint() != null

auto-configurations/mcp/spring-ai-autoconfigure-mcp-client-webflux/src/main/java/org/springframework/ai/mcp/client/webflux/autoconfigure/SseWebFluxTransportAutoConfiguration.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@
2323
import com.fasterxml.jackson.databind.ObjectMapper;
2424
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
2525

26+
import org.springframework.ai.mcp.client.common.autoconfigure.McpSseClientConnectionDetails;
2627
import org.springframework.ai.mcp.client.common.autoconfigure.NamedClientMcpTransport;
28+
import org.springframework.ai.mcp.client.common.autoconfigure.PropertiesMcpSseClientConnectionDetails;
2729
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpClientCommonProperties;
2830
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties;
2931
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties.SseParameters;
@@ -63,6 +65,11 @@
6365
matchIfMissing = true)
6466
public class SseWebFluxTransportAutoConfiguration {
6567

68+
@Bean
69+
PropertiesMcpSseClientConnectionDetails mcpSseClientConnectionDetails(McpSseClientProperties sseProperties) {
70+
return new PropertiesMcpSseClientConnectionDetails(sseProperties);
71+
}
72+
6673
/**
6774
* Creates a list of WebFlux-based SSE transports for MCP communication.
6875
*
@@ -73,14 +80,14 @@ public class SseWebFluxTransportAutoConfiguration {
7380
* <li>ObjectMapper for JSON processing
7481
* <li>Server connection parameters from properties
7582
* </ul>
76-
* @param sseProperties the SSE client properties containing server configurations
83+
* @param connectionDetails the SSE client properties containing server configurations
7784
* @param webClientBuilderProvider the provider for WebClient.Builder
7885
* @param objectMapperProvider the provider for ObjectMapper or a new instance if not
7986
* available
8087
* @return list of named MCP transports
8188
*/
8289
@Bean
83-
public List<NamedClientMcpTransport> sseWebFluxClientTransports(McpSseClientProperties sseProperties,
90+
public List<NamedClientMcpTransport> sseWebFluxClientTransports(McpSseClientConnectionDetails connectionDetails,
8491
ObjectProvider<WebClient.Builder> webClientBuilderProvider,
8592
ObjectProvider<ObjectMapper> objectMapperProvider) {
8693

@@ -89,7 +96,7 @@ public List<NamedClientMcpTransport> sseWebFluxClientTransports(McpSseClientProp
8996
var webClientBuilderTemplate = webClientBuilderProvider.getIfAvailable(WebClient::builder);
9097
var objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new);
9198

92-
for (Map.Entry<String, SseParameters> serverParameters : sseProperties.getConnections().entrySet()) {
99+
for (Map.Entry<String, SseParameters> serverParameters : connectionDetails.getConnections().entrySet()) {
93100
var webClientBuilder = webClientBuilderTemplate.clone().baseUrl(serverParameters.getValue().url());
94101
String sseEndpoint = serverParameters.getValue().sseEndpoint() != null
95102
? serverParameters.getValue().sseEndpoint() : "/sse";

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/docker-compose.adoc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ The following service connection factories are provided in the `spring-ai-spring
5454

5555
| `WeaviateConnectionDetails`
5656
| Containers named `semitechnologies/weaviate`, `cr.weaviate.io/semitechnologies/weaviate`
57+
58+
| `McpSseClientConnectionDetails`
59+
| Containers named `docker/mcp-gateway`
5760
|====
5861

5962
More service connections are provided by the spring boot module `spring-boot-docker-compose`. Refer to the https://docs.spring.io/spring-boot/reference/features/dev-services.html#features.dev-services.docker-compose[Docker Compose Support] documentation page for the full list.

spring-ai-spring-boot-docker-compose/pom.xml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,20 @@
8181
<optional>true</optional>
8282
</dependency>
8383

84+
<dependency>
85+
<groupId>org.springframework.ai</groupId>
86+
<artifactId>spring-ai-autoconfigure-mcp-client-httpclient</artifactId>
87+
<version>${project.version}</version>
88+
<optional>true</optional>
89+
</dependency>
90+
91+
<dependency>
92+
<groupId>org.springframework.ai</groupId>
93+
<artifactId>spring-ai-autoconfigure-mcp-client-webflux</artifactId>
94+
<version>${project.version}</version>
95+
<optional>true</optional>
96+
</dependency>
97+
8498
<!-- production dependencies -->
8599

86100
<dependency>
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* Copyright 2023-2025 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.docker.compose.service.connection.docker;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.ai.mcp.client.common.autoconfigure.McpSseClientConnectionDetails;
22+
import org.springframework.ai.mcp.client.common.autoconfigure.properties.McpSseClientProperties;
23+
import org.springframework.boot.docker.compose.core.RunningService;
24+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
25+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
26+
27+
/**
28+
* A {@link DockerComposeConnectionDetailsFactory} implementation that creates
29+
* {@link McpSseClientConnectionDetails} for a Docker MCP Gateway instance running in a
30+
* Docker container.
31+
*
32+
* @author Eddú Meléndez
33+
*/
34+
class DockerMcpGatewayDockerComposeConnectionDetailsFactory
35+
extends DockerComposeConnectionDetailsFactory<McpSseClientConnectionDetails> {
36+
37+
private static final int GATEWAY_PORT = 8811;
38+
39+
protected DockerMcpGatewayDockerComposeConnectionDetailsFactory() {
40+
super("docker/mcp-gateway");
41+
}
42+
43+
@Override
44+
protected McpSseClientConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
45+
return new DockerAgentsGatewayContainerConnectionDetails(source.getRunningService());
46+
}
47+
48+
/**
49+
* {@link McpSseClientConnectionDetails} backed by a {@code Docker MCP Gateway}
50+
* {@link RunningService}.
51+
*/
52+
static class DockerAgentsGatewayContainerConnectionDetails extends DockerComposeConnectionDetails
53+
implements McpSseClientConnectionDetails {
54+
55+
private final String url;
56+
57+
DockerAgentsGatewayContainerConnectionDetails(RunningService service) {
58+
super(service);
59+
this.url = String.format("http://%s:%d", service.host(), service.ports().get(GATEWAY_PORT));
60+
}
61+
62+
@Override
63+
public Map<String, McpSseClientProperties.SseParameters> getConnections() {
64+
return Map.of("gateway", new McpSseClientProperties.SseParameters(this.url, "/sse"));
65+
}
66+
67+
}
68+
69+
}

spring-ai-spring-boot-docker-compose/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
org.springframework.boot.autoconfigure.service.connection.ConnectionDetailsFactory=\
1818
org.springframework.ai.docker.compose.service.connection.chroma.ChromaDockerComposeConnectionDetailsFactory,\
19+
org.springframework.ai.docker.compose.service.connection.docker.DockerMcpGatewayDockerComposeConnectionDetailsFactory,\
1920
org.springframework.ai.docker.compose.service.connection.mongo.MongoDbAtlasLocalDockerComposeConnectionDetailsFactory,\
2021
org.springframework.ai.docker.compose.service.connection.ollama.OllamaDockerComposeConnectionDetailsFactory,\
2122
org.springframework.ai.docker.compose.service.connection.opensearch.AwsOpenSearchDockerComposeConnectionDetailsFactory,\
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2023-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.ai.docker.compose.service.connection.docker;
18+
19+
import org.junit.jupiter.api.Test;
20+
import org.testcontainers.utility.DockerImageName;
21+
22+
import org.springframework.ai.mcp.client.common.autoconfigure.McpSseClientConnectionDetails;
23+
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIT;
24+
25+
import static org.assertj.core.api.Assertions.assertThat;
26+
27+
class DockerMcpGatewayDockerComposeConnectionDetailsFactoryIT extends AbstractDockerComposeIT {
28+
29+
protected DockerMcpGatewayDockerComposeConnectionDetailsFactoryIT() {
30+
super("docker-agents-gateway-compose.yaml", DockerImageName.parse("docker/mcp-gateway"));
31+
}
32+
33+
@Test
34+
void runCreatesConnectionDetails() {
35+
McpSseClientConnectionDetails connectionDetails = run(McpSseClientConnectionDetails.class);
36+
assertThat(connectionDetails.getConnections()).hasSize(1);
37+
assertThat(connectionDetails.getConnections().get("gateway").url()).startsWith("http://");
38+
assertThat(connectionDetails.getConnections().get("gateway").sseEndpoint()).contains("/sse");
39+
}
40+
41+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
services:
2+
mcp-gateway:
3+
image: '{imageName}'
4+
ports:
5+
- 8811
6+
volumes:
7+
- "/var/run/docker.sock:/var/run/docker.sock"
8+
command:
9+
- --transport=sse

0 commit comments

Comments
 (0)