Skip to content

Commit 105feb4

Browse files
committed
2197 - AI MCP client/server - WIP
1 parent fefd9a3 commit 105feb4

File tree

5 files changed

+120
-0
lines changed

5 files changed

+120
-0
lines changed

server/apps/server-app/build.gradle.kts

+2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies {
1111
implementation(libs.org.springdoc.springdoc.openapi.starter.common)
1212
implementation(libs.org.springdoc.springdoc.openapi.starter.webmvc.ui)
1313
implementation("org.apache.activemq:artemis-jakarta-server")
14+
implementation("org.springframework.ai:spring-ai-mcp-server-webmvc-spring-boot-starter:${rootProject.libs.versions.spring.ai.get()}")
1415
implementation("org.springframework.boot:spring-boot-starter-actuator")
1516
implementation("org.springframework.boot:spring-boot-starter-amqp")
1617
implementation("org.springframework.boot:spring-boot-starter-artemis")
@@ -84,6 +85,7 @@ dependencies {
8485
implementation(project(":server:libs:embedded:embedded-configuration:embedded-configuration-rest:embedded-configuration-rest-impl"))
8586
implementation(project(":server:libs:embedded:embedded-configuration:embedded-configuration-service"))
8687
implementation(project(":server:libs:embedded:embedded-connection:embedded-connection-rest"))
88+
implementation(project(":server:libs:embedded:embedded-execution:embedded-execution-mcp-server"))
8789
implementation(project(":server:libs:embedded:embedded-execution:embedded-execution-public-rest"))
8890
implementation(project(":server:libs:embedded:embedded-execution:embedded-execution-service"))
8991
implementation(project(":server:libs:embedded:embedded-security-web:embedded-security-web-impl"))

server/libs/config/security-config/src/main/java/com/bytechef/security/config/SecurityConfiguration.java

+3
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ public SecurityFilterChain filterChain(
134134
.ignoringRequestMatchers("/api/o/**")
135135
.ignoringRequestMatchers("/approvals/**")
136136
.ignoringRequestMatchers("/graphql")
137+
.ignoringRequestMatchers("/mcp/**")
137138
.ignoringRequestMatchers("/webhooks/**"));
138139

139140
for (AuthenticationProviderContributor authenticationProviderContributor : authenticationProviderContributors) {
@@ -201,6 +202,8 @@ public SecurityFilterChain filterChain(
201202
.permitAll()
202203
.requestMatchers(mvc.pattern("/index.html"))
203204
.permitAll()
205+
.requestMatchers(mvc.pattern("/sse"))
206+
.authenticated()
204207
.requestMatchers(mvc.pattern("/swagger-ui/**"))
205208
.permitAll()
206209
.requestMatchers(mvc.pattern("/swagger-ui.html"))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
dependencies {
2+
implementation("io.modelcontextprotocol.sdk:mcp:0.7.0")
3+
implementation("io.modelcontextprotocol.sdk:mcp-spring-webmvc:0.7.0")
4+
implementation("org.springframework.ai:spring-ai-mcp:${rootProject.libs.versions.spring.ai.get()}")
5+
implementation("org.springframework:spring-web")
6+
implementation(project(":server:libs:core:commons:commons-util"))
7+
implementation(project(":server:libs:embedded:embedded-execution:embedded-execution-api"))
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2023-present ByteChef Inc.
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 com.bytechef.ai.mcp.server.config;
18+
19+
import com.bytechef.embedded.execution.facade.ToolFacade;
20+
import com.bytechef.embedded.execution.facade.dto.ToolDTO;
21+
import com.bytechef.platform.constant.Environment;
22+
import com.fasterxml.jackson.databind.ObjectMapper;
23+
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
24+
import io.modelcontextprotocol.server.McpServer;
25+
import io.modelcontextprotocol.server.McpSyncServer;
26+
import io.modelcontextprotocol.server.transport.WebMvcSseServerTransport;
27+
import io.modelcontextprotocol.spec.McpSchema;
28+
import io.modelcontextprotocol.spec.ServerMcpTransport;
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
import java.util.Map;
32+
import java.util.function.Function;
33+
import org.springframework.ai.mcp.McpToolUtils;
34+
import org.springframework.ai.tool.ToolCallback;
35+
import org.springframework.ai.tool.function.FunctionToolCallback;
36+
import org.springframework.context.annotation.Bean;
37+
import org.springframework.web.servlet.function.RouterFunction;
38+
import org.springframework.web.servlet.function.ServerResponse;
39+
40+
/**
41+
* @author Ivica Cardic
42+
*/
43+
//@Configuration
44+
public class McpServerConfiguration {
45+
46+
private final ToolFacade toolFacade;
47+
48+
@SuppressFBWarnings("EI")
49+
public McpServerConfiguration(ToolFacade toolFacade) {
50+
this.toolFacade = toolFacade;
51+
}
52+
53+
@Bean
54+
WebMvcSseServerTransport webMvcSseServerTransport(ObjectMapper objectMapper) {
55+
// TODO - Set /embedded/mcp/message, check ConnectedUserAuthenticationFilter
56+
// TODO - Set /embedded/sse
57+
58+
return new WebMvcSseServerTransport(objectMapper, "/api/embedded/v1/mcp/message");
59+
}
60+
61+
@Bean
62+
RouterFunction<ServerResponse> routerFunction(WebMvcSseServerTransport transport) {
63+
return transport.getRouterFunction();
64+
}
65+
66+
@Bean
67+
McpSyncServer mcpServer(ServerMcpTransport transport) {
68+
var capabilities = McpSchema.ServerCapabilities.builder()
69+
.resources(false, true)
70+
.tools(true)
71+
.prompts(true)
72+
.logging()
73+
.build();
74+
75+
return McpServer.sync(transport)
76+
.serverInfo("MCP ByteChef Embedded Server", "1.0.0")
77+
.capabilities(capabilities)
78+
.tools(McpToolUtils.toSyncToolRegistration(getToolCallbacks()))
79+
.build();
80+
}
81+
82+
public List<ToolCallback> getToolCallbacks() {
83+
List<ToolCallback> toolCallbacks = new ArrayList<>();
84+
85+
List<ToolDTO> toolDTOs = toolFacade.getTools();
86+
87+
for (ToolDTO toolDTO : toolDTOs) {
88+
FunctionToolCallback.Builder<Map<String, Object>, Object> builder = FunctionToolCallback
89+
.builder(toolDTO.name(), getToolCallbackFunction(toolDTO.name()))
90+
.inputType(Map.class)
91+
.inputSchema(toolDTO.parameters());
92+
93+
if (toolDTO.description() != null) {
94+
builder.description(toolDTO.description());
95+
}
96+
97+
toolCallbacks.add(builder.build());
98+
}
99+
100+
return toolCallbacks;
101+
}
102+
103+
private Function<Map<String, Object>, Object> getToolCallbackFunction(String toolName) {
104+
return request -> toolFacade.executeTool(toolName, request, Environment.PRODUCTION, null);
105+
}
106+
}

settings.gradle.kts

+1
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ include("server:libs:embedded:embedded-configuration:embedded-configuration-rest
125125
include("server:libs:embedded:embedded-configuration:embedded-configuration-service")
126126
include("server:libs:embedded:embedded-connection:embedded-connection-rest")
127127
include("server:libs:embedded:embedded-execution:embedded-execution-api")
128+
include("server:libs:embedded:embedded-execution:embedded-execution-mcp-server")
128129
include("server:libs:embedded:embedded-execution:embedded-execution-public-rest")
129130
include("server:libs:embedded:embedded-execution:embedded-execution-service")
130131
include("server:libs:embedded:embedded-security-web:embedded-security-web-impl")

0 commit comments

Comments
 (0)