master
c 181 lines 7.43 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 /**
4 * MCP Resources Namespace
5 *
6 * The MCP Resources namespace provides methods for accessing and managing resources on the server.
7 * In the MCP protocol, resources are application-controlled data stores that provide context to the model.
8 * Resources are passive, meaning they provide data but don't perform actions on their own.
9 *
10 * Standard methods in the MCP specification:
11 *
12 * 1. resources/list - Lists available resources
13 * - Returns a collection of resources the server can provide
14 * - May include resource metadata such as name, description, and URI
15 * - Can be paginated for large resource collections
16 *
17 * 2. resources/read - Reads a specific resource by URI
18 * - Takes a resource URI and returns its contents
19 * - Contents can be text, binary data, or structured information
20 * - URIs follow a standard format, typically with a scheme prefix
21 *
22 * 3. resources/templates/list - Lists available resource templates
23 * - Returns a collection of URI templates for constructing resource URIs
24 * - Templates describe how to construct valid resource URIs
25 * - May include template descriptions and parameter information
26 *
27 * 4. resources/subscribe - Subscribes to changes in a resource
28 * - Takes a resource URI and registers for change notifications
29 * - When the resource changes, the server sends notifications
30 * - Allows clients to maintain up-to-date views of resources
31 *
32 * 5. resources/unsubscribe - Unsubscribes from a resource
33 * - Takes a resource URI and removes the subscription
34 * - Stops receiving notifications for that resource
35 *
36 * In the Netdata context, resources include:
37 * - metrics: Time-series data collected from various sources
38 * - logs: Log entries from system and application logs
39 * - alerts: Health monitoring alerts and notifications
40 * - contexts: Hierarchical organization of metrics and their metadata
41 * - nodes: Monitored infrastructure nodes with their metadata
42 *
43 * Resources are identified by URIs (e.g., "nd://contexts") and can be hierarchical or flat,
44 * supporting different access patterns like time-based querying for metrics.
45 */
46
47 #include "mcp-resources.h"
48 #include "database/contexts/rrdcontext.h"
49
50 // Audience enum - bitmask for the intended audience of a resource
51 typedef enum {
52 RESOURCE_AUDIENCE_USER = 1 << 0, // Resource useful for users
53 RESOURCE_AUDIENCE_ASSISTANT = 1 << 1, // Resource useful for assistants
54 RESOURCE_AUDIENCE_BOTH = RESOURCE_AUDIENCE_USER | RESOURCE_AUDIENCE_ASSISTANT
55 } RESOURCE_AUDIENCE;
56
57 // Function pointer type for resource-read callbacks
58 typedef MCP_RETURN_CODE (*resource_read_fn)(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id);
59
60 // Function pointer type for resource size callbacks
61 typedef size_t (*resource_size_fn)(void);
62
63 // Resource structure definition
64 typedef struct {
65 const char *name; // Resource name
66 const char *uri; // Resource URI
67 const char *description; // Human-readable description
68 HTTP_CONTENT_TYPE content_type; // Content type enum
69 RESOURCE_AUDIENCE audience; // Intended audience
70 double priority; // Priority (0.0-1.0)
71 resource_read_fn read_fn; // Callback function to read the resource
72 resource_size_fn size_fn; // Optional callback function to return approximate size in bytes
73 } MCP_RESOURCE;
74
75 // Resource template structure definition
76 typedef struct {
77 const char *name; // Template name
78 const char *uri_template; // URI template following RFC 6570
79 const char *description; // Human-readable description
80 HTTP_CONTENT_TYPE content_type; // Content type enum
81 RESOURCE_AUDIENCE audience; // Intended audience
82 double priority; // Priority (0.0-1.0)
83 } MCP_RESOURCE_TEMPLATE;
84
85 // Implementation of resources/list
86 static MCP_RETURN_CODE mcp_resources_method_list(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
87 if (!mcpc || !params) return MCP_RC_INTERNAL_ERROR;
88
89 // Initialize success response
90 mcp_init_success_result(mcpc, id);
91
92 // Create an empty resource array object
93 buffer_json_member_add_array(mcpc->result, "resources");
94 buffer_json_array_close(mcpc->result); // Close resources array
95
96 buffer_json_finalize(mcpc->result);
97 return MCP_RC_OK;
98 }
99
100 // Implementation of resources/read
101 static MCP_RETURN_CODE mcp_resources_method_read(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
102 if (!mcpc || !params) return MCP_RC_INTERNAL_ERROR;
103
104 // Extract URI from params
105 struct json_object *uri_obj = NULL;
106 if (!json_object_object_get_ex(params, "uri", &uri_obj)) {
107 buffer_strcat(mcpc->error, "Missing 'uri' parameter");
108 return MCP_RC_INVALID_PARAMS;
109 }
110
111 const char *uri = json_object_get_string(uri_obj);
112 if (!uri) {
113 buffer_strcat(mcpc->error, "Invalid 'uri' parameter");
114 return MCP_RC_INVALID_PARAMS;
115 }
116
117 netdata_log_debug(D_MCP, "MCP resources/read for URI: %s", uri);
118
119 // Since we have no resources, always return not found
120 buffer_sprintf(mcpc->error, "Unknown resource URI: %s", uri);
121 return MCP_RC_NOT_FOUND;
122 }
123
124 // Implementation of resources/templates/list
125 static MCP_RETURN_CODE mcp_resources_method_templates_list(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
126 if (!mcpc || !params) return MCP_RC_INTERNAL_ERROR;
127
128 // Initialize success response
129 mcp_init_success_result(mcpc, id);
130
131 // Create an empty resourceTemplates array object
132 buffer_json_member_add_array(mcpc->result, "resourceTemplates");
133 buffer_json_array_close(mcpc->result); // Close resourceTemplates array
134
135 buffer_json_finalize(mcpc->result);
136 return MCP_RC_OK;
137 }
138
139 // Implementation of resources/subscribe (transport-agnostic)
140 static MCP_RETURN_CODE mcp_resources_method_subscribe(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
141 if (!mcpc || !params) return MCP_RC_INTERNAL_ERROR;
142 return MCP_RC_NOT_IMPLEMENTED;
143 }
144
145 // Implementation of resources/unsubscribe (transport-agnostic)
146 static MCP_RETURN_CODE mcp_resources_method_unsubscribe(MCP_CLIENT *mcpc, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
147 if (!mcpc || !params) return MCP_RC_INTERNAL_ERROR;
148 return MCP_RC_NOT_IMPLEMENTED;
149 }
150
151 // Resource namespace method dispatcher (transport-agnostic)
152 MCP_RETURN_CODE mcp_resources_route(MCP_CLIENT *mcpc, const char *method, struct json_object *params, MCP_REQUEST_ID id __maybe_unused) {
153 if (!mcpc || !method) return MCP_RC_INTERNAL_ERROR;
154
155 netdata_log_debug(D_MCP, "MCP resources method: %s", method);
156
157 MCP_RETURN_CODE rc;
158
159 if (strcmp(method, "list") == 0) {
160 rc = mcp_resources_method_list(mcpc, params, id);
161 }
162 else if (strcmp(method, "read") == 0) {
163 rc = mcp_resources_method_read(mcpc, params, id);
164 }
165 else if (strcmp(method, "templates/list") == 0) {
166 rc = mcp_resources_method_templates_list(mcpc, params, id);
167 }
168 else if (strcmp(method, "subscribe") == 0) {
169 rc = mcp_resources_method_subscribe(mcpc, params, id);
170 }
171 else if (strcmp(method, "unsubscribe") == 0) {
172 rc = mcp_resources_method_unsubscribe(mcpc, params, id);
173 }
174 else {
175 // Method not found in resource namespace
176 buffer_sprintf(mcpc->error, "Method 'resources/%s' not implemented yet", method);
177 rc = MCP_RC_NOT_IMPLEMENTED;
178 }
179
180 return rc;
181 }