Skip to main content
Glama
Meticulous Espresso MCP Server

Meticulous Espresso MCP Server

by erdos2n

Meticulous Espresso MCP Server

Your Meticulous espresso machine, connected to an LLM. Generate recipes from natural language, analyze shots, dial in your grinder, and keep a persistent shot diary — all through Claude.

No Anthropic API key required. No cloud subscription. Just your machine, your LLM, and a local IP.


Get started in 60 seconds

Add this to your Claude Desktop or Claude Code config and you're done:

Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json

Claude Code — ~/.claude.json

{
  "mcpServers": {
    "meticulous": {
      "command": "npx",
      "args": ["-y", "github:erdos2n/meticulous-mcp-server"],
      "env": {
        "METICULOUS_IP": "192.168.x.x"
      }
    }
  }
}

Replace 192.168.x.x with your machine's local IP (find it in your router or the Meticulous app). Restart Claude. That's it — no cloning, no building, no dependencies to manage.

Want this on Claude mobile or claude.ai? You'll need a Raspberry Pi on your local network. See LLM_SETUP.md and PI_SETUP_INSTRUCTIONS.md.


Related MCP server: AbletonMCP

What you can do

Pull the shot data from my last espresso and tell me what to adjust.
Generate a recipe for a washed Ethiopian, 18g dose, 1:2.5 ratio, slow bloom.
Save my grinder setting — I'm on the DF83 at 10.2 for the Osmotic flow profile.
Read my shot diary and tell me what's been working.
My last three shots were sour. Look at the shot data and suggest a fix.
List all my profiles and load the one I used last week for the natural.

What it does

  • Generate and tweak recipes from plain language, validated and loaded to the machine

  • Analyze shots — pulls sensor data and gives concrete recipe improvement suggestions

  • Manage profiles — list, load, save, delete, browse factory and community recipes

  • Control the machine — start, stop, tare, preheat, reset

  • Track grinder settings per profile across sessions — never re-explain your dial-in

  • Keep a shot diary — tasting notes and observations that persist between chats

The grinder settings and diary are stored as plain files in ~/.meticulous-mcp/ on your machine. No database, no setup — just open them in any text editor.


All available tools

Machine control

Tool

What it does

get_device_info

Firmware, serial, model, software version

execute_action

start / stop / tare / preheat / reset / calibration

get_settings

Read machine settings

update_setting

Change machine settings

get_notifications

Pending or acknowledged machine notifications

Profiles

Tool

What it does

list_profiles

All profiles stored on the machine

get_all_profiles

Full details for every profile

get_profile

Single profile by UUID

get_last_profile

Currently active profile

get_default_profiles

Factory + community profiles

load_profile

Load a recipe (temporary)

load_profile_by_id

Load an existing profile by UUID

save_profile

Save a recipe to the machine permanently

delete_profile

Remove a profile by UUID

validate_recipe

Check schema + auto-fix simple errors

Shot history

Tool

What it does

get_shot_history

Recent shots with metadata

search_history

Filter by name, date, order, limit

get_current_shot

Real-time data for a shot in progress

get_last_shot

Sensor data for the most recent shot

get_shot_statistics

Total shots, breakdown by profile

get_shot_data_for_analysis

Full shot + profile for deep analysis

rate_shot

Mark a shot as like / dislike

search_historical_profiles

Find past profile versions

Grinder + diary

Tool

What it does

get_grinder_context

Recall saved grinder settings for all profiles

set_grinder_context

Save current grinder setting for a profile

read_diary

Read the full shot diary

append_diary_entry

Log a shot with tasting notes


Shot data verbosity

Shot tools default to compact responses to keep context windows manageable:

Option

What you get

verbosity: "summary"

Key metadata only

verbosity: "compact"

Metadata + sampled trace (default)

verbosity: "full"

Full raw payload


Full setup options

See LLM_SETUP.md for all installation paths — laptop, clone-and-build, and Raspberry Pi remote access.


Project layout

meticulous-mcp-server/
├── src/
│   ├── server.ts          # All 25 MCP tools + machine logic
│   ├── index.ts           # stdio entry point (laptop / Claude Desktop / Claude Code)
│   └── http.ts            # HTTP entry point (Pi / Cloudflare / claude.ai)
├── dist/                  # Compiled output
├── LLM_SETUP.md           # Setup guide for all install paths
├── PI_SETUP_INSTRUCTIONS.md  # Full Pi + Cloudflare Tunnel walkthrough
├── Justfile               # Build, run, deploy, test commands
└── pi-setup.sh            # Pi dependency installer

License

MIT — see LICENSE. Maintainer release steps are in RELEASING.md.

Available Tools

28 tools
append_diary_entryA

Append a new entry to the espresso shot diary. Call this after each shot to log tasting notes, grinder setting, yield, and observations. Use Markdown formatting matching the diary style.

Inputs: entry (required).

delete_profileA

Delete a profile from the machine's internal storage by UUID.

Inputs: profile_id (required).

execute_actionA

Send a control action to the machine. Actions: 'start' (begin shot), 'stop' (abort shot), 'continue' (resume), 'reset' (reset machine state), 'tare' (tare scale), 'preheat' (start heating), 'calibration' (run calibration), 'scale_master_calibration'.

Inputs: action (required).

get_all_profilesA

Fetch all profiles stored on the machine with full details (all stages, dynamics, triggers). Use this when you need to inspect or compare complete recipes.

Inputs: no named parameters.

get_current_shotA

Get data for the shot currently being brewed (returns null if no shot is in progress). Defaults to a compact summary to avoid huge responses.

Inputs: verbosity, max_points.

get_default_profilesA

Get the built-in factory profiles and community profiles that ship with the machine. Good starting points for recipe creation or modification.

Inputs: no named parameters.

get_device_infoA

Get hardware info about the Meticulous machine: firmware version, model, serial number, software version, and current status.

Inputs: no named parameters.

get_grinder_contextA

Get the saved grinder model and setting for one or all profiles. Call this at the start of a session to recall where you left off.

Inputs: profile_name.

get_last_profileA

Get the most recently loaded (active) profile on the machine, along with the time it was last loaded.

Inputs: no named parameters.

get_last_shotA

Get the most recently completed shot. Defaults to a compact summary to avoid token overflow.

Inputs: verbosity, max_points.

get_notificationsB

Get machine notifications (firmware updates, maintenance reminders, error messages).

Inputs: acknowledged.

get_profileC

Get the full details of a specific profile by its UUID.

Inputs: profile_id (required).

get_settingsA

Read the current machine settings (auto-preheat, auto-start shot, purge after shot, sounds, timezone, heating timeout, etc.). Optionally filter to a specific setting key.

Inputs: setting_name.

get_shot_data_for_analysisA

Fetch shot data and profile for analysis. Defaults to compact output with a sampled trace to stay within chat context limits.

Inputs: verbosity, max_points, shot_db_key.

get_shot_historyA

Get a listing of past espresso shots (metadata only). Shows shot name, time, profile used, and rating.

Inputs: no named parameters.

get_shot_statisticsA

Get aggregate statistics: total shots pulled, shots per profile, and profile version counts.

Inputs: no named parameters.

list_profilesA

List all espresso profiles (recipes) currently stored on the machine. Returns an array of profile identifiers with their names and IDs.

Inputs: no named parameters.

load_profileA

Load a profile JSON onto the machine as the active recipe (temporary — use save_profile to persist). Validates the schema before sending. Profile JSON must include: name (string), id (UUID v4), author (string), author_id (UUID v4), temperature (number, Celsius), final_weight (number, yield grams), previous_authors ([]), variables ([]), version (1), stages (array). Each stage needs: name, key, type ("flow"|"pressure"), dynamics.points ([[time,value],...] starting at [0,x]), dynamics.over ("time"), dynamics.interpolation ("linear"|"curve"), exit_triggers (array). Last stage must exit on {type:"weight", value:<final_weight>}.

Inputs: profile (required).

load_profile_by_idB

Activate an existing profile on the machine by its UUID (profile must already be saved on the machine).

Inputs: profile_id (required).

rate_shotA

Rate a completed shot as 'like', 'dislike', or null (remove rating). Use db_key from shot history.

Inputs: rating (required), shot_db_key (required).

read_diaryA

Read the full espresso shot diary. Call this at the start of a session to recall past shots, tasting notes, and dial-in history.

Inputs: no named parameters.

save_profileA

Permanently save a profile to the machine's internal storage. Validates the schema before saving. Profile JSON must include: name (string), id (UUID v4), author (string), author_id (UUID v4), temperature (number, Celsius), final_weight (number, yield grams), previous_authors ([]), variables ([]), version (1), stages (array). Each stage needs: name, key, type ("flow"|"pressure"), dynamics.points ([[time,value],...] starting at [0,x]), dynamics.over ("time"), dynamics.interpolation ("linear"|"curve"), exit_triggers (array). Last stage must exit on {type:"weight", value:<final_weight>}.

Inputs: profile (required).

search_historical_profilesA

Search for historical versions of profiles by name. Useful for finding old recipe iterations.

Inputs: query (required).

search_historyC

Search shot history with flexible filters. All parameters are optional.

Inputs: sort, query, end_date, order_by, +3 more.

set_grinder_contextA

Save the grinder model and setting for a profile. Call this whenever you change your grind size so Claude remembers it next session.

Inputs: grinder (required), setting (required), profile_name (required), notes.

update_profileA

Update an existing profile in place by ID. Fetches the current profile, merges your changes on top, and saves back — preserving the profile image and avoiding duplicates. Pass only the fields you want to change in updates; everything else is kept from the existing profile.

Inputs: updates (required), profile_id (required).

update_settingA

Update one or more machine settings. Pass a partial Settings object with only the keys you want to change. Available keys: auto_preheat (number), auto_purge_after_shot (bool), auto_start_shot (bool), enable_sounds (bool), heating_timeout (number), partial_retraction (number), ssh_enabled (bool), update_channel (string).

Inputs: settings (required).

validate_recipeA

Validate a recipe JSON against the Meticulous profile schema. Returns a list of errors if invalid. If auto_fix is true, automatically fills in simple missing fields (id, author_id, version, previous_authors, variables) — structural errors like missing stages must be corrected manually.

Inputs: recipe (required), auto_fix.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.4/5.0

    Scored across 28 tools

    Disambiguation3/5

    Many tools have overlapping purposes, such as list_profiles vs get_all_profiles vs get_profile, and get_shot_history vs search_history. The descriptions clarify the distinctions, but the sheer number of similar read operations could still cause misselection.

    Naming Consistency3/5

    Tool names mostly follow a verb_noun pattern, but the verbs are inconsistent across similar actions (e.g., list_profiles vs get_all_profiles, read_diary vs get_shot_history). While not chaotic, the mix of get, list, search, read, and append deviates from a predictable convention.

    Tool Count2/5

    With 28 tools, the server exceeds the typical well-scoped range. Many tools could be consolidated (e.g., merging list_profiles and get_all_profiles, or combining get_current_shot and get_last_shot into a single parameterized tool), making the set feel overcrowded.

    Completeness4/5

    The tool surface covers the major workflows: device control, settings, profile CRUD, shot history, grinder context, and diary. Minor gaps exist, such as no way to fetch a specific shot by ID or clear diary entries, but these are not critical to the core functionality.

    Maintenance

    ActivityInactive
    ResponsivenessLimited data

    Related MCP Connectors

    Related MCP Servers