balanceit-mcp

balanceit-mcp

An MCP server that automates a balance.it account, providing tools for calorie calculation, food search, catalogue listing, and recipe generation for pet diets.

Category
Visit Server

README

balanceit-mcp

A stdio MCP server that drives your own balance.it account through its recipe autobalancer.

Balance IT formulates home-prepared canine and feline diets. This server acts as your signed-in account. It exposes the calorie calculator, the food catalogue, and the recipe builder as MCP tools.

Use your own account credentials. Read and respect the Balance IT terms of service before you automate anything against the site. This project has no affiliation with Balance IT.

What it does

The server exposes six tools over the Model Context Protocol.

Tool Kind Latency Purpose
calculate_calories HTTP under 500 ms Return the daily maintenance calories for a pet.
search_foods HTTP under 500 ms Search the curated m* and USDA n* food entries.
list_catalogue Browser 5 to 8 s, then cached 7 days Return the full ingredient catalogue for one species and life stage.
generate_recipe Browser 45 to 90 s Fill the pet profile, choose ingredients, and wait for the built options.
get_recipe Browser 5 to 10 s Read the macros and the gram weights for one recipe option.
session_status Local instant Report whether a usable session is on disk.

Every tool returns structured JSON. Two of the tools call the site JSON endpoints directly. The other three drive a Chrome browser through Playwright. The /recipes page and the build flow render only inside a logged-in browser session.

A dead session produces a distinct session_expired error with a remedy hint. The site answers an unauthenticated request with HTTP 200 and an empty array. A caller cannot otherwise tell a dead session from an empty result.

Requirements

  • Node.js 20 or later.
  • Google Chrome. Playwright launches it through channel: 'chrome'.
  • A Balance IT account of your own.
  • A logged-in balance.it browser session, exported as a Playwright storageState file.

Install

npm install
npm run build

Configuration

Session state

The server reads its session from ~/.config/balanceit/state.json. It creates that file with mode 0600, inside a directory with mode 0700.

Export a session yourself. Sign in to balance.it in a Playwright Chromium context. Then write context.storageState({ path }) to the configuration path above. The export must hold the _balance_session and aws-waf-token cookies on the balance.it domain.

Set BALANCEIT_STATE_SEED to seed the session from an export that sits elsewhere. On first run the server copies that file to the configuration path, and it applies mode 0600. The server ignores the variable once the configuration file exists.

Re-export the session when a tool returns session_expired. The session cookies expire after a few days.

Environment variables

Variable Purpose
BALANCEIT_EMAIL Your balance.it account email.
BALANCEIT_PASSWORD Your balance.it account password.
BALANCEIT_STATE_SEED Path to a storageState export used to seed the session.

The server reads the credentials from the environment only. It never writes them to disk. It never logs them. It never puts them in an error message.

The credentials are documented for a future automatic sign-in. The current code does not use them, because it authenticates from the exported session.

MCP client

Add the server to your MCP client configuration. Replace /path/to/balanceit-mcp with the path to your own clone.

{
  "mcpServers": {
    "balanceit": {
      "command": "node",
      "args": ["/path/to/balanceit-mcp/dist/index.js"]
    }
  }
}

Usage

Run the browser tools from a foreground shell. Playwright with channel: 'chrome' does not launch Chrome from a backgrounded shell on macOS. The Node process then stays alive, logs nothing, and looks like a hang.

generate_recipe

generate_recipe takes a pet profile and a list of food_id values. It returns one option list, plus three fields for verification.

  • submitted_food_ids lists the identifiers read from the hidden form inputs at submit time. This is what balance.it received.
  • typeahead_added lists the subset that the typeahead added rather than a chip click.
  • missing_from_first_option lists each requested ingredient that the first built option does not appear to contain. An empty list is the normal case. A non-empty list means that the site optimizer substituted or skipped the ingredient on that option. Call get_recipe on each option when you need per-option certainty.

The tool rejects a bad food_id before it opens a browser. A malformed identifier fails immediately. A well-formed identifier that search_foods does not return fails after the resolve pass.

Contract notes

These details describe how the site behaves. Keep them so that later maintenance does not have to rediscover them.

  • The /recipes page returns an empty body to a plain fetch. Use the browser tools for any DOM content.
  • The two JSON endpoints are /r/api/v1/pets/vet_approvals/auto_calculate_calories and /r/api/v1/foods/search/<QUERY>. Both work with a plain fetch, the persisted cookie header, a normal desktop user agent, and X-Requested-With: XMLHttpRequest.
  • foods/search takes the query as a path segment. The ?q= form returns 404.
  • On tab 2 of /recipes, the ingredient chips sit inside seven collapsed accordions. Each chip is present in the DOM but not visible. Playwright times out on a click against a hidden chip. Click the accordion header (.ingredients-box > a) first.
  • The one-pot toggle #one_pot_cooking is hidden by CSS. Toggle the visible label[for=one_pot_cooking] instead.
  • A food that has no chip is added through the tab-2 typeahead (input.food-typeahead.tt-input). This is the common case when one_pot_cooking is true.
  • Each typeahead suggestion carries a class of the form li-<category>-<food_id>, such as li-protein-n13326. Match that class to find the exact suggestion, then click it with the mouse.
  • A .tt-suggestion click reports success without registering the food when it targets the wrong suggestion. Do not click "the first suggestion". Match the li-<category>-<food_id> class.
  • Every registered selection appears as a hidden <input name="<category>_foods[]" value="<food_id>">. The pre-submit invariant is that every requested identifier is present as such an input.
  • Typing a saved pet name by hand reads as an edit to that pet record. The site then raises an update gate. Select the pet from the #pet_name typeahead instead, which sets the hidden pet_id and raises no gate.
  • A recipe build is asynchronous. After the submit navigation lands on /recipes/<recipe_id>, poll until the option cards render or the "N of N complete" status reaches parity.

Repository layout

src/
  index.ts    MCP server entry and tool registration
  session.ts  storageState persistence and Cookie header derivation
  http.ts     the two pure-fetch tools, SessionError, and UpstreamError
  browser.ts  Playwright flows for catalogue, generate, and detail scrape
scripts/
  smoke.ts    live check against the site

Tests

This repository has no offline test suite. scripts/smoke.ts runs against the live site, and it needs a valid session.

npm run smoke

The smoke run calls calculate_calories for a spayed female and an intact female. It asserts that each result falls inside the reported calorie bracket. It checks that search_foods('chicken') returns m4. It then builds a recipe. It repeats the build for the same pet name, which exercises the saved-pet gate. It reads the first option back. It asserts that a malformed food_id is rejected.

The reference profile for the run is an adult dog of 22 kg.

Set SMOKE_SKIP_RECIPE=1 to skip the slow browser leg.

SMOKE_SKIP_RECIPE=1 npm run smoke

Development

npm run dev     # run the server from source through tsx
npm run build   # compile TypeScript into dist/
npm start       # run the compiled server

Licence

Licensed under the PolyForm Noncommercial License 1.0.0. Copyright 2026 Seraphine Renard.

Recommended Servers

playwright-mcp

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.

Official
Featured
TypeScript
Magic Component Platform (MCP)

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.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

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.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

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.

Official
Featured
TypeScript
Kagi MCP Server

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.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

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.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured