mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2026-03-31 07:12:23 -07:00
Merge pull request #1484 from adamoutler/agentic-workflows
MCP Enhancements: Named Totals, OpenAPI Resource, and Dev Skills
This commit is contained in:
@@ -73,6 +73,7 @@ from .openapi.schemas import ( # noqa: E402 [flake8 lint suppression]
|
||||
DeviceInfo,
|
||||
BaseResponse, DeviceTotalsResponse,
|
||||
DeviceTotalsNamedResponse,
|
||||
EventsTotalsNamedResponse,
|
||||
DeleteDevicesRequest, DeviceImportRequest,
|
||||
DeviceImportResponse, UpdateDeviceColumnRequest,
|
||||
LockDeviceFieldRequest, UnlockDeviceFieldsRequest,
|
||||
@@ -1509,8 +1510,8 @@ def api_delete_old_events(days: int, payload=None):
|
||||
@app.route("/sessions/totals", methods=["GET"])
|
||||
@validate_request(
|
||||
operation_id="get_events_totals",
|
||||
summary="Get Events Totals",
|
||||
description="Retrieve event totals for a specified period.",
|
||||
summary="Get Events Totals (Deprecated)",
|
||||
description="Retrieve event totals for a specified period. Deprecated: use /sessions/totals/named instead.",
|
||||
query_params=[{
|
||||
"name": "period",
|
||||
"description": "Time period (e.g., '7 days')",
|
||||
@@ -1527,6 +1528,37 @@ def api_get_events_totals(payload=None):
|
||||
return jsonify(totals)
|
||||
|
||||
|
||||
@app.route("/sessions/totals/named", methods=["GET"])
|
||||
@validate_request(
|
||||
operation_id="get_events_totals_named",
|
||||
summary="Get Named Event Totals",
|
||||
description="Retrieve event/session totals with named fields for a specified period.",
|
||||
query_params=[{
|
||||
"name": "period",
|
||||
"description": "Time period (e.g., '7 days')",
|
||||
"required": False,
|
||||
"schema": {"type": "string", "default": "7 days"}
|
||||
}],
|
||||
response_model=EventsTotalsNamedResponse,
|
||||
tags=["events"],
|
||||
auth_callable=is_authorized
|
||||
)
|
||||
def api_get_events_totals_named(payload=None):
|
||||
period = request.args.get("period", "7 days")
|
||||
event_handler = EventInstance()
|
||||
totals = event_handler.getEventsTotals(period)
|
||||
# totals order: [all_events, sessions, missing, voided, new, down]
|
||||
totals_dict = {
|
||||
"total": totals[0] if len(totals) > 0 else 0,
|
||||
"sessions": totals[1] if len(totals) > 1 else 0,
|
||||
"missing": totals[2] if len(totals) > 2 else 0,
|
||||
"voided": totals[3] if len(totals) > 3 else 0,
|
||||
"new": totals[4] if len(totals) > 4 else 0,
|
||||
"down": totals[5] if len(totals) > 5 else 0
|
||||
}
|
||||
return jsonify({"success": True, "totals": totals_dict})
|
||||
|
||||
|
||||
@app.route('/events/recent', methods=['GET', 'POST'])
|
||||
@validate_request(
|
||||
operation_id="get_recent_events",
|
||||
|
||||
@@ -795,8 +795,17 @@ def get_log_dir() -> str:
|
||||
|
||||
|
||||
def _list_resources() -> List[Dict[str, Any]]:
|
||||
"""List available MCP resources (read-only data like logs)."""
|
||||
"""List available MCP resources (read-only data like logs and API spec)."""
|
||||
resources = []
|
||||
|
||||
# API Specification
|
||||
resources.append({
|
||||
"uri": "netalertx://api/openapi.json",
|
||||
"name": "OpenAPI Specification",
|
||||
"description": "The full OpenAPI 3.1 specification for the NetAlertX API and MCP tools",
|
||||
"mimeType": "application/json"
|
||||
})
|
||||
|
||||
log_dir = get_log_dir()
|
||||
if not log_dir:
|
||||
return resources
|
||||
@@ -840,6 +849,16 @@ def _list_resources() -> List[Dict[str, Any]]:
|
||||
|
||||
def _read_resource(uri: str) -> List[Dict[str, Any]]:
|
||||
"""Read a resource by URI."""
|
||||
# Handle API Specification
|
||||
if uri == "netalertx://api/openapi.json":
|
||||
from flask import current_app
|
||||
spec = get_openapi_spec(flask_app=current_app)
|
||||
return [{
|
||||
"uri": uri,
|
||||
"mimeType": "application/json",
|
||||
"text": json.dumps(spec, indent=2)
|
||||
}]
|
||||
|
||||
log_dir = get_log_dir()
|
||||
if not log_dir:
|
||||
return [{"uri": uri, "text": "Error: NETALERTX_LOG directory not configured"}]
|
||||
|
||||
@@ -318,6 +318,24 @@ class DeviceTotalsNamedResponse(BaseResponse):
|
||||
)
|
||||
|
||||
|
||||
class EventsTotalsNamedResponse(BaseResponse):
|
||||
"""Response with named event/session statistics."""
|
||||
totals: Dict[str, int] = Field(
|
||||
...,
|
||||
description="Dictionary of counts: total, sessions, missing, voided, new, down",
|
||||
json_schema_extra={
|
||||
"examples": [{
|
||||
"total": 100,
|
||||
"sessions": 50,
|
||||
"missing": 0,
|
||||
"voided": 0,
|
||||
"new": 5,
|
||||
"down": 2
|
||||
}]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
class DeviceExportRequest(BaseModel):
|
||||
"""Request for exporting devices."""
|
||||
format: Literal["csv", "json"] = Field(
|
||||
|
||||
Reference in New Issue
Block a user