Skip to main content

JSON-first CLI + MCP server for Italian fuel-station prices and EV charging — MIMIT, OpenStreetMap, ISTAT.

Project description

pitstop

CI Release Upstream smoke

A JSON-first CLI and MCP server for Italian fuel-station prices and EV charging stations, designed for AI agents, scripts, and humans.

Italy publishes per-station fuel prices daily (MIMIT Osservaprezzi Carburanti open data) and OpenStreetMap maps every EV charger in the country, but raw access means downloading multi-megabyte CSVs, joining files, sorting through misreports, and translating between Italian comune names and the ones a user actually types. pitstop does all of that locally and returns a small, well-formed JSON envelope.

Built for questions like:

  • "What's the cheapest diesel near Rome right now?"pitstop stations --fuel Gasolio --near 41.9,12.5 --cheapest
  • "Where can I fast-charge my EV in Bolzano?"pitstop chargers --comune Bozen --fast
  • "Are these station prices statistically reliable?" → every price says whether it was screened against its local market; screened ones carry a regional_median, a deviation_pct, and outlier: true when the price looks like a misreport.

International city names work out of the box (Rome, Milan, Bozen, Mailand, Venise, …).

Disclaimer

Unofficial community project. Not affiliated with or endorsed by MIMIT. Fuel data belongs to MIMIT and is redistributed here under its open-data terms; pitstop always emits source and extraction-date provenance in its output.

Data scope & freshness

  • Source: MIMIT Osservaprezzi Carburanti open data — a station registry (anagrafica, ~23.8k active stations) and a daily practiced-price file, joined on idImpianto.
  • Freshness: prices reflect values reported by operators as of ~08:00 the day before the published extraction date. This is daily, not real-time.
  • Coverage: Italy only (by design, for now).
  • Known caveats:
    • Some operators report placeholder values (e.g. 1.000); use --min-price (e.g. 1.2) to drop them.
    • Some price records are stale (a few were last updated years ago); use --fresh-within-days and check the UPDATED column / updated field.
    • Some stations are mis-geocoded in the registry. As of v0.4.0 pitstop joins a second data source (ISTAT-derived comune coordinates from opendatasicilia/comuni-italiani, 97.5% match) to validate each station's coordinate against its declared comune's true location. Stations >30 km off are flagged coordinate_suspect (* in the table), and --near excludes stations whose declared comune is geographically too far from the query point — even single-station comuni like RASUN-ANTERSELVA. Pass --no-comune-validate to disable.

Install

Requires Python ≥ 3.10. No third-party runtime dependencies.

From PyPI (the package is published as pitstop-cli; the CLI binary is pitstop):

pipx install pitstop-cli           # or
uv tool install pitstop-cli        # or just run on-demand:
uvx --from pitstop-cli pitstop --help

For the MCP server (optional extra):

pipx install "pitstop-cli[mcp]"
pitstop-mcp                        # stdio MCP server

Run from a source checkout during development:

PYTHONPATH=src python3 -m pitstop --help

Usage

# Cheapest *fresh* diesel in a municipality (skip placeholder + stale prices)
pitstop stations --comune ROMA --fuel Gasolio --cheapest --min-price 1.2 --fresh-within-days 90 --limit 5

# Self-service petrol within 5 km of a coordinate, as JSON
pitstop stations --near 46.498,11.354 --radius 5 --fuel Benzina --self --json

# Discover the fuel-type names present in the data
pitstop fuels

# Fast EV chargers (≥50 kW) within 5 km of Bolzano
pitstop chargers --near 46.498,11.354 --radius 5 --fast --json

stations flags: --comune, --provincia, --brand, --near "lat,lon", --radius, --fuel (substring, case-insensitive), --self, --served, --cheapest (needs --fuel), --min-price (drop values below a floor; e.g. 1.2 to skip placeholders), --fresh-within-days (drop stale prices), --max-deviation-pct (drop prices more than N% below their fuel's provincial median — catches misreports), --no-comune-validate, --limit, --json. Loading flags (--refresh, --max-age, --timeout) apply to the MIMIT data commands (stations, fuels, stats); chargers uses its own OSM cache and takes only --refresh.

Every returned price carries a median_basis. A screened price also carries regional_median and deviation_pct, plus outlier: true when it is >15% below the local median or below the Tukey lower fence Q1−1.5·IQR (the Tukey rule catches misreports in tight markets that the percent rule alone misses). The outlier key is emitted only when it is true, so read it as optional. Pass --drop-outliers to remove flagged prices entirely.

A price is unscreened when its (fuel, provincia) bucket holds too few samples for a median, so no outlier check ran on it and it is returned as reported (the table marks these ~). The --json envelope's quality block counts screened vs unscreened prices for the answer you got.

MCP server

For agents that speak MCP, the same data is exposed as tools (list_fuels, find_stations, find_cheapest, find_chargers, get_stats) over the shared core:

pip install "pitstop-cli[mcp]"   # or: uv tool install "pitstop-cli[mcp]"
pitstop-mcp                      # stdio MCP server

Example client config entry:

{ "mcpServers": { "pitstop": { "command": "pitstop-mcp" } } }

Development

pip install -e ".[dev]"
pytest -q

Automation contract

  • stdout is command output; stderr is diagnostics.
  • --json emits a stable object with source, *_extraction_date, generated_at, query, count, quality, stations[], and disclaimer.
  • Exit codes: 0 success, 1 runtime error, 2 usage error.
  • Source files are cached (default 24h) under $XDG_CACHE_HOME/pitstop; use --refresh to bypass.
  • Non-interactive; no hidden browser state or scraping.

Status & roadmap

v1.1.0 — stable public release: fuel-price core (registry+price join, filters, proximity, cheapest, --min-price floor, --fresh-within-days freshness, combined 15% + Tukey IQR outlier rule, ISTAT comune-coordinate validation, JSON) + EV charging stations via OSM Overpass (operator, plug types, max kW, fee, access — pitstop chargers) + operator tariff-page URLs attached to each EV result. Includes multi-fuel query support, international municipality mapping (EN/FR/DE), macro price statistics (pitstop stats), and navigation/GeoJSON support. MCP server, agent skill, tests, CI.

Planned, roughly in order:

  • per-station EV tariff data if a source pitstop can read starts publishing per-kWh prices (today it parses only OSM's fee yes/no flag, no price field);
  • additional countries behind a per-country source adapter, only where the source's own terms permit the bulk download and locally derived ranking pitstop does.

Data sources & attributions

  • Fuel stations and prices: MIMIT Osservaprezzi Carburanti open data.
  • Comune coordinates (validation): opendatasicilia/comuni-italiani (ISTAT-derived).
  • EV charging stations: OpenStreetMap via the Overpass API (© OpenStreetMap contributors, ODbL).

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pitstop_cli-1.1.0.tar.gz (48.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pitstop_cli-1.1.0-py3-none-any.whl (32.6 kB view details)

Uploaded Python 3

File details

Details for the file pitstop_cli-1.1.0.tar.gz.

File metadata

  • Download URL: pitstop_cli-1.1.0.tar.gz
  • Upload date:
  • Size: 48.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pitstop_cli-1.1.0.tar.gz
Algorithm Hash digest
SHA256 1166dab068e4e0f5f291e50206b8f3efe91a1d60ebe71c0d46d39d01eef0c995
MD5 9f9b92a180492f9e3c7b2845a1684dc0
BLAKE2b-256 5c686d73945c19ef58ef9b3aa61210b5dc9266825bf2d192c421d50bf51ae3e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for pitstop_cli-1.1.0.tar.gz:

Publisher: release.yml on galjos/pitstop-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pitstop_cli-1.1.0-py3-none-any.whl.

File metadata

  • Download URL: pitstop_cli-1.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for pitstop_cli-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8a03da1b59893f2125c5256899069f6f8d6035d61922802017b4938af0b3d450
MD5 906e70eccb6b140139ee0320f7e452f0
BLAKE2b-256 e570826b87ab821a074a813c8fbb5c66987257aff668ad0274ff53535d3e2e2e

See more details on using hashes here.

Provenance

The following attestation bundles were made for pitstop_cli-1.1.0-py3-none-any.whl:

Publisher: release.yml on galjos/pitstop-cli

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page