haematite_cli/mcp/
stdio_error.rs1use super::{USAGE, adapter, rpc};
2use crate::client;
3use std::{fmt, io};
4
5#[derive(Debug)]
6pub enum RelayError {
7 Input(io::Error),
8 ReceiptOutput {
9 cause: io::Error,
10 response: Vec<u8>,
11 },
12 ResultEncoding {
13 refusal: rpc::Refusal,
14 result: adapter::ToolResult,
15 },
16 Encoding(serde_json::Error),
17 Adapter(adapter::EncodeError),
18 Arguments(&'static str),
19 ConfigRead(io::Error),
20 ConfigDecode(serde_json::Error),
21 Runtime(crate::serve::runtime::Refusal),
22 SocketCap(client::Ended),
23 CapNotRepresentable,
24}
25
26impl fmt::Display for RelayError {
27 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
28 let code = match self {
30 Self::Input(_) => "mcp_input_read_failed",
31 Self::ReceiptOutput { .. } => "mcp_output_write_failed",
32 Self::ResultEncoding { .. } | Self::Encoding(_) => "mcp_response_encoding_failed",
33 Self::Adapter(_) => "mcp_result_encoding_failed",
34 Self::Arguments(why) => {
35 return write!(formatter, "mcp_arguments_invalid: {why}; {USAGE}");
36 }
37 Self::ConfigRead(_) => "mcp_config_read_failed",
38 Self::ConfigDecode(_) => "mcp_config_invalid",
39 Self::Runtime(error) => return fmt::Display::fmt(error, formatter),
40 Self::SocketCap(_) => "mcp_socket_cap_unavailable",
41 Self::CapNotRepresentable => "mcp_frame_cap_unrepresentable",
42 };
43 formatter.write_str(code)
44 }
45}
46
47impl std::error::Error for RelayError {
48 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
49 match self {
50 Self::Input(error) | Self::ConfigRead(error) => Some(error),
51 Self::Encoding(error) | Self::ConfigDecode(error) => Some(error),
52 Self::Adapter(error) => Some(error),
53 Self::Runtime(error) => Some(error),
54 Self::ReceiptOutput { cause, .. } => Some(cause),
55 Self::ResultEncoding { .. }
56 | Self::Arguments(_)
57 | Self::SocketCap(_)
58 | Self::CapNotRepresentable => None,
59 }
60 }
61}