YAZIO MCP Server

YAZIO MCP Server

MCP server over the YAZIO food diary that lets a model read what you've eaten today, log meals, build recipes from tracked products, track water, weight and exercise, and query nutrition summaries, goals and profiles.

Category
访问服务器

README

yazio-mcp-server

An MCP server over the YAZIO food diary. Ask a model what you have eaten today, log a meal, build a recipe from tracked products.

Hand-written, unlike the SDK it sits on: it exists to turn ~48 raw endpoints into a couple of dozen tools a model can use without a manual, which is judgement work a generator cannot do.

[!IMPORTANT] Unofficial and unaffiliated. YAZIO does not publish, endorse or support this server, and the API it uses is private: it can change without notice, and using it is subject to YAZIO's terms of service.

Built on yazio-sdk, which is generated from yazio-api-specification.

Running it

pip install yazio-mcp-server
yazio-mcp-server

Or from a checkout:

nix-shell --run "make run"

Or in a container:

docker compose up -d

The endpoint is http://127.0.0.1:8931/mcp, speaking streamable HTTP. The port avoids 8000 on purpose — that one collides with too much other tooling for a server whose URL is registered somewhere in advance.

In a container

The Dockerfile builds an Alpine image that runs the server as an unprivileged user (uid 10001) and holds nothing but the interpreter and the installed virtualenv — 60 MB on disk, 21 MB to pull. It binds 0.0.0.0, because a container's own loopback is reachable from nothing else.

One thing the image does that a plain pip install does not: it removes cryptography after installing. That package is 15 MB and arrives through mcp → pyjwt[crypto], for OAuth and JWT verification paths a Basic-auth server never takes — PyJWT falls back to its HMAC-only algorithm set, and TLS to YAZIO goes through the standard library's ssl either way. Adding an OAuth path to this server means dropping that line from the Dockerfile first.

Tagged releases are published to GHCR for amd64 and arm64, so there is usually nothing to build:

docker run --rm -p 127.0.0.1:8931:8931 ghcr.io/yazio-community/yazio-mcp-server:latest

v1.4.2 publishes 1.4.2, 1.4 and 1; latest follows final releases only, never a prerelease. From a checkout:

docker build -t yazio-mcp-server .
docker run --rm -p 127.0.0.1:8931:8931 yazio-mcp-server

The one thing worth knowing before deploying it: every hostname clients use to reach the server has to be named. The transport's DNS-rebinding guard accepts loopback and nothing more, so a compose service name, a Kubernetes Service or an Ingress host all come back as 421 Invalid Host header until they are added:

docker run --rm -p 8931:8931 yazio-mcp-server \
  yazio-mcp-server --host 0.0.0.0 --allowed-host yazio.example.com

docker-compose.yml does exactly this for the service name and publishes the port on loopback only — the credentials in play are a YAZIO password in reversible encoding, so anything wider belongs behind TLS.

On Kubernetes the same argument goes in args, and probes have to be TCP: the whole app sits behind Basic auth, so an unauthenticated HTTP probe reports 401 for a healthy server.

containers:
  - name: yazio-mcp
    image: yazio-mcp-server
    args: ["yazio-mcp-server", "--host", "0.0.0.0", "--allowed-host", "yazio-mcp.default.svc.cluster.local:*"]
    ports:
      - containerPort: 8931
    readinessProbe:
      tcpSocket:
        port: 8931
    securityContext:
      runAsNonRoot: true
      readOnlyRootFilesystem: true
      allowPrivilegeEscalation: false

Nothing is written to disk and no state survives a restart — tokens are cached in memory, per credential pair — so replicas need no coordination and can be scaled freely.

Using it from Claude Code

Registered at user scope, so it is available in every directory:

claude mcp add --transport http --scope user yazio http://127.0.0.1:8931/mcp \
  --header "Authorization: Basic $(printf '%s:%s' "$YAZIO_USERNAME" "$YAZIO_PASSWORD" | base64 -w0)"

The server has to be running for Claude Code to reach it; start it with the command above, and it will show as failed in claude mcp list when it is not.

Note that this writes the Basic credential into ~/.claude.json, where it sits in a form that is trivially reversible — it is your YAZIO password, not a token you can revoke on its own. claude mcp remove yazio --scope user takes it back out.

Authenticating

There is no separate account for this server: clients authenticate with the same username and password they use to log in to YAZIO, sent as HTTP Basic credentials — or, if the client cannot build those, as two plain headers. The server exchanges them for a YAZIO OAuth token on the first tool call and caches it per credential pair until it expires.

{
  "mcpServers": {
    "yazio": {
      "type": "http",
      "url": "http://127.0.0.1:8931/mcp",
      "headers": {
        // base64 of "username:password"
        "Authorization": "Basic bWVAZXhhbXBsZS5jb206aHVudGVyMg=="
      }
    }
  }
}

Basic auth is not what the MCP specification prescribes for HTTP transports — it expects OAuth — so clients have to be pointed at the server with an explicit header rather than through a discovery flow.

Without the base64 step

Some clients — LibreChat among them — let an administrator define custom headers but pass the values through verbatim, so there is no way to have the client assemble the base64 credential from a username and a password. For those, send the two values as separate headers instead:

{
  "mcpServers": {
    "yazio": {
      "type": "http",
      "url": "http://127.0.0.1:8931/mcp",
      "headers": {
        "X-Auth-Username": "me@example.com",
        "X-Auth-Password": "hunter2"
      }
    }
  }
}

The two forms are equivalent — the same login, the same token cache. When a request carries both, Authorization wins and the X-Auth-* headers are ignored. Sending only one half of the pair is refused with 400 Bad Request, rather than the 401 an unauthenticated request gets, so a client that is only missing a field can tell that apart from credentials YAZIO turned down. A blank value is not a credential either: once one of the headers is on the request, both have to carry something or the request is a 400.

Basic credentials are encoded, not encrypted. Bind to loopback, or terminate TLS in front of the server; never expose it over plain HTTP on a network you do not control.

Behind a reverse proxy, name the public hostname or the transport's DNS-rebinding guard will reject the request:

python3 -m yazio_mcp --host 0.0.0.0 --allowed-host yazio.example.com

Tools

Overview and nutrition

Tool What it answers
get_daily_summary How is today going: intake against goal, per meal, water, activity, weight
get_diary What was actually eaten, item by item, with the entry_id needed to remove one
get_nutrition_range Energy and macros per day across a range, plus averages
get_goals The day's energy, macro, water, step and weight goals
get_water Water intake against goal
get_activity_summary Steps and exercise energy across a range

Products

Tool What it does
search_products Search the food database by name or barcode
get_product One product in full, including its serving options
get_suggested_products What this user usually eats at a given meal

Tracking

Tool What it does
track_product Log a product, by amount or by named serving
track_recipe Log portions of a recipe
untrack_item Remove a logged item by its entry_id
log_water Set the day's water total
log_weight Log a weight measurement
log_exercise Log energy burned, steps and distance

Recipes

Tool What it does
list_my_recipes The user's own recipes
get_recipe One recipe: ingredients, instructions, nutrients per portion
create_recipe Build a recipe from tracked products
delete_recipe Remove one of the user's own recipes; logged portions stay
set_recipe_photo Upload a photo for one of the user's own recipes
delete_recipe_photo Remove the photo from one of the user's own recipes
browse_recipes YAZIO's editorial catalogue for a country
get_favorite_recipes Recipes marked as favourites

Profile

get_profile returns the goal direction, activity level, units, height and birth date — context worth having before interpreting anyone's numbers.

Units

Energy is in kilocalories and macros are in grams. Vitamins and minerals are reported in milligrams: YAZIO stores them in grams too, but at that scale they are values like 0.00012 that round away to nothing. Every nutrient block carries a units map, so the mixture cannot be misread.

Micronutrients stay small even in milligrams, because product nutrients are per one base unit (see below) rather than per 100. Numbers that would round to zero at two decimals are reported to three significant digits instead, so a trace amount never reads as an absent one.

Product nutrients are stored per one base unit, not per 100: olive oil reads 8.84 kcal per gram. This is the factor create_recipe scales by, so it is worth knowing before touching that code.

How create_recipe works

YAZIO's recipe endpoint stores what the client submits and derives nothing: a recipe carries its own nutrient totals. So create_recipe resolves every ingredient to a real product, scales that product's nutrients to the amount the recipe uses, and sums them before posting. An ingredient that cannot be resolved fails the call rather than silently contributing zero.

Two of its rules come from the API rather than from taste, and both are enforced before the request goes out because the API signals them badly:

  • At least two ingredients. One is rejected with "This collection should contain 2 elements or more".
  • portion_count must be a whole number. Not merely integral in value — it has to serialise without a decimal point. 2 is accepted; 2.0 and 2.5 are both answered with a bare 500 and no message.

API behaviour this server works around

The full catalogue of undocumented API behaviour lives in the spec repo. These are the ones that shaped code here rather than the spec:

  • The client version is checked, and it lives in the User-Agent. Anything unrecognised gets 403 {"error":"version_blocked"} on every endpoint except the token exchange. config.USER_AGENT carries the captured app's string and will need bumping when YAZIO retires that version — a sudden wall of 403s is the symptom, and it is the single most likely reason this server stops working one day.
  • Product search requires sex and countries. search_products fills both from the user's profile rather than making a caller supply them.
  • untrack_item cannot trust the delete endpoint. DELETE /v22/user/consumed-items takes a body of {"<bucket>": "<uuid>"} — a single string, not a list — and it also accepts an ?id= query parameter, answers 204, and does nothing. So the tool looks the entry up first to learn its bucket, and reads the day back afterwards rather than believing the status code.
  • create_recipe validates before sending. Two API rules are enforced client-side because the API signals them badly: fewer than two ingredients is rejected with a message about collections, and a portion_count that serialises with a decimal point (2.0, 2.5) is answered with a bare 500 and no message at all.

Development

nix-shell            # builds yazio_sdk from its PyPI release
make test            # mocked suite, never touches a real account
make lint

yazio_sdk comes from PyPI everywhere — the dev shell, CI and released builds alike. The dev shell pins one version of it (see shell.nix); keep that inside the range pyproject.toml declares when either moves.

The suite mocks every HTTP call, so it covers the shaping logic but cannot catch the API contradicting the spec. If a shape looks wrong rather than the server's handling of it, the problem is upstream — reproduce it against the spec repo and fix it there.

Licence

MIT.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选