An MCP (Model Context Protocol) server for managing espresso profiles on your Meticulous espresso machine. Use AI assistants like Claude Desktop or Goose to create, validate, and manage espresso profiles without diving deep in application or manual JSON editing.
Meticulous MCP allows you to create and install Meticulous profiles on your machine via AI agents.
You can use natural language to describe the kind of profile you want, stages required, flow rate, temperature, etc., and an agent will build a profile for you -- no JSON or fiddling in the app required. The server helps agents understand espresso profiling and gives them tools to interact with your Meticulous via the API. The server is built off of Meticulous' Python API, the Meticulous espresso profile schema, and wisdom from Lance Hedrick, Aramse, and Home-Barista.com. The knowledge base for Agents needs work, and will evolve over time. It's not perfect and you may not like its suggestions, but you can be specific with your guidance to get around that.
You must have access to an agent that can use desktop/local MCP via STDIO. Popular clients for this include Claude Desktop, Goose, LibreChat, Cherry Studio, and LM Studio. It's only been tested with Goose, Cursor, and Claude Desktop. ChatGPT can not currently call MCP tools on your desktop.
Lastly, Meticulous MCP is not a product of Meticulous Home. Please don't bother the Meticulous development team about Meticulous MCP. We did not submit it to Meticulous intentionally, because it does not meet Meticulous' standards for review. The server is a fun tool to build profiles, not part of the product.
Have fun profiling!
Mac:
# Check if you have Python 3.11+
python3.11 --version
# If not installed, install via Homebrew:
brew install python@3.11Windows:
- Download Python 3.11+ from python.org
- During installation, check "Add Python to PATH"
- Verify installation: Open Command Prompt and run
python --version
Download or clone the Meticulous MCP repository from GitHub:
Option 1: Clone with Git
git clone https://github.com/twchad/meticulous-mcp.git
cd meticulous-mcpOption 2: Download ZIP
- Visit https://github.com/twchad/meticulous-mcp
- Click the green "Code" button
- Select "Download ZIP"
- Extract the downloaded file to your preferred location
Navigate to the meticulous-mcp directory and install:
cd meticulous-mcp
pip install -r requirements.txtNote: All dependencies (including pyMeticulous and the MCP SDK) are installed automatically from PyPI via requirements.txt.
Add the Meticulous MCP server to your MCP client configuration.
Mac: Edit ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: Edit %APPDATA%\Claude\claude_desktop_config.json
Add this configuration:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python3.11",
"args": [
"/absolute/path/to/meticulous-mcp/meticulous-mcp/run_server.py"
],
"env": {
"PYTHONPATH": "/absolute/path/to/meticulous-mcp/meticulous-mcp/src"
}
}
}
}Replace /absolute/path/to/meticulous-mcp with the path where you cloned the repository.
Note: run_server.py automatically sets up paths internally, so PYTHONPATH is optional but serves as a safeguard. All other dependencies (pyMeticulous, mcp) are installed via pip in Step 3.
Mac example:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python3.11",
"args": [
"/Users/yourname/meticulous-mcp/meticulous-mcp/run_server.py"
],
"env": {
"PYTHONPATH": "/Users/yourname/meticulous-mcp/meticulous-mcp/src"
}
}
}
}Windows example:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python",
"args": [
"C:\\Users\\YourName\\meticulous-mcp\\meticulous-mcp\\run_server.py"
],
"env": {
"PYTHONPATH": "C:\\Users\\YourName\\meticulous-mcp\\meticulous-mcp\\src"
}
}
}
}Note for Windows: Use backslashes (\\) in paths and semicolons (;) in PYTHONPATH.
Edit ~/.cursor/mcp.json (Mac) or %APPDATA%\Cursor\mcp.json (Windows) and add the same configuration as above.
Mac:
cd meticulous-mcp
python3.11 test_server.pyOr run from the parent directory (make sure to include the forward slash):
python3.11 meticulous-mcp/test_server.pyWindows:
cd meticulous-mcp
python test_server.pyOr run from the parent directory (make sure to include the backslash):
python meticulous-mcp\test_server.pyYou should see:
Testing imports...
✓ Successfully imported meticulous_mcp.server
✓ Server name: Meticulous Espresso Profile Server
✓ All imports successful!
- Claude Desktop: Quit and restart Claude Desktop
- Cursor: Restart Cursor
Your Meticulous MCP server should now be available!
If you prefer containerized deployment, you can run the server via Docker instead of the local setup above.
- Docker and Docker Compose installed.
- A Meticulous machine on your local network.
-
Clone the repository (if you haven't already) and enter it:
git clone https://github.com/twchad/meticulous-mcp.git cd meticulous-mcp -
Configure your machine's address. The default is
http://meticulous.local(mDNS). To override, either:- Set the environment variable:
export METICULOUS_API_URL=http://192.168.1.5 - Or create a
.envfile:echo "METICULOUS_API_URL=http://192.168.1.5" > .env
- Set the environment variable:
-
Build and start:
docker compose up -d --build --wait
Option 1: SSE / HTTP (Recommended)
Works whether the container is local or remote:
{
"mcpServers": {
"meticulous": {
"url": "http://<HOST_IP>:8080/mcp"
}
}
}Option 2: Docker Exec (Local Only)
{
"mcpServers": {
"meticulous": {
"command": "docker",
"args": [
"exec", "-i", "meticulous-mcp-server",
"python", "meticulous-mcp/run_server.py"
]
}
}
}Once connected, you can ask your AI assistant to:
- Machine info - "What firmware is my machine running?"
- Manage settings - "Enable auto-preheat" or "Change the sound theme"
- Access shot history - "Get the log file for my last shot"
- Create espresso profiles - "Create a new espresso profile with..."
- List profiles - "Show me all my espresso profiles"
- Get profile details - "Show me the details of profile X or explain this profile to me.."
- Update profiles - "Modify profile X to..."
- Duplicate profiles - "Copy profile X and name it Y"
- Validate profiles - "Check if this profile JSON is valid"
- Select profiles - "Select profile X on the machine" (without starting)
- Run profiles - "Execute profile X on the machine"
Here's a realistic example of how an AI agent would interact with your Meticulous machine to create a new espresso profile:
User: "I'd like to create a turbo shot profile for my light roast Ethiopian coffee. I want a bright, clear shot with good acidity."
Agent: "I'll create a turbo shot profile optimized for light roast coffee. This profile will use higher temperature and a 1:3 ratio for brightness and clarity."
Agent calls: create_profile with the following data:
{
"name": "Turbo Light Roast v1",
"author": "AI Assistant",
"temperature": 94.0,
"final_weight": 54.0,
"stages": [
{
"name": "Preinfusion",
"key": "preinfusion",
"type": "flow",
"dynamics_points": [[0, 6]],
"dynamics_over": "time",
"dynamics_interpolation": "linear",
"exit_triggers": [
{"type": "pressure", "value": 1.5, "comparison": ">="},
{"type": "time", "value": 20, "comparison": ">="}
]
},
{
"name": "Infusion",
"key": "infusion",
"type": "pressure",
"dynamics_points": [[0, 6.0], [3, 6.0]],
"dynamics_over": "time",
"dynamics_interpolation": "linear",
"exit_triggers": [
{"type": "time", "value": 15, "comparison": ">="},
{"type": "weight", "value": 35, "comparison": ">="}
],
"limits": [{"type": "flow", "value": 8}]
},
{
"name": "Decline",
"key": "decline",
"type": "pressure",
"dynamics_points": [[0, 6.0], [10, 3.0]],
"dynamics_over": "time",
"dynamics_interpolation": "linear",
"exit_triggers": [
{"type": "weight", "value": 54, "comparison": ">="},
{"type": "time", "value": 30, "comparison": ">="}
]
}
]
}Response from Meticulous Machine:
{
"profile_id": "d188ba5f-4939-489a-9c0e-38fb879c9fdd",
"profile_name": "Turbo Light Roast v1",
"message": "Profile 'Turbo Light Roast v1' created successfully"
}Final Profile JSON Sent to Meticulous Machine:
{
"name": "Turbo Light Roast v1",
"id": "d188ba5f-4939-489a-9c0e-38fb879c9fdd",
"author": "AI Assistant",
"author_id": "f2d7b244-b2cd-4f9d-ae27-baee5f9ebaa8",
"display": {
"image": "/api/v1/profile/image/f9e16abcc19c1a34deaa9c2ac3bc7653.png",
"accentColor": "#5098C8"
},
"temperature": 94.0,
"final_weight": 54.0,
"stages": [
{
"name": "Preinfusion",
"key": "preinfusion",
"type": "flow",
"dynamics": {
"points": [[0.0, 6.0]],
"over": "time",
"interpolation": "linear"
},
"exit_triggers": [
{"type": "pressure", "value": 1.5, "relative": false, "comparison": ">="},
{"type": "time", "value": 20.0, "relative": false, "comparison": ">="}
],
"limits": []
},
{
"name": "Infusion",
"key": "infusion",
"type": "pressure",
"dynamics": {
"points": [[0.0, 6.0], [3.0, 6.0]],
"over": "time",
"interpolation": "linear"
},
"exit_triggers": [
{"type": "time", "value": 15.0, "relative": false, "comparison": ">="},
{"type": "weight", "value": 35.0, "relative": false, "comparison": ">="}
],
"limits": [{"type": "flow", "value": 8.0}]
},
{
"name": "Decline",
"key": "decline",
"type": "pressure",
"dynamics": {
"points": [[0.0, 6.0], [10.0, 3.0]],
"over": "time",
"interpolation": "linear"
},
"exit_triggers": [
{"type": "weight", "value": 54.0, "relative": false, "comparison": ">="},
{"type": "time", "value": 30.0, "relative": false, "comparison": ">="}
],
"limits": []
}
]
}Agent: "I've created a turbo shot profile called 'Turbo Light Roast v1' for your Ethiopian coffee. Here's what it does:
- Temperature: 94°C (ideal for light roasts to extract sweetness)
- Pre-infusion: Fast flow at 6 ml/s until pressure reaches 1.5 bar
- Infusion: Holds 6 bar pressure for quick extraction (exits at 35g or 15 seconds)
- Decline: Gradually reduces pressure from 6 to 3 bar for a smooth finish
- Final yield: 54g (1:3 ratio for bright, tea-like clarity)
The profile is now saved on your Meticulous machine and ready to use!"
- Natural Language Input: The user describes what they want in plain English
- Agent Intelligence: The AI understands the request and applies espresso profiling knowledge
- Structured API Calls: The agent constructs proper JSON with all required fields
- Automatic Normalization: Missing fields like
relativeandlimitsare automatically added - Machine-Ready Output: The final JSON is fully compliant with the Meticulous schema
- User-Friendly Response: The agent explains what the profile does in understandable terms
- Structured Profile Creation: Create profiles using typed parameters instead of raw JSON
- Profile Validation: Validate profiles against JSON schema with helpful error messages
- Profile Management: List, get, update, duplicate, and delete profiles
- Profile Execution: Load and run profiles on the machine
- MCP Resources: Access espresso knowledge, schema reference, and profiles as resources
- MCP Prompts: Prompt templates for creating and modifying profiles
Set the METICULOUS_API_URL environment variable to your machine's address. Each Meticulous machine has a unique hostname (e.g. meticulousmodel<words>.local). You can find it in your machine's settings, or use the IP address directly.
Add the METICULOUS_API_URL environment variable to your MCP client configuration:
Mac example:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python3.11",
"args": [
"/Users/yourname/meticulous-mcp/meticulous-mcp/run_server.py"
],
"env": {
"PYTHONPATH": "/Users/yourname/meticulous-mcp/meticulous-mcp/src",
"METICULOUS_API_URL": "http://your-machine-name.local"
}
}
}
}Windows example:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python",
"args": [
"C:\\Users\\YourName\\meticulous-mcp\\meticulous-mcp\\run_server.py"
],
"env": {
"PYTHONPATH": "C:\\Users\\YourName\\meticulous-mcp\\meticulous-mcp\\src",
"METICULOUS_API_URL": "http://your-machine-name.local"
}
}
}
}Mac (Terminal):
export METICULOUS_API_URL=http://your-machine-name.localMac (persistent - add to ~/.zshrc or ~/.bash_profile):
echo 'export METICULOUS_API_URL=http://your-machine-name.local' >> ~/.zshrc
source ~/.zshrcWindows (Command Prompt):
set METICULOUS_API_URL=http://your-machine-name.localWindows (persistent - System Properties):
- Right-click "This PC" → Properties
- Advanced system settings → Environment Variables
- Add new System variable:
METICULOUS_API_URL=http://your-machine-name.local
Required: METICULOUS_API_URL must be set. The server will not start without it.
If you prefer to use the Python module directly instead of the run script:
Mac:
{
"mcpServers": {
"meticulous-mcp": {
"command": "python3.11",
"args": [
"-m",
"meticulous_mcp.server"
],
"env": {
"PYTHONPATH": "/Users/yourname/meticulous-mcp/meticulous-mcp/src"
}
}
}
}Windows: Same format, but use python instead of python3.11.
Note: When using the module approach (-m meticulous_mcp.server), the PYTHONPATH environment variable is required because the module needs to know where to find the dependencies.
Problem: Error about match statement or syntax errors
Solution: Ensure you're using Python 3.11 or higher:
- Mac:
python3.11 --version - Windows:
python --version
Problem: Module not found errors
Solution:
- If using
run_server.py: The script should handle paths automatically, but ensure PYTHONPATH is set in your MCP config as a safeguard - If using the module approach (
-m meticulous_mcp.server): PYTHONPATH is required - Verify your PYTHONPATH includes
meticulous-mcp/src - Ensure dependencies are installed:
pip install -r meticulous-mcp/requirements.txt
Problem: Paths with spaces not working
Solution:
- Use double backslashes:
C:\\Users\\YourName\\Meticulous MCP\\... - Or use forward slashes:
C:/Users/YourName/Meticulous MCP/... - Windows Python accepts both formats
Problem: MCP client can't connect to server
Solutions:
- Check that Python path is correct in your config
- Verify the
run_server.pypath is absolute and correct - Test manually:
python3.11 /path/to/run_server.py(should start without errors) - Check that all dependencies are installed:
pip install -r requirements.txt
Problem: Agent gets errors when trying to create profiles
Solutions:
- Make sure your MCP server is up to date (restart your MCP client after updating)
- Check that the agent has access to the espresso profiling knowledge resources
- Try asking the agent to rephrase your request more simply
- If errors persist, check the error message and try creating a simpler profile first
Problem: Cannot connect to Meticulous machine
Solutions:
- Verify your machine is powered on and on the same network
- Check the hostname in your machine's settings
- Set
METICULOUS_API_URLenvironment variable (see Advanced Configuration) - Try accessing
http://your-machine-name.localin a browser
Get machine device info (firmware, serial, name, etc.).
Read and modify machine settings like auto_preheat, enable_sounds, etc.
Browse history by date and retrieve direct download links for shot logs.
Create a new espresso profile with structured parameters.
Required fields:
name: Profile nameauthor: Author nametemperature: Brew temperature in Celsius (typically 82-96°C)final_weight: Target output weight in gramsstages: Array of stage objects (see example conversation above)
Optional fields:
variables: Custom variables for dynamic valuesaccent_color: Hex color code (e.g., "#FF5733")image: Base64 data URI or relative URL for profile image
List all available profiles.
Get full profile details by ID.
Update an existing profile.
Required fields:
profile_id: ID of the profile to update
Optional fields:
name: New profile nametemperature: New temperature in Celsiusfinal_weight: New target weight in gramsimage: Base64 data URI or relative URL for profile imagestages_json: JSON string containing updated stages array
Example:
{
"profile_id": "profile-uuid-here",
"name": "Updated Name",
"temperature": 92.0
}Duplicate a profile and optionally modify it.
Delete a profile permanently.
Validate a profile JSON against the schema.
Select a profile on the machine's display.
Load and execute a profile (without saving).
Get expert knowledge on espresso profiling. Accepts a topic parameter:
rfc- Open Espresso Profile Format RFCguide- General profiling guideschema- JSON schema referencemechanics- Meticulous hardware axioms (hydraulic inertia, sensing, trigger behavior, transitions)
espresso://knowledge- Espresso profiling knowledgeespresso://schema- Profile schema referenceespresso://rfc- Open Espresso Profile Format RFCmeticulous://mechanics- Machine-specific physics and control axiomsespresso://profile/{id}- Individual profile as resource
create_espresso_profile- Prompt template for creating profilesmodify_espresso_profile- Prompt template for modifying profilestroubleshoot_profile- Prompt template for diagnosing shot issues
Run tests:
pytest- pyMeticulous: Python API wrapper for Meticulous machine
- mcp: Model Context Protocol SDK
- jsonschema: JSON schema validation
- pydantic: Data validation
All dependencies are installed via pip install -r meticulous-mcp/requirements.txt.
This project is licensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later).
This project depends on pyMeticulous, which is licensed under GPL 3.0. As a result, this project is also licensed under GPL 3.0 in accordance with the GPL copyleft requirements.
For full license terms, see the LICENSE file in this directory.