DEV Community

Cover image for Part 2: Building MCP Servers to Control a Home Coffee Roaster - An Agentic Development Journey with Warp Agent
sy
sy

Posted on

Part 2: Building MCP Servers to Control a Home Coffee Roaster - An Agentic Development Journey with Warp Agent

Introduction

In this 3-part series, we are building an autonomous coffee roasting agent with Warp. The first part covered how we fine-tuned a model to detect first crack — a critical phase in the roasting process. This was a nice warm-up implementing a key component for our end goal, but detection alone isn't enough. Now we need to expose this functionality so the agent we'll build can both detect first crack and control the roasting process.

This post focuses on:

  • The objective: Turning ML predictions into real-world roaster control actions.
  • Solution overview: Model Context Protocol (MCP) servers as the bridge between AI agents and hardware
  • Implementation: The two MCP servers we built—First Crack Detector MCP + Hottop Controller MCP

📊 TL;DR

  • Connect trained ML model to physical roaster control using an agent to achieve autonomous coffee roasting
  • Build two MCP servers — FirstCrackDetector + HottopController
    • Stack: Python MCP SDK, pyserial, pyhottop, Auth0 authentication
  • Real-time detection + safe roaster control via AI agents (208+ tests passing)
  • Using Warp Agent mode, Context7 MCP Server, Auth0 MCP Server during development
  • Next Part: Part 3 orchestrates both servers with Microsoft Agent Framework

Integrating software, hardware and agents without reinventing the wheel

Traditional approach: Build custom APIs, handle authentication, manage state

  • Write integration code using imperative/declarative patterns to manage task lifecycles.
  • Homegrown specifications make it harder to leverage emerging ML/AI technologies.
  • Each new AI model or agent requires custom integration work.

The MCP option: Standardised protocol for AI <-> tool communication

  • Provides deterministic tools for non-deterministic AI systems.
  • Benefits: Discoverability, type safety, streaming support, composability, and interoperability across AI models and agents.
  • Write once, connect to MCP-compatible AI (Claude, ChatGPT, custom agents).

🤖 Warp Agent Contributions

  • Provided MCP server scaffolding and tool definitions using standard MCP SDK.
  • Helped integrate pyhottop library for Hottop serial protocol communication.
  • Debugged serial communication timing issues and state synchronization.
  • Generated Auth0 authentication middleware with role-based access control.
  • Created comprehensive test suites (208+ tests across both MCP servers).
  • Suggested testing strategies including simulation mode for hardware free development.

What is MCP (Model Context Protocol) and Why Use It?

What is MCP?

MCP is a protocol that enables AI assistants like Claude, ChatGPT, Warp Agent Mode to connect to external resources through a client-server architecture following standard protocols. This allows using the same MCP server with various agent technologies without having to modify the code.

Client-Server Concept

MCP Server

A program that exposes specific data and tools (functionality) that an AI Agents can use. For example, a server might provide access to a database, file system, or even as in our case specific hardware.

MCP Client

The application that connects to MCP servers and makes their capabilities available to the AI. As an example, Claude /ChatGPT acts as an MCP client.

Transport Types

MCP supports different ways for clients and servers to communicate:

  • stdio (Standard Input/Output)
    • Most common for local integrations
    • Server runs as a subprocess, communicating via stdin/stdout
    • Simple and works well for local tools
  • SSE (Server-Sent Events) -Used for remote servers over HTTP
    • Server pushes updates to client
    • Good for web-based integrations
  • Custom transports can also be implemented
    • The protocol is designed to be transport-agnostic
Flow

When user asks Claude (MCP Client) something that is exposed by an MCP Server, the client can call the MCP server to retrieve data or execute tools, then use that information in its response.

MCP Overview

Server 1: First Crack Detector MCP

In this section, we will briefly cover how the detector we have trained in the previous article is exposed as an MCP Server.

The following diagram illustrates how the components are exposed as an MCP Server:

First Crack Detection MCP Server

Implementation Details

  • MCP SDK setup: Server initialisation using standard Python MCP SDK with stdio and SSE transports.
  • Tool definitions: start_detection, stop_detection, get_status with Auth0 role-based authorisation.
  • Session management: Thread-safe singleton pattern with idempotency enforcement.
  • Real-time monitoring: Streaming detection events via SSE for live status updates.
  • Error handling: Audio device enumeration failures, model loading issues, thread crashes, timeout scenarios.

Code Walkthrough

# Key implementation components:
# - MCP SDK decorators for tool registration
# - Auth0 JWT validation middleware
# - Session manager with thread-safe state
# - OpenTelemetry tracing integration

# First Crack Detection MCP Server setup
from mcp.server import Server
from mcp.types import Tool, TextContent

mcp_server = Server("first-crack-detection")

@mcp_server.list_tools()
async def list_tools() -> list[Tool]:
    return [
        Tool(
            name="start_first_crack_detection",
            description="Start monitoring audio for first crack events",
            inputSchema={
                "type": "object",
                "properties": {
                    "audio_source_type": {
                        "type": "string",
                        "enum": ["audio_file", "usb_microphone", "builtin_microphone"]
                    }
                },
                "required": ["audio_source_type"]
            }
        )
    ]

@mcp_server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    if name == "start_first_crack_detection":
        # Thread-safe session management
        result = session_manager.start_session(
            audio_config=AudioConfig(**arguments)
        )
        return [TextContent(
            type="text",
            text=json.dumps(result, indent=2)
        )]

Enter fullscreen mode Exit fullscreen mode

Testing Approach

  • Custom test scripts: Python scripts using stdio communication (test_mcp_roaster.py)
  • Shell integration tests: Bash scripts for end-to-end workflows (test_roaster_server.sh)
  • Unit test coverage: 86 passing tests with pytest, mocking audio devices and model inference
  • Manual hardware testing: Real USB microphone validation with live roasting sessions

Server 2: Hottop Roaster Controller MCP

The Second MCP Server is to expose the status of the roaster and also to run commands to set heat, fan as well as start / stop commands for the roast.

This is implemented as a separate MCP server due to different hardware requirements which might require running these on different hosts.

The Hottop KN-8828B-2K+ Protocol

Initial approach with pyhottop library

Initially, we have attempted to use the pyhottop library for serial communication with the Hottop KN-8828B-2K+ roaster. However, we encountered compatibility issues that prevented reliable operation and had to consider an alternative approach.

Adapting to Artisan's protocol

After pyhottop proved unreliable, we analyzed the Artisan roasting software source code — a mature, widely-used open-source application for coffee roaster control. Being a user of Artisan's Hottop integration, I knew it has been working well for me. Given it has been battle-tested by the roasting community for a long time, it was an obvious next choice.

Warp Agent Mode has successfully analysed and adapted Artisan's serial protocol implementation.

Roaster MCP Server

Implementation Details

  • Serial connection management: USB serial at 115200 baud, continuous 0.3s command intervals (required by Hottop)
  • Command encoding: Artisan-compatible 36-byte protocol with checksums
  • Status parsing: Real-time temperature readings (bean + chamber) from serial responses
  • Input validation:
    • Heat/fan values: 0-100% in 10% increments
    • Connection state checks before commands
    • Thread-safe state management with locks
  • Authentication: Auth0 JWT with role-based access control
    • read:roaster - Status monitoring only
    • write:roaster - Full hardware control
    • Per-user audit logging

Code Architecture

# Key implementation layers:
# 1. MCP Server (sse_server.py) - Auth0 + tool definitions
# 2. SessionManager - Thread-safe orchestration
# 3. HardwareInterface - Artisan serial protocol
# 4. Continuous command loop - 0.3s intervals with temperature polling
Enter fullscreen mode Exit fullscreen mode

Roaster MCP Server Overview

Testing Strategy

  • MockRoaster: Realistic thermal simulation for development without hardware. Unfortunately, due to time restrictions, this has provided limited utility.
  • Hardware verification: Validated with physical Hottop KN-8828B-2K+ (October 2025).
  • Test coverage: 122 passing unit tests.
  • Manual test scripts: test_hottop_interactive.py, test_hottop_auto.py.
  • Integration tests: SSE transport, Auth0 authentication, command sequences.

Hardware verification

The implementation was verified with physical Hottop KN-8828B-2K+ hardware on October 25, 2025:

  • Drum motor control
  • Heat control (0-100%)
  • Fan control (0-100%)
  • Bean drop sequence
  • Cooling system
  • Continuous temperature readings (Bean & Chamber)

Security and Safety Considerations

Transport and Security Architecture

Why SSE (Server-Sent Events)?

Although both MCP servers currently run on the same machine as the agent (hint hint: stdio transport would be simpler), we designed for a distributed architecture from the start. The plan is to eventually deploy:

  • Roasting MCP servers need to run close to the hardware - Running on the machine physically connected to the roaster and microphone.
  • Agent on a separate device - A cloud server or different local machine for orchestration.

This approach means we could potentially use a low powered computer (such as RaspBerry PI) for the servers and also make it easier to plugh and start instead of having to use a laptop next to roaster every time.

  • SSE benefits: Real-time streaming, works over standard HTTP/HTTPS, firewall-friendly
  • MCP compatibility: Follows MCP specification for HTTP+SSE transport
  • Future-proof: Easy transition from localhost to remote deployment

Authentication and Authorisation with Auth0

Once MCP servers are exposed over the Internet / network, security becomes critical—especially for hardware control. This section briefly covers our approach for integrating Auth0 for authentication and authorisation.

Why Auth0?

  • Ease of integration: Well-documented SDKs and middleware
  • OAuth 2.0 Client Credentials: Perfect for machine-to-machine authentication
  • Role-based access control: Granular permissions via scopes
  • Bonus: Auth0 MCP Server for Warp Agent Mode to perform configuration tasks.

Security implementation:

  • JWT validation: Every MCP request validates Auth0 JWT tokens
  • Scope-based authorization:
    • read:roaster - Status monitoring only (observer role)
    • write:roaster - Full hardware control (operator role)
    • admin:roaster - Administrative functions (future)
  • Token expiration: JWTs expire, requiring regular re-authentication

Authorisation overview

This architecture ensures that only authorised clients can control the roaster, with full traceability of who did what and when—essential for safety-critical hardware operations.

Lessons Learned

It has been a fun side project seeing how far Warp Agent Mode (Coding Agent) and emerging MCP Servers for developer documentation (Context 7) and service access (Auth0 MCP Server) cam in terms of speeding up development process.

It is still required have a clear architecture, requirements and a final picture before starting. When these are used in conjunction with Agentic development tools, tasks could take several days can be completed in a day or so.

What Worked Well and Lessons Learned

  • Standard MCP SDK: Provided solid foundation for both stdio and SSE transports.
  • SSE transport: Future-proofed the architecture for distributed deployment.
    • Tested working with N8N, LangFlow and Python based local agents.
  • Auth0 integration: Straightforward OAuth 2.0 implementation with role-based access control.
  • Warp Agent Mode assistance: Accelerated MCP protocol understanding, test generation, and Auth0 middleware implementation.
  • Context7 and Auth0 MCP servers: Using MCP servers to build MCP servers (via Warp) streamlined development.
  • pyhottop library: Initial attempt failed, but pivoting to Artisan's proven protocol worked as expected.
  • MockRoaster simulation: Due to time restrictions, this was not explored sufficiently and ended up manually testing using local agents.
    • This is needs to be revisited in the future especially to be able to test agent loop.

MCP-Specific Insights

  • Transport choice matters: SSE enables remote deployment but requires careful auth implementation.
  • Tool vs resource patterns: Tools for actions (hardware control), resources for data streams (status monitoring) so far working well with agents.
  • Idempotency is critical: Start/stop commands must be safe to call multiple times.
    • Initial attempts caused hardware to go into start stop loop and required manual intervention.
  • Scope-based authorization: Fine-grained permissions (read:roaster vs write:roaster) essential for hardware safety.
    • Although in the current integration mode, only a single client is used.
  • Observability: Using Open Telemetry helped troubleshooting issues quickly.
  • Testing strategies: Combination of unit tests (208 total), MockRoaster simulation, and manual hardware validation.

Real-World Usage Examples

Warp Agnt with Roaster Control (initial testing)

The following are sample prompts intended for testing the MCP server from Warp.

User: "Start the roaster"
Warp Agent Mode: [calls roaster_control MCP: start_roaster()]
         "Roaster started. Ready to add beans."

User: "Check the roaster status"
Warp Agent Mode: [calls roaster_control MCP: read_roaster_status()]
         "Status:
         • Drum: Running
         • Bean temp: 172°C
         • Chamber temp: 185°C
         • Heat: 0%
         • Fan: 0%"

User: "Stop the drum"
Warp Agent Mode: [calls roaster_control MCP: stop_roaster()]
         "Roaster drum stopped. Heat automatically turned off for safety."
Enter fullscreen mode Exit fullscreen mode

What's Next: Part 3 Preview

Now that we have:

  • A trained first crack detection model (Part 1).
  • Built two MCP servers with hardware control + ML inference (Part 2).
  • Used Auth0 for security and SSE transport for distributed deployment (Part 2).

In Part 3: Building an Autonomous Roasting Agent, we'll bring it all together:

  • Comparing multiple Agent frameworks and assessing their suitability for such long running workflows.
    • N8N
    • LangFlow
    • Python based
    • Using Microsoft Agent Framework
    • Using OpenAI Python SDK
  • Real-time decision making: Agent analyses temperature trends, RoR, and first crack to adjust roast.
  • Extending OpenTelemetry observability: Distributed tracing across agent + MCP servers + hardware.
  • Safety systems:
    • Temperature bounds monitoring.
    • Emergency stop on anomalies.
    • Human override via UI.
  • Full end-to-end test: Press start -> Preheat -> Add beans -> Hands off -> First crack -> Development -> Drop -> (hope for) Perfect roast :)

The goal: An AI that roasts coffee consistently, safely, and (hopefully) better than manual control.

Resources

MCP & Standards:

Project Code:

Hardware & Serial Communication:

Authentication:

Tools:

Top comments (0)