Skip to main content

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

1//! `agents mcp resources` — call the per-`response_id` MCP listener's
2//! resource ops over its local socket. Subcommands:
3//!
4//! - `list --response-id <id> --params <json>` — `resources/list`.
5//! - `read --response-id <id> --params <json>` — `resources/read`.
6//!
7//! `--params` is the strongly typed MCP request body supplied as a
8//! JSON string; the command returns the MCP result.
9
10use crate::cli::command::CommandRequest;
11
12pub mod list;
13pub mod read;
14
15#[derive(clap::Subcommand)]
16pub enum Command {
17    /// Invoke `resources/list` against the agent's MCP aggregation.
18    List(list::Command),
19    /// Invoke `resources/read` against the agent's MCP aggregation.
20    Read(read::Command),
21}
22
23#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
24#[serde(untagged)]
25#[schemars(rename = "cli.command.agents.mcp.resources.Request")]
26pub enum Request {
27    #[schemars(title = "List")]
28    List(list::Request),
29    #[schemars(title = "ListRequestSchema")]
30    ListRequestSchema(list::request_schema::Request),
31    #[schemars(title = "ListResponseSchema")]
32    ListResponseSchema(list::response_schema::Request),
33    #[schemars(title = "Read")]
34    Read(read::Request),
35    #[schemars(title = "ReadRequestSchema")]
36    ReadRequestSchema(read::request_schema::Request),
37    #[schemars(title = "ReadResponseSchema")]
38    ReadResponseSchema(read::response_schema::Request),
39}
40
41// Exempt from json-schema coverage: tier aggregate (see the root
42// `ResponseItem` in command.rs - TS7056).
43#[objectiveai_sdk_macros::json_schema_ignore]
44#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
45#[schemars(rename = "cli.command.agents.mcp.resources.ResponseItem")]
46#[serde(untagged)]
47pub enum ResponseItem {
48    #[schemars(title = "List")]
49    List(list::Response),
50    #[schemars(title = "ListRequestSchema")]
51    ListRequestSchema(list::request_schema::Response),
52    #[schemars(title = "ListResponseSchema")]
53    ListResponseSchema(list::response_schema::Response),
54    #[schemars(title = "Read")]
55    Read(read::Response),
56    #[schemars(title = "ReadRequestSchema")]
57    ReadRequestSchema(read::request_schema::Response),
58    #[schemars(title = "ReadResponseSchema")]
59    ReadResponseSchema(read::response_schema::Response),
60}
61
62#[cfg(feature = "mcp")]
63impl crate::cli::command::CommandResponse for ResponseItem {
64    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
65        match self {
66            ResponseItem::List(v) => v.into_mcp(),
67            ResponseItem::ListRequestSchema(v) => v.into_mcp(),
68            ResponseItem::ListResponseSchema(v) => v.into_mcp(),
69            ResponseItem::Read(v) => v.into_mcp(),
70            ResponseItem::ReadRequestSchema(v) => v.into_mcp(),
71            ResponseItem::ReadResponseSchema(v) => v.into_mcp(),
72        }
73    }
74}
75
76impl TryFrom<Command> for Request {
77    type Error = crate::cli::command::FromArgsError;
78    fn try_from(command: Command) -> Result<Self, Self::Error> {
79        match command {
80            Command::List(cmd) => match cmd.schema {
81                None => Ok(Request::List(list::Request::try_from(cmd.args)?)),
82                Some(list::Schema::RequestSchema(args)) => Ok(
83                    Request::ListRequestSchema(list::request_schema::Request::try_from(args)?),
84                ),
85                Some(list::Schema::ResponseSchema(args)) => Ok(
86                    Request::ListResponseSchema(list::response_schema::Request::try_from(args)?),
87                ),
88            },
89            Command::Read(cmd) => match cmd.schema {
90                None => Ok(Request::Read(read::Request::try_from(cmd.args)?)),
91                Some(read::Schema::RequestSchema(args)) => Ok(
92                    Request::ReadRequestSchema(read::request_schema::Request::try_from(args)?),
93                ),
94                Some(read::Schema::ResponseSchema(args)) => Ok(
95                    Request::ReadResponseSchema(read::response_schema::Request::try_from(args)?),
96                ),
97            },
98        }
99    }
100}
101
102impl CommandRequest for Request {
103    fn request_base(&self) -> &crate::cli::command::RequestBase {
104        match self {
105            Request::List(inner) => inner.request_base(),
106            Request::ListRequestSchema(inner) => inner.request_base(),
107            Request::ListResponseSchema(inner) => inner.request_base(),
108            Request::Read(inner) => inner.request_base(),
109            Request::ReadRequestSchema(inner) => inner.request_base(),
110            Request::ReadResponseSchema(inner) => inner.request_base(),
111        }
112    }
113
114    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
115        match self {
116            Request::List(inner) => inner.request_base_mut(),
117            Request::ListRequestSchema(inner) => inner.request_base_mut(),
118            Request::ListResponseSchema(inner) => inner.request_base_mut(),
119            Request::Read(inner) => inner.request_base_mut(),
120            Request::ReadRequestSchema(inner) => inner.request_base_mut(),
121            Request::ReadResponseSchema(inner) => inner.request_base_mut(),
122        }
123    }
124}
125
126#[cfg(feature = "cli-executor")]
127pub async fn execute<E: crate::cli::command::CommandExecutor>(
128    executor: &E,
129    request: Request,
130    agent_arguments: Option<&crate::cli::command::AgentArguments>,
131) -> Result<
132    std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>>,
133    E::Error,
134> {
135    let stream: std::pin::Pin<
136        Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>,
137    > = match request {
138        Request::List(req) => {
139            let value = list::execute(executor, req, agent_arguments).await?;
140            Box::pin(crate::cli::command::StreamOnce::new(Ok(
141                ResponseItem::List(value),
142            )))
143        }
144        Request::ListRequestSchema(req) => {
145            let value =
146                list::request_schema::execute(executor, req, agent_arguments).await?;
147            Box::pin(crate::cli::command::StreamOnce::new(Ok(
148                ResponseItem::ListRequestSchema(value),
149            )))
150        }
151        Request::ListResponseSchema(req) => {
152            let value =
153                list::response_schema::execute(executor, req, agent_arguments).await?;
154            Box::pin(crate::cli::command::StreamOnce::new(Ok(
155                ResponseItem::ListResponseSchema(value),
156            )))
157        }
158        Request::Read(req) => {
159            let value = read::execute(executor, req, agent_arguments).await?;
160            Box::pin(crate::cli::command::StreamOnce::new(Ok(
161                ResponseItem::Read(value),
162            )))
163        }
164        Request::ReadRequestSchema(req) => {
165            let value =
166                read::request_schema::execute(executor, req, agent_arguments).await?;
167            Box::pin(crate::cli::command::StreamOnce::new(Ok(
168                ResponseItem::ReadRequestSchema(value),
169            )))
170        }
171        Request::ReadResponseSchema(req) => {
172            let value =
173                read::response_schema::execute(executor, req, agent_arguments).await?;
174            Box::pin(crate::cli::command::StreamOnce::new(Ok(
175                ResponseItem::ReadResponseSchema(value),
176            )))
177        }
178    };
179    Ok(stream)
180}
181
182#[cfg(feature = "cli-executor")]
183pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
184    executor: &E,
185    request: Request,
186    transform: crate::cli::command::Transform,
187    agent_arguments: Option<&crate::cli::command::AgentArguments>,
188) -> Result<
189    std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>>,
190    E::Error,
191> {
192    let stream: std::pin::Pin<
193        Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>,
194    > = match request {
195        Request::List(req) => {
196            let value = list::execute_transform(executor, req, transform, agent_arguments).await?;
197            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
198        }
199        Request::ListRequestSchema(req) => {
200            let value =
201                list::request_schema::execute_transform(executor, req, transform, agent_arguments).await?;
202            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
203        }
204        Request::ListResponseSchema(req) => {
205            let value =
206                list::response_schema::execute_transform(executor, req, transform, agent_arguments).await?;
207            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
208        }
209        Request::Read(req) => {
210            let value = read::execute_transform(executor, req, transform, agent_arguments).await?;
211            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
212        }
213        Request::ReadRequestSchema(req) => {
214            let value =
215                read::request_schema::execute_transform(executor, req, transform, agent_arguments).await?;
216            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
217        }
218        Request::ReadResponseSchema(req) => {
219            let value =
220                read::response_schema::execute_transform(executor, req, transform, agent_arguments).await?;
221            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
222        }
223    };
224    Ok(stream)
225}
226
227/// `/listen` mirror of [`Request`]: one variant per child, wrapping
228/// its `ListenerExecution`. See [`crate::cli::websocket_listener`].
229#[cfg(feature = "cli-listener")]
230pub enum ListenerExecution {
231    List(list::ListenerExecution),
232    ListRequestSchema(list::request_schema::ListenerExecution),
233    ListResponseSchema(list::response_schema::ListenerExecution),
234    Read(read::ListenerExecution),
235    ReadRequestSchema(read::request_schema::ListenerExecution),
236    ReadResponseSchema(read::response_schema::ListenerExecution),
237}