flappy.simulate
Simulate avian flight dynamics by providing wing morphology, control schedules, and duration. Returns pose histories, energy metrics, and solver provenance for bird flight analysis.
Instructions
Run the Flappy dynamics simulator for a mission profile. Provide wing morphology, control schedule, and duration. Returns pose histories, energy metrics, and solver provenance. Example: {"scenario_id":"demo","duration_s":8.0}
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| request | Yes |
Implementation Reference
- src/flappy_mcp/core.py:18-32 (handler)Primary handler implementing the tool logic: orchestrates Flappy CLI execution or fallback stub trajectory generation.def execute_flappy(request: FlappyRequest) -> FlappyResponse: """Execute Flappy using the request payload. If the configured binary exists, the helper writes a temporary configuration file containing the scenario dictionary and launches the CLI. Otherwise a deterministic sinusoidal trajectory is generated using the fallback parameters. """ scenario_dict = request.scenario or _build_fallback_scenario(request.fallback) if _binary_exists(): # pragma: no cover - integration path return _run_cli(scenario_dict, request.fallback) trajectory = _generate_stub_trajectory(scenario_dict, request.fallback) return FlappyResponse(trajectory=trajectory, source="generated", scenario=scenario_dict)
- src/flappy_mcp/tool.py:14-25 (registration)Registers the flappy.simulate tool on the FastMCP app, wrapping execute_flappy as the handler.@app.tool( name="flappy.simulate", description=( "Run the Flappy dynamics simulator for a mission profile. " "Provide wing morphology, control schedule, and duration. " "Returns pose histories, energy metrics, and solver provenance. " "Example: {\"scenario_id\":\"demo\",\"duration_s\":8.0}" ), meta={"version": "0.1.0", "categories": ["simulation", "dynamics"]}, ) def run(request: FlappyRequest) -> FlappyResponse: return execute_flappy(request)
- src/flappy_mcp/models.py:19-30 (schema)Pydantic input schema defining the tool's request parameters: scenario and fallback.class FlappyRequest(BaseModel): """Request payload for a Flappy simulation.""" scenario: dict[str, Any] | None = Field( default=None, description="Full scenario dictionary passed directly to flappy_cli.", ) fallback: FlappyFallback = Field( default_factory=FlappyFallback, description="Parameters used if the binary is unavailable or when generating a stub trajectory.", )
- src/flappy_mcp/models.py:32-43 (schema)Pydantic output schema: FlappyResponse with trajectory points and metadata.class TrajectoryPoint(BaseModel): t: float angle: float class FlappyResponse(BaseModel): """Response returned by `execute_flappy`.""" trajectory: list[TrajectoryPoint] source: str scenario: dict[str, Any] | None = None
- src/flappy_mcp/core.py:39-61 (helper)Helper function to execute the Flappy CLI binary using subprocess with temp files.def _run_cli(scenario: dict[str, Any], fallback: FlappyFallback) -> FlappyResponse: with tempfile.TemporaryDirectory(prefix="flappy_mcp_") as tmpdir: cfg_path = Path(tmpdir) / "config.json" out_path = Path(tmpdir) / "trajectory.json" cfg_payload = {"scenario": scenario} cfg_path.write_text(json.dumps(cfg_payload), encoding="utf-8") try: result = subprocess.run( # pragma: no cover - integration path [FLAPPY_BIN, "--config", str(cfg_path), "--output", str(out_path)], check=False, capture_output=True, ) except FileNotFoundError as exc: # pragma: no cover raise RuntimeError("Flappy binary not found") from exc if result.returncode != 0: # pragma: no cover raise RuntimeError(result.stderr.decode("utf-8", errors="ignore")) trajectory_data = json.loads(out_path.read_text(encoding="utf-8")) trajectory = [TrajectoryPoint(**point) for point in trajectory_data.get("trajectory", [])] return FlappyResponse(trajectory=trajectory, source=str(out_path), scenario=scenario)