Skip to content

Commit 6eb2307

Browse files
committed
agent uses mcp tools
1 parent 26e2e57 commit 6eb2307

File tree

13 files changed

+280
-35
lines changed

13 files changed

+280
-35
lines changed

core/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,14 @@
2424
<groupId>org.springframework.ai</groupId>
2525
<artifactId>spring-ai-client-chat</artifactId>
2626
</dependency>
27+
<dependency>
28+
<groupId>org.springframework.ai</groupId>
29+
<artifactId>spring-ai-mcp</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.springframework.ai</groupId>
33+
<artifactId>spring-ai-autoconfigure-mcp-client</artifactId>
34+
</dependency>
2735
<dependency>
2836
<groupId>org.jspecify</groupId>
2937
<artifactId>jspecify</artifactId>
@@ -33,6 +41,10 @@
3341
<groupId>io.micrometer</groupId>
3442
<artifactId>micrometer-observation</artifactId>
3543
</dependency>
44+
<dependency>
45+
<groupId>org.slf4j</groupId>
46+
<artifactId>slf4j-api</artifactId>
47+
</dependency>
3648
</dependencies>
3749

3850
</project>

core/src/main/java/com/javaaidev/agenticpatterns/core/Agent.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ protected Agent(ChatClient chatClient) {
1818
this.observationRegistry = null;
1919
}
2020

21-
protected Agent(ChatClient chatClient, @Nullable ObservationRegistry observationRegistry) {
21+
protected Agent(ChatClient chatClient,
22+
@Nullable ObservationRegistry observationRegistry) {
2223
this.chatClient = chatClient;
2324
this.observationRegistry = observationRegistry;
2425
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.javaaidev.agenticpatterns.core;
2+
3+
import io.modelcontextprotocol.client.transport.ServerParameters;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
import org.jspecify.annotations.Nullable;
7+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpSseClientProperties.SseParameters;
8+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpStdioClientProperties.Parameters;
9+
10+
public record McpClientConfiguration(
11+
@Nullable StdioClientProperties stdioClientProperties,
12+
@Nullable SseClientProperties sseClientProperties
13+
) {
14+
15+
public record StdioClientProperties(Map<String, Parameters> connections) {
16+
17+
public Map<String, ServerParameters> toServerParameters() {
18+
Map<String, ServerParameters> serverParameters = new HashMap<>();
19+
for (Map.Entry<String, Parameters> entry : this.connections.entrySet()) {
20+
serverParameters.put(entry.getKey(),
21+
entry.getValue().toServerParameters());
22+
}
23+
return serverParameters;
24+
}
25+
}
26+
27+
public record SseClientProperties(Map<String, SseParameters> connections) {
28+
29+
}
30+
}

examples/pom.xml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
<maven.compiler.source>21</maven.compiler.source>
1919
<maven.compiler.target>21</maven.compiler.target>
2020
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
21-
<spring-ai.version>1.0.0</spring-ai.version>
22-
<spring-boot.version>3.4.6</spring-boot.version>
21+
<spring-ai.version>1.0.3</spring-ai.version>
22+
<spring-boot.version>3.4.10</spring-boot.version>
2323
</properties>
2424

2525
<dependencyManagement>
@@ -38,6 +38,13 @@
3838
<type>pom</type>
3939
<scope>import</scope>
4040
</dependency>
41+
<dependency>
42+
<groupId>io.opentelemetry</groupId>
43+
<artifactId>opentelemetry-bom</artifactId>
44+
<version>1.55.0</version>
45+
<type>pom</type>
46+
<scope>import</scope>
47+
</dependency>
4148
<dependency>
4249
<groupId>io.opentelemetry.instrumentation</groupId>
4350
<artifactId>opentelemetry-instrumentation-bom</artifactId>
@@ -93,7 +100,7 @@
93100
<dependency>
94101
<groupId>org.springdoc</groupId>
95102
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
96-
<version>2.5.0</version>
103+
<version>2.8.9</version>
97104
</dependency>
98105
<dependency>
99106
<groupId>io.micrometer</groupId>

examples/src/main/java/com/javaaidev/agenticpatterns/examples/taskexecution/UserGenerationConfiguration.java

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package com.javaaidev.agenticpatterns.examples.taskexecution;
22

33
import com.javaaidev.agenticpatterns.core.AgentUtils;
4+
import com.javaaidev.agenticpatterns.core.McpClientConfiguration;
5+
import com.javaaidev.agenticpatterns.core.McpClientConfiguration.StdioClientProperties;
46
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
57
import io.micrometer.observation.ObservationRegistry;
8+
import java.util.List;
9+
import java.util.Map;
610
import org.springframework.ai.chat.client.ChatClient;
711
import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
12+
import org.springframework.ai.mcp.client.autoconfigure.properties.McpStdioClientProperties.Parameters;
813
import org.springframework.beans.factory.annotation.Qualifier;
914
import org.springframework.context.annotation.Bean;
1015
import org.springframework.context.annotation.Configuration;
@@ -21,14 +26,32 @@ public TaskExecutionAgent<UserGenerationRequest, UserGenerationResponse> userGen
2126
SimpleLoggerAdvisor simpleLoggerAdvisor,
2227
ObservationRegistry observationRegistry
2328
) {
24-
var chatClient = chatClientBuilder.defaultAdvisors(simpleLoggerAdvisor).build();
29+
var chatClient = chatClientBuilder.defaultAdvisors(simpleLoggerAdvisor)
30+
.build();
2531
return TaskExecutionAgent.<UserGenerationRequest, UserGenerationResponse>defaultBuilder()
2632
.chatClient(chatClient)
2733
.responseType(UserGenerationResponse.class)
2834
.promptTemplate(
29-
AgentUtils.loadPromptTemplateFromClasspath("prompt_template/generate-user.st"))
35+
AgentUtils.loadPromptTemplateFromClasspath(
36+
"prompt_template/generate-user.st"))
3037
.name("UserGeneration")
3138
.observationRegistry(observationRegistry)
39+
.mcpClientConfiguration(new McpClientConfiguration(
40+
new StdioClientProperties(
41+
Map.of(
42+
"file-system", new Parameters(
43+
"npx",
44+
List.of(
45+
"-y",
46+
"@modelcontextprotocol/server-filesystem",
47+
"/tmp"
48+
),
49+
Map.of()
50+
)
51+
)
52+
),
53+
null
54+
))
3255
.build();
3356
}
3457
}

examples/src/main/resources/prompt_template/generate-user.st

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Goal: Generate {count} users
1+
Goal: Generate {count} users. Generated users are also saved as a JSON file to `/tmp`.
22

33
Requirements:
44
- Id should be a version 4 random UUID.

patterns/chain-workflow/src/main/java/com/javaaidev/agenticpatterns/chainworkflow/ChainStepAgent.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package com.javaaidev.agenticpatterns.chainworkflow;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.javaaidev.agenticpatterns.core.McpClientConfiguration;
35
import com.javaaidev.agenticpatterns.taskexecution.AbstractTaskExecutionAgentBuilder;
46
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
57
import io.micrometer.observation.ObservationRegistry;
68
import java.lang.reflect.Type;
79
import java.util.Map;
810
import java.util.function.Consumer;
911
import java.util.function.Function;
12+
import java.util.function.Predicate;
1013
import org.jspecify.annotations.Nullable;
1114
import org.springframework.ai.chat.client.ChatClient;
1215
import org.springframework.ai.chat.client.ChatClient.ChatClientRequestSpec;
@@ -38,10 +41,15 @@ public ChainStepAgent(ChatClient chatClient,
3841
@Nullable Type responseType,
3942
@Nullable Function<Request, Map<String, Object>> promptTemplateContextProvider,
4043
@Nullable Consumer<ChatClientRequestSpec> chatClientRequestSpecUpdater,
44+
@Nullable McpClientConfiguration mcpClientConfiguration,
45+
@Nullable Predicate<String> toolFilter,
4146
@Nullable String name,
42-
@Nullable ObservationRegistry observationRegistry) {
43-
super(chatClient, promptTemplate, responseType, promptTemplateContextProvider,
44-
chatClientRequestSpecUpdater, name, observationRegistry);
47+
@Nullable ObservationRegistry observationRegistry,
48+
@Nullable ObjectMapper objectMapper) {
49+
super(chatClient, promptTemplate, responseType,
50+
promptTemplateContextProvider,
51+
chatClientRequestSpecUpdater, mcpClientConfiguration, toolFilter,
52+
name, observationRegistry, objectMapper);
4553
}
4654

4755
public static <Req, Res> Builder<Req, Res> builder() {
@@ -69,19 +77,24 @@ public Builder<Request, Response> order(int order) {
6977
public ChainStepAgent<Request, Response> build() {
7078
Assert.notNull(chatClient, "ChatClient cannot be null");
7179
Assert.hasText(promptTemplate, "Prompt template cannot be empty");
72-
Assert.notNull(nextRequestPreparer, "nextRequestPreparer cannot be null");
80+
Assert.notNull(nextRequestPreparer,
81+
"nextRequestPreparer cannot be null");
7382
return new ChainStepAgent<>(chatClient,
7483
promptTemplate,
7584
responseType,
7685
promptTemplateContextProvider,
7786
chatClientRequestSpecUpdater,
87+
mcpClientConfiguration,
88+
toolFilter,
7889
name,
79-
observationRegistry) {
90+
observationRegistry,
91+
objectMapper) {
8092
@Override
8193
public Response call(Request request, Map<String, Object> context,
8294
WorkflowChain<Request, Response> chain) {
8395
var response = this.call(request);
84-
return chain.callNext(nextRequestPreparer.apply(response), response);
96+
return chain.callNext(nextRequestPreparer.apply(response),
97+
response);
8598
}
8699

87100
@Override

patterns/parallelization-workflow/src/main/java/com/javaaidev/agenticpatterns/parallelizationworkflow/DefaultResponseAssembler.java

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.javaaidev.agenticpatterns.parallelizationworkflow;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.javaaidev.agenticpatterns.core.McpClientConfiguration;
35
import com.javaaidev.agenticpatterns.parallelizationworkflow.DefaultResponseAssembler.AssemblingInput;
46
import com.javaaidev.agenticpatterns.taskexecution.AbstractTaskExecutionAgentBuilder;
57
import com.javaaidev.agenticpatterns.taskexecution.TaskExecutionAgent;
@@ -8,12 +10,14 @@
810
import java.util.Map;
911
import java.util.function.Consumer;
1012
import java.util.function.Function;
13+
import java.util.function.Predicate;
1114
import org.jspecify.annotations.Nullable;
1215
import org.springframework.ai.chat.client.ChatClient;
1316
import org.springframework.ai.chat.client.ChatClient.ChatClientRequestSpec;
1417

1518
/**
16-
* A {@linkplain ResponseAssembler} implemented using {@linkplain TaskExecutionAgent}
19+
* A {@linkplain ResponseAssembler} implemented using
20+
* {@linkplain TaskExecutionAgent}
1721
*
1822
* @param <Request>
1923
* @param <Response>
@@ -26,14 +30,20 @@ public DefaultResponseAssembler(ChatClient chatClient,
2630
String promptTemplate, @Nullable Type responseType,
2731
@Nullable Function<AssemblingInput<Request>, Map<String, Object>> promptTemplateContextProvider,
2832
@Nullable Consumer<ChatClientRequestSpec> chatClientRequestSpecUpdater,
33+
@Nullable McpClientConfiguration mcpClientConfiguration,
34+
@Nullable Predicate<String> toolFilter,
2935
@Nullable String name,
30-
@Nullable ObservationRegistry observationRegistry) {
31-
super(chatClient, promptTemplate, responseType, promptTemplateContextProvider,
32-
chatClientRequestSpecUpdater, name, observationRegistry);
36+
@Nullable ObservationRegistry observationRegistry,
37+
@Nullable ObjectMapper objectMapper) {
38+
super(chatClient, promptTemplate, responseType,
39+
promptTemplateContextProvider,
40+
chatClientRequestSpecUpdater, mcpClientConfiguration, toolFilter,
41+
name, observationRegistry, objectMapper);
3342
}
3443

3544
@Override
36-
public Response assemble(@Nullable Request request, TaskExecutionResults results) {
45+
public Response assemble(@Nullable Request request,
46+
TaskExecutionResults results) {
3747
return this.call(new AssemblingInput<>(request, results));
3848
}
3949

@@ -57,8 +67,11 @@ public DefaultResponseAssembler<Request, Response> build() {
5767
responseType,
5868
promptTemplateContextProvider,
5969
chatClientRequestSpecUpdater,
70+
mcpClientConfiguration,
71+
toolFilter,
6072
name,
61-
observationRegistry
73+
observationRegistry,
74+
objectMapper
6275
);
6376
}
6477
}

patterns/task-execution/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# Task Execution Agent
22

3-
Implementation
4-
of [Task Execution pattern](https://javaaidev.com/docs/agentic-patterns/patterns/task-execution)
3+
Implementation of [Task Execution pattern](https://javaaidev.com/docs/agentic-patterns/patterns/task-execution)
54

65
See [doc](https://javaaidev.com/docs/agentic-patterns/reference-implementation/task-execution-agent)

patterns/task-execution/src/main/java/com/javaaidev/agenticpatterns/taskexecution/AbstractTaskExecutionAgentBuilder.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.javaaidev.agenticpatterns.taskexecution;
22

3+
import com.fasterxml.jackson.databind.ObjectMapper;
4+
import com.javaaidev.agenticpatterns.core.McpClientConfiguration;
35
import io.micrometer.observation.ObservationRegistry;
46
import java.lang.reflect.Type;
57
import java.util.Map;
68
import java.util.function.Consumer;
79
import java.util.function.Function;
10+
import java.util.function.Predicate;
811
import org.jspecify.annotations.Nullable;
912
import org.springframework.ai.chat.client.ChatClient;
1013
import org.springframework.ai.chat.client.ChatClient.ChatClientRequestSpec;
@@ -20,6 +23,9 @@ public abstract class AbstractTaskExecutionAgentBuilder<Request, Response, T ext
2023
protected @Nullable ObservationRegistry observationRegistry;
2124
protected @Nullable Function<Request, Map<String, Object>> promptTemplateContextProvider;
2225
protected @Nullable Consumer<ChatClientRequestSpec> chatClientRequestSpecUpdater;
26+
protected @Nullable McpClientConfiguration mcpClientConfiguration;
27+
protected @Nullable Predicate<String> toolFilter;
28+
protected @Nullable ObjectMapper objectMapper;
2329

2430
@SuppressWarnings("unchecked")
2531
protected T self() {
@@ -66,4 +72,23 @@ public T chatClientRequestSpecUpdater(
6672
this.chatClientRequestSpecUpdater = chatClientRequestSpecUpdater;
6773
return self();
6874
}
75+
76+
@Override
77+
public T mcpClientConfiguration(
78+
McpClientConfiguration mcpClientConfiguration) {
79+
this.mcpClientConfiguration = mcpClientConfiguration;
80+
return self();
81+
}
82+
83+
@Override
84+
public T toolFilter(Predicate<String> toolFilter) {
85+
this.toolFilter = toolFilter;
86+
return self();
87+
}
88+
89+
@Override
90+
public T objectMapper(ObjectMapper objectMapper) {
91+
this.objectMapper = objectMapper;
92+
return self();
93+
}
6994
}

0 commit comments

Comments
 (0)