Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docker/build/build_dev.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ if [ -z "$1" ]; then
build "hawkbit-update-server"
# db init
build "hawkbit-repository-jpa-init"
# mcp server
build "hawkbit-mcp-server"
else
echo "Build $1"
build $1
Expand Down
109 changes: 109 additions & 0 deletions hawkbit-mcp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# hawkBit MCP Server

A standalone [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that provides AI assistants with tools to interact with [Eclipse hawkBit](https://www.eclipse.org/hawkbit/) for IoT device software update management.

## Building

From the project root directory:

```bash
mvn clean package -pl hawkbit-mcp -am -DskipTests
```

The JAR will be created at: `hawkbit-mcp/target/hawkbit-mcp-server-0-SNAPSHOT.jar`

## Configuration

The MCP server supports two transport modes:

| Mode | Use Case | Authentication |
|------|----------|----------------|
| **HTTP/SSE** | Remote access, multi-user | Per-request via `Authorization` header |
| **STDIO** | Local CLI tools (e.g., Claude Code) | Environment variables |


### HTTP Transport

Use HTTP transport when running the server as a standalone service:

```json
{
"mcpServers": {
"hawkbit-mcp": {
"type": "http",
"url": "http://localhost:8081/mcp",
"headers": {
"Authorization": "Basic <BASE64_ENCODED_CREDENTIALS>"
}
}
}
}
```

Start the server separately:

```bash
java -jar hawkbit-mcp-server-0-SNAPSHOT.jar \
--hawkbit.mcp.mgmt-url=<HAWKBIT_URL>
```

**Generating Base64 credentials:**

```bash
# Linux/Mac
echo -n "<USERNAME>:<PASSWORD>" | base64

# PowerShell
[Convert]::ToBase64String([Text.Encoding]::UTF8.GetBytes("<USERNAME>:<PASSWORD>"))
```

### STDIO Transport

Use STDIO transport for direct integration:

```json
{
"mcpServers": {
"hawkbit-mcp": {
"command": "java",
"args": [
"-Dspring.ai.mcp.server.stdio=true",
"-Dspring.main.web-application-type=none",
"-jar",
"/path/to/hawkbit-mcp-server-0-SNAPSHOT.jar"
],
"env": {
"HAWKBIT_URL": "<HAWKBIT_URL>",
"HAWKBIT_USERNAME": "<USERNAME>",
"HAWKBIT_PASSWORD": "<PASSWORD>"
}
}
}
}
```

## Configuration Properties

| Property | Environment Variable | Description | Default |
|----------|---------------------|-------------|---------|
| `hawkbit.mcp.mgmt-url` | `HAWKBIT_URL` | hawkBit Management API URL | `http://localhost:8080` |
| `hawkbit.mcp.username` | `HAWKBIT_USERNAME` | Username for STDIO mode | - |
| `hawkbit.mcp.password` | `HAWKBIT_PASSWORD` | Password for STDIO mode | - |
| `hawkbit.mcp.validation.enabled` | - | Validate credentials against hawkBit | `true` |
| `hawkbit.mcp.validation.cache-ttl` | - | Cache TTL for auth validation | `600s` |

### Operation Controls

You can enable/disable specific operations globally or per-entity:

```properties
# Global: disable all deletes
hawkbit.mcp.operations.delete-enabled=false

# Per-entity: allow delete for targets only
hawkbit.mcp.operations.targets.delete-enabled=true

# Disable rollout lifecycle operations
hawkbit.mcp.operations.rollouts.start-enabled=false
hawkbit.mcp.operations.rollouts.approve-enabled=false
```
135 changes: 135 additions & 0 deletions hawkbit-mcp/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<!--

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

-->
<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-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>

<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>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</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>
<configuration>
<mainClass>org.eclipse.hawkbit.mcp.server.HawkbitMcpServerApplication</mainClass>
<attach>false</attach>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<configuration>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* 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.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;

/**
* Standalone MCP Server application that connects to hawkBit via REST API.
* <p>
* This server acts as a proxy between MCP clients and hawkBit,
* passing through authentication credentials to the hawkBit REST API.
* </p>
*/
@SpringBootApplication(exclude = UserDetailsServiceAutoConfiguration.class)
@EnableConfigurationProperties(HawkbitMcpProperties.class)
public class HawkbitMcpServerApplication {

public static void main(String[] args) {
SpringApplication.run(HawkbitMcpServerApplication.class, args);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/**
* 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.mcp.server.client;

/**
* Interface for authentication validation.
* Implementations can validate credentials against hawkBit or provide no-op validation.
*/
public interface AuthenticationValidator {

/**
* Validates the given authorization header.
*
* @param authHeader the Authorization header value
* @return validation result
*/
ValidationResult validate(String authHeader);

/**
* Result of authentication validation.
*/
enum ValidationResult {
/**
* Credentials are valid (authenticated user).
*/
VALID,

/**
* No credentials provided.
*/
MISSING_CREDENTIALS,

/**
* Credentials are invalid (401 from hawkBit).
*/
INVALID_CREDENTIALS,

/**
* hawkBit is unavailable or returned unexpected error.
*/
HAWKBIT_ERROR
}
}
Loading
Loading