mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-09-17 09:40:58 +00:00
feat: support mcp streamable http protocol and upgrade spring ai version (#3890)
Signed-off-by: tomsun28 <tomsun28@outlook.com> Co-authored-by: shown <yuluo08290126@gmail.com>
This commit is contained in:
@@ -31,7 +31,7 @@
|
||||
"MD025": true,
|
||||
"MD029": true,
|
||||
"MD033": {
|
||||
"allowed_elements": ["table", "tr", "td", "a", "img", "sub", "b", "br", "img", "tbody", "mark", "font"]
|
||||
"allowed_elements": ["table", "tr", "td", "a", "img", "sub", "b", "br", "img", "tbody", "mark", "font", "Tabs", "TabItem"]
|
||||
},
|
||||
"MD036": false,
|
||||
"MD040": true,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<artifactId>hertzbeat-ai</artifactId>
|
||||
<version>${hertzbeat.version}</version>
|
||||
<properties>
|
||||
<spring-ai.version>1.0.3</spring-ai.version>
|
||||
<spring-ai.version>1.1.1</spring-ai.version>
|
||||
<java.version>17</java.version>
|
||||
</properties>
|
||||
|
||||
|
||||
-246
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* 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.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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,7 @@
|
||||
|
||||
package org.apache.hertzbeat.ai.service;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.apache.hertzbeat.ai.config.CustomSseServerTransport;
|
||||
import org.springframework.ai.mcp.server.autoconfigure.McpServerProperties;
|
||||
import org.springframework.ai.tool.ToolCallbackProvider;
|
||||
import org.springframework.web.servlet.function.RouterFunction;
|
||||
import org.springframework.web.servlet.function.ServerResponse;
|
||||
|
||||
/**
|
||||
* Service interface for MCP server operations.
|
||||
@@ -35,22 +30,4 @@ public interface McpServerService {
|
||||
* @return ToolCallbackProvider with all HertzBeat monitoring tools
|
||||
*/
|
||||
ToolCallbackProvider hertzbeatTools();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
CustomSseServerTransport webMvcSseServerTransportProvider(
|
||||
ObjectMapper objectMapper,
|
||||
McpServerProperties serverProperties
|
||||
);
|
||||
|
||||
/**
|
||||
* Provides the MCP server router function for web MVC
|
||||
* @param transport Custom SSE server transport
|
||||
* @return RouterFunction for handling MCP server requests
|
||||
*/
|
||||
RouterFunction<ServerResponse> mvcMcpRouterFunction(CustomSseServerTransport transport);
|
||||
}
|
||||
|
||||
-2
@@ -34,7 +34,6 @@ import org.springframework.ai.chat.messages.Message;
|
||||
import org.springframework.ai.chat.messages.UserMessage;
|
||||
import org.springframework.ai.tool.ToolCallbackProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
@@ -54,7 +53,6 @@ public class ChatClientProviderServiceImpl implements ChatClientProviderService
|
||||
|
||||
private final GeneralConfigDao generalConfigDao;
|
||||
|
||||
@Qualifier("hertzbeatTools")
|
||||
@Autowired
|
||||
private ToolCallbackProvider toolCallbackProvider;
|
||||
|
||||
|
||||
-38
@@ -18,23 +18,17 @@
|
||||
|
||||
package org.apache.hertzbeat.ai.service.impl;
|
||||
|
||||
import org.apache.hertzbeat.ai.config.CustomSseServerTransport;
|
||||
import org.apache.hertzbeat.ai.service.McpServerService;
|
||||
import org.apache.hertzbeat.ai.tools.AlertDefineTools;
|
||||
import org.apache.hertzbeat.ai.tools.AlertTools;
|
||||
import org.apache.hertzbeat.ai.tools.MetricsTools;
|
||||
import org.apache.hertzbeat.ai.tools.MonitorTools;
|
||||
import org.springframework.ai.mcp.server.autoconfigure.McpServerProperties;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.stereotype.Service;
|
||||
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 com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.web.servlet.function.RouterFunction;
|
||||
import org.springframework.web.servlet.function.ServerResponse;
|
||||
|
||||
/**
|
||||
* Implementation of the McpServerService interface.
|
||||
@@ -56,36 +50,4 @@ public class McpServerServiceImpl implements McpServerService {
|
||||
public ToolCallbackProvider hertzbeatTools() {
|
||||
return MethodToolCallbackProvider.builder().toolObjects(monitorTools, alertTools, alertDefineTools, metricsTools).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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,26 +30,16 @@ public interface MonitorTools {
|
||||
*
|
||||
* @param name Monitor name
|
||||
* @param app Monitor type/application (e.g., 'linux', 'mysql', 'http')
|
||||
* @param host Target host (IP address or domain name)
|
||||
* @param port Target port (optional, depends on monitor type)
|
||||
* @param intervals Collection interval in seconds (default: 600)
|
||||
* @param username Username for authentication (optional)
|
||||
* @param password Password for authentication (optional)
|
||||
* @param database Database name (for database monitors)
|
||||
* @param additionalParams Additional app-specific parameters as JSON string (optional)
|
||||
* @param params Monitor-specific parameters as JSON string (e.g., host, port, username, password, etc.)
|
||||
* @param description Monitor description (optional)
|
||||
* @return Result message with monitor ID if successful
|
||||
*/
|
||||
String addMonitor(
|
||||
String name,
|
||||
String app,
|
||||
String host,
|
||||
Integer port,
|
||||
Integer intervals,
|
||||
String username,
|
||||
String password,
|
||||
String database,
|
||||
String additionalParams,
|
||||
String params,
|
||||
String description
|
||||
);
|
||||
|
||||
@@ -93,5 +83,5 @@ public interface MonitorTools {
|
||||
* @param app Monitor type/application name (e.g., 'linux', 'mysql', 'redis')
|
||||
* @return Formatted string with parameter definitions including field names, types, and requirements
|
||||
*/
|
||||
String getMonitorAdditionalParams(String app);
|
||||
String getMonitorParams(String app);
|
||||
}
|
||||
|
||||
+6
-6
@@ -54,7 +54,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "create_alert_rule", description = """
|
||||
ALERT RULE means when to alert a user
|
||||
HertzBeat: ALERT RULE means when to alert a user
|
||||
THESE ARE ALERT RULES WITH THRESHOLD VALUES. USERS CAN SPECIFY THE THRESHOLD VALUES FOR EXAMPLE,
|
||||
IF THE USER SAYS "ALERT ME WHEN MY COST EXCEEDS 700, THE EXPRESSION SHOULD BE 'cost > 700' NOT 'cost < 700'.
|
||||
APPLY THE SAME LOGIC FOR LESS THAN OPERATOR.
|
||||
@@ -281,7 +281,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "list_alert_rules", description = """
|
||||
List existing alert rules with filtering options.
|
||||
HertzBeat: List existing alert rules with filtering options.
|
||||
Shows configured thresholds and alert definitions.
|
||||
""")
|
||||
public String listAlertRules(
|
||||
@@ -343,7 +343,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "toggle_alert_rule", description = """
|
||||
Enable or disable an alert rule.
|
||||
HertzBeat: Enable or disable an alert rule.
|
||||
Allows activating or deactivating threshold monitoring.
|
||||
""")
|
||||
public String toggleAlertRule(
|
||||
@@ -382,7 +382,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_alert_rule_details", description = """
|
||||
Get detailed information about a specific alert rule.
|
||||
HertzBeat: Get detailed information about a specific alert rule.
|
||||
Shows complete threshold configuration and rule settings.
|
||||
""")
|
||||
public String getAlertRuleDetails(
|
||||
@@ -441,7 +441,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_apps_metrics_hierarchy", description = """
|
||||
Get the hierarchical structure of all available apps and their metrics for alert rule creation.
|
||||
HertzBeat: Get the hierarchical structure of all available apps and their metrics for alert rule creation.
|
||||
This tool provides the exact app name, metric name and corresponding param names according to each metric.
|
||||
Returns structured JSON data showing the complete hierarchy with field parameters for alert expressions.
|
||||
|
||||
@@ -494,7 +494,7 @@ public class AlertDefineToolsImpl implements AlertDefineTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "bind_monitors_to_alert_rule", description = """
|
||||
Bind monitors to an alert rule.
|
||||
HertzBeat: Bind monitors to an alert rule.
|
||||
Call this tool if users want to bind specific monitors to their alert rule.
|
||||
Get the right monitor ids for a particular app using the query_monitors tool.
|
||||
Get the alert rule ID from the create_alert_rule tool output OR use the list_alert_rules tool with app_name search filter, if the output of create_alert_rule is not applicable.
|
||||
|
||||
@@ -45,7 +45,7 @@ public class AlertToolsImpl implements AlertTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "query_alerts", description = """
|
||||
Query alerts with comprehensive filtering and pagination options.
|
||||
HertzBeat: Query alerts with comprehensive filtering and pagination options.
|
||||
|
||||
ALERT TYPES:
|
||||
- Pass alertType='single' for individual alert instances
|
||||
@@ -196,7 +196,7 @@ public class AlertToolsImpl implements AlertTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_alerts_summary", description = """
|
||||
Get alerts summary statistics including total counts, status distribution, and recent trends.
|
||||
HertzBeat: Get alerts summary statistics including total counts, status distribution, and recent trends.
|
||||
Returns comprehensive overview of the current alerting status across all monitors.
|
||||
""")
|
||||
public String getAlertsSummary() {
|
||||
|
||||
@@ -47,7 +47,7 @@ public class MetricsToolsImpl implements MetricsTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "query_realtime_metrics", description = """
|
||||
Get the supported monitor types/names from the list_monitor_types tool, make sure to use right name in the next call
|
||||
HertzBeat: Get the supported monitor types/names from the list_monitor_types tool, make sure to use right name in the next call
|
||||
Use the query_monitors tool to find monitor IDs in case the user does not tell the id explicitly. You might have to use this multiple times based on the user's query
|
||||
Get real-time metrics data for a specific monitor.
|
||||
Returns current metrics values including CPU, memory, disk usage, etc.
|
||||
@@ -144,7 +144,7 @@ public class MetricsToolsImpl implements MetricsTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_historical_metrics", description = """
|
||||
Get historical metrics data for analysis and trending.
|
||||
HertzBeat: Get historical metrics data for analysis and trending.
|
||||
Returns time-series data for specified metrics over a time range.
|
||||
Use the query_monitors tool to find the correct monitor IDs/ name or type for the monitor(s) user asked the metrics for
|
||||
Pass that name into the get_apps_metrics_hierarchy tool to get the metrics hierarchy i.e metrics and the field paramater
|
||||
@@ -226,7 +226,7 @@ public class MetricsToolsImpl implements MetricsTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_warehouse_status", description = """
|
||||
Check the status of the metrics storage warehouse system.
|
||||
HertzBeat: Check the status of the metrics storage warehouse system.
|
||||
Returns whether the metrics storage is operational and accessible.
|
||||
""")
|
||||
public String getWarehouseStatus() {
|
||||
|
||||
+113
-95
@@ -20,6 +20,7 @@ package org.apache.hertzbeat.ai.tools.impl;
|
||||
import com.usthe.sureness.subject.SubjectSum;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.ai.config.McpContextHolder;
|
||||
import org.apache.hertzbeat.manager.pojo.dto.MonitorDto;
|
||||
import org.apache.hertzbeat.manager.service.MonitorService;
|
||||
import org.apache.hertzbeat.manager.service.AppService;
|
||||
import org.apache.hertzbeat.ai.utils.UtilityClass;
|
||||
@@ -36,7 +37,6 @@ import org.apache.hertzbeat.common.entity.manager.ParamDefine;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Implementation of Monitoring Tools functionality
|
||||
@@ -58,7 +58,7 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
*/
|
||||
@Override
|
||||
@Tool(name = "query_monitors", description = """
|
||||
Query Existing/configured monitors in HertzBeat.
|
||||
HertzBeat: Query Existing/configured monitors in HertzBeat.
|
||||
This tool retrieves monitors based on various filters and parameters.
|
||||
Comprehensive monitor querying with flexible filtering, pagination, and specialized views.
|
||||
|
||||
@@ -196,7 +196,7 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
|
||||
@Override
|
||||
@Tool(name = "add_monitor", description = """
|
||||
Add a new monitoring target to HertzBeat with comprehensive configuration.
|
||||
HertzBeat: Add a new monitoring target to HertzBeat with comprehensive configuration.
|
||||
This tool dynamically handles different parameter requirements for each monitor type.
|
||||
|
||||
This tool creates monitors with proper app-specific parameters.
|
||||
@@ -215,33 +215,28 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
- "Monitor Linux server health on host server.company.com via SSH"
|
||||
- "Set up Redis monitoring on localhost port 6379 with password"
|
||||
|
||||
PARAMETER MAPPING: The tool intelligently maps common parameters:
|
||||
- host: Target server/domain
|
||||
- port: Service port (auto-detected if not specified)
|
||||
- username: Authentication username
|
||||
- password: Authentication password
|
||||
- database: Database name (for DB monitors)
|
||||
- additionalParams: JSON string for app-specific parameters (to be obtained from get_monitor_param_defines)
|
||||
PARAMETER MAPPING: Use the 'params' parameter to pass all monitor-specific configuration.
|
||||
The params should be a JSON string containing key-value pairs for the monitor type.
|
||||
Use get_monitor_additional_params tool to see what parameters are required for each monitor type.
|
||||
|
||||
ADDITIONAL PARAMETERS EXAMPLES:
|
||||
- Website: {"uri":"/api/health", "ssl":"true", "method":"POST"}
|
||||
- Linux: {"privateKey":"ssh-key-content", "script":"custom-script"}
|
||||
- Database: {"url":"jdbc:mysql://custom", "timeout":"10000"}
|
||||
PARAMS EXAMPLES:
|
||||
- Website: {"host":"example.com", "port":"443", "uri":"/api/health", "ssl":"true", "method":"GET"}
|
||||
- Linux: {"host":"192.168.1.10", "port":"22", "username":"root", "password":"xxx"}
|
||||
- MySQL: {"host":"db.server.com", "port":"3306", "username":"admin", "password":"xxx", "database":"mydb"}
|
||||
- Redis: {"host":"redis.server.com", "port":"6379", "password":"xxx"}
|
||||
""")
|
||||
public String addMonitor(
|
||||
@ToolParam(description = "Monitor name (required)", required = true) String name,
|
||||
@ToolParam(description = "Monitor type: website, mysql, postgresql, redis, linux, windows, etc.", required = true) String app,
|
||||
@ToolParam(description = "Target host: IP address or domain name", required = true) String host,
|
||||
@ToolParam(description = "Target port (optional, auto-detected if not specified)", required = false) Integer port,
|
||||
@ToolParam(description = "Collection interval in seconds (default: 600)", required = false) Integer intervals,
|
||||
@ToolParam(description = "Username for authentication (optional)", required = false) String username,
|
||||
@ToolParam(description = "Password for authentication (optional)", required = false) String password,
|
||||
@ToolParam(description = "Database name (for database monitors)", required = false) String database,
|
||||
@ToolParam(description = "Additional app-specific parameters as JSON: {\"uri\":\"/api\", \"ssl\":\"true\", \"method\":\"POST\"}", required = false) String additionalParams,
|
||||
@ToolParam(description = "Monitor-specific parameters as JSON string. "
|
||||
+ "Use get_monitor_additional_params to see required fields. "
|
||||
+ "Example: {\"host\":\"192.168.1.1\", \"port\":\"22\", \"username\":\"root\"}",
|
||||
required = true) String params,
|
||||
@ToolParam(description = "Monitor description (optional)", required = false) String description) {
|
||||
|
||||
try {
|
||||
log.info("Adding monitor: name={}, app={}, host={}", name, app, host);
|
||||
log.info("Adding monitor: name={}, app={}", name, app);
|
||||
|
||||
// Validate required parameters
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
@@ -250,8 +245,8 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
if (app == null || app.trim().isEmpty()) {
|
||||
return "Error: Monitor type/application is required";
|
||||
}
|
||||
if (host == null || host.trim().isEmpty()) {
|
||||
return "Error: Host is required";
|
||||
if (params == null || params.trim().isEmpty()) {
|
||||
return "Error: Monitor params is required. Use get_monitor_additional_params to see required fields for this monitor type.";
|
||||
}
|
||||
|
||||
// Set defaults
|
||||
@@ -259,7 +254,20 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
intervals = 600;
|
||||
}
|
||||
|
||||
String instance = Objects.nonNull(port) ? host.trim() + ":" + port : host.trim();
|
||||
// Parse params to extract host and port for instance
|
||||
List<Param> paramList = parseParams(params);
|
||||
String host = paramList.stream()
|
||||
.filter(p -> "host".equals(p.getField()))
|
||||
.map(Param::getParamValue)
|
||||
.findFirst()
|
||||
.orElse("");
|
||||
String port = paramList.stream()
|
||||
.filter(p -> "port".equals(p.getField()))
|
||||
.map(Param::getParamValue)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
String instance = (port != null && !port.isEmpty()) ? host.trim() + ":" + port : host.trim();
|
||||
|
||||
// Create Monitor entity
|
||||
Monitor monitor = Monitor.builder()
|
||||
@@ -272,47 +280,23 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
.description(description != null ? description.trim() : "")
|
||||
.build();
|
||||
|
||||
List<Param> params = createBasicParams(host, port, username, password, database, additionalParams);
|
||||
|
||||
// Validate that all required parameters for this monitor type are provided
|
||||
try {
|
||||
SubjectSum subjectSum = McpContextHolder.getSubject();
|
||||
log.debug("Current security subject for getMonitorParamDefines: {}", subjectSum);
|
||||
|
||||
List<ParamDefine> requiredParams = appService.getAppParamDefines(app.toLowerCase().trim());
|
||||
log.info("Checking required parameters for monitor type '{}': {}", app, requiredParams);
|
||||
List<String> missingParams = new ArrayList<>();
|
||||
|
||||
for (ParamDefine paramDefine : requiredParams) {
|
||||
if (paramDefine.isRequired()) {
|
||||
String fieldName = paramDefine.getField();
|
||||
boolean hasParam = params.stream()
|
||||
.anyMatch(param -> fieldName.equals(param.getField()));
|
||||
if (!hasParam) {
|
||||
missingParams.add(fieldName);
|
||||
MonitorDto monitorDto = MonitorDto.builder().monitor(monitor).params(paramList).build();
|
||||
monitorService.validate(monitorDto, false);
|
||||
} catch (IllegalArgumentException argumentException) {
|
||||
if (argumentException.getMessage().contains("required")) {
|
||||
return String.format("Error: %s. "
|
||||
+ "Or use get_monitor_additional_params tool to see all required parameters.",
|
||||
argumentException.getMessage());
|
||||
} else {
|
||||
return String.format("Error: %s. ", argumentException.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!missingParams.isEmpty()) {
|
||||
return String.format("Error: Missing required parameters for monitor type '%s': %s. "
|
||||
+ "Use get_monitor_additional_params tool to see all required parameters.",
|
||||
app, String.join(", ", missingParams));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Could not validate required parameters for monitor type '{}': {}", app, e.getMessage());
|
||||
}
|
||||
|
||||
// Call monitor service - it handles all the complexity (validation, defaults, app-specific logic)
|
||||
SubjectSum subjectSum = McpContextHolder.getSubject();
|
||||
log.debug("Current security subject for addMonitor: {}", subjectSum);
|
||||
|
||||
monitorService.addMonitor(monitor, params, null, null);
|
||||
Long monitorId = monitor.getId();
|
||||
|
||||
log.info("Successfully added monitor '{}' with ID: {}", name, monitorId);
|
||||
return String.format("Successfully added %s monitor '%s' with ID: %d (Host: %s, Interval: %d seconds)",
|
||||
app.toUpperCase(), name, monitorId, host, intervals);
|
||||
monitorService.addMonitor(monitor, paramList, null, null);
|
||||
log.info("Successfully added monitor '{}' with ID: {}", monitor.getName(), monitor.getId());
|
||||
return String.format("Successfully added %s monitor '%s' with ID: %d (Instance: %s, Interval: %d seconds)",
|
||||
app.toUpperCase(), monitor.getName(), monitor.getId(), monitor.getInstance(), monitor.getIntervals());
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to add monitor '{}': {}", name, e.getMessage(), e);
|
||||
@@ -321,53 +305,87 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create basic parameter list from user inputs
|
||||
* Parse params JSON string to list of Param objects
|
||||
*/
|
||||
private List<Param> createBasicParams(String host, Integer port, String username,
|
||||
String password, String database, String additionalParams) {
|
||||
List<Param> params = new ArrayList<>();
|
||||
private List<Param> parseParams(String params) {
|
||||
List<Param> paramList = new ArrayList<>();
|
||||
|
||||
// Add host (always required)
|
||||
params.add(Param.builder().field("host").paramValue(host.trim()).type((byte) 1).build());
|
||||
|
||||
// Add optional common parameters
|
||||
if (port != null) {
|
||||
params.add(Param.builder().field("port").paramValue(port.toString()).type((byte) 0).build());
|
||||
}
|
||||
if (username != null && !username.trim().isEmpty()) {
|
||||
params.add(Param.builder().field("username").paramValue(username.trim()).type((byte) 1).build());
|
||||
}
|
||||
if (password != null && !password.trim().isEmpty()) {
|
||||
params.add(Param.builder().field("password").paramValue(password.trim()).type((byte) 2).build());
|
||||
}
|
||||
if (database != null && !database.trim().isEmpty()) {
|
||||
params.add(Param.builder().field("database").paramValue(database.trim()).type((byte) 1).build());
|
||||
if (params == null || params.trim().isEmpty()) {
|
||||
return paramList;
|
||||
}
|
||||
|
||||
// Parse additional parameters if provided
|
||||
if (additionalParams != null && !additionalParams.trim().isEmpty()) {
|
||||
try {
|
||||
String cleaned = additionalParams.trim().replaceAll("[{}]", "");
|
||||
String[] pairs = cleaned.split(",");
|
||||
String cleaned = params.trim();
|
||||
// Remove outer braces if present
|
||||
if (cleaned.startsWith("{") && cleaned.endsWith("}")) {
|
||||
cleaned = cleaned.substring(1, cleaned.length() - 1);
|
||||
}
|
||||
|
||||
// Split by comma, but handle values that might contain commas within quotes
|
||||
List<String> pairs = splitJsonPairs(cleaned);
|
||||
|
||||
for (String pair : pairs) {
|
||||
String[] keyValue = pair.split(":");
|
||||
if (keyValue.length == 2) {
|
||||
String key = keyValue[0].trim().replaceAll("\"", "");
|
||||
String value = keyValue[1].trim().replaceAll("\"", "");
|
||||
params.add(Param.builder().field(key).paramValue(value).type((byte) 1).build());
|
||||
int colonIndex = pair.indexOf(':');
|
||||
if (colonIndex > 0) {
|
||||
String key = pair.substring(0, colonIndex).trim().replaceAll("\"", "");
|
||||
String value = pair.substring(colonIndex + 1).trim().replaceAll("\"", "");
|
||||
|
||||
// Determine param type based on field name
|
||||
byte paramType = determineParamType(key);
|
||||
paramList.add(Param.builder().field(key).paramValue(value).type(paramType).build());
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to parse additionalParams: {}", e.getMessage());
|
||||
log.warn("Failed to parse params: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return paramList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split JSON key-value pairs, handling quoted values that may contain commas
|
||||
*/
|
||||
private List<String> splitJsonPairs(String json) {
|
||||
List<String> pairs = new ArrayList<>();
|
||||
StringBuilder current = new StringBuilder();
|
||||
boolean inQuotes = false;
|
||||
|
||||
for (char c : json.toCharArray()) {
|
||||
if (c == '"') {
|
||||
inQuotes = !inQuotes;
|
||||
current.append(c);
|
||||
} else if (c == ',' && !inQuotes) {
|
||||
if (current.length() > 0) {
|
||||
pairs.add(current.toString().trim());
|
||||
current = new StringBuilder();
|
||||
}
|
||||
} else {
|
||||
current.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
if (current.length() > 0) {
|
||||
pairs.add(current.toString().trim());
|
||||
}
|
||||
|
||||
return pairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine param type based on field name
|
||||
*/
|
||||
private byte determineParamType(String fieldName) {
|
||||
if ("password".equalsIgnoreCase(fieldName) || "privateKey".equalsIgnoreCase(fieldName)) {
|
||||
return (byte) 2; // Password type
|
||||
} else if ("port".equalsIgnoreCase(fieldName) || "timeout".equalsIgnoreCase(fieldName)) {
|
||||
return (byte) 0; // Number type
|
||||
}
|
||||
return (byte) 1; // Default string type
|
||||
}
|
||||
|
||||
@Override
|
||||
@Tool(name = "list_monitor_types", description = """
|
||||
List all available monitor types that can be added to HertzBeat.
|
||||
HertzBeat: List all available monitor types that can be added to HertzBeat.
|
||||
This tool shows all supported monitor types with their display names.
|
||||
Use this to see what types of monitors you can create with the add_monitor tool.
|
||||
""")
|
||||
@@ -420,13 +438,13 @@ public class MonitorToolsImpl implements MonitorTools {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Tool(name = "get_monitor_additional_params", description = """
|
||||
Get the parameter definitions required for a specific monitor type.
|
||||
@Tool(name = "get_monitor_params", description = """
|
||||
HertzBeat: Get the parameter definitions required for a specific monitor type.
|
||||
This tool shows what parameters are needed when adding a monitor of the specified type,
|
||||
ALWAYS use this before adding a monitor to understand what parameters the user needs to provide.
|
||||
Use the app parameter to specify the monitor type/application name (e.g., 'linux', 'mysql', 'redis') this can be obtained from the list_monitor_types tool.
|
||||
""")
|
||||
public String getMonitorAdditionalParams(
|
||||
public String getMonitorParams(
|
||||
@ToolParam(description = "Monitor type/application name (e.g., 'linux', 'mysql', 'redis')", required = true) String app) {
|
||||
|
||||
try {
|
||||
|
||||
@@ -25,6 +25,7 @@ import java.util.Enumeration;
|
||||
import java.util.regex.Pattern;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.hertzbeat.common.constants.NetworkConstants;
|
||||
import org.apache.hertzbeat.common.constants.SignConstants;
|
||||
import org.apache.http.conn.util.InetAddressUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -81,6 +82,23 @@ public final class IpDomainUtil {
|
||||
return DOMAIN_SCHEMA.matcher(domainIp).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* if instance has the port with mark
|
||||
* @param instance instance ip:port
|
||||
* @return true if has
|
||||
*/
|
||||
public static boolean isHasPortWithMark(String instance) {
|
||||
if (instance == null || !StringUtils.hasText(instance)) {
|
||||
return false;
|
||||
}
|
||||
String[] parts = instance.split(SignConstants.DOUBLE_MARK);
|
||||
if (parts.length >= 2) {
|
||||
String port = parts[parts.length - 1];
|
||||
return CommonUtil.isNumeric(port);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* get localhost IP.
|
||||
* @return ip
|
||||
|
||||
@@ -24,7 +24,10 @@ import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.hertzbeat.common.entity.grafana.GrafanaDashboard;
|
||||
import org.apache.hertzbeat.common.entity.manager.Monitor;
|
||||
import org.apache.hertzbeat.common.entity.manager.Param;
|
||||
@@ -34,6 +37,9 @@ import org.apache.hertzbeat.common.entity.manager.Param;
|
||||
*/
|
||||
@Data
|
||||
@Schema(description = "Monitoring information entities")
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MonitorDto {
|
||||
|
||||
@Schema(description = "monitor content", accessMode = READ_WRITE)
|
||||
|
||||
+2
-1
@@ -43,6 +43,7 @@ import org.apache.hertzbeat.common.entity.manager.ParamDefine;
|
||||
import org.apache.hertzbeat.common.entity.message.CollectRep;
|
||||
import org.apache.hertzbeat.common.support.event.MonitorDeletedEvent;
|
||||
|
||||
import org.apache.hertzbeat.common.util.IpDomainUtil;
|
||||
import org.apache.hertzbeat.common.util.JexlCheckerUtil;
|
||||
import org.apache.hertzbeat.common.util.SnowFlakeIdGenerator;
|
||||
import org.apache.hertzbeat.grafana.service.DashboardService;
|
||||
@@ -188,7 +189,7 @@ public class MonitorServiceImpl implements MonitorService {
|
||||
String portWithMark = (Objects.isNull(portParam) || !StringUtils.hasText(portParam.getParamValue()))
|
||||
? ""
|
||||
: SignConstants.DOUBLE_MARK + portParam.getParamValue();
|
||||
if (Objects.nonNull(instance)) {
|
||||
if (!IpDomainUtil.isHasPortWithMark(instance)) {
|
||||
instance = instance + portWithMark;
|
||||
}
|
||||
monitor.setInstance(instance);
|
||||
|
||||
@@ -24,19 +24,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
@@ -46,7 +46,7 @@ contributing to our community's success.
|
||||
|
||||
## Committer requirements
|
||||
|
||||
There are no strict rules for becoming a committer or PPMC member.
|
||||
There are no strict rules for becoming a committer or new PMC member.
|
||||
Candidates for new committers are typically people that are active
|
||||
contributors and community members. Anyway, if the rules can be
|
||||
clarified a little bit, it can somehow clear the doubts in the minds
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: 'become_pmc_member'
|
||||
title: 'Become A PPMC member'
|
||||
title: 'Become A new PMC member'
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
@@ -21,10 +21,10 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
## Become A PPMC member of Apache HertzBeat
|
||||
## Become A new PMC member of Apache HertzBeat
|
||||
|
||||
Anyone being supportive of the community and working in any of the
|
||||
CoPDoC areas can become an Apache HertzBeat™ PPMC member. The CoPDoC is an
|
||||
CoPDoC areas can become an Apache HertzBeat™ new PMC member. The CoPDoC is an
|
||||
acronym from ASF to describe how we recognize your contributions not
|
||||
only by code.
|
||||
|
||||
@@ -38,16 +38,16 @@ only by code.
|
||||
|
||||
Apache HertzBeat™ community strives to be meritocratic. Thus, once someone
|
||||
has contributed sufficiently to any area of CoPDoC they can be a
|
||||
candidate for PPMC membership and at last voted in as a HertzBeat
|
||||
PMC member. Being an Apache HertzBeat™ PPMC member does not necessarily mean
|
||||
candidate for new PMC membership and at last voted in as a HertzBeat
|
||||
PMC member. Being an Apache HertzBeat™ new PMC member does not necessarily mean
|
||||
you must commit code with your commit privilege to the codebase; it
|
||||
means you are committed to the HertzBeat project and are productively
|
||||
contributing to our community's success.
|
||||
|
||||
## PPMC member requirements
|
||||
## new PMC member requirements
|
||||
|
||||
There are no strict rules for becoming a committer or PPMC member.
|
||||
Candidates for new PPMC member are typically people that are active
|
||||
There are no strict rules for becoming a committer or new PMC member.
|
||||
Candidates for new PMC member are typically people that are active
|
||||
contributors and community members. Anyway, if the rules can be
|
||||
clarified a little bit, it can somehow clear the doubts in the minds
|
||||
of contributors and make the community more transparent, reasonable,
|
||||
|
||||
@@ -149,26 +149,14 @@ You can refer to this article: [ASF Third Party License Policy](https://apache.o
|
||||
### 3. Email reply
|
||||
|
||||
If you initiate a posting vote, you can refer to this response example to reply to the email after verification
|
||||
<font color="red">
|
||||
|
||||
:::caution Attention
|
||||
When replying to the email, you must bring the information that you have checked by yourself. Simply replying to `+1 approve` is invalid.
|
||||
|
||||
When PPMC votes in the <dev@hertzbeat.apache.org> hertzbeat community, Please bring the binding suffix to indicate that it has a binding vote for the vote in the hertzbeat community, and it is convenient to count the voting results.
|
||||
|
||||
When IPMC votes in the <general@incubator.apache.org> incubator community. Please bring the binding suffix to indicate that the voting in the incubator community has a binding vote, which is convenient for counting the voting results.
|
||||
</font>
|
||||
|
||||
:::caution
|
||||
If you have already voted on <dev@hertzbeat.apache.org>, you can take it directly to the incubator community when you reply to the vote, such as:
|
||||
|
||||
```html
|
||||
//Incubator community voting, only IPMC members have binding binding,PPMC needs to be aware of binding changes
|
||||
Forward my +1 from dev@listhertzbeatnkis (non-binding)
|
||||
Copy my +1 from hertzbeat DEV ML (non-binding)
|
||||
```
|
||||
|
||||
When new PMC votes in the <dev@hertzbeat.apache.org> hertzbeat community, Please bring the binding suffix to indicate that it has a binding vote for the vote in the hertzbeat community, and it is convenient to count the voting results.
|
||||
:::
|
||||
|
||||
Non-PPMC/Non-IPMC member:
|
||||
Non-PMC member:
|
||||
|
||||
```text
|
||||
+1 (non-binding)
|
||||
@@ -180,10 +168,9 @@ I checked:
|
||||
5.
|
||||
```
|
||||
|
||||
PPMC/IPMC member:
|
||||
PMC member:
|
||||
|
||||
```text
|
||||
//Incubator community voting, only IPMC members have binding binding
|
||||
+1 (binding)
|
||||
I checked:
|
||||
1. All download links are valid
|
||||
|
||||
@@ -69,7 +69,7 @@ community members are welcome to comment and modify it.
|
||||
| **CO10** | The project has a well-known homepage that points to all the information required to operate according to this maturity model. | **YES** The [official website](https://hertzbeat.apache.org/) includes all information user need to run Apache HertzBeat. |
|
||||
| **CO20** | The community welcomes contributions from anyone who acts in good faith and in a respectful manner, and who adds value to the project. | **Yes** We provide contributing guides for every component. And we also have a [general contributing guide](https://hertzbeat.apache.org/docs/community/contribution) |
|
||||
| **CO30** | Contributions include source code, documentation, constructive bug reports, constructive discussions, marketing and generally anything that adds value to the project. | **YES** All good contributions including code and non-code are welcomed. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 3 new PPMC members and 13 new committers so far. |
|
||||
| **CO40** | The community strives to be meritocratic and gives more rights and responsibilities to contributors who, over time, add value to the project. | **YES** The community has elected 3 new PMC members and 13 new committers so far. |
|
||||
| **CO50** | The project documents how contributors can earn more rights such as commit access or decision power, and applies these principles consistently. | **YES** The community has clear docs on nominating committers and PPMC members |
|
||||
| **CO60** | The community operates based on consensus of its members (see CS10) who have decision power. Dictators, benevolent or not, are not welcome in Apache projects. | **YES** All decisions are made after vote by community members. |
|
||||
| **CO70** | The project strives to answer user questions in a timely manner. | **YES** We use <dev@hertzbeat.apache.org>, [GitHub issue](https://github.com/apache/hertzbeat/issues) and [GitHub discussion](https://github.com/apache/hertzbeat/discussions) to do this in a timely manner. |
|
||||
|
||||
@@ -73,7 +73,7 @@ Subject: [VOTE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_COMMITTER_NAME} as our community new committer.
|
||||
|
||||
@@ -121,7 +121,7 @@ Subject: [RESULT] [VOTE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
The vote has now closed. The results are:
|
||||
|
||||
@@ -260,7 +260,7 @@ requires adherence to the ASF Code of Conduct:
|
||||
https://www.apache.org/foundation/policies/conduct.html
|
||||
|
||||
Yours,
|
||||
The Apache HertzBeat PPMC
|
||||
The Apache HertzBeat new PMC
|
||||
```
|
||||
|
||||
### Announce New Committer Template
|
||||
@@ -273,7 +273,7 @@ Subject: [ANNOUNCE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```text
|
||||
Hello Community,
|
||||
|
||||
The Podling Project Management Committee (PPMC) for Apache HertzBeat
|
||||
The Podling Project Management Committee (new PMC) for Apache HertzBeat
|
||||
has invited ${NEW_COMMITTER_NAME} to become a committer and we are pleased to
|
||||
announce that he has accepted.
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
id: 'new_pmc_ember_process'
|
||||
title: 'New PPMC Member Process'
|
||||
title: 'new PMC Member Process'
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
@@ -23,7 +23,7 @@ limitations under the License.
|
||||
|
||||
[Apache New Committer Guideline](https://community.apache.org/newcommitter.html#new-committer-process)
|
||||
|
||||
## The process of new PPMC member
|
||||
## The process of new PMC member
|
||||
|
||||
- Call a vote in mailing `private@hertzbeat.apache.org`
|
||||
|
||||
@@ -33,23 +33,23 @@ limitations under the License.
|
||||
|
||||
see **Close Vote Template**
|
||||
|
||||
- Board Approval of new PPMC member
|
||||
- Board Approval of new PMC member
|
||||
|
||||
see **Board Approval of new PPMC member**
|
||||
see **Board Approval of new PMC member**
|
||||
|
||||
- If the result is positive, invite the new PPMC member
|
||||
- If the result is positive, invite the new PMC member
|
||||
|
||||
see **PMC member Invite Template**
|
||||
|
||||
- If accept, then: Accept the PPMC member
|
||||
- If accept, then: Accept the PMC member
|
||||
|
||||
see **PMC Member Accept Template**
|
||||
|
||||
- Notify the PPMC member of completion
|
||||
- Notify the PMC member of completion
|
||||
|
||||
see **PMC Member Done Template**
|
||||
|
||||
- Announce the new PPMC member
|
||||
- Announce the new PMC member
|
||||
|
||||
see **PMC Member Announce Template**
|
||||
|
||||
@@ -61,17 +61,17 @@ Note that, there are three placeholder in template should be replaced before usi
|
||||
- NEW_PMC_EMAIL
|
||||
- NEW_PMC_APACHE_NAME
|
||||
|
||||
### PPMC Member Vote Template
|
||||
### PMC member Vote Template
|
||||
|
||||
```text
|
||||
To: private@hertzbeat.apache.org
|
||||
Subject: [VOTE] New PPMC member candidate: ${NEW_PMC_NAME}
|
||||
Subject: [VOTE] new PMC member candidate: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_PMC_NAME} as our new PPMC member.
|
||||
This is a formal vote about inviting ${NEW_PMC_NAME} as our new PMC member.
|
||||
|
||||
${Work list}[1]
|
||||
|
||||
@@ -85,11 +85,11 @@ Note that, Voting ends one week from today, i.e. [midnight UTC on YYYY-MM-DD](ht
|
||||
|
||||
```text
|
||||
To: private@hertzbeat.apache.org
|
||||
Subject: [RESULT] [VOTE] New PPMC member: ${NEW_PMC_NAME}
|
||||
Subject: [RESULT] [VOTE] new PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
The vote has now closed. The results are:
|
||||
|
||||
@@ -102,12 +102,12 @@ Binding Votes:
|
||||
The vote is ***successful/not successful***
|
||||
```
|
||||
|
||||
### Board Approval of new PPMC member Template
|
||||
### Board Approval of new PMC member Template
|
||||
|
||||
```text
|
||||
To: board@apache.org
|
||||
Cc: private@<project>.apache.org
|
||||
Subject: [NOTICE] ${NEW_PMC_NAME} for HertzBeat PPMC member
|
||||
Subject: [NOTICE] ${NEW_PMC_NAME} for HertzBeat PMC member
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -118,12 +118,12 @@ The vote result is available here: https://lists.apache.org/...
|
||||
|
||||
[Apache New Pmc Guide](https://www.apache.org/dev/pmc.html#newpmc)
|
||||
|
||||
### PPMC Member Invite Template
|
||||
### PMC member Invite Template
|
||||
|
||||
```text
|
||||
To: ${NEW_PMC_EMAIL}
|
||||
Cc: private@hertzbeat.apache.org
|
||||
Subject: Invitation to become HertzBeat PPMC member: ${NEW_PMC_NAME}
|
||||
Subject: Invitation to become HertzBeat PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -136,9 +136,9 @@ These privileges are offered on the understanding that
|
||||
you'll use them reasonably and with common sense.
|
||||
We like to work on trust rather than unnecessary constraints.
|
||||
|
||||
Being a PPMC member enables you to guide the direction of the project.
|
||||
Being a PMC member enables you to guide the direction of the project.
|
||||
|
||||
Being a PPMC member does not require you to
|
||||
Being a PMC member does not require you to
|
||||
participate any more than you already do. It does
|
||||
tend to make one even more committed. You will
|
||||
probably find that you spend more time here.
|
||||
@@ -164,20 +164,20 @@ B. If you accept, the next step is to register an iCLA:
|
||||
unique Apache ID. Look to see if your preferred
|
||||
ID is already taken at
|
||||
https://people.apache.org/committer-index.html
|
||||
This will allow the Secretary to notify the PPMC
|
||||
This will allow the Secretary to notify the PMC
|
||||
when your iCLA has been recorded.
|
||||
|
||||
When recording of your iCLA is noted, you will
|
||||
receive a follow-up message with the next steps for
|
||||
establishing you as a PPMC member.
|
||||
establishing you as a PMC member.
|
||||
```
|
||||
|
||||
### PPMC Member Accept Template
|
||||
### PMC member Accept Template
|
||||
|
||||
```text
|
||||
To: ${NEW_PMC_EMAIL}
|
||||
Cc: private@hertzbeat.apache.org
|
||||
Subject: Re: invitation to become HertzBeat PPMC member
|
||||
Subject: Re: invitation to become HertzBeat PMC member
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -214,15 +214,15 @@ in incubating projects:
|
||||
https://incubator.apache.org/guides/committer.html
|
||||
https://incubator.apache.org/guides/ppmc.html
|
||||
|
||||
Just as before you became a PPMC member, participation in any ASF community
|
||||
Just as before you became a PMC member, participation in any ASF community
|
||||
requires adherence to the ASF Code of Conduct:
|
||||
https://www.apache.org/foundation/policies/conduct.html
|
||||
|
||||
Yours,
|
||||
The Apache HertzBeat PPMC
|
||||
The Apache HertzBeat PMC
|
||||
```
|
||||
|
||||
### PPMC Member Done Template
|
||||
### PMC member Done Template
|
||||
|
||||
```text
|
||||
To: private@hertzbeat.apache.org, ${NEW_PMC_EMAIL}
|
||||
@@ -253,21 +253,21 @@ Naturally, if you don't understand anything be sure to ask us on the dev@hertzbe
|
||||
Documentation is maintained by volunteers and hence can be out-of-date and incomplete - of course
|
||||
you can now help fix that.
|
||||
|
||||
A PPMC member will announce your election to the dev list soon.
|
||||
A PMC member will announce your election to the dev list soon.
|
||||
```
|
||||
|
||||
### PPMC Member Announce Template
|
||||
### PMC member Announce Template
|
||||
|
||||
```text
|
||||
To: dev@hertzbeat.apache.org
|
||||
[ANNONCE] New PPMC member: ${NEW_PMC_NAME}
|
||||
[ANNONCE] new PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat Community,
|
||||
|
||||
The Podling Project Management Committee (PPMC) for Apache HertzBeat
|
||||
has invited ${NEW_PMC_NAME} to become our PPMC member and
|
||||
The Podling Project Management Committee (PMC) for Apache HertzBeat
|
||||
has invited ${NEW_PMC_NAME} to become our PMC member and
|
||||
we are pleased to announce that he has accepted.
|
||||
|
||||
### add specific details here ###
|
||||
@@ -277,8 +277,8 @@ Please join me in congratulating ${NEW_PMC_NAME}!
|
||||
Being a committer enables easier contribution to the
|
||||
project since there is no need to go via the patch
|
||||
submission process. This should enable better productivity.
|
||||
A PPMC member helps manage and guide the direction of the project.
|
||||
A PMC member helps manage and guide the direction of the project.
|
||||
|
||||
Thanks,
|
||||
On behalf of the Apache HertzBeat PPMC
|
||||
On behalf of the Apache HertzBeat PMC
|
||||
```
|
||||
|
||||
@@ -2,21 +2,24 @@
|
||||
id: mcp_server
|
||||
title: MCP Server
|
||||
sidebar_label: MCP Server
|
||||
keywords: [MCP, SSE, streaming, server]
|
||||
keywords: [MCP, StreamableHttp, 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.
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
This page explains how connect to the HertzBeat MCP 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.
|
||||
- Provides Streamable-Http protocol MCP server.
|
||||
- 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`
|
||||
- URL: `http://your-hertzbeat-server-host:1157/api/mcp`
|
||||
|
||||
### Authentication
|
||||
|
||||
@@ -31,7 +34,57 @@ Note: You can generate a JWT token from the HertzBeat web UI under the Log Integ
|
||||
- Basic authentication
|
||||
- Header: `Authorization: Basic <base64(username:password)>`
|
||||
|
||||
### Cursor MCP configuration
|
||||
### Editor MCP configuration
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="claude-code" label="Claude Code MCP">
|
||||
|
||||
Claude Code use a global config file `~/.claude.json` to config mcp server. You can add HertzBeat MCP by CLI or edit this file directly.
|
||||
|
||||
Method A: Use the CLI.
|
||||
|
||||
```bash
|
||||
claude mcp add -s user -t http hertzbeat-mcp http://your-hertzbeat-server-host:1157/api/mcp --header "Authorization: Bearer your_jwt_key"
|
||||
```
|
||||
|
||||
Method B: Edit the file directly.
|
||||
|
||||
Basic auth:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcpServers": {
|
||||
"hertzbeat-mcp": {
|
||||
"type": "sse",
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Basic <base64(username:password)>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
JWT bearer:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcpServers": {
|
||||
"hertzbeat-mcp": {
|
||||
"type": "sse",
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer <your-jwt-token>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After saving `~/.claude.json`, restart or reload Claude Code to make the new MCP configuration take effect.
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cursor" label="Cursor MCP" default>
|
||||
|
||||
Create or edit `.cursor/mcp.json` in your home directory or project root.
|
||||
|
||||
@@ -39,8 +92,8 @@ Basic auth:
|
||||
|
||||
```json
|
||||
{
|
||||
"Hertzbeat-MCP": {
|
||||
"url": "http://localhost:1157/api/sse",
|
||||
"hertzbeat-mcp": {
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Basic <base64(username:password)>"
|
||||
}
|
||||
@@ -52,8 +105,8 @@ JWT bearer:
|
||||
|
||||
```json
|
||||
{
|
||||
"Hertzbeat-MCP": {
|
||||
"url": "http://localhost:1157/api/sse",
|
||||
"hertzbeat-mcp": {
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer <your-jwt-token>"
|
||||
}
|
||||
@@ -63,6 +116,9 @@ JWT bearer:
|
||||
|
||||
After saving, reload MCP in Cursor or restart the editor.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### Tools available
|
||||
|
||||
#### Monitor Management Tools
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ Apache HertzBeat™ 社区努力追求基于功绩的原则。因此,一旦有
|
||||
|
||||
## Committer 的要求
|
||||
|
||||
没有成为 Committer 或 PPMC 成员的严格规则。新的 Committer 的候选人通常是积极的贡献者和社区成员。但是,如果能稍微明确一些规则,就可以在一定程度上消除贡献者的疑虑,使社区更加透明、合理和公平。
|
||||
没有成为 Committer 或 PMC 成员的严格规则。新的 Committer 的候选人通常是积极的贡献者和社区成员。但是,如果能稍微明确一些规则,就可以在一定程度上消除贡献者的疑虑,使社区更加透明、合理和公平。
|
||||
|
||||
### 持续的贡献
|
||||
|
||||
|
||||
+4
-4
@@ -21,7 +21,7 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
## 成为 Apache HertzBeat™ 的 PPMC 成员
|
||||
## 成为 Apache HertzBeat™ 的 PMC 成员
|
||||
|
||||
任何支持社区并在 CoPDoC 领域中工作的人都可以成为 Apache HertzBeat™ 的PMC 成员。CoPDoC 是 ASF 的缩写,用来描述我们如何不仅仅通过代码来认识到您的贡献。
|
||||
|
||||
@@ -30,11 +30,11 @@ limitations under the License.
|
||||
- **Documentation** - 没有它,内容只会停留在作者的头脑中。
|
||||
- **Code** - 没有代码,讨论就毫无意义。
|
||||
|
||||
Apache HertzBeat™ 社区努力追求基于功绩的原则。因此,一旦有人在 CoPDoC 的任何领域有了足够的贡献,他们就可以成为 PPMC 成员资格的候选人,最终被投票选为 HertzBeat 的 PPMC 成员。成为 Apache HertzBeat™ 的 PPMC 成员并不一定意味着您必须使用您的提交权限向代码库提交代码;它意味着您致力于 HertzBeat 项目并为我们社区的成功做出了积极的贡献。
|
||||
Apache HertzBeat™ 社区努力追求基于功绩的原则。因此,一旦有人在 CoPDoC 的任何领域有了足够的贡献,他们就可以成为 PMC 成员资格的候选人,最终被投票选为 HertzBeat 的 PMC 成员。成为 Apache HertzBeat™ 的 PMC 成员并不一定意味着您必须使用您的提交权限向代码库提交代码;它意味着您致力于 HertzBeat 项目并为我们社区的成功做出了积极的贡献。
|
||||
|
||||
## PPMC 成员的要求
|
||||
## PMC 成员的要求
|
||||
|
||||
没有成为 Committer 或 PPMC 成员的严格规则。新的 PPMC 成员的候选人通常是积极的贡献者和社区成员。但是,如果能稍微明确一些规则,就可以在一定程度上消除贡献者的疑虑,使社区更加透明、合理和公平。
|
||||
没有成为 Committer 或 PMC 成员的严格规则。新的 PMC 成员的候选人通常是积极的贡献者和社区成员。但是,如果能稍微明确一些规则,就可以在一定程度上消除贡献者的疑虑,使社区更加透明、合理和公平。
|
||||
|
||||
### 持续的贡献
|
||||
|
||||
|
||||
@@ -150,23 +150,11 @@ cd apache-hertzbeat-${release_version}-incubating-src
|
||||
:::caution 注意
|
||||
回复的邮件一定要带上自己检查了那些项信息,仅仅回复`+1 approve`,是无效的。
|
||||
|
||||
PPMC 在 <dev@hertzbeat.apache.org> HertzBeat 的社区投票时,请带上 binding 后缀,表示对 HertzBeat 社区中的投票具有约束性投票,方便统计投票结果。
|
||||
|
||||
IPMC 在 <general@incubator.apache.org> incubator 社区投票,请带上 binding 后缀,表示对 incubator 社区中的投票具有约束性投票,方便统计投票结果。
|
||||
:::
|
||||
|
||||
:::caution 注意
|
||||
如果在<dev@hertzbeat.apache.org>已经投过票,在incubator社区进行投票回复时,可以直接带过去,<font color="red">需要注意约束性</font> 如:
|
||||
|
||||
```html
|
||||
//incubator社区 投票时,只有IPMC成员才具有约束性 binding,PPMC需要注意约束性的变化
|
||||
Forward my +1 from dev@hertzbeat (non-binding)
|
||||
Copy my +1 from hertzbeat DEV ML (non-binding)
|
||||
```
|
||||
PMC 在 <dev@hertzbeat.apache.org> HertzBeat 的社区投票时,请带上 binding 后缀,表示对 HertzBeat 社区中的投票具有约束性投票,方便统计投票结果。
|
||||
|
||||
:::
|
||||
|
||||
非PPMC/IPMC成员
|
||||
非PMC成员
|
||||
|
||||
```html
|
||||
+1 (non-binding)
|
||||
@@ -178,10 +166,9 @@ I checked:
|
||||
5. ....
|
||||
```
|
||||
|
||||
PPMC/IPMC成员
|
||||
PMC成员
|
||||
|
||||
```html
|
||||
//incubator社区 投票时,只有IPMC成员才具有约束性 binding
|
||||
+1 (binding)
|
||||
I checked:
|
||||
1. All download links are valid
|
||||
|
||||
+5
-5
@@ -73,7 +73,7 @@ Subject: [VOTE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_COMMITTER_NAME} as our community new committer.
|
||||
|
||||
@@ -118,7 +118,7 @@ Subject: [RESULT] [VOTE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
The vote has now closed. The results are:
|
||||
|
||||
@@ -257,7 +257,7 @@ requires adherence to the ASF Code of Conduct:
|
||||
https://www.apache.org/foundation/policies/conduct.html
|
||||
|
||||
Yours,
|
||||
The Apache HertzBeat PPMC
|
||||
The Apache HertzBeat PMC
|
||||
```
|
||||
|
||||
### Announce New Committer Template
|
||||
@@ -270,7 +270,7 @@ Subject: [ANNOUNCE] New committer: ${NEW_COMMITTER_NAME}
|
||||
```text
|
||||
Hello Community,
|
||||
|
||||
The Podling Project Management Committee (PPMC) for Apache HertzBeat
|
||||
The Podling Project Management Committee (PMC) for Apache HertzBeat
|
||||
has invited ${NEW_COMMITTER_NAME} to become a committer and we are pleased to
|
||||
announce that he has accepted.
|
||||
|
||||
@@ -290,7 +290,7 @@ Best Wishes!
|
||||
```text
|
||||
Hello xxxx,
|
||||
|
||||
The HertzBeat Project Management Committee (PPMC)
|
||||
The HertzBeat Project Management Committee (PMC)
|
||||
hereby offers you committer privileges to the project.
|
||||
These privileges are offered on the understanding that
|
||||
you'll use them reasonably and with common sense.
|
||||
|
||||
+21
-21
@@ -65,13 +65,13 @@ limitations under the License.
|
||||
|
||||
```text
|
||||
To: private@hertzbeat.apache.org
|
||||
Subject: [VOTE] New PPMC member candidate: ${NEW_PMC_NAME}
|
||||
Subject: [VOTE] New PMC member candidate: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
This is a formal vote about inviting ${NEW_PMC_NAME} as our new PPMC member.
|
||||
This is a formal vote about inviting ${NEW_PMC_NAME} as our new PMC member.
|
||||
|
||||
${Work list}[1]
|
||||
|
||||
@@ -86,11 +86,11 @@ ${Work list}[1]
|
||||
|
||||
```text
|
||||
To: private@hertzbeat.apache.org
|
||||
Subject: [RESULT] [VOTE] New PPMC member: ${NEW_PMC_NAME}
|
||||
Subject: [RESULT] [VOTE] New PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat PPMC,
|
||||
Hi HertzBeat PMC,
|
||||
|
||||
The vote has now closed. The results are:
|
||||
|
||||
@@ -103,12 +103,12 @@ Binding Votes:
|
||||
The vote is ***successful/not successful***
|
||||
```
|
||||
|
||||
### Board Approval of new PPMC member Template
|
||||
### Board Approval of new PMC member Template
|
||||
|
||||
```text
|
||||
To: board@apache.org
|
||||
Cc: private@<project>.apache.org
|
||||
Subject: [NOTICE] ${NEW_PMC_NAME} for HertzBeat PPMC member
|
||||
Subject: [NOTICE] ${NEW_PMC_NAME} for HertzBeat PMC member
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -124,7 +124,7 @@ The vote result is available here: https://lists.apache.org/...
|
||||
```text
|
||||
To: ${NEW_PMC_EMAIL}
|
||||
Cc: private@hertzbeat.apache.org
|
||||
Subject: Invitation to become HertzBeat PPMC member: ${NEW_PMC_NAME}
|
||||
Subject: Invitation to become HertzBeat PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -137,9 +137,9 @@ These privileges are offered on the understanding that
|
||||
you'll use them reasonably and with common sense.
|
||||
We like to work on trust rather than unnecessary constraints.
|
||||
|
||||
Being a PPMC member enables you to guide the direction of the project.
|
||||
Being a PMC member enables you to guide the direction of the project.
|
||||
|
||||
Being a PPMC member does not require you to
|
||||
Being a PMC member does not require you to
|
||||
participate any more than you already do. It does
|
||||
tend to make one even more committed. You will
|
||||
probably find that you spend more time here.
|
||||
@@ -165,12 +165,12 @@ B. If you accept, the next step is to register an iCLA:
|
||||
unique Apache ID. Look to see if your preferred
|
||||
ID is already taken at
|
||||
https://people.apache.org/committer-index.html
|
||||
This will allow the Secretary to notify the PPMC
|
||||
This will allow the Secretary to notify the PMC
|
||||
when your iCLA has been recorded.
|
||||
|
||||
When recording of your iCLA is noted, you will
|
||||
receive a follow-up message with the next steps for
|
||||
establishing you as a PPMC member.
|
||||
establishing you as a PMC member.
|
||||
```
|
||||
|
||||
### PMC成员接受模板
|
||||
@@ -178,7 +178,7 @@ establishing you as a PPMC member.
|
||||
```text
|
||||
To: ${NEW_PMC_EMAIL}
|
||||
Cc: private@hertzbeatv.apache.org
|
||||
Subject: Re: invitation to become HertzBeat PPMC member
|
||||
Subject: Re: invitation to become HertzBeat PMC member
|
||||
```
|
||||
|
||||
```text
|
||||
@@ -215,12 +215,12 @@ in incubating projects:
|
||||
https://incubator.apache.org/guides/committer.html
|
||||
https://incubator.apache.org/guides/ppmc.html
|
||||
|
||||
Just as before you became a PPMC member, participation in any ASF community
|
||||
Just as before you became a PMC member, participation in any ASF community
|
||||
requires adherence to the ASF Code of Conduct:
|
||||
https://www.apache.org/foundation/policies/conduct.html
|
||||
|
||||
Yours,
|
||||
The Apache HertzBeat PPMC
|
||||
The Apache HertzBeat PMC
|
||||
```
|
||||
|
||||
### PMC成员完成模板
|
||||
@@ -254,21 +254,21 @@ Naturally, if you don't understand anything be sure to ask us on the dev@hertzbe
|
||||
Documentation is maintained by volunteers and hence can be out-of-date and incomplete - of course
|
||||
you can now help fix that.
|
||||
|
||||
A PPMC member will announce your election to the dev list soon.
|
||||
A PMC member will announce your election to the dev list soon.
|
||||
```
|
||||
|
||||
### PMC成员通知模板
|
||||
|
||||
```text
|
||||
To: dev@hertzbeat.apache.org
|
||||
[ANNONCE] New PPMC member: ${NEW_PMC_NAME}
|
||||
[ANNONCE] New PMC member: ${NEW_PMC_NAME}
|
||||
```
|
||||
|
||||
```text
|
||||
Hi HertzBeat Community,
|
||||
|
||||
The Podling Project Management Committee (PPMC) for Apache HertzBeat
|
||||
has invited ${NEW_PMC_NAME} to become our PPMC member and
|
||||
The Podling Project Management Committee (PMC) for Apache HertzBeat
|
||||
has invited ${NEW_PMC_NAME} to become our PMC member and
|
||||
we are pleased to announce that he has accepted.
|
||||
|
||||
### add specific details here ###
|
||||
@@ -278,8 +278,8 @@ Please join me in congratulating ${NEW_PMC_NAME}!
|
||||
Being a committer enables easier contribution to the
|
||||
project since there is no need to go via the patch
|
||||
submission process. This should enable better productivity.
|
||||
A PPMC member helps manage and guide the direction of the project.
|
||||
A PMC member helps manage and guide the direction of the project.
|
||||
|
||||
Thanks,
|
||||
On behalf of the Apache HertzBeat PPMC
|
||||
On behalf of the Apache HertzBeat PMC
|
||||
```
|
||||
|
||||
@@ -2,21 +2,24 @@
|
||||
id: mcp_server
|
||||
title: MCP 服务器
|
||||
sidebar_label: MCP 服务器
|
||||
keywords: [MCP, SSE, 流式传输, 服务器]
|
||||
keywords: [MCP, StreamabelHttp, 流式传输, 服务器]
|
||||
---
|
||||
|
||||
本页面介绍如何连接到 HertzBeat MCP SSE 服务器。当您启动 HertzBeat 服务器时,MCP 服务器会自动在默认端口 1157 上启动。
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
|
||||
本页面介绍如何连接到 HertzBeat MCP 服务器。当您启动 HertzBeat 服务器时,MCP 服务器会自动在默认端口 1157 上启动。
|
||||
|
||||
### 概述
|
||||
|
||||
- 提供用于工具调用的服务器发送事件 (SSE) 流。
|
||||
- 提供 StreamabelHttp 协议的 MCP服务器。
|
||||
- 专为 MCP 集成和消费流式事件的客户端而设计。
|
||||
|
||||
### 连接到 MCP 服务器
|
||||
|
||||
确保 HertzBeat 服务器已启动并正在运行。如果您使用的端口不是 1157,请相应地替换以下内容:
|
||||
|
||||
- URL: `http://localhost:1157/api/sse`
|
||||
- URL: `http://your-hertzbeat-server-host:1157/api/mcp`
|
||||
|
||||
### 身份验证
|
||||
|
||||
@@ -31,16 +34,66 @@ keywords: [MCP, SSE, 流式传输, 服务器]
|
||||
- 基本身份验证
|
||||
- 请求头: `Authorization: Basic <base64(username:password)>`
|
||||
|
||||
### Cursor MCP 配置
|
||||
### MCP 配置
|
||||
|
||||
在您的主目录或项目根目录中创建或编辑 `.cursor/mcp.json`。
|
||||
<Tabs>
|
||||
<TabItem value="claude-code" label="Claude Code MCP">
|
||||
|
||||
基本身份验证:
|
||||
Claude Code 使用一个全局配置文件 `~/.claude.json` 来管理 MCP 服务器,你可以通过 CLI 或直接编辑这个文件来添加 HertzBeat MCP:
|
||||
|
||||
方式一: 使用 CLI 快速创建:
|
||||
|
||||
```bash
|
||||
claude mcp add -s user -t http hertzbeat-mcp http://your-hertzbeat-server-host:1157/api/mcp --header "Authorization: Bearer your_jwt_key"
|
||||
```
|
||||
|
||||
方式二:打开 `~/.claude.json`,在顶层的 `mcpServers` 下添加 HertzBeat MCP 配置。
|
||||
|
||||
Basic auth:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcpServers": {
|
||||
"hertzbeat-mcp": {
|
||||
"type": "sse",
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Basic <base64(username:password)>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
JWT bearer:
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"mcpServers": {
|
||||
"hertzbeat-mcp": {
|
||||
"type": "sse",
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer <your-jwt-token>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
保存 `~/.claude.json` 后,重启或重新加载 Claude Code,让新的 MCP 配置生效。
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="cursor" label="Cursor MCP" default>
|
||||
|
||||
Cursor 使用配置文件 `.cursor/mcp.json` 来管理 MCP 服务器,在用户目录或者项目目录下创建或者编辑这个文件:
|
||||
|
||||
Basic auth:
|
||||
|
||||
```json
|
||||
{
|
||||
"Hertzbeat-MCP": {
|
||||
"url": "http://localhost:1157/api/sse",
|
||||
"hertzbeat-mcp": {
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Basic <base64(username:password)>"
|
||||
}
|
||||
@@ -48,12 +101,12 @@ keywords: [MCP, SSE, 流式传输, 服务器]
|
||||
}
|
||||
```
|
||||
|
||||
JWT Bearer:
|
||||
JWT bearer:
|
||||
|
||||
```json
|
||||
{
|
||||
"Hertzbeat-MCP": {
|
||||
"url": "http://localhost:1157/api/sse",
|
||||
"hertzbeat-mcp": {
|
||||
"url": "http://your-hertzbeat-server-host:1157/api/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer <your-jwt-token>"
|
||||
}
|
||||
@@ -61,7 +114,10 @@ JWT Bearer:
|
||||
}
|
||||
```
|
||||
|
||||
保存后,在 Cursor 中重新加载 MCP 或重启编辑器。
|
||||
After saving, reload MCP in Cursor or restart the editor.
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### 可用工具
|
||||
|
||||
|
||||
+4
-11
@@ -24,19 +24,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
|
||||
@@ -25,19 +25,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
jackson:
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
@@ -25,19 +25,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
jackson:
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
@@ -25,19 +25,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
jackson:
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
@@ -25,19 +25,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
jackson:
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
@@ -25,19 +25,12 @@ spring:
|
||||
server:
|
||||
enabled: true
|
||||
stdio: false
|
||||
name: sse-mcp-server
|
||||
protocol: streamable
|
||||
streamable-http:
|
||||
mcp-endpoint: /api/mcp
|
||||
name: hertzbeat-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
|
||||
mvc:
|
||||
static-path-pattern: /**
|
||||
jackson:
|
||||
|
||||
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
Submodule script/helm/hertzbeat-helm-chart updated: 2906774fe8...4a4fbb796e
+4
-17
@@ -66,10 +66,10 @@ 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]
|
||||
- /api/mcp/**===get===[admin]
|
||||
- /api/mcp/**===post===[admin]
|
||||
- /api/chat/**===get===[admin,user]
|
||||
- /api/chat/**===post===[admin,user]
|
||||
- /api/chat/**===post===[admin]
|
||||
- /api/logs/ingest/**===post===[admin,user]
|
||||
|
||||
# config the resource restful api that need bypass auth protection
|
||||
@@ -114,7 +114,7 @@ excludedResource:
|
||||
# h2 database
|
||||
- /h2-console/**===*
|
||||
|
||||
# account info config
|
||||
# account info config refer the https://hertzbeat.apache.org/docs/start/account-modify
|
||||
# eg: admin has role [admin,user], password is hertzbeat
|
||||
# eg: tom has role [user], password is hertzbeat
|
||||
# eg: lili has role [guest], plain password is lili, salt is 123, salted password is 1A676730B0C7F54654B0E09184448289
|
||||
@@ -122,16 +122,3 @@ account:
|
||||
- appId: admin
|
||||
credential: hertzbeat
|
||||
role: [admin]
|
||||
- appId: tom
|
||||
credential: hertzbeat
|
||||
role: [user]
|
||||
- appId: guest
|
||||
credential: hertzbeat
|
||||
role: [guest]
|
||||
- appId: lili
|
||||
# credential = MD5(password + salt)
|
||||
# plain password: hertzbeat
|
||||
# attention: digest authentication does not support salted encrypted password accounts
|
||||
credential: 94C6B34E7A199A9F9D4E1F208093B489
|
||||
salt: 123
|
||||
role: [user]
|
||||
|
||||
Reference in New Issue
Block a user