mcp_utils/client/
options.rs1use super::{Elicitation, ElicitationSink};
2use aether_auth::OAuthCredentialStorage;
3use rmcp::model::{ClientCapabilities, ClientConfig, Implementation};
4use std::sync::Arc;
5use tokio::sync::mpsc;
6
7#[derive(Clone)]
8pub struct ClientOptions {
9 pub(super) implementation: Implementation,
10 pub(super) elicitation: Option<ElicitationSink>,
11 pub(super) oauth_store: Option<Arc<dyn OAuthCredentialStorage>>,
12 tasks: bool,
13}
14
15impl Default for ClientOptions {
16 fn default() -> Self {
17 Self {
18 implementation: Implementation::new(env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")),
19 elicitation: None,
20 oauth_store: None,
21 tasks: true,
22 }
23 }
24}
25
26impl ClientOptions {
27 pub fn implementation(mut self, implementation: Implementation) -> Self {
28 self.implementation = implementation;
29 self
30 }
31
32 pub fn elicitation(mut self, sink: ElicitationSink) -> Self {
33 self.elicitation = Some(sink);
34 self
35 }
36
37 pub fn oauth_store(mut self, store: Arc<dyn OAuthCredentialStorage>) -> Self {
38 self.oauth_store = Some(store);
39 self
40 }
41
42 #[cfg(any(test, feature = "testing"))]
43 pub fn without_tasks(mut self) -> Self {
44 self.tasks = false;
45 self
46 }
47
48 pub(super) fn client_config(&self) -> ClientConfig {
49 let mut capabilities = if self.tasks {
50 ClientCapabilities::builder().enable_tasks().build()
51 } else {
52 ClientCapabilities::default()
53 };
54 capabilities.elicitation = self
55 .elicitation
56 .as_ref()
57 .map(|sink| sink.capability.clone())
58 .filter(|capability| capability.form.is_some() || capability.url.is_some());
59 ClientConfig::new(capabilities, self.implementation.clone())
60 }
61
62 pub(super) fn elicitations(&self) -> Option<&mpsc::Sender<Elicitation>> {
63 self.elicitation.as_ref().map(|sink| &sink.events)
64 }
65
66 pub(super) fn oauth_prompts(&self) -> Option<&mpsc::Sender<Elicitation>> {
67 self.elicitation.as_ref().filter(|sink| sink.capability.url.is_some()).map(|sink| &sink.events)
68 }
69}