servomotor-mcp
Drive open-source Gearotons M17 servomotors from natural language.
An MCP server that exposes the M17 β a NEMA-17
integrated, closed-loop, RS-485 servomotor β to Claude Desktop, Claude Code, or any MCP
client. Control real motors by just asking:
"Find my motors and rotate the one on the bench two full turns, slowly."
Nothing is hardcoded: the server discovers your serial ports, auto-detects the
motors on the bus (the firmware's "Detect devices" command), and exposes the entire
firmware command set β every command in the servomotor library's catalog becomes an
MCP tool automatically (48 commands as of library 0.10.0), plus a few high-level tools
for everyday moves. It ships with a mock backend, so you can try the whole thing with
no hardware.
βΆ 50-second video: the real motor and this session side by side β recorded 2026-09-09 on a bench M17; every line above is from the session log.
Step-by-step tutorial (boxed motor to "talk to it" in about twenty minutes): Talk to a servomotor from Claude Code on Hackster.
The first servomotor with an official MCP server. Open hardware, open firmware, open
software β and now an open, AI-native control interface.
Quickstart (no hardware, ~2 minutes)
uvx --from servomotor-mcp servomotor-mcp
pip install servomotor-mcp
servomotor-mcp
Then add it to Claude Desktop β copy the block from
examples/claude_desktop_config.json into your
claude_desktop_config.json, restart Claude Desktop, and ask:
"What serial ports do you see? Connect and find my motors."
See examples/demo_prompts.md for a scripted demo.
Drive real motors
Plug an M17 (or a daisy-chain of them) into a USBβRS-485 adapter and install the
[serial] extra β that's it, no configuration:
pip install 'servomotor-mcp[serial]'
servomotor-mcp
With the servomotor library installed the server uses the real serial backend
automatically. Without it, the server runs its simulator and says so: list_serial_ports
and connect return a notice field, and a warning goes to stderr. With uv, use
uvx --from 'servomotor-mcp[serial]' servomotor-mcp. In a session, the model then:
list_serial_ports β enumerates the machine's ports (macOS /dev/cu.*,
Windows COM*, Linux /dev/ttyUSB*), flagging USB serial adapters;
connect β opens the port you (or it) picked, at 230400 baud;
- auto-detects every motor on that bus (unique ID + alias) β no address maps to write;
- drives them. Tell it in plain English which adapter to use if you have several.
High-level (discovery + everyday motion):
| Tool | What it does |
|---|
list_serial_ports | Enumerate serial ports with USB metadata (call first). |
connect / disconnect | Open a port and auto-detect the motors on that bus. |
detect_devices | Re-scan the bus (reboots the motors on it). |
list_motors | Detected motors with live position/voltage/temperature/status. |
move_to / move_relative | Absolute / relative moves in degrees; waits for completion. |
stop | Emergency-stop one or all motors. |
get_motor_status | One motor's snapshot, fatal errors decoded to plain English. |
run_sequence | Choreographed steps ("draw a square"), incl. raw command steps. |
Plus one tool per firmware command, generated from the library's command catalog:
enable_mosfets, go_to_position, move_with_velocity, move_with_acceleration,
multimove, homing, zero_position, get_position, get_temperature,
set_device_alias, set_pid_constants, system_reset, vibrate, ping, β¦ β anything
the motor can do, the model can do. Motors are addressed by their alias number, their
16-hex-digit unique ID, or "all" (broadcast). Values are in friendly units (degrees,
seconds, degrees/s, volts, Β°C); the server converts to firmware units.
How it works
natural language β Claude β MCP tool calls β this server β RS-485 β M17 motors
The server is a thin layer over the Gearotons servomotor Python library. The library is
data-driven β motor_commands.json defines every firmware command β and the server turns
that same catalog into MCP tools, so new library commands appear automatically. Tool calls
are forwarded straight to the hardware β no software clamping; full multi-turn travel, any
speed. The motor's own firmware protections (over-current / over-voltage /
over-temperature) still apply. The same tools run against the mock backend
(GEAROTONS_MOTOR_BACKEND=mock) for development and CI.
Environment variables (all optional):
GEAROTONS_MOTOR_BACKEND β auto (default: serial when the servomotor library is
installed, else mock), serial, or mock.
GEAROTONS_SERIAL_PORT β default port for connect when the model doesn't pass one.
GEAROTONS_DEFAULT_SPEED_DPS β default speed for move_to/move_relative (180).
Develop / test
pip install -e '.[dev]'
GEAROTONS_MOTOR_BACKEND=mock pytest
hardware_tests/ contains scripts that exercise the real serial path end to end
(port sweep, full command suite, stdio MCP session) against a bench motor.
Status
- β
Full firmware command surface (48 commands), serial-port discovery, bus
auto-detection β verified on a physical M17 (fw 0.15.3.0) over a real stdio MCP
session and via
uvx, on all four test adapters (motor found only where it truly is).
- β
Mock backend + 39 unit tests, no hardware needed.
- β
Cross-platform port handling (macOS / Windows / Linux) via pyserial enumeration.
License
MIT. Hardware, firmware, and software for the M17 are open-source β
see github.com/tomrodinger/servomotor.