turbomcp_client/client/operations/
resources.rs

1//! Resource operations for MCP client
2//!
3//! This module provides resource-related functionality including listing resources,
4//! reading resource content, and managing resource templates.
5
6use std::sync::atomic::Ordering;
7
8use turbomcp_protocol::types::{
9    ListResourceTemplatesResult, ListResourcesResult, ReadResourceRequest, ReadResourceResult,
10};
11use turbomcp_protocol::{Error, Result};
12
13impl<T: turbomcp_transport::Transport + 'static> super::super::core::Client<T> {
14    /// List available resources from the MCP server
15    ///
16    /// Returns a list of resource URIs that are available for reading.
17    /// Resources represent data or content that can be accessed by the client.
18    ///
19    /// # Returns
20    ///
21    /// Returns a vector of resource URIs that can be read using `read_resource()`.
22    ///
23    /// # Errors
24    ///
25    /// Returns an error if:
26    /// - The client is not initialized
27    /// - The server doesn't support resources
28    /// - The request fails
29    ///
30    /// # Examples
31    ///
32    /// ```rust,no_run
33    /// # use turbomcp_client::Client;
34    /// # use turbomcp_transport::stdio::StdioTransport;
35    /// # async fn example() -> turbomcp_protocol::Result<()> {
36    /// let mut client = Client::new(StdioTransport::new());
37    /// client.initialize().await?;
38    ///
39    /// let resources = client.list_resources().await?;
40    /// for resource in resources {
41    ///     println!("Available resource: {}", resource);
42    /// }
43    /// # Ok(())
44    /// # }
45    /// ```
46    pub async fn list_resources(&self) -> Result<Vec<String>> {
47        if !self.inner.initialized.load(Ordering::Relaxed) {
48            return Err(Error::bad_request("Client not initialized"));
49        }
50
51        // Execute with plugin middleware
52        let response: ListResourcesResult =
53            self.execute_with_plugins("resources/list", None).await?;
54
55        let resource_uris = response
56            .resources
57            .into_iter()
58            .map(|resource| resource.uri)
59            .collect();
60        Ok(resource_uris)
61    }
62
63    /// Read the content of a specific resource by URI
64    ///
65    /// Retrieves the content of a resource identified by its URI.
66    /// Resources can contain text, binary data, or structured content.
67    ///
68    /// # Arguments
69    ///
70    /// * `uri` - The URI of the resource to read
71    ///
72    /// # Returns
73    ///
74    /// Returns `ReadResourceResult` containing the resource content and metadata.
75    ///
76    /// # Errors
77    ///
78    /// Returns an error if:
79    /// - The client is not initialized
80    /// - The URI is empty or invalid
81    /// - The resource doesn't exist
82    /// - Access to the resource is denied
83    ///
84    /// # Examples
85    ///
86    /// ```rust,no_run
87    /// # use turbomcp_client::Client;
88    /// # use turbomcp_transport::stdio::StdioTransport;
89    /// # async fn example() -> turbomcp_protocol::Result<()> {
90    /// let mut client = Client::new(StdioTransport::new());
91    /// client.initialize().await?;
92    ///
93    /// let result = client.read_resource("file:///path/to/document.txt").await?;
94    /// for content in result.contents {
95    ///     println!("Resource content: {:?}", content);
96    /// }
97    /// # Ok(())
98    /// # }
99    /// ```
100    pub async fn read_resource(&self, uri: &str) -> Result<ReadResourceResult> {
101        if !self.inner.initialized.load(Ordering::Relaxed) {
102            return Err(Error::bad_request("Client not initialized"));
103        }
104
105        if uri.is_empty() {
106            return Err(Error::bad_request("Resource URI cannot be empty"));
107        }
108
109        // Send read_resource request
110        let request = ReadResourceRequest {
111            uri: uri.to_string(),
112            _meta: None,
113        };
114
115        let response: ReadResourceResult = self
116            .execute_with_plugins("resources/read", Some(serde_json::to_value(request)?))
117            .await?;
118        Ok(response)
119    }
120
121    /// List available resource templates from the MCP server
122    ///
123    /// Returns a list of resource template URIs that define patterns for
124    /// generating resource URIs. Templates allow servers to describe
125    /// families of related resources without listing each individual resource.
126    ///
127    /// # Returns
128    ///
129    /// Returns a vector of resource template URI patterns.
130    ///
131    /// # Errors
132    ///
133    /// Returns an error if:
134    /// - The client is not initialized
135    /// - The server doesn't support resource templates
136    /// - The request fails
137    ///
138    /// # Examples
139    ///
140    /// ```rust,no_run
141    /// # use turbomcp_client::Client;
142    /// # use turbomcp_transport::stdio::StdioTransport;
143    /// # async fn example() -> turbomcp_protocol::Result<()> {
144    /// let mut client = Client::new(StdioTransport::new());
145    /// client.initialize().await?;
146    ///
147    /// let templates = client.list_resource_templates().await?;
148    /// for template in templates {
149    ///     println!("Resource template: {}", template);
150    /// }
151    /// # Ok(())
152    /// # }
153    /// ```
154    pub async fn list_resource_templates(&self) -> Result<Vec<String>> {
155        if !self.inner.initialized.load(Ordering::Relaxed) {
156            return Err(Error::bad_request("Client not initialized"));
157        }
158
159        // Send resources/templates request with plugin middleware
160        let response: ListResourceTemplatesResult = self
161            .execute_with_plugins("resources/templates", None)
162            .await?;
163        let template_uris = response
164            .resource_templates
165            .into_iter()
166            .map(|template| template.uri_template)
167            .collect();
168        Ok(template_uris)
169    }
170}