@@ -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