Skip to main content

turbomcp_client/client/operations/
completion.rs

1//! Completion operations for MCP client
2//!
3//! This module provides autocompletion functionality for prompts and resources,
4//! supporting the MCP completion protocol with context and argument validation.
5
6use std::sync::atomic::Ordering;
7use turbomcp_protocol::types::{
8    ArgumentInfo, CompleteRequestParams, CompleteResult, CompletionContext, CompletionReference,
9    CompletionResponse, PromptReferenceData, ResourceTemplateReferenceData,
10};
11use turbomcp_protocol::{Error, Result};
12
13impl<T: turbomcp_transport::Transport + 'static> super::super::core::Client<T> {
14    /// Internal helper for completion operations - DRYed up common logic
15    async fn complete_internal(
16        &self,
17        argument_name: &str,
18        argument_value: &str,
19        reference: CompletionReference,
20        context: Option<CompletionContext>,
21    ) -> Result<CompletionResponse> {
22        if !self.inner.initialized.load(Ordering::Relaxed) {
23            return Err(Error::invalid_request("Client not initialized"));
24        }
25
26        let request_params = CompleteRequestParams {
27            argument: ArgumentInfo {
28                name: argument_name.to_string(),
29                value: argument_value.to_string(),
30            },
31            reference,
32            context,
33        };
34
35        let serialized_params = serde_json::to_value(&request_params)?;
36
37        let result: CompleteResult = self
38            .inner
39            .protocol
40            .request("completion/complete", Some(serialized_params))
41            .await?;
42
43        Ok(CompletionResponse {
44            completion: result.completion,
45            _meta: result._meta,
46        })
47    }
48
49    /// Request completion suggestions from the server
50    ///
51    /// Simple completion interface for basic autocompletion needs.
52    /// Uses a prompt-based reference with hardcoded "partial" argument name.
53    ///
54    /// # Arguments
55    ///
56    /// * `handler_name` - The completion handler name
57    /// * `argument_value` - The partial value to complete
58    ///
59    /// # Examples
60    ///
61    /// ```rust,no_run
62    /// # use turbomcp_client::Client;
63    /// # use turbomcp_transport::stdio::StdioTransport;
64    /// # async fn example() -> turbomcp_protocol::Result<()> {
65    /// let mut client = Client::new(StdioTransport::new());
66    /// client.initialize().await?;
67    ///
68    /// let result = client.complete("complete_path", "/usr/b").await?;
69    /// println!("Completions: {:?}", result.completion.values);
70    /// # Ok(())
71    /// # }
72    /// ```
73    pub async fn complete(
74        &self,
75        handler_name: &str,
76        argument_value: &str,
77    ) -> Result<CompletionResponse> {
78        let reference = CompletionReference::Prompt(PromptReferenceData {
79            name: handler_name.to_string(),
80            title: None,
81        });
82
83        self.complete_internal("partial", argument_value, reference, None)
84            .await
85    }
86
87    /// Complete a prompt argument with full MCP protocol support
88    ///
89    /// This method provides access to the complete MCP completion protocol,
90    /// allowing specification of argument names, prompt references, and context.
91    ///
92    /// # Arguments
93    ///
94    /// * `prompt_name` - Name of the prompt to complete for
95    /// * `argument_name` - Name of the argument being completed
96    /// * `argument_value` - Current value for completion matching
97    /// * `context` - Optional context with previously resolved arguments
98    ///
99    /// # Examples
100    ///
101    /// ```rust,no_run
102    /// # use turbomcp_client::Client;
103    /// # use turbomcp_transport::stdio::StdioTransport;
104    /// # use turbomcp_protocol::types::CompletionContext;
105    /// # use std::collections::HashMap;
106    /// # async fn example() -> turbomcp_protocol::Result<()> {
107    /// let mut client = Client::new(StdioTransport::new());
108    /// client.initialize().await?;
109    ///
110    /// // Complete with context
111    /// let mut context_args = HashMap::new();
112    /// context_args.insert("language".to_string(), "rust".to_string());
113    /// let context = CompletionContext { arguments: Some(context_args) };
114    ///
115    /// let completions = client.complete_prompt(
116    ///     "code_review",
117    ///     "framework",
118    ///     "tok",
119    ///     Some(context)
120    /// ).await?;
121    ///
122    /// for completion in completions.completion.values {
123    ///     println!("Suggestion: {}", completion);
124    /// }
125    /// # Ok(())
126    /// # }
127    /// ```
128    pub async fn complete_prompt(
129        &self,
130        prompt_name: &str,
131        argument_name: &str,
132        argument_value: &str,
133        context: Option<CompletionContext>,
134    ) -> Result<CompletionResponse> {
135        let reference = CompletionReference::Prompt(PromptReferenceData {
136            name: prompt_name.to_string(),
137            title: None,
138        });
139
140        self.complete_internal(argument_name, argument_value, reference, context)
141            .await
142    }
143
144    /// Complete a resource template URI with full MCP protocol support
145    ///
146    /// This method provides completion for resource template URIs, allowing
147    /// servers to suggest values for URI template variables.
148    ///
149    /// # Arguments
150    ///
151    /// * `resource_uri` - Resource template URI (e.g., "/files/{path}")
152    /// * `argument_name` - Name of the argument being completed
153    /// * `argument_value` - Current value for completion matching
154    /// * `context` - Optional context with previously resolved arguments
155    ///
156    /// # Examples
157    ///
158    /// ```rust,no_run
159    /// # use turbomcp_client::Client;
160    /// # use turbomcp_transport::stdio::StdioTransport;
161    /// # async fn example() -> turbomcp_protocol::Result<()> {
162    /// let mut client = Client::new(StdioTransport::new());
163    /// client.initialize().await?;
164    ///
165    /// let completions = client.complete_resource(
166    ///     "/files/{path}",
167    ///     "path",
168    ///     "/home/user/doc",
169    ///     None
170    /// ).await?;
171    ///
172    /// for completion in completions.completion.values {
173    ///     println!("Path suggestion: {}", completion);
174    /// }
175    /// # Ok(())
176    /// # }
177    /// ```
178    pub async fn complete_resource(
179        &self,
180        resource_uri: &str,
181        argument_name: &str,
182        argument_value: &str,
183        context: Option<CompletionContext>,
184    ) -> Result<CompletionResponse> {
185        let reference = CompletionReference::ResourceTemplate(ResourceTemplateReferenceData {
186            uri: resource_uri.to_string(),
187        });
188
189        self.complete_internal(argument_name, argument_value, reference, context)
190            .await
191    }
192}