+ * Spring AI MCP auto-discovers {@code @McpTool} annotated methods on this bean.
+ * Override by defining your own {@code HawkBitMcpToolProvider} bean.
+ * Disable by setting {@code hawkbit.mcp.tools-enabled=false}.
+ * Individual operations can be enabled/disabled via {@code hawkbit.mcp.operations.*} properties.
+ *
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(name = "hawkbit.mcp.tools-enabled", havingValue = "true", matchIfMissing = true)
+ public HawkBitMcpToolProvider hawkBitMcpToolProvider(
+ final HawkbitClient hawkbitClient,
+ final Tenant dummyTenant,
+ final HawkBitMcpProperties properties) {
+ return new HawkBitMcpToolProvider(hawkbitClient, dummyTenant, properties);
+ }
+
+ /**
+ * Creates the hawkBit documentation resource provider.
+ *
+ * Spring AI MCP auto-discovers {@code @McpResource} annotated methods on this bean.
+ * Override by defining your own {@code HawkBitDocumentationResource} bean.
+ * Disable by setting {@code hawkbit.mcp.resources-enabled=false}.
+ *
+ * Spring AI MCP auto-discovers {@code @McpPrompt} annotated methods on this bean.
+ * Override by defining your own {@code HawkBitPromptProvider} bean.
+ * Disable by setting {@code hawkbit.mcp.prompts-enabled=false}.
+ *
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ @ConditionalOnProperty(name = "hawkbit.mcp.prompts-enabled", havingValue = "true", matchIfMissing = true)
+ public HawkBitPromptProvider hawkBitPromptProvider() {
+ return new HawkBitPromptProvider();
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ActionOperation.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ActionOperation.java
new file mode 100644
index 0000000000..2a5bce899e
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ActionOperation.java
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+/**
+ * Operations for action management (actions are created indirectly via DS assignment).
+ */
+public enum ActionOperation {
+ DELETE,
+ DELETE_BATCH
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ListRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ListRequest.java
new file mode 100644
index 0000000000..c165df4678
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ListRequest.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import com.fasterxml.jackson.annotation.JsonPropertyDescription;
+
+/**
+ * Common request parameters for list operations.
+ */
+public record ListRequest(
+ @JsonPropertyDescription("RSQL filter query (e.g., 'name==test*')")
+ String rsql,
+
+ @JsonPropertyDescription("Number of items to skip (default: 0)")
+ Integer offset,
+
+ @JsonPropertyDescription("Maximum number of items to return (default: 50)")
+ Integer limit
+) {
+
+ public static final int DEFAULT_OFFSET = 0;
+ public static final int DEFAULT_LIMIT = 50;
+
+ public int getOffsetOrDefault() {
+ return offset != null ? offset : DEFAULT_OFFSET;
+ }
+
+ public int getLimitOrDefault() {
+ return limit != null ? limit : DEFAULT_LIMIT;
+ }
+
+ public String getRsqlOrNull() {
+ return rsql != null && !rsql.isBlank() ? rsql : null;
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageActionRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageActionRequest.java
new file mode 100644
index 0000000000..af373a0a24
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageActionRequest.java
@@ -0,0 +1,28 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import java.util.List;
+
+/**
+ * Request wrapper for action management operations.
+ * Actions are created indirectly via distribution set assignment, so only DELETE operations are supported.
+ *
+ * @param operation the operation to perform (DELETE, DELETE_BATCH)
+ * @param actionId the action ID (for DELETE single action)
+ * @param actionIds list of action IDs (for DELETE_BATCH)
+ * @param rsql RSQL filter query (alternative for DELETE_BATCH)
+ */
+public record ManageActionRequest(
+ ActionOperation operation,
+ Long actionId,
+ List actionIds,
+ String rsql
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageDistributionSetRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageDistributionSetRequest.java
new file mode 100644
index 0000000000..33612efa4f
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageDistributionSetRequest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPost;
+import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSetRequestBodyPut;
+
+/**
+ * Request wrapper for distribution set management operations.
+ * Reuses existing {@link MgmtDistributionSetRequestBodyPost} for CREATE and
+ * {@link MgmtDistributionSetRequestBodyPut} for UPDATE.
+ *
+ * @param operation the operation to perform (CREATE, UPDATE, DELETE)
+ * @param distributionSetId the distribution set ID (required for UPDATE/DELETE)
+ * @param createBody the request body for CREATE operation
+ * @param updateBody the request body for UPDATE operation
+ */
+public record ManageDistributionSetRequest(
+ Operation operation,
+ Long distributionSetId,
+ MgmtDistributionSetRequestBodyPost createBody,
+ MgmtDistributionSetRequestBodyPut updateBody
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageRolloutRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageRolloutRequest.java
new file mode 100644
index 0000000000..21ff963511
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageRolloutRequest.java
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPost;
+import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutRestRequestBodyPut;
+
+/**
+ * Request wrapper for rollout management operations including CRUD and lifecycle.
+ * Reuses existing {@link MgmtRolloutRestRequestBodyPost} for CREATE and
+ * {@link MgmtRolloutRestRequestBodyPut} for UPDATE.
+ *
+ * @param operation the operation to perform (CREATE, UPDATE, DELETE, START, PAUSE, STOP, RESUME, APPROVE, DENY, RETRY, TRIGGER_NEXT_GROUP)
+ * @param rolloutId the rollout ID (required for UPDATE/DELETE/lifecycle operations)
+ * @param createBody the request body for CREATE operation
+ * @param updateBody the request body for UPDATE operation
+ * @param remark optional remark for APPROVE/DENY operations
+ */
+public record ManageRolloutRequest(
+ RolloutOperation operation,
+ Long rolloutId,
+ MgmtRolloutRestRequestBodyPost createBody,
+ MgmtRolloutRestRequestBodyPut updateBody,
+ String remark
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageSoftwareModuleRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageSoftwareModuleRequest.java
new file mode 100644
index 0000000000..ae3b4dbaa1
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageSoftwareModuleRequest.java
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPost;
+import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModuleRequestBodyPut;
+
+/**
+ * Request wrapper for software module management operations.
+ * Reuses existing {@link MgmtSoftwareModuleRequestBodyPost} for CREATE and
+ * {@link MgmtSoftwareModuleRequestBodyPut} for UPDATE.
+ *
+ * @param operation the operation to perform (CREATE, UPDATE, DELETE)
+ * @param softwareModuleId the software module ID (required for UPDATE/DELETE)
+ * @param createBody the request body for CREATE operation
+ * @param updateBody the request body for UPDATE operation
+ */
+public record ManageSoftwareModuleRequest(
+ Operation operation,
+ Long softwareModuleId,
+ MgmtSoftwareModuleRequestBodyPost createBody,
+ MgmtSoftwareModuleRequestBodyPut updateBody
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetFilterRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetFilterRequest.java
new file mode 100644
index 0000000000..b1537563df
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetFilterRequest.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQueryRequestBody;
+
+/**
+ * Request wrapper for target filter query management operations.
+ * Reuses existing {@link MgmtTargetFilterQueryRequestBody} for CREATE/UPDATE data.
+ *
+ * @param operation the operation to perform (CREATE, UPDATE, DELETE)
+ * @param filterId the target filter query ID (required for UPDATE/DELETE)
+ * @param body the request body containing filter data (for CREATE/UPDATE)
+ */
+public record ManageTargetFilterRequest(
+ Operation operation,
+ Long filterId,
+ MgmtTargetFilterQueryRequestBody body
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetRequest.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetRequest.java
new file mode 100644
index 0000000000..2ace1c616b
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/ManageTargetRequest.java
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTargetRequestBody;
+
+/**
+ * Request wrapper for target management operations.
+ * Reuses existing {@link MgmtTargetRequestBody} for CREATE/UPDATE data.
+ *
+ * @param operation the operation to perform (CREATE, UPDATE, DELETE)
+ * @param controllerId the target controller ID (required for UPDATE/DELETE, used as identifier for CREATE)
+ * @param body the request body containing target data (for CREATE/UPDATE)
+ */
+public record ManageTargetRequest(
+ Operation operation,
+ String controllerId,
+ MgmtTargetRequestBody body
+) {}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/Operation.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/Operation.java
new file mode 100644
index 0000000000..5987bcd376
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/Operation.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+/**
+ * Standard CRUD operations for entity management tools.
+ */
+public enum Operation {
+ CREATE,
+ UPDATE,
+ DELETE
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/OperationResponse.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/OperationResponse.java
new file mode 100644
index 0000000000..910eda378b
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/OperationResponse.java
@@ -0,0 +1,55 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+/**
+ * Unified response wrapper for management operations.
+ *
+ * @param the type of the data payload
+ * @param operation the operation that was performed
+ * @param success whether the operation was successful
+ * @param message optional message (typically for success confirmations or error details)
+ * @param data the operation result data (e.g., created/updated entity)
+ */
+public record OperationResponse(
+ String operation,
+ boolean success,
+ String message,
+ T data
+) {
+
+ /**
+ * Creates a successful response with data.
+ */
+ public static OperationResponse success(final String operation, final T data) {
+ return new OperationResponse<>(operation, true, null, data);
+ }
+
+ /**
+ * Creates a successful response with a message (no data).
+ */
+ public static OperationResponse success(final String operation, final String message) {
+ return new OperationResponse<>(operation, true, message, null);
+ }
+
+ /**
+ * Creates a successful response with both message and data.
+ */
+ public static OperationResponse success(final String operation, final String message, final T data) {
+ return new OperationResponse<>(operation, true, message, data);
+ }
+
+ /**
+ * Creates a failure response with an error message.
+ */
+ public static OperationResponse failure(final String operation, final String message) {
+ return new OperationResponse<>(operation, false, message, null);
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/PagedResponse.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/PagedResponse.java
new file mode 100644
index 0000000000..62e121d89d
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/PagedResponse.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+import java.util.List;
+
+/**
+ * Generic paged response for MCP tool results.
+ *
+ * @param the type of items in the response
+ */
+public record PagedResponse(
+ List content,
+ long total,
+ int offset,
+ int limit
+) {
+
+ public static PagedResponse of(final List content, final long total, final int offset, final int limit) {
+ return new PagedResponse<>(content, total, offset, limit);
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/RolloutOperation.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/RolloutOperation.java
new file mode 100644
index 0000000000..f48113c253
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/dto/RolloutOperation.java
@@ -0,0 +1,27 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.dto;
+
+/**
+ * Operations for rollout management including CRUD and lifecycle operations.
+ */
+public enum RolloutOperation {
+ CREATE,
+ UPDATE,
+ DELETE,
+ START,
+ PAUSE,
+ STOP,
+ RESUME,
+ APPROVE,
+ DENY,
+ RETRY,
+ TRIGGER_NEXT_GROUP
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/prompts/HawkBitPromptProvider.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/prompts/HawkBitPromptProvider.java
new file mode 100644
index 0000000000..7b4dbf9db4
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/prompts/HawkBitPromptProvider.java
@@ -0,0 +1,67 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.prompts;
+
+import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
+import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
+import io.modelcontextprotocol.spec.McpSchema.Role;
+import io.modelcontextprotocol.spec.McpSchema.TextContent;
+import lombok.extern.slf4j.Slf4j;
+import org.springaicommunity.mcp.annotation.McpPrompt;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * MCP prompts for hawkBit that provide initial context to LLMs.
+ *
+ * These prompts help LLMs understand what hawkBit is and what documentation
+ * resources are available at the start of a session.
+ *
+ */
+@Slf4j
+public class HawkBitPromptProvider {
+
+ private static final String PROMPTS_PATH = "prompts/";
+
+ @McpPrompt(
+ name = "hawkbit-context",
+ description = "Provides initial context about hawkBit, available tools, and documentation resources. " +
+ "Use this prompt at the start of a session to understand what you can do with hawkBit MCP.")
+ public GetPromptResult getHawkBitContext() {
+ return new GetPromptResult(
+ "hawkBit MCP Server Context",
+ List.of(new PromptMessage(Role.ASSISTANT, new TextContent(loadPrompt("hawkbit-context.md"))))
+ );
+ }
+
+ @McpPrompt(
+ name = "rsql-help",
+ description = "Explains RSQL query syntax for filtering hawkBit entities. " +
+ "Use this when you need help constructing filter queries for targets, rollouts, etc.")
+ public GetPromptResult getRsqlHelp() {
+ return new GetPromptResult(
+ "RSQL Query Help",
+ List.of(new PromptMessage(Role.ASSISTANT, new TextContent(loadPrompt("rsql-help.md"))))
+ );
+ }
+
+ private String loadPrompt(final String filename) {
+ try {
+ ClassPathResource resource = new ClassPathResource(PROMPTS_PATH + filename);
+ return resource.getContentAsString(StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ log.error("Failed to load prompt: {}", filename, e);
+ return "Prompt content not available.";
+ }
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/resources/HawkBitDocumentationResource.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/resources/HawkBitDocumentationResource.java
new file mode 100644
index 0000000000..2f05a5fe55
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/resources/HawkBitDocumentationResource.java
@@ -0,0 +1,201 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.resources;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springaicommunity.mcp.annotation.McpResource;
+import org.springframework.core.io.ClassPathResource;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * MCP resources providing hawkBit documentation for LLMs.
+ */
+@Slf4j
+public class HawkBitDocumentationResource {
+
+ private static final String DOCS_PATH = "hawkbit-docs/";
+
+ @McpResource(
+ uri = "hawkbit://docs/overview",
+ name = "hawkBit Overview",
+ description = "High-level introduction to hawkBit: interfaces (DDI, DMF, Management API), " +
+ "rollout management, and package model for IoT software updates")
+ public String getOverview() {
+ return loadDoc("README.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/what-is-hawkbit",
+ name = "What is hawkBit",
+ description = "Explains what hawkBit is, why IoT software updates matter, " +
+ "and scalability features for cloud deployments")
+ public String getWhatIsHawkbit() {
+ return loadDoc("what-is-hawkbit.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/quick-start",
+ name = "Quick Start Guide",
+ description = "Docker-based setup guides for monolith and microservices deployments, " +
+ "building from sources, and credential configuration")
+ public String getQuickStart() {
+ return loadDoc("quick-start.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/features",
+ name = "Feature Overview",
+ description = "Comprehensive feature list: device repository, software management, " +
+ "artifact delivery, rollout management, and API interfaces")
+ public String getFeatures() {
+ return loadDoc("features.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/architecture",
+ name = "System Architecture",
+ description = "Architecture overview with module diagram and third-party technology stack")
+ public String getArchitecture() {
+ return loadDoc("architecture.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/base-setup",
+ name = "Production Setup",
+ description = "Configuring production infrastructure with MariaDB/MySQL database " +
+ "and RabbitMQ for DMF (Device Management Federation) communication")
+ public String getBaseSetup() {
+ return loadDoc("base-setup.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/sdk",
+ name = "SDK Guide",
+ description = "hawkBit SDK for device and gateway integration: configuration properties, " +
+ "Maven dependencies, and usage examples with DdiTenant and MgmtAPI clients")
+ public String getSdkGuide() {
+ return loadDoc("hawkbit-sdk.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/feign-client",
+ name = "Feign Client Guide",
+ description = "Creating Feign-based REST clients for Management API and DDI API " +
+ "with Spring Boot integration examples")
+ public String getFeignClientGuide() {
+ return loadDoc("feign-client.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/clustering",
+ name = "Clustering Guide",
+ description = "Running hawkBit in clustered environments: Spring Cloud Stream event distribution, " +
+ "caching with TTL, scheduler behavior, and DoS filter constraints")
+ public String getClusteringGuide() {
+ return loadDoc("clustering.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/authentication",
+ name = "Authentication",
+ description = "Security token authentication (target and gateway tokens), certificate-based auth " +
+ "via reverse proxy, TLS/mTLS setup, and Nginx configuration examples")
+ public String getAuthentication() {
+ return loadDoc("authentication.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/authorization",
+ name = "Authorization",
+ description = "Fine-grained permission system for Management API/UI, DDI API authorization, " +
+ "permission groups, OpenID Connect support, and role-based access control")
+ public String getAuthorization() {
+ return loadDoc("authorization.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/datamodel",
+ name = "Data Model",
+ description = "Entity definitions: provisioning targets, distribution sets, software modules, " +
+ "artifacts, entity relationships, and soft/hard delete strategies")
+ public String getDataModel() {
+ return loadDoc("datamodel.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/rollout-management",
+ name = "Rollout Management",
+ description = "Rollout campaigns: cascading deployment groups, success/error thresholds, " +
+ "approval workflow, multi-assignments (beta), action weight prioritization, and state machines")
+ public String getRolloutManagement() {
+ return loadDoc("rollout-management.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/target-state",
+ name = "Target State",
+ description = "Target state definitions (UNKNOWN, IN_SYNC, PENDING, ERROR, REGISTERED) " +
+ "and state transition diagrams")
+ public String getTargetState() {
+ return loadDoc("targetstate.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/management-api",
+ name = "Management API",
+ description = "RESTful API for CRUD operations on targets and software: API versioning, " +
+ "HTTP methods, headers, error handling, and embedded Swagger UI reference")
+ public String getManagementApi() {
+ return loadDoc("management-api.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/ddi-api",
+ name = "DDI API (Direct Device Integration)",
+ description = "HTTP polling-based device integration API: state machine mapping, " +
+ "status feedback mechanisms, update retrieval, and embedded Swagger UI reference")
+ public String getDdiApi() {
+ return loadDoc("direct-device-integration-api.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/dmf-api",
+ name = "DMF API (Device Management Federation)",
+ description = "AMQP-based indirect device integration: message formats (THING_CREATED, etc.), " +
+ "exchanges, queues, bindings, and high-throughput service-to-service communication")
+ public String getDmfApi() {
+ return loadDoc("device-management-federation-api.md");
+ }
+
+ @McpResource(
+ uri = "hawkbit://docs/entity-definitions",
+ name = "hawkBit Entity Definitions",
+ description = "RSQL filtering syntax for querying targets, rollouts, distribution sets, " +
+ "actions, software modules, and target filter queries with examples")
+ public String getEntityDefinitions() {
+ return loadResource("hawkbit-entity-definitions.md");
+ }
+
+ private String loadDoc(final String filename) {
+ return loadResource(DOCS_PATH + filename);
+ }
+
+ private String loadResource(final String path) {
+ try {
+ ClassPathResource resource = new ClassPathResource(path);
+ return resource.getContentAsString(StandardCharsets.UTF_8);
+ } catch (IOException e) {
+ log.error("Failed to load documentation: {}", path, e);
+ return "Documentation not available. Please refer to the hawkBit documentation at https://eclipse.dev/hawkbit/";
+ }
+ }
+}
diff --git a/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/tools/HawkBitMcpToolProvider.java b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/tools/HawkBitMcpToolProvider.java
new file mode 100644
index 0000000000..ec6a14d51f
--- /dev/null
+++ b/hawkbit-mcp/src/main/java/org/eclipse/hawkbit/mcp/server/tools/HawkBitMcpToolProvider.java
@@ -0,0 +1,553 @@
+/**
+ * Copyright (c) 2025 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.mcp.server.tools;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.eclipse.hawkbit.mcp.server.config.HawkBitMcpProperties;
+import org.eclipse.hawkbit.mcp.server.dto.ActionOperation;
+import org.eclipse.hawkbit.mcp.server.dto.ListRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageActionRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageDistributionSetRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageRolloutRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageSoftwareModuleRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageTargetFilterRequest;
+import org.eclipse.hawkbit.mcp.server.dto.ManageTargetRequest;
+import org.eclipse.hawkbit.mcp.server.dto.Operation;
+import org.eclipse.hawkbit.mcp.server.dto.OperationResponse;
+import org.eclipse.hawkbit.mcp.server.dto.PagedResponse;
+import org.eclipse.hawkbit.mcp.server.dto.RolloutOperation;
+import org.eclipse.hawkbit.mgmt.json.model.PagedList;
+import org.eclipse.hawkbit.mgmt.json.model.action.MgmtAction;
+import org.eclipse.hawkbit.mgmt.json.model.distributionset.MgmtDistributionSet;
+import org.eclipse.hawkbit.mgmt.json.model.rollout.MgmtRolloutResponseBody;
+import org.eclipse.hawkbit.mgmt.json.model.softwaremodule.MgmtSoftwareModule;
+import org.eclipse.hawkbit.mgmt.json.model.target.MgmtTarget;
+import org.eclipse.hawkbit.mgmt.json.model.targetfilter.MgmtTargetFilterQuery;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtActionRestApi;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtDistributionSetRestApi;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtRolloutRestApi;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtSoftwareModuleRestApi;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetFilterQueryRestApi;
+import org.eclipse.hawkbit.mgmt.rest.api.MgmtTargetRestApi;
+import org.eclipse.hawkbit.sdk.HawkbitClient;
+import org.eclipse.hawkbit.sdk.Tenant;
+import org.springaicommunity.mcp.annotation.McpTool;
+import org.springframework.http.ResponseEntity;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * MCP tools for hawkBit using the SDK.
+ *
+ * Provides tools for managing targets, rollouts, distribution sets, actions,
+ * software modules, and target filter queries via the hawkBit REST API.
+ *
+ */
+@Slf4j
+@RequiredArgsConstructor
+public class HawkBitMcpToolProvider {
+
+ private static final String OP_CREATE = "CREATE";
+ private static final String OP_UPDATE = "UPDATE";
+ private static final String OP_DELETE = "DELETE";
+ private static final String OP_DELETE_BATCH = "DELETE_BATCH";
+ private static final String OP_START = "START";
+ private static final String OP_PAUSE = "PAUSE";
+ private static final String OP_STOP = "STOP";
+ private static final String OP_RESUME = "RESUME";
+ private static final String OP_APPROVE = "APPROVE";
+ private static final String OP_DENY = "DENY";
+ private static final String OP_RETRY = "RETRY";
+ private static final String OP_TRIGGER_NEXT_GROUP = "TRIGGER_NEXT_GROUP";
+
+ private final HawkbitClient hawkbitClient;
+ private final Tenant dummyTenant;
+ private final HawkBitMcpProperties properties;
+
+ private PagedResponse toPagedResponse(final PagedList pagedList, final ListRequest request) {
+ if (pagedList == null) {
+ return PagedResponse.of(
+ Collections.emptyList(),
+ 0L,
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault());
+ }
+ return PagedResponse.of(
+ pagedList.getContent(),
+ pagedList.getTotal(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault());
+ }
+
+ @McpTool(name = "list_targets",
+ description = "Retrieves a paged list of targets (devices) with optional RSQL filtering. " +
+ "Targets represent devices that can receive software updates.")
+ public PagedResponse listTargets(final ListRequest request) {
+ log.debug("Listing targets with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtTargetRestApi targetApi = hawkbitClient.mgmtService(MgmtTargetRestApi.class, dummyTenant);
+ ResponseEntity> response = targetApi.getTargets(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "list_rollouts",
+ description = "Retrieves a paged list of rollouts with optional RSQL filtering. " +
+ "Rollouts are used to deploy software to groups of targets.")
+ public PagedResponse listRollouts(final ListRequest request) {
+ log.debug("Listing rollouts with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtRolloutRestApi rolloutApi = hawkbitClient.mgmtService(MgmtRolloutRestApi.class, dummyTenant);
+ ResponseEntity> response = rolloutApi.getRollouts(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null,
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "list_distribution_sets",
+ description = "Retrieves a paged list of distribution sets with optional RSQL filtering. " +
+ "Distribution sets are software packages that can be deployed to targets.")
+ public PagedResponse listDistributionSets(final ListRequest request) {
+ log.debug("Listing distribution sets with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtDistributionSetRestApi dsApi = hawkbitClient.mgmtService(MgmtDistributionSetRestApi.class, dummyTenant);
+ ResponseEntity> response = dsApi.getDistributionSets(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "list_actions",
+ description = "Retrieves a paged list of actions with optional RSQL filtering. " +
+ "Actions represent deployment operations assigned to targets.")
+ public PagedResponse listActions(final ListRequest request) {
+ log.debug("Listing actions with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtActionRestApi actionApi = hawkbitClient.mgmtService(MgmtActionRestApi.class, dummyTenant);
+ ResponseEntity> response = actionApi.getActions(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null,
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "list_software_modules",
+ description = "Retrieves a paged list of software modules with optional RSQL filtering. " +
+ "Software modules are individual software components within distribution sets.")
+ public PagedResponse listSoftwareModules(final ListRequest request) {
+ log.debug("Listing software modules with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtSoftwareModuleRestApi smApi = hawkbitClient.mgmtService(MgmtSoftwareModuleRestApi.class, dummyTenant);
+ ResponseEntity> response = smApi.getSoftwareModules(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "list_target_filters",
+ description = "Retrieves a paged list of target filter queries with optional RSQL filtering. " +
+ "Target filters define RSQL queries to group targets for rollouts or auto-assignment.")
+ public PagedResponse listTargetFilters(final ListRequest request) {
+ log.debug("Listing target filters with rsql={}, offset={}, limit={}",
+ request.rsql(), request.getOffsetOrDefault(), request.getLimitOrDefault());
+
+ MgmtTargetFilterQueryRestApi filterApi = hawkbitClient.mgmtService(MgmtTargetFilterQueryRestApi.class, dummyTenant);
+ ResponseEntity> response = filterApi.getFilters(
+ request.getRsqlOrNull(),
+ request.getOffsetOrDefault(),
+ request.getLimitOrDefault(),
+ null,
+ null);
+
+ return toPagedResponse(response.getBody(), request);
+ }
+
+ @McpTool(name = "manage_target",
+ description = "Create, update, or delete targets (devices). " +
+ "Operations: CREATE (new target with controllerId, name, description), " +
+ "UPDATE (modify existing target by controllerId), " +
+ "DELETE (remove target by controllerId)")
+ public OperationResponse