Skip to content

Commit 4ea5007

Browse files
committed
Allow the MCP to get the wagons of a given train
1 parent cf8c9dc commit 4ea5007

1 file changed

Lines changed: 50 additions & 0 deletions

File tree

Framework/Core/scripts/hyperloop-server/hyperloop_server.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,56 @@ async def fetch_one(wid: str) -> dict | None:
349349
return "\n".join(lines)
350350

351351

352+
@mcp.tool()
353+
async def train_wagons(train_id: int) -> str:
354+
"""List a train's wagons with their wagon id, workflow, and owning analysis.
355+
356+
Resolves the train's wagon ids (which wagon_stats fetches internally but does
357+
not expose) and looks up each wagon's identity. Use this to locate a wagon id
358+
for cloning/inspection when you only know the train — e.g. to find the
359+
cf-femto-pair-track-track wagon to clone into O2 Development.
360+
"""
361+
t = await _get("trains/train.jsp", {"train_id": train_id})
362+
wagons_ts = t.get("wagons_timestamp") or t.get("dataset_timestamp")
363+
if not wagons_ts:
364+
return f"Cannot determine wagons timestamp for train {train_id}"
365+
366+
wagons_data = await _get("trains/wagons_derived_data.jsp",
367+
{"train_id": train_id,
368+
"wagons_timestamp": wagons_ts})
369+
wagon_ids = list(wagons_data.keys()) if isinstance(wagons_data, dict) else []
370+
if not wagon_ids:
371+
return f"No wagons found for train {train_id}"
372+
373+
async def fetch_one(wid: str) -> dict | None:
374+
try:
375+
w = await _get("analysis/wagon/wagon.jsp",
376+
{"wagon_id": int(wid), "referenceTime": 0})
377+
if isinstance(w, dict) and w.get("id") is not None:
378+
return w
379+
except Exception:
380+
pass
381+
return None
382+
383+
wagons = [w for w in await asyncio.gather(*(fetch_one(w) for w in wagon_ids))
384+
if w]
385+
if not wagons:
386+
return f"No resolvable wagons for train {train_id}"
387+
388+
lines = [f"Wagons of train {train_id} ({t.get('dataset_name', '?')}), "
389+
f"{len(wagons)} wagons:\n"]
390+
lines.append(f"{'WagonID':>8} {'Workflow':<40} {'Analysis':<24} Name")
391+
lines.append("-" * 100)
392+
for w in sorted(wagons, key=lambda x: str(x.get('work_flow_name') or '')):
393+
ana = f"{w.get('analysis_id')} {w.get('analysis_name') or ''}".strip()
394+
if len(ana) > 24:
395+
ana = ana[:23] + "…"
396+
lines.append(f"{w.get('id'):>8} "
397+
f"{str(w.get('work_flow_name') or '?'):<40} "
398+
f"{ana:<24} {w.get('name') or '?'}")
399+
return "\n".join(lines)
400+
401+
352402
# ---------------------------------------------------------------------------
353403
# Analysis / wagon browsing
354404
#

0 commit comments

Comments
 (0)