{
  "markdown": "# SGP MCP Server\n\nAn [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that exposes **Sailplane Grand Prix (SGP)** competition data from [crosscountry.aero](https://www.crosscountry.aero) — the official data source for gliding championships.\n\n## What it does\n\nRead-only access to SGP competition datasets: events, pilots, daily tasks, turnpoints, day results, and cumulative standings. Also validates individual pilot FAI ranking-list IDs.\n\n## Quick start\n\n```bash\n# Direct (no Docker)\n./run.sh\n\n# Docker\nmake build\nmake exec\n```\n\nThe server listens on **`http://0.0.0.0:9010/sgp`** (streamable HTTP transport).\n\n## Tools\n\n| Tool | Description |\n|------|-------------|\n| `list_competitions` | List all SGP competitions (id, title, venue, country, dates, status) |\n| `get_competition(comp_id)` | Get one competition's details + day index (each day carries a `day_id`) |\n| `get_pilots(comp_id)` | List pilots entered in a competition (name, country, aircraft, registration, flarm, ranking\\_id) |\n| `get_task(comp_id, day_id)` | Get the task for a given day (name, type, length, airfield, start/finish altitude, decoded turnpoints) |\n| `get_task_waypoints(comp_id, day_id)` | Get just the ordered turnpoints (index, name, role, lat/lng, observation zone, radius) |\n| `get_task_length(comp_id, day_id)` | Get task length and waypoint count (lightweight summary) |\n| `get_day_results(comp_id, day_id)` | Get individual daily results (rank, points, speed, distance, task time, IGC file) |\n| `get_total_results(comp_id, day_id)` | Get cumulative standings as of a given day (total points, ranked) |\n| `validate_ranking_id(ranking_id)` | Validate a pilot's FAI ranking-list ID against the FAI ranking API |\n| `download_sgp_file(comp_id, day_id, competition_number, save_dir=None)` | Download a pilot's raw IGC flight log for a given day from crosscountry.aero (returns filename + IGC text; optionally writes it to `save_dir`) |\n\n### Typical workflow\n\n```\nlist_competitions()\n  → pick an id (e.g. 91 for \"Italy SGP 2026\")\nget_competition(91)\n  → pick a day_id (e.g. 1610)\nget_task(91, 1610)        → task geometry + turnpoints\nget_task_waypoints(91, 1610)  → turnpoints only\nget_task_length(91, 1610) → length summary\nget_pilots(91)            → pilot roster\nget_day_results(91, 1610) → daily scoring\nget_total_results(91, 1610) → cumulative standings\ndownload_sgp_file(91, 1610, \"YO\") → pilot YO's IGC flight log (returned as text)\ndownload_sgp_file(91, 1610, \"YO\", save_dir=\"/tmp/igc\")\n  → also writes /tmp/igc/YO.8AQ.igc and returns its saved_path\n```\n\n## Architecture\n\n```\nsgp_server.py          ← MCP tools (FastMCP, HTTP transport)\nsgp_api.py             ← API fetchers + pure decoders (single-letter keys → readable dicts)\ntests/                 ← 19 unit tests against JSON fixtures (no network needed)\ntests/fixtures/        ← Saved API responses for offline testing\n```\n\n- **`sgp_server.py`** — Thin MCP server wrapping `sgp_api.py`. 10 tools exposed.\n- **`sgp_api.py`** — Core library. Pure `decode_*`/`build_*`/`find_*` functions (raw dict in, clean dict out) and `fetch_*` wrappers (HTTP + decode). Decodes the terse single-letter-key JSON from crosscountry.aero.\n\n### Data sources\n\n| Endpoint | URL |\n|----------|-----|\n| Competition list | `https://data.crosscountry.aero/public/get/events` |\n| Competition + pilots + days | `https://www.crosscountry.aero/c/sgp/rest/comp/{id}` |\n| Task + results | `https://www.crosscountry.aero/c/sgp/rest/day/{comp_id}/{day_id}` |\n| FAI ranking validation | `https://rankingdata.fai.org/rest/api/rlpilot?id={id}` |\n| IGC flight-log download | `https://www.crosscountry.aero/flight/download/sgp/{file_num}` |\n\n## Dependencies\n\n```\nmcp[cli]\nhttpx\n```\n\nInstall: `pip install -r requirements.txt`\n\n## Running & deployment\n\n| Method | Command |\n|--------|---------|\n| Direct | `./run.sh` |\n| Docker | `make build && make exec` |\n| Docker stop | `make clean` |\n| Manual Docker | `docker run -d -p 9010:9010 --restart unless-stopped --name sgpmcp sgpmcp` |\n\n### Docker environment variables\n\n| Variable | Default |\n|----------|---------|\n| `SGP_MCP_TRANSPORT` | `http` |\n| `SGP_MCP_HOST` | `0.0.0.0` |\n| `SGP_MCP_PORT` | `9010` |\n| `SGP_MCP_PATH` | `/sgp` |\n| `SGP_API_URL` | `http://localhost:8000` |\n| `SGP_HTTP_TIMEOUT_SEC` | `60` |\n| `SGP_VERIFY_TLS` | `true` |\n\n## Tests\n\n```bash\ncd tests\npython -m pytest test_sgp_api.py -v\n```\n\n19 tests covering all decoder functions against saved fixtures. No network required.\n\n## Project structure\n\n```\nSGP/\n├── sgp_server.py        # MCP server (FastMCP, HTTP)\n├── sgp_api.py           # API fetchers + decoders\n├── requirements.txt     # mcp[cli], httpx\n├── run.sh               # Launch script\n├── Makefile             # Docker build/exec/clean\n├── Dockerfile           # python:3.12-slim base\n├── dockerrun.sh         # Docker run helper\n├── addmcp.sh            # MCP config helper\n├── tests/\n│   ├── test_sgp_api.py  # 19 unit tests\n│   └── fixtures/        # 4 JSON fixture files\n└── README.md            # This file\n```\n",
  "bytes": 5028,
  "sha": "c3957370bf22f6a1588f5bfe0ed61a82182997a0a0202197f1900ee395c3234e",
  "repo_slug": "acasadoalonso/sgp.aero.ai",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/okf_acasadoalonso_sgp_aero_ai_okf_index_md_cf61cb33/readme"
}