Building a Model Context Protocol Server for Arduinos

Ari Mahpour
|  Created: August 4, 2025
Building a Model Context Protocol Server for Arduinos

In Vibe Coding with AI and Arduinos, we explored the idea of chatting with AI and letting the agent write code for an Arduino. We took it one step further and had Github Copilot’s agentic flow run all the compile and upload commands without lifting a finger. There were a few challenges faced with that workflow but the primary issue was the agent’s inability to run the same Arduino tool commands consistently. Starting a new conversation required giving the agent a nudge in the right direction to use the correct tool and correct commands. At the bare minimum, the agent would waste a few extra tokens trying to determine the correct commands to communicate with the device.

In this article, we’re going to present the solution to this problem: Model Context Protocol (MCP). We’ll show you how to implement your own MCP server that interfaces with an Arduino from the ground up.

What Is MCP and Why Use It?

Model Context Protocol is a standard that uses JSON-RPC 2.0 to communicate between agents and servers. These servers present themselves as tools to the AI agent. The server can contain tools ranging from a simple echo of  “Hello world” when called upon to perform complex tasks involving large datasets or connected hardware. In Building an AI Lab Assistant, we used custom GPT actions with a webserver to connect AI with controlling lab instruments over Python. In that respect, MCP is very similar but it is an open standard that any tool can use. Since it’s an open standard we can connect it to AI agents in our code editors such as Cursor or GitHub Copilot. Instead of nudging the AI agent to figure out how to perform a task (in our case uploading a sketch to an Arduino), we give it an endpoint to talk to and let the toolbmake that call. This eliminates all the messy back and forth getting an environment set up and allows the AI agent to focus on the task at hand.

Running the MCP Tool

Before setting up the MCP server, you’ll need to clone this simple example repository: https://github.com/amahpour/arduino-mcp-server-simple.git. Following the README instructions, you’ll need to install the dependencies using:

pip install -r requirements.txt

and also install the arduino-cli tool. Make sure the tool is on your PATH as well (i.e. you can call the arduino-cli tool command from the terminal). Note that this MCP server was developed for MacOS so some adaptations may be required for other operating systems. Just to validate that everything is working, you can run

python mcp_arduino.py

to ensure the MCP server can start. If you’re running cursor, you’ll notice a .cursor folder. It contains the mcp.json file that Cursor will automatically detect as a tool. Make sure that it is enabled by going into the Cursor tool settings and ensure that the slider for the “arduino” tool is turned on:

Figure 1: Tools and Integrations settings in Cursor
Figure 1: Tools and Integrations settings in Cursor

Similarly, you can set up the same thing in VSCode with GitHub CoPilot or the Claude desktop client. At this point, you can start a conversation with your agent and ask it to do various things such as:

  • Tell me what Arduinos I have connected to my laptop
  • Compile this sketch
  • Upload this sketch
  • Send “Hello World” to the Arduino

Here is what some sample agent tool calls look like using Cursor.

Figure 2: Calling an Agent to compile the sketch
Figure 2: Calling an Agent to compile the sketch
Figure 3: Calling an Agent to upload the sketch
Figure 3: Calling an Agent to upload the sketch
Figure 4: Calling an Agent to send serial data (to test the echo)
Figure 4: Calling an Agent to send serial data (to test the echo)

There’s no more ambiguity. The Agent now knows exactly what “tool” to call in order to compile or upload a sketch. No bash session, no validating connection to the board, no environment setup. Everything has been configured for it so it can focus on what’s important.

Code Overview

There’s only one file in the repository that we ultimately care about: mcp_arduino.py. Leveraging the FastMCP Python library, we can throw together an MCP server very quickly. We instantiate the FastMCP object first like so:

mcp = FastMCP(name="ArduinoMCP")

Then we create our function for what we want to do. As a very trivial example, we can just return “pong” when you call “ping” like so:

def ping()

    return "pong"

And then we add a FastMCP decorator on top of the function like so:

@mcp.tool()

def ping()

    return "pong"

That’s it! That’s all you need to set up an MCP server. When you define your MCP JSON definition, you just tell it that the command will be “python” with the argument of the path to the file (but all of this is taken care of for you in the .cursor/mcp.json file).

At this point, we have a basic framework that enables us to create more complex functions. The simplest of these functions will just be a call to the arduino-cli command line tool to upload and compile sketches. There are some parameters in there as well that require passing in such as the board name so we need to create some helper functions. We’ve defined helper functions such as detect_fqbn() and _run_cli() as defined later in the file.

One keyword you may not be familiar with is async. When a function is marked async, it becomes a coroutine. This means it can pause and resume without blocking the rest of the program. The await keyword tells Python: “run this task, and while we wait for it to finish, go do other things.” For example, when compiling Arduino code with arduino-cli, the server can go do other things and return back to the functional call after the compilation is done. Without async and await, the entire MCP server would freeze until each compile or upload completes. Even though this demo uses a single AI agent and Arduino device (i.e. we’re okay with blocking), the async pattern is generally a best practice for FastMCP (and web) servers.

Conclusion

Model Context Protocol turns the “AI, please figure it out” game into a consistent, repeatable, hands-off tool. With one short Python file we gave our agent a menu of deterministic actions: list boards, compile, upload, talk over serial. No more prompt nudging, no more wasted token, and, most importantly, no risk of a stray command bricking our device (oops!). With this foundational work, the world is your oyster. Now you can start extending this MCP server to incorporate more functionality and interface with other embedded devices, letting AI focus on what’s important.

About Author

About Author

Ari is an engineer with broad experience in designing, manufacturing, testing, and integrating electrical, mechanical, and software systems. He is passionate about bringing design, verification, and test engineers together to work as a cohesive unit.

Related Resources

Back to Home
Thank you, you are now subscribed to updates.