Skip to main content

objectiveai_sdk/cli/command/agents/mcp/servers/
mod.rs

1//! `agents mcp servers` — list the upstream MCP servers connected for a live
2//! agent's `response_id`. Subcommands:
3//!
4//! - `list --response-id <id>` — `servers/list` (proxy-local aggregate).
5
6use crate::cli::command::CommandRequest;
7
8pub mod list;
9
10#[derive(clap::Subcommand)]
11pub enum Command {
12    /// List the agent's connected MCP servers and their metadata.
13    List(list::Command),
14}
15
16#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
17#[serde(untagged)]
18#[schemars(rename = "cli.command.agents.mcp.servers.Request")]
19pub enum Request {
20    #[schemars(title = "List")]
21    List(list::Request),
22    #[schemars(title = "ListRequestSchema")]
23    ListRequestSchema(list::request_schema::Request),
24    #[schemars(title = "ListResponseSchema")]
25    ListResponseSchema(list::response_schema::Request),
26}
27
28// Exempt from json-schema coverage: tier aggregate (see the root
29// `ResponseItem` in command.rs - TS7056).
30#[objectiveai_sdk_macros::json_schema_ignore]
31#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
32#[schemars(rename = "cli.command.agents.mcp.servers.ResponseItem")]
33#[serde(untagged)]
34pub enum ResponseItem {
35    #[schemars(title = "List")]
36    List(list::Response),
37    #[schemars(title = "ListRequestSchema")]
38    ListRequestSchema(list::request_schema::Response),
39    #[schemars(title = "ListResponseSchema")]
40    ListResponseSchema(list::response_schema::Response),
41}
42
43#[cfg(feature = "mcp")]
44impl crate::cli::command::CommandResponse for ResponseItem {
45    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
46        match self {
47            ResponseItem::List(v) => v.into_mcp(),
48            ResponseItem::ListRequestSchema(v) => v.into_mcp(),
49            ResponseItem::ListResponseSchema(v) => v.into_mcp(),
50        }
51    }
52}
53
54impl TryFrom<Command> for Request {
55    type Error = crate::cli::command::FromArgsError;
56    fn try_from(command: Command) -> Result<Self, Self::Error> {
57        match command {
58            Command::List(cmd) => match cmd.schema {
59                None => Ok(Request::List(list::Request::try_from(cmd.args)?)),
60                Some(list::Schema::RequestSchema(args)) => Ok(
61                    Request::ListRequestSchema(list::request_schema::Request::try_from(args)?),
62                ),
63                Some(list::Schema::ResponseSchema(args)) => Ok(
64                    Request::ListResponseSchema(list::response_schema::Request::try_from(args)?),
65                ),
66            },
67        }
68    }
69}
70
71impl CommandRequest for Request {
72    fn request_base(&self) -> &crate::cli::command::RequestBase {
73        match self {
74            Request::List(inner) => inner.request_base(),
75            Request::ListRequestSchema(inner) => inner.request_base(),
76            Request::ListResponseSchema(inner) => inner.request_base(),
77        }
78    }
79
80    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
81        match self {
82            Request::List(inner) => inner.request_base_mut(),
83            Request::ListRequestSchema(inner) => inner.request_base_mut(),
84            Request::ListResponseSchema(inner) => inner.request_base_mut(),
85        }
86    }
87}
88
89#[cfg(feature = "cli-executor")]
90pub async fn execute<E: crate::cli::command::CommandExecutor>(
91    executor: &E,
92    request: Request,
93    agent_arguments: Option<&crate::cli::command::AgentArguments>,
94) -> Result<
95    std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>>,
96    E::Error,
97> {
98    let stream: std::pin::Pin<
99        Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>,
100    > = match request {
101        Request::List(req) => {
102            let value = list::execute(executor, req, agent_arguments).await?;
103            Box::pin(crate::cli::command::StreamOnce::new(Ok(
104                ResponseItem::List(value),
105            )))
106        }
107        Request::ListRequestSchema(req) => {
108            let value = list::request_schema::execute(executor, req, agent_arguments).await?;
109            Box::pin(crate::cli::command::StreamOnce::new(Ok(
110                ResponseItem::ListRequestSchema(value),
111            )))
112        }
113        Request::ListResponseSchema(req) => {
114            let value = list::response_schema::execute(executor, req, agent_arguments).await?;
115            Box::pin(crate::cli::command::StreamOnce::new(Ok(
116                ResponseItem::ListResponseSchema(value),
117            )))
118        }
119    };
120    Ok(stream)
121}
122
123#[cfg(feature = "cli-executor")]
124pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
125    executor: &E,
126    request: Request,
127    transform: crate::cli::command::Transform,
128    agent_arguments: Option<&crate::cli::command::AgentArguments>,
129) -> Result<
130    std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>>,
131    E::Error,
132> {
133    let stream: std::pin::Pin<
134        Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>,
135    > = match request {
136        Request::List(req) => {
137            let value = list::execute_transform(executor, req, transform, agent_arguments).await?;
138            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
139        }
140        Request::ListRequestSchema(req) => {
141            let value =
142                list::request_schema::execute_transform(executor, req, transform, agent_arguments).await?;
143            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
144        }
145        Request::ListResponseSchema(req) => {
146            let value =
147                list::response_schema::execute_transform(executor, req, transform, agent_arguments).await?;
148            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
149        }
150    };
151    Ok(stream)
152}
153
154/// `/listen` mirror of [`Request`]: one variant per child, wrapping
155/// its `ListenerExecution`. See [`crate::cli::websocket_listener`].
156#[cfg(feature = "cli-listener")]
157pub enum ListenerExecution {
158    List(list::ListenerExecution),
159    ListRequestSchema(list::request_schema::ListenerExecution),
160    ListResponseSchema(list::response_schema::ListenerExecution),
161}