Skip to content

hawkBit MCP server#2871

Open
denislavprinov wants to merge 4 commits intoeclipse-hawkbit:masterfrom
boschglobal:feature/hawkbit-mcp-server
Open

hawkBit MCP server#2871
denislavprinov wants to merge 4 commits intoeclipse-hawkbit:masterfrom
boschglobal:feature/hawkbit-mcp-server

Conversation

@denislavprinov
Copy link
Contributor

  • Introduces a new Model Context Protocol (MCP) server module (hawkbit-mcp) that enables AI assistants to interact with hawkBit
  • Provides MCP tools for managing all hawkBit entities: Targets, Distribution Sets, Software Modules, Rollouts, Actions, and Target Filters
  • Includes MCP resources for hawkBit documentation
  • Exposes predefined prompts
  • Supports credential pass-through authentication to hawkBit REST API

@denislavprinov denislavprinov force-pushed the feature/hawkbit-mcp-server branch from dc059b7 to b0d48e0 Compare January 15, 2026 16:47
Signed-off-by: Denislav Prinov <[email protected]>
@denislavprinov denislavprinov force-pushed the feature/hawkbit-mcp-server branch from f1f3e2d to 1607ecf Compare January 20, 2026 09:52
@denislavprinov denislavprinov force-pushed the feature/hawkbit-mcp-server branch from 1607ecf to 5946a09 Compare January 20, 2026 12:46
… authentication validator conditional, and separate HTTP/STDIO client configurations

Signed-off-by: Denislav Prinov <[email protected]>
public static final String AUTH_HEADER_ATTRIBUTE = "hawkbit.mcp.auth.header";

private final HawkbitAuthenticationValidator authenticationValidator;
private final AuthenticationValidator authenticationValidator;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need a dummy validator when validation is disabled? Consider making it Optional and just skip the http.addFilterBefore(...);

log.debug("Managing target: operation={}, controllerId={}", request.operation(), request.controllerId());
"DELETE (remove target by controllerId). " +
"Use 'type' field to select operation: " +
"{\"type\":\"Create\",\"body\":{\"controllerId\":\"id\",\"name\":\"name\"}}, " +

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add Note: When creating a target without a specific target type, set \"targetType\": null. to set target type as null if not specified explicitly.

log.debug("Managing rollout: operation={}, rolloutId={}", request.operation(), request.rolloutId());
"Use 'type' field to select operation. " +
"Types: Create, Update, Delete, Start, Pause, Stop, Resume, Approve, Deny, Retry, TriggerNextGroup. " +
"Examples: {\"type\":\"Create\",\"body\":{...}}, " +

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is a good idea to add the knowledge that

  • for the rollout type, enum names ("soft", "forced", "timeforced", "downloadonly") should be used, not constants ("SOFT", "FORCED", etc.).
  • if groups property is specified, the amountGroups should be skipped

*
* @param actionIds list containing the single action ID to delete (use single-element list)
*/
record Delete(List<Long> actionIds) implements ActionRequest {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Long actionId for this request

Comment on lines 45 to 57
public HawkbitClient hawkbitClient(final HawkbitServer server,
final Encoder encoder,
final Decoder decoder,
final Contract contract) {
log.info("Configuring hawkBit client for HTTP mode (per-request authentication)");
return HawkbitClient.builder()
.hawkBitServer(server)
.encoder(encoder)
.decoder(decoder)
.contract(contract)
.requestInterceptorFn(httpRequestInterceptor())
.build();
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider moving this method to the HawkbitClientConfiguration, providing only the requestInterceptorFn in the dedicated config.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tenant\\username is not supported in hawkbit

Comment on lines 38 to 39

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it is better to annotate the respective properties in HawkbitMcpProperties with

  • @Value("${HAWKBIT_USERNAME:#{null}}")
  • @Value("${HAWKBIT_PASSWORD:#{null}}")

and have it null when not set?
This will allow setting an empty string as a valid value?

log.info("Configured tenant with static credentials for STDIO mode");
} else {
tenant.setUsername(null);
tenant.setPassword(null);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider this comment and if the suggested approach is used, there will be no need to check if credentials are set.

@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 4, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants