bring-hermes
MCP server that exposes the Bring! shopping list API as tools, enabling an AI assistant to read lists, add items, and import recipes with correct quantities.
README
bring-hermes
An MCP server that exposes the Bring! shopping list API as tools — so an assistant ("hermes") can read your lists and add items or whole recipes (with the correct quantity) to Bring!.
It is served over the MCP Streamable HTTP transport, protected by an API key, and built to run on Docker and Kubernetes (TLS terminated at the Ingress).
Built on the actively maintained bring-api
Python library (the one behind Home Assistant's Bring! integration), which
provides batch updates, automatic token refresh, and a recipe-URL parser.
What it can do
| Tool | Description |
|---|---|
list_shopping_lists |
List all lists on the account with their UUIDs. |
get_list_items |
Show the items currently on a list (name + quantity). |
add_item |
Add a single item; quantity → the item's specification. |
add_recipe |
Add all ingredients of a recipe in one call, with optional servings scaling. |
import_recipe_from_url |
Parse a recipe URL via Bring! and add its ingredients. |
remove_item |
Remove an item from a list. |
complete_item |
Mark an item as bought (moves it to "recently used"). |
Quantities: Bring! stores an item's amount in a free-text
specificationfield. Pass amounts like"500 g","2", or"1 EL"in thequantityfield — that is exactly what shows up under the item in the app.
Servings scaling
add_recipe (and import_recipe_from_url) accept base_servings and
target_servings. When both are given, the leading number of each quantity is
scaled by target / base (units and text are preserved):
"500 g" + base=4, target=6 -> "750 g"
"2" + base=4, target=6 -> "3"
"1 EL" + base=4, target=2 -> "0.5 EL"
"Salz" (no number) -> "Salz" (unchanged)
Configuration
All configuration is via environment variables (see .env.example):
| Variable | Required | Default | Description |
|---|---|---|---|
BRING_EMAIL |
✅ | — | Bring! account email. |
BRING_PASSWORD |
✅ | — | Bring! account password. |
MCP_API_KEY |
✅ | — | One or more API keys (comma-separated) clients must present. |
BRING_DEFAULT_LIST |
— | first list | Default list (name or UUID) when a tool call omits one. |
HOST |
— | 0.0.0.0 |
Bind address. |
PORT |
— | 8080 |
Bind port. |
MCP_PATH |
— | /mcp |
Path the MCP endpoint is served at. |
MCP_JSON_RESPONSE |
— | true |
Plain-JSON Streamable HTTP responses; false = SSE-framed. |
LOG_LEVEL |
— | INFO |
Python log level. |
Run locally (Docker Compose)
cp .env.example .env
# edit .env: set BRING_EMAIL, BRING_PASSWORD, and a strong MCP_API_KEY
docker compose up --build
The server listens on http://localhost:8080 with the MCP endpoint at
http://localhost:8080/mcp. Health endpoints (/healthz, /readyz) are
unauthenticated; everything else requires the API key.
Quick check:
curl -s http://localhost:8080/healthz # -> ok
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8080/mcp # -> 401 (no key)
Run without Docker (uv)
uv sync
uv run bring-hermes # reads the same env vars (e.g. via `set -a; . ./.env`)
Connecting an MCP client
Point a Streamable-HTTP-capable MCP client at the /mcp URL and send the API
key in the Authorization header:
{
"mcpServers": {
"bring": {
"type": "http",
"url": "https://bring-hermes.example.com/mcp",
"headers": {
"Authorization": "Bearer <MCP_API_KEY>"
}
}
}
}
(X-API-Key: <MCP_API_KEY> is accepted as an alternative to the bearer header.)
Deploy to Kubernetes (Helm)
A Helm chart lives in helm/bring-hermes/ — see its
README for the full values reference. TLS is
terminated at the Ingress (cert-manager + Let's Encrypt in the example), or you
can expose it via the Gateway API instead — set httpRoute.enabled=true with a
parentRefs Gateway (see the chart README).
# Credentials as a managed Secret (recommended)
kubectl create namespace bring-hermes
kubectl -n bring-hermes create secret generic bring-hermes-credentials \
--from-literal=BRING_EMAIL='you@example.com' \
--from-literal=BRING_PASSWORD='your-bring-password' \
--from-literal=MCP_API_KEY="$(openssl rand -hex 32)"
helm install bring-hermes ./helm/bring-hermes \
--namespace bring-hermes \
--set bring.existingSecret=bring-hermes-credentials \
--set image.repository=ghcr.io/scramb/bring--mcp \
--set image.tag=0.2.0 \
--set ingress.enabled=true \
--set ingress.hosts[0].host=bring-hermes.example.com
(Or pass bring.email / bring.password / bring.apiKey directly and let the
chart create the Secret — fine for testing, not for production.)
Notes:
- Stateless MCP transport → safe to run multiple replicas behind a normal Service (no session affinity required).
- Probes:
/healthzis liveness;/readyzreturns503until the first successful Bring! login, then200. - Responses: plain-JSON Streamable HTTP by default (no SSE), so no special proxy buffering/timeout tuning is required at the Ingress.
- Hardening: runs as non-root with a read-only root filesystem and all capabilities dropped.
Releases (GitHub Actions → GHCR)
Pushing a version tag triggers .github/workflows/release.yml,
which publishes both artifacts to GHCR with the same version as the git tag
(a leading v is stripped so the value is valid SemVer for Helm):
git tag v0.2.0
git push origin v0.2.0
# -> image: ghcr.io/<owner>/bring-hermes:0.2.0 (+ :latest)
# -> chart: oci://ghcr.io/<owner>/charts/bring-hermes version 0.2.0
The chart is packaged with --version/--app-version set to that version, and
its image.tag defaults to the chart appVersion — so image tag and chart
version always match.
Build the image manually
docker build -t ghcr.io/your-org/bring-hermes:0.1.0 .
docker push ghcr.io/your-org/bring-hermes:0.1.0
How it works
- One shared
Bringclient (single login) is created in the app's lifespan and reused across requests; the underlying library refreshes the access token automatically, and an expired-token error triggers a one-shot re-login. - The FastMCP Streamable HTTP session manager is nested inside that lifespan, so the login is not re-run per request (which would otherwise happen in stateless mode).
- API-key auth is a small ASGI middleware in front of the MCP mount; health endpoints are exempt so Kubernetes probes work without credentials.
- The Streamable HTTP transport replies with plain JSON by default
(
MCP_JSON_RESPONSE=true); set it tofalseto get SSE-framed responses for streaming clients.
Security
- Treat
MCP_API_KEYas a secret; use a long random value and rotate it by setting a comma-separated list and removing the old key once clients migrate. - Always serve behind TLS (the Ingress). The API key is a bearer credential —
never expose
/mcpover plain HTTP in production. - The Bring! credentials grant full access to your shopping lists; scope and store them like any other secret.
Credits
Huge thanks to the authors of bring-api,
Cyrill Raccaud (@miaucl) and Manfred
Dennerlein Rodelo — the actively maintained Python Bring! client that also
powers Home Assistant's Bring! integration. This server is a thin MCP wrapper
around their work; all the real Bring! API heavy lifting (batch updates,
automatic token refresh, recipe parsing) is theirs. 💙
If you find this useful, please go star miaucl/bring-api.
License
MIT. bring-api is MIT-licensed by its respective authors. Bring! is a
trademark of its respective owners; this project is unofficial and not
affiliated with Bring! Labs AG.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.