Meticulous Espresso MCP Server
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| METICULOUS_IP | Yes | The local IP address of the Meticulous espresso machine. |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| get_device_infoA | Get hardware info about the Meticulous machine: firmware version, model, serial number, software version, and current status. |
| 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'. |
| 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. |
| 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). |
| list_profilesA | List all espresso profiles (recipes) currently stored on the machine. Returns an array of profile identifiers with their names and IDs. |
| 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. |
| get_profileC | Get the full details of a specific profile by its UUID. |
| get_last_profileA | Get the most recently loaded (active) profile on the machine, along with the time it was last loaded. |
| 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. |
| 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:}. |
| load_profile_by_idB | Activate an existing profile on the machine by its UUID (profile must already be saved on the machine). |
| 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:}. |
| delete_profileA | Delete a profile from the machine's internal storage by UUID. |
| get_shot_historyA | Get a listing of past espresso shots (metadata only). Shows shot name, time, profile used, and rating. |
| search_historyC | Search shot history with flexible filters. All parameters are optional. |
| 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. |
| get_last_shotA | Get the most recently completed shot. Defaults to a compact summary to avoid token overflow. |
| get_shot_statisticsA | Get aggregate statistics: total shots pulled, shots per profile, and profile version counts. |
| rate_shotA | Rate a completed shot as 'like', 'dislike', or null (remove rating). Use db_key from shot history. |
| search_historical_profilesA | Search for historical versions of profiles by name. Useful for finding old recipe iterations. |
| 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. |
| 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. |
| get_notificationsB | Get machine notifications (firmware updates, maintenance reminders, error messages). |
| 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. |
| 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. |
| 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. |
| 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. |
| 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 |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 28 tools
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.
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.
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.
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.