Skip to content

Commit 7fd8cc7

Browse files
committed
Add docker/agents_gateway docker compose service connection
Signed-off-by: Eddú Meléndez <[email protected]>
1 parent ed4fb29 commit 7fd8cc7

File tree

10 files changed

+209
-5
lines changed

10 files changed

+209
-5
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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.autoconfigure;
18+
19+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties;
20+
import org.springframework.boot.autoconfigure.service.connection.ConnectionDetails;
21+
22+
import java.util.Map;
23+
24+
public interface McpSseClientConnectionDetails extends ConnectionDetails {
25+
26+
Map<String, McpSseClientProperties.SseParameters> getConnections();
27+
28+
}
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.autoconfigure;
18+
19+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties;
20+
21+
import java.util.Map;
22+
23+
class PropertiesMcpSseClientConnectionDetails implements McpSseClientConnectionDetails {
24+
25+
private final McpSseClientProperties properties;
26+
27+
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/src/main/java/org/springframework/ai/mcp/client/autoconfigure/SseHttpClientTransportAutoConfiguration.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@
6969
matchIfMissing = true)
7070
public class SseHttpClientTransportAutoConfiguration {
7171

72+
@Bean
73+
PropertiesMcpSseClientConnectionDetails mcpSseClientConnectionDetails(McpSseClientProperties sseProperties) {
74+
return new PropertiesMcpSseClientConnectionDetails(sseProperties);
75+
}
76+
7277
/**
7378
* Creates a list of HTTP client-based SSE transports for MCP communication.
7479
*
@@ -79,20 +84,21 @@ public class SseHttpClientTransportAutoConfiguration {
7984
* <li>Server URL from properties
8085
* <li>ObjectMapper for JSON processing
8186
* </ul>
82-
* @param sseProperties the SSE client properties containing server configurations
87+
* @param connectionDetails the SSE client connection details containing server
88+
* configurations
8389
* @param objectMapperProvider the provider for ObjectMapper or a new instance if not
8490
* available
8591
* @return list of named MCP transports
8692
*/
8793
@Bean
88-
public List<NamedClientMcpTransport> mcpHttpClientTransports(McpSseClientProperties sseProperties,
94+
public List<NamedClientMcpTransport> mcpHttpClientTransports(McpSseClientConnectionDetails connectionDetails,
8995
ObjectProvider<ObjectMapper> objectMapperProvider) {
9096

9197
ObjectMapper objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new);
9298

9399
List<NamedClientMcpTransport> sseTransports = new ArrayList<>();
94100

95-
for (Map.Entry<String, SseParameters> serverParameters : sseProperties.getConnections().entrySet()) {
101+
for (Map.Entry<String, SseParameters> serverParameters : connectionDetails.getConnections().entrySet()) {
96102

97103
String baseUrl = serverParameters.getValue().url();
98104
String sseEndpoint = serverParameters.getValue().sseEndpoint() != null

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@
6262
matchIfMissing = true)
6363
public class SseWebFluxTransportAutoConfiguration {
6464

65+
@Bean
66+
PropertiesMcpSseClientConnectionDetails mcpSseClientConnectionDetails(McpSseClientProperties sseProperties) {
67+
return new PropertiesMcpSseClientConnectionDetails(sseProperties);
68+
}
69+
6570
/**
6671
* Creates a list of WebFlux-based SSE transports for MCP communication.
6772
*
@@ -79,7 +84,7 @@ public class SseWebFluxTransportAutoConfiguration {
7984
* @return list of named MCP transports
8085
*/
8186
@Bean
82-
public List<NamedClientMcpTransport> webFluxClientTransports(McpSseClientProperties sseProperties,
87+
public List<NamedClientMcpTransport> webFluxClientTransports(McpSseClientConnectionDetails connectionDetails,
8388
ObjectProvider<WebClient.Builder> webClientBuilderProvider,
8489
ObjectProvider<ObjectMapper> objectMapperProvider) {
8590

@@ -88,7 +93,7 @@ public List<NamedClientMcpTransport> webFluxClientTransports(McpSseClientPropert
8893
var webClientBuilderTemplate = webClientBuilderProvider.getIfAvailable(WebClient::builder);
8994
var objectMapper = objectMapperProvider.getIfAvailable(ObjectMapper::new);
9095

91-
for (Map.Entry<String, SseParameters> serverParameters : sseProperties.getConnections().entrySet()) {
96+
for (Map.Entry<String, SseParameters> serverParameters : connectionDetails.getConnections().entrySet()) {
9297
var webClientBuilder = webClientBuilderTemplate.clone().baseUrl(serverParameters.getValue().url());
9398
String sseEndpoint = serverParameters.getValue().sseEndpoint() != null
9499
? 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,4 +54,7 @@ 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/agents_gateway`
5760
|====

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

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

84+
<dependency>
85+
<groupId>org.springframework.ai</groupId>
86+
<artifactId>spring-ai-autoconfigure-mcp-client</artifactId>
87+
<version>${project.version}</version>
88+
<optional>true</optional>
89+
</dependency>
90+
8491
<!-- production dependencies -->
8592

8693
<dependency>
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 org.springframework.ai.mcp.client.autoconfigure.McpSseClientConnectionDetails;
20+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties;
21+
import org.springframework.boot.docker.compose.core.RunningService;
22+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
23+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
24+
25+
import java.util.Map;
26+
27+
/**
28+
* A {@link DockerComposeConnectionDetailsFactory} implementation that creates
29+
* {@link McpSseClientConnectionDetails} for a Docker Agent Gateway instance running in a
30+
* Docker container.
31+
*
32+
* @author Eddú Meléndez
33+
*/
34+
class DockerAgentsGatewayDockerComposeConnectionDetailsFactory
35+
extends DockerComposeConnectionDetailsFactory<McpSseClientConnectionDetails> {
36+
37+
private static final int GATEWAY_PORT = 8811;
38+
39+
protected DockerAgentsGatewayDockerComposeConnectionDetailsFactory() {
40+
super("docker/agents_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 Agents 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(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.DockerAgentsGatewayDockerComposeConnectionDetailsFactory,\
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,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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.springframework.ai.mcp.client.autoconfigure.McpSseClientConnectionDetails;
21+
import org.springframework.boot.docker.compose.service.connection.test.AbstractDockerComposeIT;
22+
import org.testcontainers.utility.DockerImageName;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
26+
class DockerAgentsGatewayDockerComposeConnectionDetailsFactoryIT extends AbstractDockerComposeIT {
27+
28+
protected DockerAgentsGatewayDockerComposeConnectionDetailsFactoryIT() {
29+
super("docker-agents-gateway-compose.yaml", DockerImageName.parse("docker/agents_gateway:v2"));
30+
}
31+
32+
@Test
33+
void runCreatesConnectionDetails() {
34+
McpSseClientConnectionDetails connectionDetails = run(McpSseClientConnectionDetails.class);
35+
assertThat(connectionDetails.getConnections()).hasSize(1);
36+
assertThat(connectionDetails.getConnections().get("gateway").url()).startsWith("http://");
37+
assertThat(connectionDetails.getConnections().get("gateway").sseEndpoint()).contains("/sse");
38+
}
39+
40+
}
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)