turbomcp_client/client/operations/prompts.rs
1//! Prompt operations for MCP client
2//!
3//! This module provides prompt-related functionality including listing prompts,
4//! retrieving prompt templates, and supporting parameter substitution.
5
6use std::sync::atomic::Ordering;
7
8use turbomcp_protocol::types::{
9 GetPromptRequest, GetPromptResult, ListPromptsResult, Prompt, PromptInput,
10};
11use turbomcp_protocol::{Error, Result};
12
13impl<T: turbomcp_transport::Transport + 'static> super::super::core::Client<T> {
14 /// List available prompt templates from the server
15 ///
16 /// Retrieves the complete list of prompt templates that the server provides,
17 /// including all metadata: title, description, and argument schemas. This is
18 /// the MCP-compliant implementation that provides everything needed for UI generation
19 /// and dynamic form creation.
20 ///
21 /// # Returns
22 ///
23 /// Returns a vector of `Prompt` objects containing:
24 /// - `name`: Programmatic identifier
25 /// - `title`: Human-readable display name (optional)
26 /// - `description`: Description of what the prompt does (optional)
27 /// - `arguments`: Array of argument schemas with validation info (optional)
28 ///
29 /// # Errors
30 ///
31 /// Returns an error if:
32 /// - The client is not initialized
33 /// - The server doesn't support prompts
34 /// - The request fails
35 ///
36 /// # Examples
37 ///
38 /// ```rust,no_run
39 /// # use turbomcp_client::Client;
40 /// # use turbomcp_transport::stdio::StdioTransport;
41 /// # async fn example() -> turbomcp_protocol::Result<()> {
42 /// let mut client = Client::new(StdioTransport::new());
43 /// client.initialize().await?;
44 ///
45 /// let prompts = client.list_prompts().await?;
46 /// for prompt in prompts {
47 /// println!("Prompt: {} ({})", prompt.name, prompt.title.unwrap_or("No title".to_string()));
48 /// if let Some(args) = prompt.arguments {
49 /// println!(" Arguments: {:?}", args);
50 /// for arg in args {
51 /// let required = arg.required.unwrap_or(false);
52 /// println!(" - {}: {} (required: {})", arg.name,
53 /// arg.description.unwrap_or("No description".to_string()), required);
54 /// }
55 /// }
56 /// }
57 /// # Ok(())
58 /// # }
59 /// ```
60 pub async fn list_prompts(&self) -> Result<Vec<Prompt>> {
61 if !self.inner.initialized.load(Ordering::Relaxed) {
62 return Err(Error::bad_request("Client not initialized"));
63 }
64
65 // Execute with plugin middleware - return full Prompt objects per MCP spec
66 let response: ListPromptsResult = self.execute_with_plugins("prompts/list", None).await?;
67 Ok(response.prompts)
68 }
69
70 /// Get a specific prompt template with argument support
71 ///
72 /// Retrieves a specific prompt template from the server with support for
73 /// parameter substitution. When arguments are provided, the server will
74 /// substitute them into the prompt template using {parameter} syntax.
75 ///
76 /// This is the MCP-compliant implementation that supports the full protocol specification.
77 ///
78 /// # Arguments
79 ///
80 /// * `name` - The name of the prompt to retrieve
81 /// * `arguments` - Optional parameters for template substitution
82 ///
83 /// # Returns
84 ///
85 /// Returns `GetPromptResult` containing the prompt template with parameters substituted.
86 ///
87 /// # Errors
88 ///
89 /// Returns an error if:
90 /// - The client is not initialized
91 /// - The prompt name is empty
92 /// - The prompt doesn't exist
93 /// - Required arguments are missing
94 /// - Argument types don't match schema
95 /// - The request fails
96 ///
97 /// # Examples
98 ///
99 /// ```rust,no_run
100 /// # use turbomcp_client::Client;
101 /// # use turbomcp_transport::stdio::StdioTransport;
102 /// # use turbomcp_protocol::types::PromptInput;
103 /// # use std::collections::HashMap;
104 /// # async fn example() -> turbomcp_protocol::Result<()> {
105 /// let mut client = Client::new(StdioTransport::new());
106 /// client.initialize().await?;
107 ///
108 /// // Get prompt without arguments (template form)
109 /// let template = client.get_prompt("greeting", None).await?;
110 /// println!("Template has {} messages", template.messages.len());
111 ///
112 /// // Get prompt with arguments (substituted form)
113 /// let mut args = HashMap::new();
114 /// args.insert("name".to_string(), serde_json::Value::String("Alice".to_string()));
115 /// args.insert("greeting".to_string(), serde_json::Value::String("Hello".to_string()));
116 ///
117 /// let result = client.get_prompt("greeting", Some(args)).await?;
118 /// println!("Generated prompt with {} messages", result.messages.len());
119 /// # Ok(())
120 /// # }
121 /// ```
122 pub async fn get_prompt(
123 &self,
124 name: &str,
125 arguments: Option<PromptInput>,
126 ) -> Result<GetPromptResult> {
127 if !self.inner.initialized.load(Ordering::Relaxed) {
128 return Err(Error::bad_request("Client not initialized"));
129 }
130
131 if name.is_empty() {
132 return Err(Error::bad_request("Prompt name cannot be empty"));
133 }
134
135 // Send prompts/get request with full argument support
136 let request = GetPromptRequest {
137 name: name.to_string(),
138 arguments, // Support for parameter substitution
139 _meta: None,
140 };
141
142 self.execute_with_plugins(
143 "prompts/get",
144 Some(serde_json::to_value(request).map_err(|e| {
145 Error::protocol(format!("Failed to serialize prompt request: {}", e))
146 })?),
147 )
148 .await
149 }
150}