Skip to main content

prism_mcp_rs/protocol/
methods.rs

1//! MCP Protocol Method Constants
2//!
3//! Module contains all the method name constants used in the MCP protocol
4//! as defined in the 2025-03-26 specification.
5
6// Core protocol methods
7pub const INITIALIZE: &str = "initialize";
8pub const INITIALIZED: &str = "notifications/initialized";
9pub const PING: &str = "ping";
10/// Stateless capability and revision discovery (MCP 2026-07-28).
11pub const SERVER_DISCOVER: &str = "server/discover";
12
13// Tool-related methods
14pub const TOOLS_LIST: &str = "tools/list";
15pub const TOOLS_CALL: &str = "tools/call";
16pub const TOOLS_LIST_CHANGED: &str = "notifications/tools/list_changed";
17
18// Resource-related methods
19pub const RESOURCES_LIST: &str = "resources/list";
20pub const RESOURCES_TEMPLATES_LIST: &str = "resources/templates/list"; // New in 2025-11-25
21pub const RESOURCES_READ: &str = "resources/read";
22pub const RESOURCES_SUBSCRIBE: &str = "resources/subscribe";
23pub const RESOURCES_UNSUBSCRIBE: &str = "resources/unsubscribe";
24pub const RESOURCES_UPDATED: &str = "notifications/resources/updated";
25pub const RESOURCES_LIST_CHANGED: &str = "notifications/resources/list_changed";
26
27// Prompt-related methods
28pub const PROMPTS_LIST: &str = "prompts/list";
29pub const PROMPTS_GET: &str = "prompts/get";
30pub const PROMPTS_LIST_CHANGED: &str = "notifications/prompts/list_changed";
31
32// Sampling methods
33pub const SAMPLING_CREATE_MESSAGE: &str = "sampling/createMessage";
34
35// Root-related methods (New in 2025-11-25)
36pub const ROOTS_LIST: &str = "roots/list";
37pub const ROOTS_LIST_CHANGED: &str = "notifications/roots/list_changed";
38
39// Completion methods (New in 2025-11-25)
40pub const COMPLETION_COMPLETE: &str = "completion/complete";
41
42// Elicitation methods (New in 2025-11-25)
43pub const ELICITATION_CREATE: &str = "elicitation/create";
44pub const ELICITATION_COMPLETE: &str = "notifications/elicitation/complete";
45
46// Historical Prism task utility methods. Retained for source compatibility;
47// they are not part of the MCP 2026 Tasks extension.
48pub const TASKS_SEND: &str = "tasks/send";
49pub const TASKS_CANCEL: &str = "tasks/cancel";
50pub const TASKS_STATUS_UPDATE: &str = "notifications/tasks/status/update";
51/// MCP Tasks extension methods (2026-07-28 extension vocabulary).
52pub const TASKS_GET: &str = "tasks/get";
53pub const TASKS_UPDATE: &str = "tasks/update";
54pub const TASKS_STATUS: &str = "notifications/tasks";
55
56/// Stateless notification stream request (MCP 2026-07-28).
57pub const SUBSCRIPTIONS_LISTEN: &str = "subscriptions/listen";
58pub const SUBSCRIPTIONS_ACKNOWLEDGED: &str = "notifications/subscriptions/acknowledged";
59
60// Logging methods
61pub const LOGGING_SET_LEVEL: &str = "logging/setLevel";
62pub const LOGGING_MESSAGE: &str = "notifications/message";
63
64// Progress and notification methods
65pub const PROGRESS: &str = "notifications/progress";
66pub const CANCELLED: &str = "notifications/cancelled"; // New in 2025-11-25
67
68// Discovery methods (Optional RPC discovery mechanism)
69pub const RPC_DISCOVER: &str = "rpc.discover";
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_all_method_constants_valid() {
77        // Test that all method constants are valid strings
78        let methods = vec![
79            INITIALIZE,
80            INITIALIZED,
81            PING,
82            TOOLS_LIST,
83            TOOLS_CALL,
84            TOOLS_LIST_CHANGED,
85            RESOURCES_LIST,
86            RESOURCES_TEMPLATES_LIST,
87            RESOURCES_READ,
88            RESOURCES_SUBSCRIBE,
89            RESOURCES_UNSUBSCRIBE,
90            RESOURCES_UPDATED,
91            RESOURCES_LIST_CHANGED,
92            PROMPTS_LIST,
93            PROMPTS_GET,
94            PROMPTS_LIST_CHANGED,
95            SAMPLING_CREATE_MESSAGE,
96            ROOTS_LIST,
97            ROOTS_LIST_CHANGED,
98            COMPLETION_COMPLETE,
99            ELICITATION_CREATE,
100            ELICITATION_COMPLETE,
101            TASKS_SEND,
102            TASKS_CANCEL,
103            TASKS_STATUS_UPDATE,
104            LOGGING_SET_LEVEL,
105            LOGGING_MESSAGE,
106            PROGRESS,
107            CANCELLED,
108        ];
109
110        for method in methods {
111            assert!(
112                !method.is_empty(),
113                "Method constant should not be empty: {method}"
114            );
115            assert!(
116                !method.contains(' '),
117                "Method constant should not contain spaces: {method}"
118            );
119        }
120    }
121
122    #[test]
123    fn test_method_name_consistency() {
124        // Test core protocol methods
125        assert_eq!(INITIALIZE, "initialize");
126        assert_eq!(INITIALIZED, "notifications/initialized");
127        assert_eq!(PING, "ping");
128
129        // Test tool methods
130        assert_eq!(TOOLS_LIST, "tools/list");
131        assert_eq!(TOOLS_CALL, "tools/call");
132        assert_eq!(TOOLS_LIST_CHANGED, "notifications/tools/list_changed");
133
134        // Test resource methods
135        assert_eq!(RESOURCES_LIST, "resources/list");
136        assert_eq!(RESOURCES_TEMPLATES_LIST, "resources/templates/list");
137        assert_eq!(RESOURCES_READ, "resources/read");
138        assert_eq!(RESOURCES_SUBSCRIBE, "resources/subscribe");
139        assert_eq!(RESOURCES_UNSUBSCRIBE, "resources/unsubscribe");
140        assert_eq!(RESOURCES_UPDATED, "notifications/resources/updated");
141        assert_eq!(
142            RESOURCES_LIST_CHANGED,
143            "notifications/resources/list_changed"
144        );
145
146        // Test prompt methods
147        assert_eq!(PROMPTS_LIST, "prompts/list");
148        assert_eq!(PROMPTS_GET, "prompts/get");
149        assert_eq!(PROMPTS_LIST_CHANGED, "notifications/prompts/list_changed");
150
151        // Test sampling methods
152        assert_eq!(SAMPLING_CREATE_MESSAGE, "sampling/createMessage");
153
154        // Test 2025-11-25 new methods
155        assert_eq!(ROOTS_LIST, "roots/list");
156        assert_eq!(ROOTS_LIST_CHANGED, "notifications/roots/list_changed");
157        assert_eq!(COMPLETION_COMPLETE, "completion/complete");
158        assert_eq!(ELICITATION_CREATE, "elicitation/create");
159        assert_eq!(ELICITATION_COMPLETE, "notifications/elicitation/complete");
160        assert_eq!(TASKS_SEND, "tasks/send");
161        assert_eq!(TASKS_CANCEL, "tasks/cancel");
162        assert_eq!(TASKS_STATUS_UPDATE, "notifications/tasks/status/update");
163        assert_eq!(CANCELLED, "notifications/cancelled");
164
165        // Test logging methods
166        assert_eq!(LOGGING_SET_LEVEL, "logging/setLevel");
167        assert_eq!(LOGGING_MESSAGE, "notifications/message");
168        assert_eq!(PROGRESS, "notifications/progress");
169    }
170
171    #[test]
172    fn test_notification_methods_prefix() {
173        // All notification methods should start with "notifications/"
174        let notification_methods = vec![
175            INITIALIZED,
176            TOOLS_LIST_CHANGED,
177            RESOURCES_UPDATED,
178            RESOURCES_LIST_CHANGED,
179            PROMPTS_LIST_CHANGED,
180            ROOTS_LIST_CHANGED,
181            ELICITATION_COMPLETE,
182            TASKS_STATUS_UPDATE,
183            LOGGING_MESSAGE,
184            PROGRESS,
185            CANCELLED,
186        ];
187
188        for method in notification_methods {
189            assert!(
190                method.starts_with("notifications/"),
191                "Notification method should start with 'notifications/': {method}"
192            );
193        }
194    }
195
196    #[test]
197    fn test_request_methods_no_notification_prefix() {
198        // Request methods should not start with "notifications/"
199        let request_methods = vec![
200            INITIALIZE,
201            PING,
202            TOOLS_LIST,
203            TOOLS_CALL,
204            RESOURCES_LIST,
205            RESOURCES_TEMPLATES_LIST,
206            RESOURCES_READ,
207            RESOURCES_SUBSCRIBE,
208            RESOURCES_UNSUBSCRIBE,
209            PROMPTS_LIST,
210            PROMPTS_GET,
211            SAMPLING_CREATE_MESSAGE,
212            ROOTS_LIST,
213            COMPLETION_COMPLETE,
214            ELICITATION_CREATE,
215            TASKS_SEND,
216            TASKS_CANCEL,
217            LOGGING_SET_LEVEL,
218        ];
219
220        for method in request_methods {
221            assert!(
222                !method.starts_with("notifications/"),
223                "Request method should not start with 'notifications/': {method}"
224            );
225        }
226    }
227
228    #[test]
229    fn test_method_categories() {
230        // Test that methods are properly categorized
231        let tool_methods = vec![TOOLS_LIST, TOOLS_CALL, TOOLS_LIST_CHANGED];
232        for method in tool_methods {
233            assert!(
234                method.contains("tools"),
235                "Tool method should contain 'tools': {method}"
236            );
237        }
238
239        let resource_methods = vec![
240            RESOURCES_LIST,
241            RESOURCES_TEMPLATES_LIST,
242            RESOURCES_READ,
243            RESOURCES_SUBSCRIBE,
244            RESOURCES_UNSUBSCRIBE,
245            RESOURCES_UPDATED,
246            RESOURCES_LIST_CHANGED,
247        ];
248        for method in resource_methods {
249            assert!(
250                method.contains("resources"),
251                "Resource method should contain 'resources': {method}"
252            );
253        }
254
255        let prompt_methods = vec![PROMPTS_LIST, PROMPTS_GET, PROMPTS_LIST_CHANGED];
256        for method in prompt_methods {
257            assert!(
258                method.contains("prompts"),
259                "Prompt method should contain 'prompts': {method}"
260            );
261        }
262    }
263
264    #[test]
265    fn test_2025_06_18_new_methods() {
266        // Test that new methods introduced in 2025-11-25 are present
267        let new_methods = vec![
268            RESOURCES_TEMPLATES_LIST,
269            ROOTS_LIST,
270            ROOTS_LIST_CHANGED,
271            COMPLETION_COMPLETE,
272            ELICITATION_CREATE,
273            CANCELLED,
274        ];
275
276        // Just verify they exist and are not empty
277        for method in new_methods {
278            assert!(
279                !method.is_empty(),
280                "New 2025-11-25 method should not be empty: {method}"
281            );
282        }
283    }
284
285    #[test]
286    fn test_method_constants_unique() {
287        // Test that all method constants are unique
288        let methods = vec![
289            INITIALIZE,
290            INITIALIZED,
291            PING,
292            TOOLS_LIST,
293            TOOLS_CALL,
294            TOOLS_LIST_CHANGED,
295            RESOURCES_LIST,
296            RESOURCES_TEMPLATES_LIST,
297            RESOURCES_READ,
298            RESOURCES_SUBSCRIBE,
299            RESOURCES_UNSUBSCRIBE,
300            RESOURCES_UPDATED,
301            RESOURCES_LIST_CHANGED,
302            PROMPTS_LIST,
303            PROMPTS_GET,
304            PROMPTS_LIST_CHANGED,
305            SAMPLING_CREATE_MESSAGE,
306            ROOTS_LIST,
307            ROOTS_LIST_CHANGED,
308            COMPLETION_COMPLETE,
309            ELICITATION_CREATE,
310            LOGGING_SET_LEVEL,
311            LOGGING_MESSAGE,
312            PROGRESS,
313            CANCELLED,
314        ];
315
316        let mut unique_methods = std::collections::HashSet::new();
317        for method in methods {
318            assert!(
319                unique_methods.insert(method),
320                "Duplicate method constant found: {method}"
321            );
322        }
323    }
324
325    #[test]
326    fn test_method_naming_conventions() {
327        // Test that method names follow proper conventions
328        // Should use lowercase with underscores for separators in constant names
329        // Should use camelCase in the actual method strings where appropriate
330
331        // Check camelCase in method strings
332        assert!(SAMPLING_CREATE_MESSAGE.contains("createMessage"));
333        assert!(LOGGING_SET_LEVEL.contains("setLevel"));
334
335        // Check slash separators for namespacing
336        assert!(TOOLS_LIST.contains("/"));
337        assert!(RESOURCES_LIST.contains("/"));
338        assert!(PROMPTS_LIST.contains("/"));
339        assert!(COMPLETION_COMPLETE.contains("/"));
340    }
341}