Carrefour Drive MCP
MCP server for Carrefour Drive (carrefour.fr) that lets AI agents search the French grocery catalog, manage a shopping cart, book pickup/delivery slots, and access account data like loyalty points and receipts.
README
Carrefour Drive MCP — grocery shopping for your AI agent
MCP server for Carrefour Drive (carrefour.fr). Let Claude, Cursor, or any Model Context Protocol client search the French grocery catalogue, build a cart, pick a Drive pickup or delivery slot, read loyalty points and past receipts — on your own Carrefour account.
48 tools. 43 real carrefour.fr API endpoints described as JSON and run by a
generic executor, plus 5 session-management tools. Adding an endpoint means
dropping in a JSON file — no code.
"What did I buy last month?" → get_loyalty_order_receipts
"Refill my usual weekly groceries." → get_frequent_purchases + add_item_to_cart
"Cheapest organic pasta under 2 €?" → search_products
"Book the Saturday morning Drive slot." → get_delivery_timeslots + select_cart_delivery_slot
- Standalone — no
spectralbinary, no external gateway, no API key. Clone, build, run. - Cloudflare-proof — every call is issued from a real Chromium page, because
nothing else gets a
200. - Stays logged in — you log in once in a browser window; the server renews the session by itself through the OAuth2 SSO loop.
Table of contents
- Install
- Connect it to your agent — Claude Code · Claude Desktop · Cursor, Windsurf, Zed, VS Code
- Log in
- Tool reference
- Why a real browser
- How authentication works
- How the executor works
- Configuration
- Verify the install
- FAQ
Install
Nothing to clone. Node.js 20+ is the only prerequisite (native fetch,
FormData, node:test).
npx -y github:maximeallanic/CarrefourDriveMCP
That single command fetches, builds and starts the server on stdio — the first run also downloads the Chromium it uses as HTTP transport. Most of the time you never type it yourself: you put it in your MCP client config (next section) and the client runs it for you.
Prefer it installed once, globally?
npm install -g github:maximeallanic/CarrefourDriveMCP
carrefour-drive-mcp
Your session, browser profile and logs live in ~/.carrefour-drive-mcp
($XDG_DATA_HOME/carrefour-drive-mcp when set), so upgrades never log you out.
Override with CARREFOUR_DATA_DIR.
<details> <summary>From source instead</summary>
git clone https://github.com/maximeallanic/CarrefourDriveMCP.git
cd CarrefourDriveMCP
npm install # builds, and downloads the Chromium transport
node dist/index.js
A source checkout keeps its data in the repo's own data/ directory.
</details>
Connect it to your agent
Claude Code
claude mcp add carrefour-drive -- npx -y github:maximeallanic/CarrefourDriveMCP
Then, in any session:
> Log me in to Carrefour (runs carrefour_browser_login)
> Add 2 L of semi-skimmed milk to my Drive cart
Claude Desktop
Edit claude_desktop_config.json:
- macOS —
~/Library/Application Support/Claude/claude_desktop_config.json - Windows —
%APPDATA%\Claude\claude_desktop_config.json - Linux —
~/.config/Claude/claude_desktop_config.json
{
"mcpServers": {
"carrefour-drive": {
"command": "npx",
"args": ["-y", "github:maximeallanic/CarrefourDriveMCP"]
}
}
}
Restart Claude Desktop; the Carrefour tools appear in the tools menu.
On Windows, use
"command": "cmd"with"args": ["/c", "npx", "-y", "github:maximeallanic/CarrefourDriveMCP"].
Cursor, Windsurf, Zed, VS Code and other MCP clients
Any client that speaks MCP over stdio takes the same two fields:
{
"command": "npx",
"args": ["-y", "github:maximeallanic/CarrefourDriveMCP"]
}
- Cursor —
~/.cursor/mcp.json(or.cursor/mcp.jsonin a project) - Windsurf —
~/.codeium/windsurf/mcp_config.json - VS Code / Copilot —
.vscode/mcp.json, under"servers" - Zed —
settings.json, under"context_servers"
Installed globally or cloned instead? Swap in
{"command": "carrefour-drive-mcp"} or
{"command": "node", "args": ["/absolute/path/to/dist/index.js"]}.
Already have cookies? Pass them in an "env" block instead of logging in:
{"CARREFOUR_COOKIES": "…cookie header…"}.
Log in
carrefour.fr signs you in with cookies, behind a Cloudflare Turnstile captcha and an OTP. So the login is interactive, once:
- Ask your agent to run
carrefour_browser_login. - A browser window opens on the Carrefour login page. Type your email, password and the OTP code yourself.
- Don't close the window — the server detects the end of the OAuth loop, grabs the session cookies from memory and closes it for you.
From then on the session renews itself silently: the server replays the SSO
authorize → callback redirect before authenticated calls, after a 401/403,
and every 30 minutes as a keep-alive. You only log in again when the SSO cookie
itself expires (24 h max, or 60 min idle) — the tools say so explicitly.
Check the state at any time with carrefour_session_status (verify: true makes
a real call).
| Session tool | What it does |
|---|---|
carrefour_browser_login |
open a window to sign in (captcha + OTP) |
carrefour_session_status |
stored cookies, browser profile, SSO time left |
carrefour_refresh_session |
force a renewal (rarely needed — it's automatic) |
carrefour_set_cookies |
import cookies manually (header, JSON map, or JSON array) |
carrefour_clear_session |
wipe the local session |
For
carrefour_set_cookies, only the JSON array format carries the cookie domain — it's the only one that can supplyc4iamsecuretk, without which automatic renewal is impossible.
The cookie jar lives in <data dir>/sessions/cookies.json (0600) and is
re-injected into the browser profile on every start.
Tool reference
Search & catalogue (no account needed)
| Tool | Endpoint | Required params |
|---|---|---|
search_products |
GET /s | q |
autocomplete_search |
GET /autocomplete | q |
get_products_by_gtins |
POST /products | gtins |
get_products_by_query |
GET /products/query/{query_id} | query_id |
get_product_reviews |
GET /product/{ean}/reviews | ean |
get_navigation_tree |
GET /navigation | — |
get_marketing_placements |
POST /api/marketing/{placement} | placement, searchTerm, categories, productFilters |
get_donation_products |
GET /donation | — |
get_chat_preprompts |
POST ocb.carrefour.fr/preprompts | modes, count, navigationCurrentPageTitle, navigationCurrentPageType |
get_eligible_drive_stores |
GET /api/eligibility/drive | latitude, longitude, postalCode, city |
Cart & checkout
| Tool | Endpoint | Required params |
|---|---|---|
get_cart |
GET /api/cart | — |
add_item_to_cart |
PATCH /api/cart | ean, counter, basketServiceId, subBasketType |
add_item_to_cart_by_ean |
PATCH /api/cart/items | ean, basketServiceId, subBasketType |
apply_promo_code_to_cart |
POST /api/cart/promo_code | code, facilityServiceId, subBasketType |
simulate_cart_for_store |
GET /api/cart/simulate | storeRef |
get_delivery_timeslots |
GET /api/timeslots | facilityServiceId |
select_cart_delivery_slot |
PUT /api/cart/slot | slotRef, storeRef |
validate_checkout_slot |
POST /api/checkout/{basket_service_type}/validate/slot | basket_service_type, deviceFingerPrintId |
validate_checkout_summary |
POST /api/checkout/{basket_service_type}/validate/summary | basket_service_type, deviceFingerPrintId |
get_checkout_recommendations |
GET /api/checkout/recommendations/{facility_id}/{basket_service} | facility_id, basket_service |
submit_checkout_payment ⚠️ |
POST /api/checkout/payment | checkout_type, device_fingerprint_id, payments |
⚠️
submit_checkout_paymentcharges a real payment. Four of its parameters were captured as query string while their description suggests HTTP headers — check against a real trace before using it in production.
Account, orders & loyalty
| Tool | Endpoint | Required params |
|---|---|---|
get_orders |
GET /api/user/orders | — |
get_last_orders |
GET /api/user/orders/last | — |
get_frequent_purchases |
GET /mon-compte/achats-frequents | — |
get_loyalty_balance |
GET /api/user/secured/loyalty/balance | — |
get_loyalty_cards |
GET /api/user/secured/loyalty/my-cards | — |
get_loyalty_coupons_dashboard |
GET /api/user/loyalty/coupons-dashboard | — |
get_loyalty_coupon_collection |
GET /api/user/loyalty/coupon-collection | — |
get_loyalty_order_receipts |
GET /api/user/secured/loyalty/orders/receipts | loyaltyCardNumber, loyaltyCardType |
get_loyalty_order_receipt_details |
GET /api/user/secured/loyalty/orders/receipt/{gln}/{date_key}/{receipt_number} | gln, date_key, receipt_number |
get_advantage_codes |
GET /api/advantage-code | — |
get_vignettes_products |
GET /api/user/products/vignettes-products | — |
get_olympic_games_prime |
GET /api/user/loyalty/olympic-games/prime | — |
get_account_kpis |
GET /api/user/my-account/kpis | codes |
get_user_consents |
GET /api/user/my-account/consents | — |
get_favorite_store |
GET /api/favoritestore | — |
get_store_information_inserts |
POST /api/information-insert/stores/{store_id} | store_id, insert_ids |
get_homepage_returning_banner |
GET /api/homepage/returningBanner | — |
get_personalized_recommendations |
GET /api/user/recommendation/cdp | — |
get_product_recommendations |
GET /api/recommendations | context |
Shopping lists
| Tool | Endpoint | Required params |
|---|---|---|
get_shopping_lists |
GET /api/shopping-lists | — |
get_shopping_list |
GET /api/shopping-lists-id/{list_id} | list_id |
create_shopping_list |
POST /api/shopping-lists/memo-list | title |
Why a real browser
carrefour.fr sits behind a Cloudflare managed challenge that fingerprints the client. Measured from one IP, on the same day:
| Client | GET /api/cart |
|---|---|
fetch (undici) |
403 cf-mitigated: challenge, on the very first request |
curl |
200 for a few calls, then 403 |
| Chrome | 200 |
No amount of header tweaking changes that: the only viable transport is a
browser. And the requests must be issued from a page — Playwright's
APIRequestContext uses a Node HTTP stack and gets blocked like fetch.
So the server keeps a persistent Chromium and runs every API call as a fetch
inside a page parked on the target origin (one page per origin, because of CORS).
It runs windowless, but not in standard headless mode:
| Launch mode | Result |
|---|---|
headless: true (headless shell) |
403 — the UA announces HeadlessChrome |
headless: false |
200 |
channel: 'chromium' + masked UA + --disable-blink-features=AutomationControlled |
200, navigator.webdriver is false |
The last line is what ships.
How authentication works
Two distinct cookie systems:
| Domain | Role | Lifetime |
|---|---|---|
moncompte.carrefour.fr |
ForgeRock SSO, cookie c4iamsecuretk |
24 h max, dies after 60 min idle |
www.carrefour.fr |
store session (HttpOnly cookies) |
short, renewable |
Login is interactive because of two constraints: the form is behind a
Cloudflare Turnstile captcha that refuses to validate in a CDP-driven
browser, and c4iamsecuretk is a session cookie Chromium never writes to
disk. So the window is a plain Chromium with a debug port open but nothing
attached until login finishes; the server polls the tab over plain HTTP on
/json/list (no CDP domain enabled, so no automation trace), attaches the moment
the OAuth loop lands back on the store, and reads the cookies from memory.
Renewal afterwards is a plain navigation — Chromium follows the redirects and sets the cookies itself:
GET moncompte.carrefour.fr/iam/oauth2/CarrefourConnect/authorize?client_id=…&redirect_uri=https://www.carrefour.fr/login/check
└─302─► www.carrefour.fr/login/check?code=… (the BFF exchanges the code)
└─302─► www.carrefour.fr/ (fresh session cookies)
How the executor works
tools/*.json ──► loader (validation) ──► params (JSON Schema ➜ zod) ──► MCP tools/list
└─► resolve ($param ➜ URL/query/headers/body)
└─► http.service (cookies + rate limit + fetch)
Every file in tools/ is self-describing:
{
"name": "add_item_to_cart",
"parameters": { "type": "object", "properties": { … }, "required": [ … ] },
"request": {
"method": "PATCH",
"url": "https://www.carrefour.fr/api/cart",
"headers": { … },
"query": {},
"body": { "items": [ { "ean": { "$param": "ean" }, … } ] },
"content_type": "application/json"
},
"requires_auth": true
}
The engine (src/spec/):
- recursively substitutes
{"$param": "name"}nodes inheaders,queryandbody, preserving the original type (number, boolean, array); - drops placeholders with no argument, so optional params vanish from the
request instead of being sent as
null; - fills URL segments
{basket_service_type},{store_id}, … with encoding, failing with a clear message when a required segment is missing; - serialises arrays as repeated query keys (
codes[]=14&codes[]=15); - encodes the body per
content_type: JSON,x-www-form-urlencodedormultipart/form-data(boundary left tofetch); - applies a sliding rate limit with jitter, plus browser headers.
Adding an endpoint = dropping a new JSON file into tools/. No code to write.
Configuration
See .env.example. Main variables:
| Variable | Default | Role |
|---|---|---|
CARREFOUR_COOKIES |
— | session cookies (header, JSON map or JSON array) |
CARREFOUR_COOKIE_FILE |
— | path to a JSON cookie export |
CARREFOUR_DATA_DIR |
~/.carrefour-drive-mcp (repo data/ from source) |
root of everything written below |
CARREFOUR_SESSION_FILE |
<data>/sessions/cookies.json |
persisted cookie jar |
CARREFOUR_BROWSER_PROFILE |
<data>/browser-profile |
persistent Chromium profile |
CARREFOUR_KEEPALIVE_MINUTES |
30 |
SSO keep-alive period; 0 disables |
CARREFOUR_OAUTH_CLIENT_ID |
carrefour_onecarrefour_web |
OAuth2 client used for refresh |
CARREFOUR_OAUTH_REDIRECT_URI |
https://www.carrefour.fr/login/check |
BFF callback |
CARREFOUR_OAUTH_SCOPE |
openid iam |
requested scopes |
CARREFOUR_TOOLS_DIR |
<project>/tools |
JSON tool definitions directory |
CARREFOUR_MAX_RESPONSE_CHARS |
60000 |
truncation of large responses |
REQUEST_TIMEOUT_MS |
30000 |
HTTP timeout |
RATE_LIMIT_REQUESTS / RATE_LIMIT_WINDOW_MS |
10 / 60000 |
rate-limit window |
MIN_DELAY_MS / MAX_DELAY_MS |
100 / 500 |
jitter between requests |
LOG_LEVEL, CARREFOUR_LOG_DIR |
info, <data> |
winston logs (files + stderr, never stdout) |
Verify the install
From a source checkout:
npm run build # tsc
npm test # build + unit tests (node:test)
npm run smoke # build + real MCP stdio handshake + tools/list
npm run verify # all three
Tests cover $param substitution, URL segments, arrays in query strings, the
three body encodings, and cookie-jar handling. The smoke test actually boots the
server, performs the JSON-RPC handshake and lists the tools.
Network calls to carrefour.fr are not tested automatically — they need a real account and valid cookies.
FAQ
Do I need an API key? No. Carrefour has no public API; this server drives the same private endpoints the website uses, with your own session.
Does it work outside France? The catalogue and stores are French (carrefour.fr). Cloudflare may be stricter from some IPs.
Is my password stored? No. You type it in a browser window; only cookies are
persisted, in ~/.carrefour-drive-mcp/sessions/cookies.json with 0600
permissions. No credential
lives in this repo, and data/ and .env are gitignored.
Can it place a real order? Yes — submit_checkout_payment charges a real
payment. Treat it accordingly.
Can I add endpoints? Drop a JSON file in tools/. See
How the executor works.
Which clients are supported? Anything speaking MCP over stdio: Claude Code, Claude Desktop, Cursor, Windsurf, VS Code / Copilot, Zed, Continue, custom agents using the MCP SDK.
Disclaimer
Unofficial project, not affiliated with, endorsed by, or supported by Carrefour. For personal and educational use on your own account. Respect Carrefour's terms of service and rate-limit yourself accordingly.
License
MIT © Maxime Allanic
<sub>Keywords: Carrefour MCP server · Carrefour Drive API · Model Context Protocol grocery · Claude Desktop MCP · Claude Code MCP server · Cursor MCP · French grocery shopping AI agent · courses en ligne · drive · liste de courses · fidélité Carrefour · MCP shopping cart automation.</sub>
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。