Skip to content

Commit e00aaa9

Browse files
committed
Fix cargo fmt
1 parent 2d387d3 commit e00aaa9

1 file changed

Lines changed: 183 additions & 2 deletions

File tree

crates/runtime/src/toolclad/executor.rs

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ impl ToolCladExecutor {
239239

240240
// Interpolate URL with args and secrets
241241
let url = interpolate(&http.url, validated);
242-
let url =
243-
super::template_vars::inject_secrets(&url).map_err(|e| format!("URL secret error: {}", e))?;
242+
let url = super::template_vars::inject_secrets(&url)
243+
.map_err(|e| format!("URL secret error: {}", e))?;
244244

245245
// Interpolate headers with secrets
246246
let mut headers = Vec::new();
@@ -1215,4 +1215,185 @@ type = "object"
12151215
"2.5.0"
12161216
);
12171217
}
1218+
1219+
// ---- MCP Proxy Tests ----
1220+
1221+
#[test]
1222+
fn test_mcp_proxy_tool_def_generation() {
1223+
let manifest: Manifest = toml::from_str(
1224+
r#"
1225+
[tool]
1226+
name = "governed_search"
1227+
version = "1.0.0"
1228+
description = "Search via governed MCP proxy"
1229+
1230+
[args.query]
1231+
position = 1
1232+
required = true
1233+
type = "string"
1234+
description = "Search query"
1235+
1236+
[args.max_results]
1237+
position = 2
1238+
required = false
1239+
type = "integer"
1240+
description = "Maximum results to return"
1241+
default = 10
1242+
1243+
[mcp]
1244+
server = "brave-search"
1245+
tool = "brave_web_search"
1246+
1247+
[mcp.field_map]
1248+
query = "q"
1249+
max_results = "count"
1250+
1251+
[output]
1252+
format = "json"
1253+
1254+
[output.schema]
1255+
type = "object"
1256+
"#,
1257+
)
1258+
.unwrap();
1259+
let td = generate_oneshot_tool_def(&manifest);
1260+
assert_eq!(td.name, "governed_search");
1261+
assert_eq!(td.description, "Search via governed MCP proxy");
1262+
let props = td.parameters["properties"].as_object().unwrap();
1263+
assert!(props.contains_key("query"));
1264+
assert!(props.contains_key("max_results"));
1265+
let required = td.parameters["required"].as_array().unwrap();
1266+
assert!(required.contains(&serde_json::json!("query")));
1267+
}
1268+
1269+
#[test]
1270+
fn test_mcp_proxy_execution_returns_delegated_envelope() {
1271+
let manifest: Manifest = toml::from_str(
1272+
r#"
1273+
[tool]
1274+
name = "governed_search"
1275+
version = "1.0.0"
1276+
description = "Search via governed MCP proxy"
1277+
1278+
[args.query]
1279+
position = 1
1280+
required = true
1281+
type = "string"
1282+
description = "Search query"
1283+
1284+
[mcp]
1285+
server = "brave-search"
1286+
tool = "brave_web_search"
1287+
1288+
[mcp.field_map]
1289+
query = "q"
1290+
1291+
[output]
1292+
format = "json"
1293+
1294+
[output.schema]
1295+
type = "object"
1296+
"#,
1297+
)
1298+
.unwrap();
1299+
1300+
let executor =
1301+
ToolCladExecutor::new(vec![("governed_search".to_string(), manifest.clone())]);
1302+
1303+
let mut args = HashMap::new();
1304+
args.insert("query".to_string(), "rust async".to_string());
1305+
let result = executor
1306+
.execute_mcp_backend("governed_search", &manifest, &args)
1307+
.unwrap();
1308+
1309+
assert_eq!(result["status"], "delegated");
1310+
assert_eq!(result["tool"], "governed_search");
1311+
assert_eq!(result["mcp_server"], "brave-search");
1312+
assert_eq!(result["mcp_tool"], "brave_web_search");
1313+
assert_eq!(result["exit_code"], 0);
1314+
1315+
// Check that field mapping was applied
1316+
let mcp_args = &result["mcp_arguments"];
1317+
assert_eq!(mcp_args["q"], "rust async");
1318+
}
1319+
1320+
#[test]
1321+
fn test_mcp_proxy_field_map_passthrough() {
1322+
let manifest: Manifest = toml::from_str(
1323+
r#"
1324+
[tool]
1325+
name = "passthrough"
1326+
version = "1.0.0"
1327+
description = "Direct passthrough"
1328+
1329+
[args.input]
1330+
position = 1
1331+
required = true
1332+
type = "string"
1333+
description = "Input value"
1334+
1335+
[mcp]
1336+
server = "my-server"
1337+
tool = "upstream_tool"
1338+
1339+
[output]
1340+
format = "json"
1341+
1342+
[output.schema]
1343+
type = "object"
1344+
"#,
1345+
)
1346+
.unwrap();
1347+
1348+
let executor = ToolCladExecutor::new(vec![("passthrough".to_string(), manifest.clone())]);
1349+
1350+
let mut args = HashMap::new();
1351+
args.insert("input".to_string(), "hello".to_string());
1352+
let result = executor
1353+
.execute_mcp_backend("passthrough", &manifest, &args)
1354+
.unwrap();
1355+
1356+
// No field_map, so "input" stays as "input" in upstream args
1357+
let mcp_args = &result["mcp_arguments"];
1358+
assert_eq!(mcp_args["input"], "hello");
1359+
}
1360+
1361+
#[test]
1362+
fn test_mcp_proxy_dispatch_via_execute_tool() {
1363+
let manifest: Manifest = toml::from_str(
1364+
r#"
1365+
[tool]
1366+
name = "mcp_tool"
1367+
version = "1.0.0"
1368+
description = "MCP proxy tool"
1369+
1370+
[args.query]
1371+
position = 1
1372+
required = true
1373+
type = "string"
1374+
description = "Query"
1375+
1376+
[mcp]
1377+
server = "test-server"
1378+
tool = "test_tool"
1379+
1380+
[output]
1381+
format = "json"
1382+
1383+
[output.schema]
1384+
type = "object"
1385+
"#,
1386+
)
1387+
.unwrap();
1388+
1389+
let executor = ToolCladExecutor::new(vec![("mcp_tool".to_string(), manifest)]);
1390+
1391+
let result = executor
1392+
.execute_tool("mcp_tool", r#"{"query": "test"}"#)
1393+
.unwrap();
1394+
1395+
assert_eq!(result["status"], "delegated");
1396+
assert_eq!(result["mcp_server"], "test-server");
1397+
assert_eq!(result["mcp_tool"], "test_tool");
1398+
}
12181399
}

0 commit comments

Comments
 (0)