master
h 244 lines 11.2 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #ifndef NETDATA_MCP_H
4 #define NETDATA_MCP_H
5
6 #include "libnetdata/libnetdata.h"
7 #include <json-c/json.h>
8 #include "libnetdata/buffer/buffer.h"
9
10 // Request ID type - adapters may use 0 when no correlation is required
11 typedef size_t MCP_REQUEST_ID;
12
13 // MCP tool names - use these constants when referring to tools
14 #define MCP_TOOL_LIST_METRICS "list_metrics"
15 #define MCP_TOOL_GET_METRICS_DETAILS "get_metrics_details"
16 #define MCP_TOOL_LIST_NODES "list_nodes"
17 #define MCP_TOOL_GET_NODES_DETAILS "get_nodes_details"
18 #define MCP_TOOL_LIST_FUNCTIONS "list_functions"
19 #define MCP_TOOL_EXECUTE_FUNCTION "execute_function"
20 #define MCP_TOOL_QUERY_METRICS "query_metrics"
21 #define MCP_TOOL_FIND_CORRELATED_METRICS "find_correlated_metrics"
22 #define MCP_TOOL_FIND_ANOMALOUS_METRICS "find_anomalous_metrics"
23 #define MCP_TOOL_FIND_UNSTABLE_METRICS "find_unstable_metrics"
24 #define MCP_TOOL_LIST_RAISED_ALERTS "list_raised_alerts"
25 #define MCP_TOOL_LIST_ALL_ALERTS "list_running_alerts"
26 #define MCP_TOOL_LIST_ALERT_TRANSITIONS "list_alert_transitions"
27
28 #define MCP_INFO_TOO_MANY_CONTEXTS_GROUPED_IN_CATEGORIES \
29 "The response has been grouped into categories to minimize size.\n" \
30 "Next Steps: repeat the '"MCP_TOOL_LIST_METRICS"' call with a pattern to match what is interesting, " \
31 "or run '" MCP_TOOL_GET_METRICS_DETAILS "' to get more information for the contexts of interest."
32
33 #define MCP_INFO_CONTEXT_ARRAY_RESPONSE \
34 "Next Steps: run the '"MCP_TOOL_GET_METRICS_DETAILS"' tool to get more information for the contexts of interest."
35
36 #define MCP_INFO_CONTEXT_NEXT_STEPS \
37 "Next Steps: Query time-series data with the '"MCP_TOOL_QUERY_METRICS"' tool, using different aggregations to inspect different views:\n" \
38 " - 'group_by: dimension' will aggregate all time-series by the listed dimensions\n" \
39 " - 'group_by: instance' will aggregate all time-series by the listed instances\n" \
40 " - 'group_by: label, group_by_label: {label_key}' will aggregate by the listed label values\n" \
41 "\n" \
42 "Dimensions, instances and labels can also be used for filtering in '"MCP_TOOL_QUERY_METRICS"':\n" \
43 " - 'dimensions: dimension1|dimension2|*dimension*' will select only the time-series with the given dimension\n" \
44 " - 'instances: instance1|instance2|*instance*' will select only the time-series with the given instance\n" \
45 " - 'labels' can be specified in two formats:\n" \
46 " • String format: 'labels: key1:value1|key1:value2|key2:value3' (values with same key are ORed, different keys are ANDed)\n" \
47 " • Structured format: 'labels: {\"key1\": [\"value1\", \"value2\"], \"key2\": \"value3\"}' (array values are ORed, different keys are ANDed)"
48
49 // MCP default values for all tools
50 #define MCP_DEFAULT_AFTER_TIME (-3600) // 1 hour ago
51 #define MCP_DEFAULT_BEFORE_TIME 0 // now
52 #define MCP_DEFAULT_TIMEOUT_WEIGHTS 300 // 5 minutes
53 #define MCP_METADATA_CARDINALITY_LIMIT 50 // For metadata queries
54 #define MCP_DATA_CARDINALITY_LIMIT 10 // For data queries
55 #define MCP_WEIGHTS_CARDINALITY_LIMIT 50 // For weights queries (minimum is 30)
56 #define MCP_METADATA_CARDINALITY_LIMIT_MAX 500 // For metadata queries
57 #define MCP_DATA_CARDINALITY_LIMIT_MAX 500 // For data queries
58 #define MCP_WEIGHTS_CARDINALITY_LIMIT_MAX 500 // For weights queries
59 #define MCP_ALERTS_CARDINALITY_LIMIT 100 // For alert queries
60 #define MCP_ALERTS_CARDINALITY_LIMIT_MAX 500 // For alert queries
61
62 // MCP query info messages
63 #define MCP_QUERY_INFO_SUMMARY_SECTION \
64 "The summary section breaks down the different sources that contribute " \
65 "data to the query. Use this to detect spikes, dives, anomalies (the % of anomalous samples vs the total samples) " \
66 "and evaluate the different groupings that may be beneficial for the task at hand."
67
68 #define MCP_QUERY_INFO_DATABASE_SECTION \
69 "The database section provides metadata about the underlying data storage, " \
70 "including retention periods and update frequencies, and data availability " \
71 "across different storage tiers."
72
73 #define MCP_QUERY_INFO_VIEW_SECTION \
74 "The view section provides summarized data for the visible time window. " \
75 "For each dimension returned, it contains the minimum, maximum, and average values, " \
76 "the anomaly rate (% of anomalous samples vs total samples) and contribution percentages, " \
77 "across all points."
78
79 #define MCP_QUERY_INFO_RESULT_SECTION \
80 "The 'result' section contains the actual time-series data points.\n" \
81 "Each point of each dimension is represented as an array of 3 values:\n" \
82 " a) the value itself, aggregated as requested\n" \
83 " b) the point anomaly rate percentage (% of anomalous samples vs total samples)\n" \
84 " c) the point annotations, a combined bitmap of 1+2+4, where:\n" \
85 " 1 = empty data, value should be ignored\n" \
86 " 2 = counter has been reset or overflown, value may not be accurate\n" \
87 " 4 = partial data, at least one of the sources aggregated had gaps at that time\n" \
88 "Summarized data across the entire time-frame is provided at the 'view' section."
89
90 // MCP protocol versions
91 typedef enum {
92 MCP_PROTOCOL_VERSION_UNKNOWN = 0,
93 MCP_PROTOCOL_VERSION_2024_11_05 = 20241105, // Using numeric date format for natural ordering
94 MCP_PROTOCOL_VERSION_2025_03_26 = 20250326,
95 // Add future versions here
96
97 // Always keep this pointing to the latest version
98 MCP_PROTOCOL_VERSION_LATEST = MCP_PROTOCOL_VERSION_2025_03_26
99 } MCP_PROTOCOL_VERSION;
100 ENUM_STR_DEFINE_FUNCTIONS_EXTERN(MCP_PROTOCOL_VERSION);
101
102 // Content types (for messages and tool responses)
103 typedef enum {
104 MCP_CONTENT_TYPE_TEXT = 0,
105 MCP_CONTENT_TYPE_IMAGE = 1,
106 MCP_CONTENT_TYPE_AUDIO = 2, // New in 2025-03-26
107 } MCP_CONTENT_TYPE;
108
109 // Logging levels (as defined in MCP schema)
110 typedef enum {
111 MCP_LOGGING_LEVEL_UNKNOWN = 0,
112 MCP_LOGGING_LEVEL_DEBUG,
113 MCP_LOGGING_LEVEL_INFO,
114 MCP_LOGGING_LEVEL_NOTICE,
115 MCP_LOGGING_LEVEL_WARNING,
116 MCP_LOGGING_LEVEL_ERROR,
117 MCP_LOGGING_LEVEL_CRITICAL,
118 MCP_LOGGING_LEVEL_ALERT,
119 MCP_LOGGING_LEVEL_EMERGENCY
120 } MCP_LOGGING_LEVEL;
121 ENUM_STR_DEFINE_FUNCTIONS_EXTERN(MCP_LOGGING_LEVEL);
122
123 // Forward declarations for transport-specific types
124 struct websocket_server_client;
125 struct web_client;
126
127 // Transport types for MCP
128 typedef enum {
129 MCP_TRANSPORT_UNKNOWN = 0,
130 MCP_TRANSPORT_WEBSOCKET,
131 MCP_TRANSPORT_HTTP,
132 MCP_TRANSPORT_SSE,
133 // Add more as needed
134 } MCP_TRANSPORT;
135
136 // Transport capabilities
137 typedef enum {
138 MCP_CAPABILITY_NONE = 0,
139 MCP_CAPABILITY_ASYNC_COMMUNICATION = (1 << 0), // Can send messages at any time
140 MCP_CAPABILITY_SUBSCRIPTIONS = (1 << 1), // Supports subscriptions
141 MCP_CAPABILITY_NOTIFICATIONS = (1 << 2), // Supports notifications
142 // Add more as needed
143 } MCP_CAPABILITY;
144
145 // Return codes for MCP functions
146 typedef enum {
147 MCP_RC_OK = 0, // Success, result buffer contains valid response
148 MCP_RC_ERROR = 1, // Generic error, error buffer contains message
149 MCP_RC_INVALID_PARAMS = 2, // Invalid parameters in request
150 MCP_RC_NOT_FOUND = 3, // Resource or method not found
151 MCP_RC_INTERNAL_ERROR = 4, // Internal server error
152 MCP_RC_NOT_IMPLEMENTED = 5, // Method not implemented
153 MCP_RC_BAD_REQUEST = 6 // Bad or malformed request
154 // Can add more specific errors as needed
155 } MCP_RETURN_CODE;
156 ENUM_STR_DEFINE_FUNCTIONS_EXTERN(MCP_RETURN_CODE);
157
158 // Response handling context
159 typedef struct mcp_client {
160 // Transport type and capabilities
161 MCP_TRANSPORT transport;
162 MCP_CAPABILITY capabilities;
163
164 // Protocol version (detected during initialization)
165 MCP_PROTOCOL_VERSION protocol_version;
166
167 // Client state
168 bool ready; // Set to true when client is ready for normal operations
169
170 // Transport-specific context
171 union {
172 struct websocket_server_client *websocket; // WebSocket client
173 struct web_client *http; // HTTP client
174 void *generic; // Generic context
175 };
176
177 // Authentication and authorization
178 USER_AUTH *user_auth; // Pointer to user auth from the underlying transport
179
180 // Client information
181 STRING *client_name; // Client name (for logging, interned)
182 STRING *client_version; // Client version (for logging, interned)
183
184 // Logging configuration
185 MCP_LOGGING_LEVEL logging_level; // Current logging level set by client
186
187 // Per-request response data
188 BUFFER *error; // Persistent buffer accumulating error messages
189 BUFFER *result; // Convenience pointer to currently active response chunk
190 struct mcp_response_chunk {
191 BUFFER *buffer; // Response payload
192 enum mcp_response_chunk_type {
193 MCP_RESPONSE_CHUNK_JSON = 0,
194 MCP_RESPONSE_CHUNK_TEXT,
195 MCP_RESPONSE_CHUNK_BINARY,
196 } type; // Encoding hint for adapters
197 } *response_chunks;
198 size_t response_chunks_used;
199 size_t response_chunks_size;
200
201 // Last response status
202 MCP_RETURN_CODE last_return_code;
203 bool last_response_error;
204 } MCP_CLIENT;
205
206 // Helper function to convert string version to numeric version
207 MCP_PROTOCOL_VERSION mcp_protocol_version_from_string(const char *version_str);
208
209 // Helper function to convert numeric version to string version
210 const char *mcp_protocol_version_to_string(MCP_PROTOCOL_VERSION version);
211
212 // Create a response context for a transport session
213 MCP_CLIENT *mcp_create_client(MCP_TRANSPORT transport, void *transport_ctx);
214
215 // Free a response context
216 void mcp_free_client(MCP_CLIENT *mcpc);
217
218 // Helper functions for creating and sending JSON-RPC responses
219
220 // Response lifecycle helpers
221 void mcp_client_prepare_response(MCP_CLIENT *mcpc);
222 void mcp_client_release_response(MCP_CLIENT *mcpc);
223 BUFFER *mcp_response_add_json_chunk(MCP_CLIENT *mcpc, size_t initial_capacity);
224 BUFFER *mcp_response_add_text_chunk(MCP_CLIENT *mcpc, size_t initial_capacity);
225 size_t mcp_client_response_chunk_count(const MCP_CLIENT *mcpc);
226 const struct mcp_response_chunk *mcp_client_response_chunks(const MCP_CLIENT *mcpc);
227 size_t mcp_client_response_size(const MCP_CLIENT *mcpc);
228 void mcp_init_success_result(MCP_CLIENT *mcpc, MCP_REQUEST_ID id);
229 MCP_RETURN_CODE mcp_error_result(MCP_CLIENT *mcpc, MCP_REQUEST_ID id, MCP_RETURN_CODE rc);
230 const char *mcp_client_error_message(MCP_CLIENT *mcpc);
231 void mcp_client_clear_error(MCP_CLIENT *mcpc);
232
233 // Check if a capability is supported by the transport
234 static inline bool mcp_has_capability(MCP_CLIENT *mcpc, MCP_CAPABILITY capability) {
235 return mcpc && (mcpc->capabilities & capability);
236 }
237
238 // Initialize the MCP subsystem
239 void mcp_initialize_subsystem(void);
240
241 // Transport-agnostic dispatcher (method string follows MCP namespace semantics)
242 MCP_RETURN_CODE mcp_dispatch_method(MCP_CLIENT *mcpc, const char *method, struct json_object *params, MCP_REQUEST_ID id);
243
244 #endif // NETDATA_MCP_H