mcp: the probe tool takes at, points whose nearest nodes are probed (#105)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01UhhZMBTviDQxZvwnyP89fo
This commit is contained in:
jyvikoandClaude Opus 5.5 authored and Irakli Kourtis committed 2026-10-15 11:07:46 -04:00
1 parent 5aace9b5b3
commit 92b6225a72
3 files changed
+20 -3

No files matched your search

+16
View File
@@ -224,6 +224,22 @@ fn screenshot_takes_a_camera_orientation() {
assert_eq!(again, turned);
}
/// `probe {at}` reads a structural result at the nodes nearest to points (#105); hostile points
/// are refused without a panic.
#[test]
fn probe_takes_points_at() {
let mut s = server();
ok(&mut s, "execute", json!({"command": "file.sample", "params": {"name": "cantilever"}}));
ok(&mut s, "solve", json!({"analysis": "static", "step": "Load"}));
let r = ok(&mut s, "probe", json!({"step": "Load", "at": [[0, 0, 0]]}));
let node = &r["nodes"][0];
assert!(node["xyz"].is_array() && node["distance"].is_number(), "{r}");
for at in [json!([[1e308, "x"]]), json!(vec![json!([0, 0, 0]); 20_000])] {
let (text, err) = call(&mut s, "probe", json!({"step": "Load", "at": at}));
assert!(err && text.len() < 100_000, "{text}");
}
}
#[test]
fn a_batch_stops_at_the_first_error() {
let mut s = server();
+3 -2
View File
@@ -251,7 +251,7 @@ pub fn tool_definitions() -> Vec<Value> {
tool(
"probe",
"Probe results",
"Stored results at nodes (solve.probe): displacement, reaction, stress and von Mises (static), the shape of \
"Stored results at nodes, or at the nodes nearest to points `at` (solve.probe): displacement, reaction, stress and von Mises (static), the shape of \
mode `mode` (frequency), displacement and velocity in field frame `frame` (explicit) and, with `elements`, \
explicit element values; for a fluid step, the flow at `points` and the force histories of `forces`.",
obj(
@@ -259,6 +259,7 @@ pub fn tool_definitions() -> Vec<Value> {
"step": string("Solved step"),
"nodes": {"type": "array", "items": {"type": "integer"}, "description": "Node labels"},
"elements": {"type": "array", "items": {"type": "integer"}, "description": "Element labels (explicit)"},
"at": {"type": "array", "items": {"type": "array"}, "description": "Points [x, y, z]; the nearest nodes are probed (structural steps)"},
"points": {"type": "array", "items": {"type": "array"}, "description": "Points [x, y, z] (fluid)"},
"forces": {"type": "array", "items": {"type": "string"}, "description": "Walls or faces whose force histories to return (fluid)"},
"mode": integer("Mode, from 1 (frequency)"),
@@ -497,7 +498,7 @@ fn dispatch(b: &mut dyn Backend, name: &str, a: &Map<String, Value>) -> Result<V
b.execute(command, params)
}
"show_results" => show_results(b, a),
"probe" => b.execute("solve.probe", pick(a, &["step", "nodes", "elements", "points", "forces", "mode", "frame"])),
"probe" => b.execute("solve.probe", pick(a, &["step", "nodes", "at", "elements", "points", "forces", "mode", "frame"])),
"reactions" => b.execute("results.reactions", pick(a, &["step", "sets", "about"])),
"select" => {
let p = pick(a, &["filter", "box_mode", "mode", "clear", "geometry", "nodes", "elements", "faces", "at", "box"]);