xfoil-mcp - Aerodynamic polars on-call for your MCP agents
TL;DR: Wrap XFOIL in an MCP-native service so agents can request lift/drag/moment polars without touching shell scripts.
Table of contents
What it provides
Scenario | Value |
Quick experiments | Compute lift/drag/moment polars from an airfoil file or NACA code without launching XFOIL manually. |
MCP integration | STDIO/HTTP transports that follow the Model Context Protocol so ToolHive or other clients can call XFOIL programmatically. |
Audit trail | Responses include on-disk work directories and metadata so you can trace which inputs produced a given polar. |
Quickstart
1. Install dependencies
Download XFOIL from the official MIT site and place the executable on your PATH (or point to it explicitly):
2. Compute your first polar
Inspect the first few rows:
The bundled
examples/naca2412.datfollows cosine-spaced sampling (identical to XFOIL'sPANEoutput) so you can drop it into your own scripts without re-gridding.The CSV header is normalised to
alpha, CL, CD, CM. XFOIL may append extra columns (e.g.CDp,Cl/Cd, transition locations); those appear after the first four fields and remain untouched.
Run as a service
CLI (STDIO / Streamable HTTP)
Use python -m xfoil_mcp --describe to view metadata and exit.
Tip (macOS/Linux): building XFOIL natively requires XQuartz/X11 headers. To avoid that setup, run the quickstart inside the repo's Docker recipe:
docker run --rm -v "$PWD/extern/xfoil-mcp:/workspace/xfoil-mcp" python:3.13-slim bash -lc ' set -euo pipefail apt-get update && apt-get install -y --no-install-recommends xfoil build-essential \ && pip install --no-cache-dir pandas /workspace/xfoil-mcp \ && python - <<"PY" from pathlib import Path from io import StringIO import pandas as pd from xfoil_mcp import PolarRequest, compute_polar airfoil_path = Path("examples/naca2412.dat") request = PolarRequest( airfoil_name="naca2412", airfoil_data=airfoil_path.read_text(encoding="utf-8"), alphas=[-2 + 0.5 * i for i in range(29)], reynolds=1.2e6, mach=0.08, ) response = compute_polar(request) print(pd.read_csv(StringIO(response.csv), comment="#").head()) PY '
Handling failures
compute_polar raises RuntimeError when XFOIL fails to emit a polar (common causes: laminar separation, too few iterations, or Reynolds numbers below ~5e4). The stderr/stdout from XFOIL is preserved in the exception message—increase ITER, seed a better initial airfoil mesh, or adjust alpha_start_deg/alpha_step_deg in response. Non-zero exit codes that still produce a polar are annotated in the CSV with a leading # xfoil exit code ... comment so you can decide whether to discard or accept the run.
FastAPI (REST)
Browse http://127.0.0.1:8001/docs to test requests and download CSVs.
python-sdk tool (STDIO / MCP)
Launch:
Connect any MCP-compatible agent (Cursor, Claude Desktop, Windsurf, ...) and ask for polars on demand.
ToolHive smoke test
Requires XFOIL_BIN pointing to the XFOIL executable:
Agent playbook
Batch sweeps - iterate through a directory of
.datfiles and persist each polar to object storage.Optimisation loops - embed the tool inside a genetic algorithm; typed responses keep mutation + evaluation deterministic.
Visualisation - feed
response.csv_pathinto Plotly or Matplotlib to plotClvs.Cdwithout manual parsing.
Stretch ideas
Compare multiple foils by merging CSVs into a parquet dataset for notebook analysis.
Pair with
ctrltest-mcpto explore control implications from polar derivatives.Schedule nightly polars via CI and publish artefacts for downstream agents.
Accessibility & upkeep
Badges include descriptive alt text and are limited to five for readability on mobile.
Tests mock XFOIL so they run quickly:
uv run pytest.Use
uv run ruff check .before submitting changes.
Contributing
Fork and
uv pip install --system -e .[dev].Run the formatting and test suite.
Open a PR with before/after polar snippets so reviewers can verify quickly.
MIT license - see LICENSE.