This is an automated email from the ASF dual-hosted git repository.
gongchao pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hertzbeat.git
The following commit(s) were added to refs/heads/master by this push:
new edfd857030 [GSOC] MCP server setup, authorization, and basic tool
support (#3610)
edfd857030 is described below
commit edfd857030610ac4eeddeca89e4ca61edc20633d
Author: Sarthak Arora <[email protected]>
AuthorDate: Sat Aug 16 16:38:13 2025 +0530
[GSOC] MCP server setup, authorization, and basic tool support (#3610)
Signed-off-by: Sarthak Arora <[email protected]>
Co-authored-by: Calvin <[email protected]>
Co-authored-by: Jast <[email protected]>
Co-authored-by: tomsun28 <[email protected]>
---
hertzbeat-ai-agent/pom.xml | 85 +++++++
.../ai/agent/adapters/MonitorServiceAdapter.java | 41 ++++
.../adapters/impl/MonitorServiceAdapterImpl.java | 100 +++++++++
.../ai/agent/config/CustomSseServerTransport.java | 246 +++++++++++++++++++++
.../hertzbeat/ai/agent/config/LlmConfig.java | 37 ++++
.../ai/agent/config/McpContextHolder.java | 53 +++++
.../hertzbeat/ai/agent/config/PromptProvider.java | 53 +++++
.../ai/agent/controller/ChatController.java | 70 ++++++
.../agent/controller/ConversationController.java | 26 +++
.../hertzbeat/ai/agent/dao/ConversationDao.java | 25 +++
.../apache/hertzbeat/ai/agent/dao/MessageDao.java | 25 +++
.../hertzbeat/ai/agent/dao/UserPreferenceDao.java | 25 +++
.../ai/agent/pojo/dto/ChatRequestContext.java | 40 ++++
.../hertzbeat/ai/agent/service/AgentService.java | 26 +++
.../agent/service/ChatClientProviderService.java | 31 +++
.../ai/agent/service/ConversationService.java | 71 ++++++
.../ai/agent/service/McpServerService.java | 28 +++
.../ai/agent/service/impl/AgentServiceImpl.java | 30 +++
.../impl/ChatClientProviderServiceImpl.java | 70 ++++++
.../service/impl/ConversationServiceImpl.java | 29 +++
.../agent/service/impl/McpServerServiceImpl.java | 82 +++++++
.../hertzbeat/ai/agent/tools/AlertTools.java | 25 +++
.../hertzbeat/ai/agent/tools/MetricsTools.java | 25 +++
.../hertzbeat/ai/agent/tools/MonitorTools.java | 50 +++++
.../ai/agent/tools/impl/AlertToolsImpl.java | 25 +++
.../ai/agent/tools/impl/MetricsToolsImpl.java | 25 +++
.../ai/agent/tools/impl/MonitorToolsImpl.java | 87 ++++++++
hertzbeat-manager/pom.xml | 5 +
.../java/org/apache/hertzbeat/manager/Manager.java | 2 +-
.../src/main/resources/application.yml | 28 +++
hertzbeat-manager/src/main/resources/sureness.yml | 3 +-
home/docs/help/mcp_sse_server.md | 71 ++++++
home/sidebars.json | 1 +
pom.xml | 2 +
34 files changed, 1540 insertions(+), 2 deletions(-)
diff --git a/hertzbeat-ai-agent/pom.xml b/hertzbeat-ai-agent/pom.xml
new file mode 100644
index 0000000000..6e637b943b
--- /dev/null
+++ b/hertzbeat-ai-agent/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one or more
+ ~ contributor license agreements. See the NOTICE file distributed with
+ ~ this work for additional information regarding copyright ownership.
+ ~ The ASF licenses this file to You under the Apache License, Version 2.0
+ ~ (the "License"); you may not use this file except in compliance with
+ ~ the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.hertzbeat</groupId>
+ <artifactId>hertzbeat</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>hertzbeat-ai-agent</artifactId>
+ <version>${hertzbeat.version}</version>
+ <properties>
+ <spring-ai.version>1.0.1</spring-ai.version>
+ <java.version>17</java.version>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.ai</groupId>
+
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.platform</groupId>
+ <artifactId>junit-platform-launcher</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework.ai</groupId>
+ <artifactId>spring-ai-starter-model-openai</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.hertzbeat</groupId>
+ <artifactId>hertzbeat-common</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>com.usthe.sureness</groupId>
+ <artifactId>spring-boot3-starter-sureness</artifactId>
+ </dependency>
+ </dependencies>
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.ai</groupId>
+ <artifactId>spring-ai-bom</artifactId>
+ <version>${spring-ai.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+
<artifactId>spring-boot-maven-plugin</artifactId>
+ <configuration>
+ <skip>true</skip>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/MonitorServiceAdapter.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/MonitorServiceAdapter.java
new file mode 100644
index 0000000000..05bdcc987c
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/MonitorServiceAdapter.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.adapters;
+
+import org.springframework.data.domain.Page;
+import org.apache.hertzbeat.common.entity.manager.Monitor;
+import java.util.List;
+
+/**
+ * Interface that provides access to monitor information by retrieving monitor
data
+ * through the underlying monitor service.
+ */
+public interface MonitorServiceAdapter {
+ Page<Monitor> getMonitors(
+ List<Long> ids,
+ String app,
+ String search,
+ Byte status,
+ String sort,
+ String order,
+ Integer pageIndex,
+ Integer pageSize,
+ String labels
+ );
+}
\ No newline at end of file
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/impl/MonitorServiceAdapterImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/impl/MonitorServiceAdapterImpl.java
new file mode 100644
index 0000000000..50d6eb4ced
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/adapters/impl/MonitorServiceAdapterImpl.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.adapters.impl;
+
+import com.usthe.sureness.subject.SubjectSum;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.ai.agent.adapters.MonitorServiceAdapter;
+import org.apache.hertzbeat.ai.agent.config.McpContextHolder;
+import org.springframework.data.domain.Page;
+import org.apache.hertzbeat.common.entity.manager.Monitor;
+import org.apache.hertzbeat.common.support.SpringContextHolder;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Implementation of the MonitorServiceAdapter interface that provides access
to monitor information
+ * through reflection by invoking the underlying monitor service
implementation.
+ */
+@Slf4j
+@Component
+public class MonitorServiceAdapterImpl implements MonitorServiceAdapter {
+
+ @Override
+ public Page<Monitor> getMonitors(
+ List<Long> ids,
+ String app,
+ String search,
+ Byte status,
+ String sort,
+ String order,
+ Integer pageIndex,
+ Integer pageSize,
+ String labels) {
+ try {
+ // Provide default values for all nullable parameters
+ if (sort == null || sort.trim().isEmpty()) {
+ sort = "gmtCreate";
+ }
+ if (order == null || order.trim().isEmpty()) {
+ order = "desc";
+ }
+ if (pageIndex == null) {
+ pageIndex = 0;
+ }
+ if (pageSize == null) {
+ pageSize = 8;
+ }
+
+ Object monitorService = null;
+ SubjectSum subjectSum = McpContextHolder.getSubject();
+ log.debug("Current security subject: {}", subjectSum);
+
+ try {
+ monitorService =
SpringContextHolder.getBean("monitorServiceImpl");
+ } catch (Exception e) {
+ log.debug("Could not find bean by name 'monitorServiceImpl',
trying by class name");
+ }
+
+ assert monitorService != null;
+ log.debug("MonitorService bean found: {}",
monitorService.getClass().getSimpleName());
+ Method method = monitorService.getClass().getMethod(
+ "getMonitors",
+ List.class, String.class, String.class, Byte.class,
+ String.class, String.class, int.class, int.class,
String.class);
+
+
+ @SuppressWarnings("unchecked")
+ Page<Monitor> result = (Page<Monitor>) method.invoke(
+ monitorService,
+ ids, app, search, status, sort, order, pageIndex,
pageSize, labels);
+ log.debug("MonitorServiceAdapter.getMonitors result: {}",
result.getContent());
+ return result;
+
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException("Method not found: getMonitors", e);
+ } catch (Exception e) {
+ log.debug("Failed to invoke getMonitors via adapter", e);
+ throw new RuntimeException("Failed to invoke getMonitors via
adapter", e);
+ }
+ }
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/CustomSseServerTransport.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/CustomSseServerTransport.java
new file mode 100644
index 0000000000..7eacfb90bb
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/CustomSseServerTransport.java
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hertzbeat.ai.agent.config;
+
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.usthe.sureness.mgt.SurenessSecurityManager;
+import com.usthe.sureness.subject.SubjectSum;
+import io.modelcontextprotocol.spec.McpError;
+import io.modelcontextprotocol.spec.McpSchema;
+import io.modelcontextprotocol.spec.McpServerSession;
+import io.modelcontextprotocol.spec.McpServerTransport;
+import io.modelcontextprotocol.spec.McpServerTransportProvider;
+import io.modelcontextprotocol.util.Assert;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.servlet.function.RouterFunction;
+import org.springframework.web.servlet.function.RouterFunctions;
+import org.springframework.web.servlet.function.ServerRequest;
+import org.springframework.web.servlet.function.ServerResponse;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Custom Server-Sent Events transport provider for Model Context Protocol.
+ */
+@Slf4j
+public class CustomSseServerTransport implements McpServerTransportProvider {
+ private final ObjectMapper objectMapper;
+ private final String messageEndpoint;
+ private final String sseEndpoint;
+ private final String baseUrl;
+ @Getter
+ private final RouterFunction<ServerResponse> routerFunction;
+ @Setter
+ private McpServerSession.Factory sessionFactory;
+ private final Map<String, Object> sessionRequest = new HashMap<>();
+ private final ConcurrentHashMap<String, McpServerSession> sessions;
+ private volatile boolean isClosing;
+
+ public CustomSseServerTransport(ObjectMapper objectMapper, String
messageEndpoint) {
+ this(objectMapper, messageEndpoint, "/sse");
+ }
+
+
+ public CustomSseServerTransport(ObjectMapper objectMapper, String
messageEndpoint, String sseEndpoint) {
+ this(objectMapper, "", messageEndpoint, sseEndpoint);
+ }
+
+ public CustomSseServerTransport(ObjectMapper objectMapper, String baseUrl,
String messageEndpoint, String sseEndpoint) {
+ this.sessions = new ConcurrentHashMap();
+ this.isClosing = false;
+ Assert.notNull(objectMapper, "ObjectMapper must not be null");
+ Assert.notNull(baseUrl, "Message base URL must not be null");
+ Assert.notNull(messageEndpoint, "Message endpoint must not be null");
+ Assert.notNull(sseEndpoint, "SSE endpoint must not be null");
+ this.objectMapper = objectMapper;
+ this.baseUrl = baseUrl;
+ this.messageEndpoint = messageEndpoint;
+ this.sseEndpoint = sseEndpoint;
+ this.routerFunction = RouterFunctions.route().GET(this.sseEndpoint,
this::handleSseConnection).POST(this.messageEndpoint,
this::handleMessage).build();
+ }
+
+ public Mono<Void> notifyClients(String method, Object params) {
+ if (this.sessions.isEmpty()) {
+ log.debug("No active sessions to broadcast message to");
+ return Mono.empty();
+ } else {
+ log.debug("Attempting to broadcast message to {} active sessions",
this.sessions.size());
+ return Flux.fromIterable(this.sessions.values())
+ .flatMap((session) -> session.sendNotification(method,
params)
+ .doOnError((e) -> log.error("Failed to send
message to session {}: {}", session.getId(), e.getMessage()))
+ .onErrorComplete())
+ .then();
+ }
+ }
+
+ public Mono<Void> closeGracefully() {
+ return Flux.fromIterable(this.sessions.values()).doFirst(() -> {
+ this.isClosing = true;
+ log.debug("Initiating graceful shutdown with {} active sessions",
this.sessions.size());
+ }).flatMap(McpServerSession::closeGracefully).then().doOnSuccess((v)
-> log.debug("Graceful shutdown completed"));
+ }
+
+ private ServerResponse handleSseConnection(ServerRequest request) {
+ log.debug("Handling SSE connection for request: {}", request);
+ HttpServletRequest servletRequest = request.servletRequest();
+
+ try {
+
+ log.debug("Processing SSE connection for servlet request: {}",
servletRequest);
+ log.debug("Authorization header: {}",
servletRequest.getHeader("Authorization"));
+
+
+ } catch (Exception e) {
+ log.error("Authentication failed for SSE connection: {}",
e.getMessage());
+ return
ServerResponse.status(HttpStatus.UNAUTHORIZED).body("Unauthorized: " +
e.getMessage());
+ }
+
+
+
+ if (this.isClosing) {
+ return
ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).body("Server is shutting
down");
+ } else {
+ String sessionId = UUID.randomUUID().toString();
+ log.debug("Generated session ID for SSE connection: {}",
sessionId);
+ log.debug("Creating new SSE connection for session: {}",
sessionId);
+
+
+ return ServerResponse.sse((sseBuilder) -> {
+ sseBuilder.onComplete(() -> {
+ log.debug("SSE connection completed for session: {}",
sessionId);
+ this.sessions.remove(sessionId);
+ });
+ sseBuilder.onTimeout(() -> {
+ log.debug("SSE connection timed out for session: {}",
sessionId);
+ this.sessions.remove(sessionId);
+ });
+ CustomSseServerTransport.WebMvcMcpSessionTransport
sessionTransport = new
CustomSseServerTransport.WebMvcMcpSessionTransport(sessionId, sseBuilder);
+ McpServerSession session =
this.sessionFactory.create(sessionTransport);
+ this.sessionRequest.put(sessionId, request.servletRequest());
+ this.sessions.put(sessionId, session);
+
+ try {
+
sseBuilder.id(sessionId).event("endpoint").data(this.baseUrl +
this.messageEndpoint + "?sessionId=" + sessionId);
+ } catch (Exception e) {
+ log.error("Failed to send initial endpoint event: {}",
e.getMessage());
+ sseBuilder.error(e);
+ }
+
+ }, Duration.ZERO);
+
+ }
+ }
+
+ private ServerResponse handleMessage(ServerRequest request) {
+ if (this.isClosing) {
+ return
ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).body("Server is shutting
down");
+ } else if (request.param("sessionId").isEmpty()) {
+ return ServerResponse.badRequest().body(new McpError("Session ID
missing in message endpoint"));
+ } else {
+ String sessionId = (String) request.param("sessionId").get();
+ McpServerSession session = (McpServerSession)
this.sessions.get(sessionId);
+ log.debug("Authorization header for message request: {}",
request.servletRequest().getHeader("Authorization"));
+ SubjectSum subject =
SurenessSecurityManager.getInstance().checkIn(sessionRequest.get(sessionId));
+ McpContextHolder.setSubject(subject);
+
+
+ if (session == null) {
+ return ServerResponse.status(HttpStatus.NOT_FOUND).body(new
McpError("Session not found: " + sessionId));
+ } else {
+ try {
+ String body = request.body(String.class);
+ McpSchema.JSONRPCMessage message =
McpSchema.deserializeJsonRpcMessage(this.objectMapper, body);
+ session.handle(message).block();
+ return ServerResponse.ok().build();
+ } catch (IOException | IllegalArgumentException e) {
+ log.error("Failed to deserialize message: {}",
((Exception) e).getMessage());
+ return ServerResponse.badRequest().body(new
McpError("Invalid message format"));
+ } catch (Exception e) {
+ log.error("Error handling message: {}", e.getMessage());
+ return
ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new
McpError(e.getMessage()));
+ }
+ }
+ }
+ }
+
+ private class WebMvcMcpSessionTransport implements McpServerTransport {
+ private final String sessionId;
+ private final ServerResponse.SseBuilder sseBuilder;
+
+ WebMvcMcpSessionTransport(String sessionId, ServerResponse.SseBuilder
sseBuilder) {
+ this.sessionId = sessionId;
+ this.sseBuilder = sseBuilder;
+ log.debug("Session transport {} initialized with SSE builder",
sessionId);
+ }
+
+ public Mono<Void> sendMessage(McpSchema.JSONRPCMessage message) {
+ return Mono.fromRunnable(() -> {
+ try {
+ String jsonText =
CustomSseServerTransport.this.objectMapper.writeValueAsString(message);
+
this.sseBuilder.id(this.sessionId).event("message").data(jsonText);
+ log.debug("Message sent to session {}", this.sessionId);
+ } catch (Exception e) {
+ log.error("Failed to send message to session {}: {}",
this.sessionId, e.getMessage());
+ this.sseBuilder.error(e);
+ }
+
+ });
+ }
+
+ public <T> T unmarshalFrom(Object data, TypeReference<T> typeRef) {
+ return (T)
CustomSseServerTransport.this.objectMapper.convertValue(data, typeRef);
+ }
+
+ public Mono<Void> closeGracefully() {
+ return Mono.fromRunnable(() -> {
+ log.debug("Closing session transport: {}", this.sessionId);
+
+ try {
+ this.sseBuilder.complete();
+ log.debug("Successfully completed SSE builder for session
{}", this.sessionId);
+ } catch (Exception e) {
+ log.warn("Failed to complete SSE builder for session {}:
{}", this.sessionId, e.getMessage());
+ }
+
+ });
+ }
+
+ public void close() {
+ try {
+ this.sseBuilder.complete();
+ log.debug("Successfully completed SSE builder for session {}",
this.sessionId);
+ } catch (Exception e) {
+ log.warn("Failed to complete SSE builder for session {}: {}",
this.sessionId, e.getMessage());
+ }
+
+ }
+ }
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
new file mode 100644
index 0000000000..eb7bd6aef4
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/LlmConfig.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.config;
+
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.openai.OpenAiChatModel;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Configuration class for Large Language Model (LLM) settings.
+ */
+
+@Configuration
+public class LlmConfig {
+ @Bean
+ public ChatClient openAiChatClient(OpenAiChatModel chatModel) {
+ return ChatClient.create(chatModel);
+ }
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/McpContextHolder.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/McpContextHolder.java
new file mode 100644
index 0000000000..2fd201c8a1
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/McpContextHolder.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hertzbeat.ai.agent.config;
+
+import com.usthe.sureness.subject.SubjectSum;
+import org.springframework.core.NamedInheritableThreadLocal;
+
+/**
+ * Context holder for AI agent security context.
+ */
+public final class McpContextHolder {
+ private static final ThreadLocal<SubjectSum> subjectHolder =
+ new NamedInheritableThreadLocal<>("MCP Security and User
Identification Context");
+
+ private McpContextHolder() {}
+
+ /**
+ * Attaches the user's context to the current thread.
+ */
+ public static void setSubject(SubjectSum subject) {
+ subjectHolder.set(subject);
+
+ }
+
+ /**
+ * Retrieves the context from the current thread.
+ */
+ public static SubjectSum getSubject() {
+ return subjectHolder.get();
+ }
+
+ /**
+ * Clears the context from the thread to prevent memory leaks.
+ */
+ public static void clear() {
+ subjectHolder.remove();
+ }
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/PromptProvider.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/PromptProvider.java
new file mode 100644
index 0000000000..fa7a685f00
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/config/PromptProvider.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.config;
+
+import org.springframework.stereotype.Component;
+
+/**
+ * Provider for system prompts used in the AI agent
+ */
+
+@Component
+public class PromptProvider {
+ /**
+ * Static version of the HertzBeat monitoring prompt
+ */
+ public static final String HERTZBEAT_MONITORING_PROMPT = """
+ You are an AI assistant specialized in monitoring infrastructure
and applications with HertzBeat.
+ Your role is to help users manage and analyze their monitoring
data using the available tools.
+ You have access to the following HertzBeat monitoring tools:
+ - list_monitors: Query monitor information with flexible filtering
and pagination
+ - add_monitor: Add a new monitor to the system
+ When users ask questions about their monitoring setup or data,
identify which tool would be most helpful
+ and use it to provide relevant information. Always provide clear
explanations of the monitoring data and
+ suggest next steps or insights based on the results.
+ For monitoring-related queries:
+ 1. If users want to see their monitors, use list_monitors with
appropriate filters
+ 2. If users want to add a new monitor, use add_monitor with the
necessary details
+ 3. If the monitoring information shows potential issues, highlight
them and suggest troubleshooting steps
+ For parameters that accept specific values:
+ - Monitor status values: 0 (no monitor), 1 (usable), 2 (disabled),
9 (all)
+ - Sort fields typically include: name, host, app, gmtCreate
+ - Sort order should be 'asc' or 'desc'
+ Keep responses focused on monitoring topics and HertzBeat
capabilities.
+ If you're unsure about specific monitoring details, ask clarifying
questions before using the tools.
+ """;
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ChatController.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ChatController.java
new file mode 100644
index 0000000000..b2d84cbe8b
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ChatController.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.controller;
+
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.http.MediaType;
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+import org.apache.hertzbeat.ai.agent.pojo.dto.ChatRequestContext;
+import org.apache.hertzbeat.ai.agent.service.ChatClientProviderService;
+
+
+/**
+ * Controller class for handling chat-related HTTP requests.
+ */
+@RestController
+@RequestMapping("/api/chat")
+public class ChatController {
+
+ private final ChatClientProviderService chatClientProviderService;
+
+ @Autowired
+ public ChatController(@Qualifier("openAiChatClient") ChatClient
openAiChatClient,
+ ChatClientProviderService chatClientProviderService) {
+ this.chatClientProviderService = chatClientProviderService;
+ }
+
+ /**
+ * Send a message and get a streaming response
+ *
+ * @param context The chat request context containing message and optional
+ * conversationId
+ * @return SSE emitter for streaming response
+ */
+ @PostMapping(value = "/stream", produces =
MediaType.TEXT_EVENT_STREAM_VALUE)
+ public SseEmitter streamChat(@RequestBody ChatRequestContext context) {
+ SseEmitter emitter = new SseEmitter();
+ new Thread(() -> {
+ try {
+ String aiResponse =
chatClientProviderService.streamChat(context);
+ emitter.send(aiResponse);
+ emitter.complete();
+ } catch (Exception e) {
+ emitter.completeWithError(e);
+ }
+ }).start();
+ return emitter;
+ }
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ConversationController.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ConversationController.java
new file mode 100644
index 0000000000..82b1114d9c
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/controller/ConversationController.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.controller;
+
+/**
+ * Controller for managing conversations.
+ */
+public class ConversationController {
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/ConversationDao.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/ConversationDao.java
new file mode 100644
index 0000000000..4fe1ffe39a
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/ConversationDao.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.dao;
+
+/**
+ * Data Access Object interface for Conversation entities.
+ */
+public interface ConversationDao {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/MessageDao.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/MessageDao.java
new file mode 100644
index 0000000000..4d66284862
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/MessageDao.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.dao;
+
+/**
+ * Data Access Object interface for Message entities.
+ */
+public interface MessageDao {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/UserPreferenceDao.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/UserPreferenceDao.java
new file mode 100644
index 0000000000..4aff3dd599
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/dao/UserPreferenceDao.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.dao;
+
+/**
+ * Data Access Object interface for UserPreference entities.
+ */
+public interface UserPreferenceDao {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ChatRequestContext.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ChatRequestContext.java
new file mode 100644
index 0000000000..043e19c57c
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/pojo/dto/ChatRequestContext.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Chat request context for AI chat endpoint.
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ChatRequestContext {
+ /**
+ * The user's message (required)
+ */
+ private String message;
+ /**
+ * Optional conversation ID for context
+ */
+ private String conversationId;
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AgentService.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AgentService.java
new file mode 100644
index 0000000000..c9c1f3b7d6
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/AgentService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service;
+
+/**
+ * Service interface for agent operations.
+ */
+public interface AgentService {
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ChatClientProviderService.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ChatClientProviderService.java
new file mode 100644
index 0000000000..b12b5537f0
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ChatClientProviderService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service;
+
+import org.apache.hertzbeat.ai.agent.pojo.dto.ChatRequestContext;
+
+/**
+ * Service for interacting with LLM providers (like OpenAI, Anthropic, etc.)
+ */
+public interface ChatClientProviderService {
+
+ String complete(String message);
+
+ String streamChat(ChatRequestContext context);
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ConversationService.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ConversationService.java
new file mode 100644
index 0000000000..724e876e5e
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/ConversationService.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service;
+
+
+import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Service for managing chat conversations and interactions with LLM providers.
+ */
+public interface ConversationService {
+
+ /**
+ * Send a message and receive a streaming response
+ *
+ * @param message The user's message
+ * @param conversationId Optional conversation ID for continuing a chat
+ * @return SseEmitter for streaming the response
+ */
+ SseEmitter streamChat(String message, String conversationId);
+
+ /**
+ * Send a message and get a complete response
+ *
+ * @param message The user's message
+ * @param conversationId Optional conversation ID for continuing a chat
+ * @return Response object containing the AI's response and conversation
metadata
+ */
+ Map<String, Object> chat(String message, String conversationId);
+
+ /**
+ * Get conversation history for a specific conversation
+ *
+ * @param conversationId Conversation ID
+ * @return Conversation data including messages
+ */
+ Map<String, Object> getConversation(String conversationId);
+
+ /**
+ * Get all conversations for the current user
+ *
+ * @return List of conversations
+ */
+ List<Map<String, Object>> getAllConversations();
+
+ /**
+ * Delete a conversation
+ *
+ * @param conversationId Conversation ID to delete
+ */
+ void deleteConversation(String conversationId);
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/McpServerService.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/McpServerService.java
new file mode 100644
index 0000000000..75b4de981d
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/McpServerService.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service;
+
+import org.springframework.ai.tool.ToolCallbackProvider;
+
+/**
+ * Service interface for MCP server operations.
+ */
+public interface McpServerService {
+ ToolCallbackProvider hertzbeatTools();
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AgentServiceImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AgentServiceImpl.java
new file mode 100644
index 0000000000..d6bf6e98a4
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/AgentServiceImpl.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service.impl;
+
+import org.apache.hertzbeat.ai.agent.service.AgentService;
+import org.springframework.stereotype.Service;
+
+/**
+ * Implementation of the AgentService interface.
+ * This service provides functionality for handling AI agent operations.
+ */
+@Service
+public class AgentServiceImpl implements AgentService {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java
new file mode 100644
index 0000000000..8d6582bae8
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ChatClientProviderServiceImpl.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service.impl;
+
+import org.apache.hertzbeat.ai.agent.config.PromptProvider;
+import org.apache.hertzbeat.ai.agent.service.ChatClientProviderService;
+import org.springframework.stereotype.Service;
+import org.apache.hertzbeat.ai.agent.pojo.dto.ChatRequestContext;
+import org.springframework.ai.chat.client.ChatClient;
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+/**
+ * Implementation of the {@link ChatClientProviderService}.
+ * Provides functionality to interact with the ChatClient for handling chat
+ * messages.
+ */
+@Service
+public class ChatClientProviderServiceImpl implements
ChatClientProviderService {
+
+ private final ChatClient chatClient;
+
+ @Qualifier("hertzbeatTools")
+ @Autowired
+ private ToolCallbackProvider toolCallbackProvider;
+
+ @Autowired
+ public ChatClientProviderServiceImpl(@Qualifier("openAiChatClient")
ChatClient openAiChatClient) {
+ this.chatClient = openAiChatClient;
+ }
+
+ @Override
+ public String complete(String message) {
+ return this.chatClient.prompt()
+ .user(message)
+ .call()
+ .content();
+ }
+
+ @Override
+ public String streamChat(ChatRequestContext context) {
+ try {
+ return
this.chatClient.prompt(PromptProvider.HERTZBEAT_MONITORING_PROMPT)
+ .user(context.getMessage())
+ .toolCallbacks(toolCallbackProvider)
+ .call()
+ .content();
+ } catch (Exception e) {
+ return "Error: " + e.getMessage();
+ }
+
+ }
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
new file mode 100644
index 0000000000..8e5a1b8eff
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/ConversationServiceImpl.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service.impl;
+
+import org.springframework.stereotype.Service;
+
+/**
+ * Implementation of the ConversationService interface for managing chat
conversations.
+ */
+@Service
+public class ConversationServiceImpl {
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/McpServerServiceImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/McpServerServiceImpl.java
new file mode 100644
index 0000000000..a22a843dc5
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/service/impl/McpServerServiceImpl.java
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.service.impl;
+
+import org.apache.hertzbeat.ai.agent.config.CustomSseServerTransport;
+import org.apache.hertzbeat.ai.agent.service.McpServerService;
+import org.springframework.ai.mcp.server.autoconfigure.McpServerProperties;
+import org.springframework.context.annotation.Primary;
+import org.springframework.stereotype.Service;
+import org.apache.hertzbeat.ai.agent.tools.impl.MonitorToolsImpl;
+import org.springframework.ai.tool.ToolCallbackProvider;
+import org.springframework.ai.tool.method.MethodToolCallbackProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.beans.factory.annotation.Autowired;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.web.servlet.function.RouterFunction;
+import org.springframework.web.servlet.function.ServerResponse;
+
+/**
+ * Implementation of the McpServerService interface.
+ * This service provides functionality for handling MCP server operations.
+ */
+@Service
+@Configuration
+public class McpServerServiceImpl implements McpServerService {
+ @Autowired
+ private MonitorToolsImpl monitorTools;
+
+ @Bean
+ public ToolCallbackProvider hertzbeatTools() {
+ return
MethodToolCallbackProvider.builder().toolObjects(monitorTools).build();
+ }
+ /**
+ * Provides a custom SSE server transport for the MCP server.
+ *
+ * @param objectMapper the ObjectMapper instance for JSON serialization
+ * @param serverProperties the properties for the MCP server configuration
+ * @return a CustomSseServerTransport instance configured with the
provided properties
+ */
+
+ @Bean
+ public CustomSseServerTransport webMvcSseServerTransportProvider(
+ ObjectMapper objectMapper,
+ McpServerProperties serverProperties
+ ) {
+ return new CustomSseServerTransport(
+ objectMapper,
+ serverProperties.getBaseUrl(),
+ serverProperties.getSseMessageEndpoint(),
+ serverProperties.getSseEndpoint()
+ );
+ }
+ /**
+ * Provides the MCP server transport bean.
+ *
+ * @param transport the custom SSE server transport
+ * @return the MCP server transport instance
+ */
+
+ @Primary
+ @Bean
+ public RouterFunction<ServerResponse>
mvcMcpRouterFunction(CustomSseServerTransport transport) {
+ return transport.getRouterFunction();
+ }
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/AlertTools.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/AlertTools.java
new file mode 100644
index 0000000000..9190539a25
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/AlertTools.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.tools;
+
+/**
+ * Tools for alert operations
+ */
+public interface AlertTools {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MetricsTools.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MetricsTools.java
new file mode 100644
index 0000000000..0c237c222a
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MetricsTools.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.tools;
+
+/**
+ * Tools for metrics operations
+ */
+public interface MetricsTools {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MonitorTools.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MonitorTools.java
new file mode 100644
index 0000000000..fc4a8cff11
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/MonitorTools.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.tools;
+
+import org.springframework.ai.chat.model.ToolContext;
+
+import java.util.List;
+
+/**
+ * Interface for Monitoring Tools
+ */
+public interface MonitorTools {
+
+ String addMonitor(String name, ToolContext context);
+
+ /**
+ * Query monitor information with flexible filtering and pagination.
+ * Supports filtering by monitor IDs, type, status, host, labels, sorting,
and
+ * pagination.
+ * Returns results as plain JSON.
+ */
+ String listMonitors(
+ List<Long> ids,
+ String app,
+ Byte status,
+ String search,
+ String labels,
+ String sort,
+ String order,
+ Integer pageIndex,
+ Integer pageSize,
+ ToolContext context);
+
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/AlertToolsImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/AlertToolsImpl.java
new file mode 100644
index 0000000000..b846d35f68
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/AlertToolsImpl.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.tools.impl;
+
+/**
+ * Implementation of Alert Tools functionality
+ */
+public class AlertToolsImpl {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MetricsToolsImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MetricsToolsImpl.java
new file mode 100644
index 0000000000..c79b1b4d83
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MetricsToolsImpl.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package org.apache.hertzbeat.ai.agent.tools.impl;
+
+/**
+ * Implementation of Metrics Tools functionality
+ */
+public class MetricsToolsImpl {
+}
diff --git
a/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MonitorToolsImpl.java
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MonitorToolsImpl.java
new file mode 100644
index 0000000000..3f07c97f35
--- /dev/null
+++
b/hertzbeat-ai-agent/src/main/java/org/apache/hertzbeat/ai/agent/tools/impl/MonitorToolsImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hertzbeat.ai.agent.tools.impl;
+
+import com.usthe.sureness.subject.SubjectSum;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.hertzbeat.ai.agent.adapters.MonitorServiceAdapter;
+import org.apache.hertzbeat.ai.agent.config.McpContextHolder;
+import org.springframework.ai.chat.model.ToolContext;
+import org.springframework.ai.tool.annotation.Tool;
+import org.springframework.data.domain.Page;
+import org.springframework.stereotype.Service;
+import org.apache.hertzbeat.ai.agent.tools.MonitorTools;
+import org.springframework.ai.tool.annotation.ToolParam;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.apache.hertzbeat.common.entity.manager.Monitor;
+
+import java.util.List;
+
+/**
+ * Implementation of Monitoring Tools functionality
+ */
+@Slf4j
+@Service
+public class MonitorToolsImpl implements MonitorTools {
+
+ @Autowired
+ private MonitorServiceAdapter monitorServiceAdapter;
+
+
+ /**
+ * Tool to query monitor information with flexible filtering and
pagination.
+ * Supports filtering by monitor IDs, type, status, host, labels, sorting,
and
+ * pagination.
+ * Returns monitor names as string.
+ */
+ @Override
+ @Tool(name = "list_monitors", returnDirect = true, description = """
+ Query monitor information with flexible filtering and pagination.
+ Supports filtering by monitor IDs, type, status, host, labels,
sorting, and pagination.
+ Returns results as String. When no parameters are available, pass
the default value as mentioned below. If the user doesn't provide any specific
parameter, the default value will be used.
+ """)
+ public String listMonitors(
+ @ToolParam(description = "List of monitor IDs to filter (default:
empty list)", required = false) List<Long> ids,
+ @ToolParam(description = "Monitor type, e.g., 'linux' (default:
null)", required = false) String app,
+ @ToolParam(description = "Monitor status (0: no monitor, 1:
usable, 2: disabled, 9: all) (default: null)", required = false) Byte status,
+ @ToolParam(description = "Fuzzy search for host or name (default:
null)", required = false) String search,
+ @ToolParam(description = "Monitor labels, e.g.,
'env:prod,instance:22' (default: null)", required = false) String labels,
+ @ToolParam(description = "Sort field, e.g., 'name' (default:
gmtCreate)", required = false) String sort,
+ @ToolParam(description = "Sort order, 'asc' or 'desc' (default:
desc)", required = false) String order,
+ @ToolParam(description = "Page index (default: 0)", required =
false) Integer pageIndex,
+ @ToolParam(description = "Page size (default: 8)", required =
false) Integer pageSize,
+ ToolContext context) {
+ try {
+ Page<Monitor> result = monitorServiceAdapter.getMonitors(ids, app,
search, status, sort, order, pageIndex, pageSize, labels);
+ log.debug("MonitorServiceAdapter.getMonitors result: {}", result);
+ return
result.getContent().stream().map(Monitor::getName).toList().toString();
+ } catch (Exception e) {
+ return "error is" + e.getMessage();
+ }
+ }
+
+ @Override
+ @Tool(name = "add_monitor", description = "Add a new monitor")
+ public String addMonitor(@ToolParam(description = "Name of the monitor")
String name, ToolContext context) {
+ log.debug("Adding monitor with name: {}", name);
+ SubjectSum subjectSum = McpContextHolder.getSubject();
+ log.debug("Current subject in tool: {}", subjectSum);
+ return "Monitor added: " + name;
+ }
+
+}
diff --git a/hertzbeat-manager/pom.xml b/hertzbeat-manager/pom.xml
index b9065fdc56..6d69f83817 100644
--- a/hertzbeat-manager/pom.xml
+++ b/hertzbeat-manager/pom.xml
@@ -210,6 +210,11 @@
<groupId>org.apache.arrow</groupId>
<artifactId>arrow-memory-netty</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.hertzbeat</groupId>
+ <artifactId>hertzbeat-ai-agent</artifactId>
+ <version>${project.version}</version>
+ </dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-registry-prometheus</artifactId>
diff --git
a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/Manager.java
b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/Manager.java
index 94584238e5..addb281ce7 100644
--- a/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/Manager.java
+++ b/hertzbeat-manager/src/main/java/org/apache/hertzbeat/manager/Manager.java
@@ -52,4 +52,4 @@ public class Manager {
public void init() {
System.setProperty("jdk.jndi.object.factoriesFilter",
"!com.zaxxer.hikari.HikariJNDIFactory");
}
-}
+}
\ No newline at end of file
diff --git a/hertzbeat-manager/src/main/resources/application.yml
b/hertzbeat-manager/src/main/resources/application.yml
index 9965183bd5..2666eec9a6 100644
--- a/hertzbeat-manager/src/main/resources/application.yml
+++ b/hertzbeat-manager/src/main/resources/application.yml
@@ -19,6 +19,33 @@ spring:
name: ${HOSTNAME:@hertzbeat@}${PID}
profiles:
active: prod
+ ai:
+ mcp:
+ server:
+ enabled: true
+ stdio: false
+ name: sse-mcp-server
+ version: 1.0.0
+ resource-change-notification: true
+ tool-change-notification: true
+ prompt-change-notification: true
+ sse-endpoint: /api/sse
+ sse-message-endpoint: /api/mcp/message
+ type: SYNC
+ capabilities:
+ tool: true
+ resource: true
+ prompt: true
+ completion: true
+ chat:
+ client:
+ enabled: false
+ openai:
+ api-key: OPENAI_API_KEY
+ chat:
+ options:
+ model: gpt-4.1-nano-2025-04-14
+
mvc:
static-path-pattern: /**
jackson:
@@ -38,6 +65,7 @@ spring:
max-file-size: 100MB
max-request-size: 100MB
+
management:
health:
mail:
diff --git a/hertzbeat-manager/src/main/resources/sureness.yml
b/hertzbeat-manager/src/main/resources/sureness.yml
index d846c6a616..39a27970a0 100644
--- a/hertzbeat-manager/src/main/resources/sureness.yml
+++ b/hertzbeat-manager/src/main/resources/sureness.yml
@@ -66,7 +66,8 @@ resourceRole:
- /api/bulletin/**===post===[admin,user]
- /api/bulletin/**===put===[admin,user]
- /api/bulletin/**===delete===[admin]
-
+ - /api/sse/**===get===[admin,user]
+ - /api/sse/**===post===[admin,user]
# config the resource restful api that need bypass auth protection
# rule: api===method
# eg: /api/v1/source3===get means /api/v1/source3===get can be access by
anyone, no need auth.
diff --git a/home/docs/help/mcp_sse_server.md b/home/docs/help/mcp_sse_server.md
new file mode 100644
index 0000000000..45cfe47272
--- /dev/null
+++ b/home/docs/help/mcp_sse_server.md
@@ -0,0 +1,71 @@
+---
+id: mcp_sse_server
+title: MCP SSE Server
+sidebar_label: MCP SSE Server
+keywords: [MCP, SSE, streaming, server]
+---
+
+This page explains how connect to the HertzBeat MCP SSE server. The MCP server
auto starts on the default port 1157 when you start the HertzBeat server.
+
+### Overview
+
+- Provides a Server‑Sent Events (SSE) stream for tool calling.
+- Intended for MCP integrations and clients that consume streaming events.
+
+### Connect to the MCP server
+
+Make sure that hertzbeat server is up and running. If you are using any other
port than 1157, replace the following accordingly
+- URL: `http://localhost:1157/api/sse`
+
+### Authentication
+
+You must authenticate each request using one of the following methods:
+
+- JWT bearer token
+
+ - Header: `Authorization: Bearer <your-jwt-token>`
+
+- Basic authentication
+ - Header: `Authorization: Basic <base64(username:password)>`
+
+### Cursor MCP configuration
+
+Create or edit `.cursor/mcp.json` in your home directory or project root.
+
+Basic auth:
+
+```json
+{
+ "Hertzbeat-MCP": {
+ "url": "http://localhost:1157/api/sse",
+ "headers": {
+ "Authorization": "Basic <base64(username:password)>"
+ }
+ }
+}
+```
+
+JWT bearer:
+
+```json
+{
+ "Hertzbeat-MCP": {
+ "url": "http://localhost:1157/api/sse",
+ "headers": {
+ "Authorization": "Bearer <your-jwt-token>"
+ }
+ }
+}
+```
+
+After saving, reload MCP in Cursor or restart the editor.
+
+### Tools available
+
+- list_monitors: Returns the list of names of all configured monitors.
+
+More tools are coming soon to expand management and query capabilities.
+
+### Notes
+
+- If the connection drops, reconnect using the same headers.
diff --git a/home/sidebars.json b/home/sidebars.json
index ebd4e7efec..c06acf8560 100755
--- a/home/sidebars.json
+++ b/home/sidebars.json
@@ -273,6 +273,7 @@
"help/plugin",
"help/time_expression",
"help/grafana_dashboard",
+ "help/mcp_sse_server",
"help/collector",
"help/ai_config",
"help/issue"
diff --git a/pom.xml b/pom.xml
index 359e290892..80d84e87cf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -92,6 +92,8 @@
<module>hertzbeat-e2e</module>
<module>hertzbeat-base</module>
<module>hertzbeat-mcp</module>
+ <module>hertzbeat-ai-agent</module>
+
</modules>
<properties>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]