Restructure hawkbit-mcp into starter/server modules following the hawkbit conventions (#2923)

Signed-off-by: Denislav Prinov <denislav.prinov@bosch.com>
This commit is contained in:
Denislav Prinov
2026-02-17 10:56:51 +02:00
committed by GitHub
parent 0ab3207568
commit 8ee76412b0
31 changed files with 239 additions and 117 deletions

View File

@@ -0,0 +1,62 @@
<!--
Copyright (c) 2026 Contributors to the Eclipse Foundation
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mcp-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hawkbit-mcp-server</artifactId>
<name>hawkBit :: MCP :: Server (Standalone)</name>
<description>Standalone MCP server that connects to hawkBit via REST API</description>
<properties>
<spring.app.class>org.eclipse.hawkbit.mcp.server.McpServerStart</spring.app.class>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mcp-starter</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>${baseDir}</outputDirectory>
<mainClass>${spring.app.class}</mainClass>
<layout>JAR</layout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
</project>

View File

@@ -9,10 +9,8 @@
*/
package org.eclipse.hawkbit.mcp.server;
import org.eclipse.hawkbit.mcp.server.config.HawkbitMcpProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration;
/**
@@ -23,7 +21,6 @@ import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServic
* </p>
*/
@SpringBootApplication(exclude = UserDetailsServiceAutoConfiguration.class)
@EnableConfigurationProperties(HawkbitMcpProperties.class)
public class McpServerStart {
public static void main(final String[] args) {

View File

@@ -0,0 +1,114 @@
<!--
Copyright (c) 2026 Contributors to the Eclipse Foundation
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
which is available at https://www.eclipse.org/legal/epl-2.0/
SPDX-License-Identifier: EPL-2.0
-->
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-mcp-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>hawkbit-mcp-starter</artifactId>
<name>hawkBit :: MCP :: Spring Boot Starter</name>
<dependencies>
<!-- hawkBit SDK -->
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-sdk-mgmt</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring AI MCP -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-annotations</artifactId>
</dependency>
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- Caching -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Copy hawkBit docs for MCP resources -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-hawkbit-docs</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/hawkbit-docs</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/../../docs</directory>
<includes>
<include>README.md</include>
<include>what-is-hawkbit.md</include>
<include>quick-start.md</include>
<include>features.md</include>
<include>architecture.md</include>
<include>base-setup.md</include>
<include>hawkbit-sdk.md</include>
<include>feign-client.md</include>
<include>clustering.md</include>
<include>authentication.md</include>
<include>authorization.md</include>
<include>datamodel.md</include>
<include>rollout-management.md</include>
<include>targetstate.md</include>
<include>management-api.md</include>
<include>direct-device-integration-api.md</include>
<include>device-management-federation-api.md</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,52 @@
/**
* Copyright (c) 2026 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.eclipse.hawkbit.autoconfigure.mcp;
import org.eclipse.hawkbit.mcp.server.client.AuthenticationValidator;
import org.eclipse.hawkbit.mcp.server.client.HawkbitAuthenticationValidator;
import org.eclipse.hawkbit.mcp.server.config.HawkbitClientConfiguration;
import org.eclipse.hawkbit.mcp.server.config.HawkbitMcpProperties;
import org.eclipse.hawkbit.mcp.server.config.McpHttpClientConfiguration;
import org.eclipse.hawkbit.mcp.server.config.McpSecurityConfiguration;
import org.eclipse.hawkbit.mcp.server.config.McpStdioClientConfiguration;
import org.eclipse.hawkbit.mcp.server.config.McpToolConfiguration;
import org.eclipse.hawkbit.sdk.HawkbitClient;
import org.eclipse.hawkbit.sdk.Tenant;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
/**
* Auto-configuration for the hawkBit MCP server.
*/
@AutoConfiguration
@ConditionalOnClass(McpToolConfiguration.class)
@Import({
McpToolConfiguration.class,
HawkbitClientConfiguration.class,
McpHttpClientConfiguration.class,
McpStdioClientConfiguration.class,
McpSecurityConfiguration.class
})
@EnableConfigurationProperties(HawkbitMcpProperties.class)
public class McpAutoConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(name = "hawkbit.mcp.validation.enabled", havingValue = "true", matchIfMissing = true)
public AuthenticationValidator hawkbitAuthenticationValidator(
final HawkbitClient hawkbitClient, final Tenant dummyTenant, final HawkbitMcpProperties properties) {
return new HawkbitAuthenticationValidator(hawkbitClient, dummyTenant, properties);
}
}

View File

@@ -22,17 +22,13 @@ import org.eclipse.hawkbit.mcp.server.config.HawkbitMcpProperties;
import org.eclipse.hawkbit.mgmt.rest.api.MgmtTenantManagementRestApi;
import org.eclipse.hawkbit.sdk.HawkbitClient;
import org.eclipse.hawkbit.sdk.Tenant;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
/**
* Validates authentication credentials against hawkBit REST API using the SDK.
* This validator is conditionally created when {@code hawkbit.mcp.validation.enabled=true}.
*/
@Slf4j
@Component
@ConditionalOnProperty(name = "hawkbit.mcp.validation.enabled", havingValue = "true", matchIfMissing = true)
public class HawkbitAuthenticationValidator implements AuthenticationValidator {
private final HawkbitClient hawkbitClient;

View File

@@ -63,6 +63,7 @@ public class McpSecurityConfiguration {
@SuppressWarnings("java:S4502") // CSRF protection is not needed for stateless REST APIs using Authorization header
public SecurityFilterChain mcpSecurityFilterChain(final HttpSecurity http) throws Exception {
http
.securityMatcher("/mcp/**")
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));

View File

@@ -0,0 +1 @@
org.eclipse.hawkbit.autoconfigure.mcp.McpAutoConfiguration

View File

@@ -1,6 +1,6 @@
<!--
Copyright (c) 2025 Contributors to the Eclipse Foundation
Copyright (c) 2026 Contributors to the Eclipse Foundation
This program and the accompanying materials are made
available under the terms of the Eclipse Public License 2.0
@@ -18,113 +18,12 @@
<version>${revision}</version>
</parent>
<artifactId>hawkbit-mcp-server</artifactId>
<name>hawkBit :: MCP Server (Standalone)</name>
<description>Standalone MCP server that connects to hawkBit via REST API</description>
<artifactId>hawkbit-mcp-parent</artifactId>
<name>hawkBit :: MCP</name>
<packaging>pom</packaging>
<properties>
<spring.app.class>org.eclipse.hawkbit.mcp.server.McpServerStart</spring.app.class>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.hawkbit</groupId>
<artifactId>hawkbit-sdk-mgmt</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-hawkbit-docs</id>
<phase>generate-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.outputDirectory}/hawkbit-docs</outputDirectory>
<resources>
<resource>
<directory>${project.basedir}/../docs</directory>
<includes>
<include>README.md</include>
<include>what-is-hawkbit.md</include>
<include>quick-start.md</include>
<include>features.md</include>
<include>architecture.md</include>
<include>base-setup.md</include>
<include>hawkbit-sdk.md</include>
<include>feign-client.md</include>
<include>clustering.md</include>
<include>authentication.md</include>
<include>authorization.md</include>
<include>datamodel.md</include>
<include>rollout-management.md</include>
<include>targetstate.md</include>
<include>management-api.md</include>
<include>direct-device-integration-api.md</include>
<include>device-management-federation-api.md</include>
</includes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<outputDirectory>${baseDir}</outputDirectory>
<mainClass>${spring.app.class}</mainClass>
<layout>JAR</layout>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
<modules>
<module>hawkbit-mcp-starter</module>
<module>hawkbit-mcp-server</module>
</modules>
</project>