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}