1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
use libmcp::{JsonPorcelainConfig, RenderMode, render_json_porcelain};
use serde::Serialize;
use serde_json::{Map, Value, json};
use crate::mcp::fault::{FaultKind, FaultRecord, FaultStage};
pub(crate) fn split_render_mode(
arguments: Value,
operation: &str,
stage: FaultStage,
) -> Result<(RenderMode, Value), FaultRecord> {
let Value::Object(mut object) = arguments else {
return Ok((RenderMode::Porcelain, arguments));
};
let render = object
.remove("render")
.map(|value| {
serde_json::from_value::<RenderMode>(value).map_err(|error| {
FaultRecord::new(
FaultKind::InvalidInput,
stage,
operation,
format!("invalid render mode: {error}"),
)
})
})
.transpose()?
.unwrap_or(RenderMode::Porcelain);
Ok((render, Value::Object(object)))
}
pub(crate) fn tool_success(
value: &impl Serialize,
render: RenderMode,
stage: FaultStage,
operation: &str,
) -> Result<Value, FaultRecord> {
let structured = serde_json::to_value(value).map_err(|error| {
FaultRecord::new(FaultKind::Internal, stage, operation, error.to_string())
})?;
tool_success_from_value(structured, render, stage, operation)
}
pub(crate) fn tool_success_from_value(
structured: Value,
render: RenderMode,
stage: FaultStage,
operation: &str,
) -> Result<Value, FaultRecord> {
let text = match render {
RenderMode::Porcelain => render_json_porcelain(&structured, JsonPorcelainConfig::default()),
RenderMode::Json => crate::to_pretty_json(&structured).map_err(|error| {
FaultRecord::new(FaultKind::Internal, stage, operation, error.to_string())
})?,
};
Ok(json!({
"content": [{
"type": "text",
"text": text,
}],
"structuredContent": structured,
"isError": false,
}))
}
pub(crate) fn with_render_property(schema: Value) -> Value {
let Value::Object(mut object) = schema else {
return schema;
};
let properties = object
.entry("properties".to_owned())
.or_insert_with(|| Value::Object(Map::new()));
if let Value::Object(properties) = properties {
let _ = properties.insert(
"render".to_owned(),
json!({
"type": "string",
"enum": ["porcelain", "json"],
"description": "Output mode. Defaults to porcelain for model-friendly summaries."
}),
);
}
let _ = object
.entry("additionalProperties".to_owned())
.or_insert(Value::Bool(false));
Value::Object(object)
}
|