soma_mcp_client/upstream/pool/
resources.rs1use crate::upstream::{
2 CapScope, McpRequestOutcome, McpRoundTrip, ResourceDescriptor, UpstreamError,
3};
4
5use super::tools::matches_filter;
6
7impl super::UpstreamPool {
8 pub async fn list_resources(
9 &self,
10 upstream: &str,
11 ) -> Result<Vec<ResourceDescriptor>, UpstreamError> {
12 self.ensure_connected(upstream).await?;
13 self.with_entry(upstream, |entry| {
14 if !entry.config.proxy_resources {
15 return Ok(Vec::new());
16 }
17 let resources: Vec<ResourceDescriptor> = entry
18 .snapshot
19 .resources
20 .iter()
21 .filter(|resource| {
22 matches_filter(entry.config.expose_resources.as_deref(), &resource.uri)
23 })
24 .cloned()
25 .collect();
26 let bytes = serde_json::to_vec(&resources).map_or(usize::MAX, |bytes| bytes.len());
27 self.response_caps()
28 .enforce(CapScope::ResourcesList, bytes)?;
29 Ok(resources)
30 })
31 }
32
33 pub async fn read_resource(
34 &self,
35 upstream: &str,
36 uri: &str,
37 ) -> Result<serde_json::Value, UpstreamError> {
38 self.ensure_connected(upstream).await?;
39 let peer =
40 self.with_entry(upstream, |entry| {
41 if !entry.config.proxy_resources {
42 return Err(UpstreamError::Unsupported {
43 upstream: upstream.to_owned(),
44 capability: "resources/read",
45 });
46 }
47 entry.live.as_ref().map(|live| live.peer()).ok_or_else(|| {
48 UpstreamError::Unsupported {
49 upstream: upstream.to_owned(),
50 capability: "resources/read",
51 }
52 })
53 })?;
54 let value = super::live::read_live_resource(upstream, peer, uri.to_owned()).await?;
55 let bytes = serde_json::to_vec(&value).map_or(usize::MAX, |bytes| bytes.len());
56 self.response_caps()
57 .enforce(CapScope::ResourcesRead, bytes)?;
58 Ok(value)
59 }
60
61 pub async fn read_resource_once(
62 &self,
63 upstream: &str,
64 uri: &str,
65 round_trip: McpRoundTrip,
66 ) -> Result<McpRequestOutcome, UpstreamError> {
67 self.ensure_connected(upstream).await?;
68 let peer =
69 self.with_entry(upstream, |entry| {
70 if !entry.config.proxy_resources {
71 return Err(UpstreamError::Unsupported {
72 upstream: upstream.to_owned(),
73 capability: "resources/read",
74 });
75 }
76 entry.live.as_ref().map(|live| live.peer()).ok_or_else(|| {
77 UpstreamError::Unsupported {
78 upstream: upstream.to_owned(),
79 capability: "resources/read",
80 }
81 })
82 })?;
83 let outcome =
84 super::live::read_live_resource_once(upstream, peer, uri.to_owned(), round_trip)
85 .await?;
86 let bytes = serde_json::to_vec(outcome.payload()).map_or(usize::MAX, |bytes| bytes.len());
87 self.response_caps()
88 .enforce(CapScope::ResourcesRead, bytes)?;
89 Ok(outcome)
90 }
91}
92
93#[cfg(test)]
94#[path = "resources_tests.rs"]
95mod tests;