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