crousandgo-mcp
The Crous & Go 1 € student menu, as tools an AI agent can use.
See what's published, get asked which variant you want, and let the agent order and pay with Izly — with you in the loop.
What it does
|
What it never does
|
Unofficial. Not affiliated with CROUS or Izly. It drives the public shop and the Izly payment page with your own account, the way you would by hand. The rule stays: one 1 € meal per order and per student.
Install
git clone https://github.com/daniilsys/crousandgo-mcp && cd crousandgo-mcp
./install.sh
It creates the virtualenv, installs the package (crousandgo and crousandgo-mcp commands) and Chromium for Playwright, and prints how to register the MCP server in your client (command .venv/bin/crousandgo-mcp). The agent skill is in skills/crousandgo-order. Then fill in ~/.config/crousandgo/.env:
CROUS_USER=... # your Crous & Go login
CROUS_PASS=...
IZLY_USER=... # your Izly login
IZLY_PASS=...
CROUSGO_ENABLE_WRITES=1 # kill switch: real orders are refused unless this is 1
CROUSGO_MAX_ORDERS=1 # real orders per server process
CROUSGO_LANG=en # language of the evening question: en or fr
and log in once: crousandgo login. The Izly account must be linked to your Crous & Go account (My account, Connexion à Izly) and funded.
Use it
crousandgo menus # what is published
crousandgo order 2026-11-02 poulet gateau gateau # dry run: checks the choices, orders nothing
crousandgo order 2026-11-02 poulet gateau gateau --yes # real order, paid with Izly
crousandgo watch 2026-11-03 poulet gateau gateau # wait for 13:00 the day before, then order
crousandgo ask # the 20:00 question, or nothing
Choices are matched by substring, accents and case ignored. --service soir picks the evening menu.
With an agent, just talk to it: "commande-moi le menu de demain, poulet, fruit et compote". The skill makes it validate with a dry run and ask when something is ambiguous.
Tools
| Tool | |
|---|---|
list_menus |
published menus, plats, side options, stock, when ordering opens |
get_cart |
current cart |
get_orders |
recent orders with status, what was ordered (plat, side options), pickup date/time/place and an upcoming flag |
clear_cart |
empty the cart |
order_menu |
order a menu. dry_run=True by default, reason is mandatory |
Every tool returns {ok, ...}. On ok: false there is a stable code and an English message the agent can relay in your language:
insufficient_funds, izly_bad_credentials, izly_not_linked, menu_not_open, menu_not_published, out_of_stock, already_ordered, bad_choice, unexpected_price, payment_not_confirmed, session_expired, site_unreachable, writes_disabled, budget_exhausted.
Safety
- Dry run by default. The agent must pass
dry_run=Falseexplicitly, and the skill only lets it do so after your answer for that exact date. - Kill switch.
CROUSGO_ENABLE_WRITESmust be1.crousandgo-mcp --read-onlydoesn't even register the write tools. - Budget.
CROUSGO_MAX_ORDERSreal orders per server process (default 1). - Price cap. The menu must cost exactly 1 € and the cart must hold only that item before checkout.
- No silent success. A payment counts only when the WooCommerce order reaches "En cours" or "Terminée". Otherwise the agent gets
payment_not_confirmedand is told to checkget_ordersbefore retrying. - Audit log. Every dry run and order is appended to
audit.jsonlwith itsreason. - Secrets. Credentials come from the environment or a
.env(keep itchmod 600). They are never returned by a tool or logged.session.jsonholds Crous & Go cookies: treat it like a password.
How it works
The shop is WordPress + WooCommerce.
- Catalogue and cart: the public Store API (
/wp-json/wc/store/v1). - Add to cart: the product page's own form POST (variation, pickup zone, date and slot).
- Checkout:
?wc-ajax=checkout, which answers with the Izly redirect. - Payment: Chromium (Playwright) fills the Izly page with your credentials. A refusal comes back in the page's
.errorblock and is mapped to a code above. - Login: Chromium logs in with
CROUS_USER/CROUS_PASSand saves the cookies tosession.json; it is replayed withhttpxand renewed automatically when it expires.crousandgo login --manualopens a visible browser instead.
Run it on a server
Everything is headless. Copy the folder (and the .env), run ./install.sh, then crousandgo login. For the "ask every evening, order on reply" setup, see docs/SCHEDULING.md. To expose the server over HTTP: crousandgo-mcp --http 8766 — there is no auth on that endpoint, keep it on a private network.
Repository
src/crousandgo/
server.py MCP server (FastMCP, stdio or HTTP) -> crousandgo-mcp
cli.py command line -> crousandgo
tools.py the agent-facing tools, guards, evening question
client.py HTTP client: catalogue, cart, checkout, orders
auth.py Chromium login, session.json
izly.py Izly payment page
errors.py error codes and messages
config.py paths, constants, env loading
skills/ agent skill
docs/ scheduling
tests/ offline tests (python -m unittest discover -s tests)
pyproject.toml
Status
Used for real: login, add to cart, checkout, Izly payment and order confirmation were run end to end on a live account. The evening question and the reply-to-order flow depend on your agent setup and are described, not guaranteed, in docs/SCHEDULING.md. The "soir" menu pickup slot is assumed to be the same as midi. If the shop changes its markup, the HTML-parsing parts (checkout form, orders table) are the first thing to break.
License
MIT. See LICENSE.