Skip to main content

codex_tools/
mcp_tool.rs

1use crate::ToolDefinition;
2use crate::parse_tool_input_schema;
3use serde_json::Value as JsonValue;
4use serde_json::json;
5
6pub fn parse_mcp_tool(tool: &rmcp::model::Tool) -> Result<ToolDefinition, serde_json::Error> {
7    let mut serialized_input_schema = serde_json::Value::Object(tool.input_schema.as_ref().clone());
8
9    // OpenAI models mandate the "properties" field in the schema. Some MCP
10    // servers omit it (or set it to null), so we insert an empty object to
11    // match the behavior of the Agents SDK.
12    if let serde_json::Value::Object(obj) = &mut serialized_input_schema
13        && obj.get("properties").is_none_or(serde_json::Value::is_null)
14    {
15        obj.insert(
16            "properties".to_string(),
17            serde_json::Value::Object(serde_json::Map::new()),
18        );
19    }
20
21    let input_schema = parse_tool_input_schema(&serialized_input_schema)?;
22    let structured_content_schema = tool
23        .output_schema
24        .as_ref()
25        .map(|output_schema| serde_json::Value::Object(output_schema.as_ref().clone()))
26        .unwrap_or_else(|| JsonValue::Object(serde_json::Map::new()));
27
28    Ok(ToolDefinition {
29        name: tool.name.to_string(),
30        description: tool.description.clone().map(Into::into).unwrap_or_default(),
31        input_schema,
32        output_schema: Some(mcp_call_tool_result_output_schema(
33            structured_content_schema,
34        )),
35        defer_loading: false,
36    })
37}
38
39pub fn mcp_call_tool_result_output_schema(structured_content_schema: JsonValue) -> JsonValue {
40    json!({
41        "type": "object",
42        "properties": {
43            "content": {
44                "type": "array",
45                "items": {
46                    "type": "object"
47                }
48            },
49            "structuredContent": structured_content_schema,
50            "isError": {
51                "type": "boolean"
52            },
53            "_meta": {
54                "type": "object"
55            }
56        },
57        "required": ["content"],
58        "additionalProperties": false
59    })
60}
61
62#[cfg(test)]
63#[path = "mcp_tool_tests.rs"]
64mod tests;