# Gearotons M17 Servomotor (pypi · servomotor-mcp)

Drive Gearotons M17 open-source servomotors from plain English over RS-485; mock mode, no hardware.

- Trust score: 55/100 (low)
- Change this week: +6
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-21

## Components

- pypi · `servomotor-mcp`: 55/100 (this document), [markdown](https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp.md), [page](https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp)

## Channel facts

- Registry: `pypi`
- Package: `servomotor-mcp`
- Version: `0.3.1`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-21.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it.
  - 0 of 29 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 45/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - Clear OSI-approved license (MIT).
  - Actively maintained (last published 11 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 63/100
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 9467 tokens (~166/item across 57 items; 57 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 40/100
  - Stability observed for 12 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 67/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 3 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "run_sequence" implies "execute" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 57 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the Gearotons M17 Servomotor MCP server?

Gearotons M17 Servomotor runs locally as a PyPI package, launched with uvx servomotor-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add gearotons-servomotor-mcp -- uvx servomotor-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "gearotons-servomotor-mcp": {
      "command": "uvx",
      "args": [
        "servomotor-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "gearotons-servomotor-mcp": {
      "command": "uvx",
      "args": [
        "servomotor-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add gearotons-servomotor-mcp -- uvx servomotor-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "gearotons-servomotor-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "servomotor-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add gearotons-servomotor-mcp --command uvx --arg servomotor-mcp
```

### Hermes

```yaml
mcp_servers:
  gearotons-servomotor-mcp:
    command: "uvx"
    args: ["servomotor-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "gearotons-servomotor-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "servomotor-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add gearotons-servomotor-mcp -t stdio -c uvx -a servomotor-mcp
```

### Other

```json
{
  "mcpServers": {
    "gearotons-servomotor-mcp": {
      "command": "uvx",
      "args": [
        "servomotor-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-21 (score 55, +1)

No change was recorded against any check on this day. Stability & Change Management went from 37 to 40. That category is still filling its 30-day observation window: 11 days of observed history at the previous scan, 12 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-19 (score 54, +1)

No change was recorded against any check on this day. Stability & Change Management went from 30 to 33. That category is still filling its 30-day observation window: 9 days of observed history at the previous scan, 10 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-17 (score 53, +4)

- [functional improvement] Stability: unverified → 0.27

### 2026-09-14 (score 49, −15)

- [security regression] Malware scan: pass → unverified

### 2026-09-13 (score 64, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-09-09 (score 49)

First indexed and scored.

## MCP tools (57)

### `list_serial_ports` (~114 tokens)

List the serial ports on this computer so one can be chosen for ``connect``.

Call this FIRST in any session. USB-RS485 adapters show up with a USB VID:PID and
usually a telling description/manufacturer (FTDI, CH340, CP210x...). If several
adapters are present, connect to the most likely one and check whether motors are
detected; it is cheap to connect to another port and look again. Relay the options
to the user in plain English if it is ambiguous.

### `connect` (~203 tokens)

Open a serial port (230400 baud) and auto-detect the motors on that RS-485 bus.

\``port`` is a device name from ``list_serial_ports`` (e.g. "/dev/cu.usbserial-210",
"COM3", "/dev/ttyUSB0"). If omitted: uses $GEAROTONS_SERIAL_PORT if set, else the
single USB serial adapter if there is exactly one, else asks you to choose.

Detection reboots every motor on the bus (positions re-zero at the current shaft
location, MOSFETs turn off) and takes ~3 s per attempt. If no motors are found, the
adapter may be the wrong one — try another port. Connecting to a different port
replaces the previous connection, but only once the new port opens successfully —
a failed attempt leaves the old connection intact.

Input parameters:

- `detect` (boolean)
- `detect_attempts` (integer)
- `port`

### `disconnect` (~27 tokens)

Close the serial port (e.g. to free it for another program, or before unplugging).

### `detect_devices` (~101 tokens)

Re-scan the connected bus for motors using the firmware's "Detect devices" command.

Use after plugging in / powering on motors, or when a motor seems missing. Runs
\``attempts`` merged detection rounds (more rounds = more reliable with many motors
on one bus). CAUTION: this reboots every motor on the bus — positions re-zero at the
current shaft location and MOSFETs turn off.

Input parameters:

- `attempts` (integer)

### `list_motors` (~77 tokens)

List the detected motors with live position, voltage, temperature, and status.

Call after ``connect`` to see what is on the bus, or any time the user asks "what
motors are connected / where are they". If this is empty but hardware is plugged in,
run ``detect_devices`` or try another serial port.

### `move_to` (~174 tokens)

Move one motor to an ABSOLUTE angle in degrees and wait for it to finish.

Use when the user names a target position ("go to 90 degrees", "one full turn" =
360). Angles are unbounded multi-turn (720 = two full turns). ``speed_dps`` is
degrees/second (default 180). Enables the motor's MOSFETs automatically and returns
the settled position. For very long moves (>30 s) prefer ``go_to_position`` plus
\``get_n_queued_items`` polling so the tool call doesn't time out.

motor: an alias number (e.g. 88) or a 16-hex-digit unique ID from list_motors.

Input parameters:

- `degrees` (number, required)
- `motor` (string, required)
- `speed_dps`

### `move_relative` (~134 tokens)

Move one motor by a RELATIVE amount in degrees (+/-) and wait for it to finish.

Use for "turn a bit more", "back off 10 degrees", or incremental jogging. Any
magnitude is allowed, including multiple full turns. ``speed_dps`` is degrees/second
(default 180). Enables the MOSFETs automatically and returns the settled position.

motor: an alias number (e.g. 88) or a 16-hex-digit unique ID from list_motors.

Input parameters:

- `degrees` (number, required)
- `motor` (string, required)
- `speed_dps`

### `stop` (~81 tokens)

Immediately halt one motor, or ALL motors if ``motor`` is omitted.

Use for "stop", "halt", or any sign something is wrong. Sends the firmware's
emergency stop: motion halts and the move queue empties; holding torque remains.
Use ``disable_mosfets`` afterwards to let the shaft spin freely.

Input parameters:

- `motor`

### `get_motor_status` (~75 tokens)

One motor's live snapshot: position, supply voltage, temperature, decoded status.

Call after moves to CONFIRM completion, or when the user asks "where is it / is it
okay". Includes any fatal error decoded to plain English with suggested fixes
(clear faults with ``system_reset``).

Input parameters:

- `motor` (string, required)

### `run_sequence` (~175 tokens)

Execute a choreographed sequence of steps, e.g. "draw a square" or "wave".

Each step is one of:
    {"action": "move_to",       "motor": "88", "degrees": 90, "speed_dps": 120}
    {"action": "move_relative", "motor": "88", "degrees": -30}
    {"action": "stop"}                          # motor optional -> all
    {"action": "wait",          "seconds": 0.5}
    {"action": "command",       "motor": "88", "name": "vibrate", "params": [1]}

Steps run in order; "command" runs any raw catalog command by tool name. Returns the
final state of every detected motor.

Input parameters:

- `steps` (array, required)

### `disable_mosfets` (~110 tokens)

Disables the MOSFETS (note that MOSFETs are disabled after initial power on). [Firmware command "Disable MOSFETs", group: Basic Control.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `enable_mosfets` (~96 tokens)

Enables the MOSFETS. [Firmware command "Enable MOSFETs", group: Basic Control.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `trapezoid_move` (~208 tokens)

Move immediately to the given position using the currently set speed (the speed is set by a separate command) [Firmware command "Trapezoid move", group: Motion Control.]
NOTE: The displacement is RELATIVE to the current position.
This QUEUES the move and returns immediately; poll get_n_queued_items for completion, or use move_to/move_relative which wait. Requires enable_mosfets first.
Parameters:
  \- displacement (in degrees): The displacement to travel. Can be positive or negative.
  \- duration (in seconds): The time over which to do the move.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `displacement` (number, required)
- `duration` (number, required)
- `motor` (string, required)

### `set_maximum_velocity` (~121 tokens)

Sets maximum velocity (this is not used at this time) [Firmware command "Set maximum velocity", group: Configuration.]
Parameters:
  \- maximumVelocity (in degrees_per_second): Maximum velocity.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `maximumVelocity` (number, required)
- `motor` (string, required)

### `go_to_position` (~191 tokens)

Move to this new given position in the amount of time specified. Acceleration and deceleration will be applied to make the move smooth. [Firmware command "Go to position", group: Motion Control.]
This QUEUES the move and returns immediately; poll get_n_queued_items for completion, or use move_to/move_relative which wait. Requires enable_mosfets first.
Parameters:
  \- position (in degrees): New absolute position value.
  \- duration (in seconds): Time allowed for executing the move.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `duration` (number, required)
- `motor` (string, required)
- `position` (number, required)

### `set_maximum_acceleration` (~115 tokens)

Sets max acceleration [Firmware command "Set maximum acceleration", group: Configuration.]
Parameters:
  \- maximumAcceleration (in degrees_per_second_squared): The maximum acceleration.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `maximumAcceleration` (number, required)
- `motor` (string, required)

### `start_calibration` (~135 tokens)

Starts a calibration, which will determine the average values of the hall sensors and will determine if they are working correctly [Firmware command "Start calibration", group: Configuration.]
NOTE: The motor spins through a calibration routine; the shaft must be free to rotate. Takes some seconds; the motor won't respond until done.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `capture_hall_sensor_data` (~355 tokens)

Start sending hall sensor data (work in progress; don't send this command) [Firmware command "Capture hall sensor data", group: Other.]
Parameters:
  \- captureType: Indicates the type of data to capture. Currently 1 to 3 are valid.
  \- nPointsToRead: Number of points to read back from the device
  \- channelsToCaptureBitmask: Channels to capture bitmask. The first three bits are valid, which will turn on (0) or turn off (0) that hall sensor channel
  \- timeStepsPerSample: Aquire a sample every this number of time steps. Time steps happen at the update frequency, which can be read with the Get product specs command
  \- nSamplesToSum: Number of samples to sum together to make one point to transmit back
  \- divisionFactor: Division factor to apply to the sum of the samples to scale it down before transmitting it so that it fits into the returned data type, which is a 16-bit number per each hall sensor
Returns:
  \- data: The data of the hall sensors after suming and averaging
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `captureType` (integer, required)
- `channelsToCaptureBitmask` (integer, required)
- `divisionFactor` (integer, required)
- `motor` (string, required)
- `nPointsToRead` (integer, required)
- `nSamplesToSum` (integer, required)
- `timeStepsPerSample` (integer, required)

### `reset_time` (~101 tokens)

Resets the absolute time to zero (call this first before issuing any movement commands) [Firmware command "Reset time", group: Basic Control.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_current_time` (~102 tokens)

Gets the current absolute time [Firmware command "Get current time", group: Status & Monitoring.]
Returns:
  \- currentTime: The current absolute time in microseconds
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `time_sync` (~185 tokens)

Sends the master time to the motor so that it can sync its own clock (do this 10 times per second). [Firmware command "Time sync", group: Device Management.]
Parameters:
  \- masterTime (in seconds): The motor absolute time that the motor should sync to (in microseconds).
Returns:
  \- timeError: The error in the motor's time compared to the master time.
  \- rccIcscr: The contents of the RCC-ICSCR register (holds the HSICAL and HSITRIM settings).
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `masterTime` (number, required)
- `motor` (string, required)

### `get_n_queued_items` (~159 tokens)

Get the number of items currently in the movement queue (if this gets too large, don't queue any more movement commands) [Firmware command "Get n queued items", group: Status & Monitoring.]
Returns:
  \- queueSize: The number of items in the movement queue. This command will return between 0 and 32. If less than 32, you can add more items to the queue to continue the movements in order without stopping.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `emergency_stop` (~100 tokens)

Emergency stop (stop all movement, disable MOSFETS, clear the queue) [Firmware command "Emergency stop", group: Basic Control.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `zero_position` (~111 tokens)

Make the current position the position zero (origin) [Firmware command "Zero position", group: Basic Control.]
NOTE: Redefines the current shaft location as 0 degrees (no movement).
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `homing` (~225 tokens)

Homing (or in other words, move until a crash and then stop immediately) [Firmware command "Homing", group: Motion Control.]
NOTE: The motor moves until it hits a physical obstruction, then zeroes there. Ensure a hard stop exists within maxDistance.
Parameters:
  \- maxDistance (in degrees): The maximum distance to move (if a crash does not occur). This can be positive or negative. the sign determines the direction of movement.
  \- maxDuration (in seconds): The maximum time to allow for homing. Make sure to give enough time for the motor to cover the maximum distance or the motor may move too fast or throw a fatal error.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `maxDistance` (number, required)
- `maxDuration` (number, required)
- `motor` (string, required)

### `get_hall_sensor_position` (~139 tokens)

Get the position as measured by the hall sensors (this should be the actual position of the motor and if everything is ok then it will be about the same as the desired position) [Firmware command "Get hall sensor position", group: Status & Monitoring.]
Returns:
  \- hallSensorPosition: The current position as determined by the hall sensors
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_status` (~169 tokens)

Gets the status of the motor [Firmware command "Get status", group: Status & Monitoring.]
Returns:
  \- statusFlags: A series of flags which are 1 bit each
  \- fatalErrorCode: The fatal error code. If 0 then there is no fatal error. Once a fatal error happens, the motor becomes disabled and cannot do much anymore until reset. You can press the reset button on the motor or you can execute the System reset command to get out of the fatal error state.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `go_to_closed_loop` (~95 tokens)

Go to closed loop position control mode [Firmware command "Go to closed loop", group: Motion Control.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_product_specs` (~160 tokens)

Get the update frequency (reciprocal of the time step) [Firmware command "Get product specs", group: Device Management.]
Returns:
  \- updateFrequency: Update frequency in Hz. This is how often the motor executes all calculations for hall sensor position, movement, PID loop, safety, etc.
  \- countsPerRotation: Counts per rotation. When commanding the motor or when reading back position, this is the number of counts per one shaft rotation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `move_with_acceleration` (~227 tokens)

Rotates the motor with the specified acceleration [Firmware command "Move with acceleration", group: Motion Control.]
This QUEUES the move and returns immediately; poll get_n_queued_items for completion, or use move_to/move_relative which wait. Requires enable_mosfets first.
Parameters:
  \- acceleration (in degrees_per_second_squared): The acceleration (the unit is microsteps per time step per time step * 2^24).
  \- timeSteps (in seconds): The number of time steps to apply this acceleration. Use command 18 to get the frequency of the time steps. After this many time steps, the acceleration will go to zero and velocity will be maintained.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `acceleration` (number, required)
- `motor` (string, required)
- `timeSteps` (number, required)

### `set_device_alias` (~166 tokens)

Sets device alias [Firmware command "Set device alias", group: Device Management.]
NOTE: Changes how the motor is addressed (takes effect immediately). Re-run detect_devices afterwards.
Parameters:
  \- alias: The alias (which is a one byte ID) ranging from 0 to 251. It cannot be 252 to 254 because those are reserved. You can set it to 255, which will remove the alias.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `alias` (integer, required)
- `motor` (string, required)

### `get_product_info` (~203 tokens)

Get product information [Firmware command "Get product info", group: Device Management.]
Returns:
  \- productCode: The product code / model number (when doing a firmware upgrade, this must match between the firmware file and the target device).
  \- firmwareCompatibility: A firmware compatibility code (when doing a firmware upgrade, this must match between the firmware file and the target device).
  \- hardwareVersion: The hardware version stored as 3 bytes. The first byte is the patch version, followed by the minor and major versions.
  \- serialNumber: The serial number.
  \- uniqueId: The unique ID for the product.
  \- reserved: Not currently used.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `firmware_upgrade` (~207 tokens)

This command will upgrade the flash memory of the servo motor. Before issuing a firmware upgrade command, you must do some calculations as shown in the examples. [Firmware command "Firmware upgrade", group: Device Management.]
NOTE: Flashes a firmware page (hex-encoded bytes). Wrong data can brick the motor. Only use with a valid firmware file and the user's explicit go-ahead.
Parameters:
  \- firmwarePage: The data to upgrade one page of flash memory. Contents includes the product model code (8 bytes), firmware compatibility code (1 byte), page number (1 byte), and the page data itself (2048 bytes).
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `firmwarePage` (string, required)
- `motor` (string, required)

### `get_product_description` (~102 tokens)

Get the product description. [Firmware command "Get product description", group: Device Management.]
Returns:
  \- productDescription: This is a brief description of the product.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_firmware_version` (~200 tokens)

Get the firmware version or the bootloader version depending on what mode we are in. This command also returns the status bits, where the least significan bit teels us if we are currently in the bootloader (=1) or the main firmware (=0) [Firmware command "Get firmware version", group: Device Management.]
Returns:
  \- firmwareVersion: The firmware version stored as 4 bytes. The first byte is the development number, then patch version, followed by the minor and major versions.
  \- inBootloader: A flag that tells us if we are in the bootloader (=1) or in the reguslar firmware (=0)
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `move_with_velocity` (~187 tokens)

Rotates the motor with the specified velocity. [Firmware command "Move with velocity", group: Motion Control.]
This QUEUES the move and returns immediately; poll get_n_queued_items for completion, or use move_to/move_relative which wait. Requires enable_mosfets first.
Parameters:
  \- velocity (in degrees_per_second): The velocity (the unit is microsteps per time step * 2^20).
  \- duration (in seconds): The time to maintain this velocity.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `duration` (number, required)
- `motor` (string, required)
- `velocity` (number, required)

### `system_reset` (~161 tokens)

System reset / go to the bootloader. The motor will reset immediately and will enter the bootloader. If there is no command sent within a short time, the motor will exit the bootloader and run the application from the beginning. [Firmware command "System reset", group: Basic Control.]
NOTE: Reboots the motor (~2 s): position re-zeroes at the current shaft location, MOSFETs disable, fatal errors clear.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `set_maximum_motor_current` (~225 tokens)

Set the maximum motor current and maximum regeneration current. The values take effect immediately but are not saved to non-volatile memory, so they revert to the firmware default after a reset. [Firmware command "Set maximum motor current", group: Configuration.]
NOTE: Higher current = more torque AND more heat; excessive settings can overheat the motor.
Parameters:
  \- motorCurrent (in milliamps): The motor current. The units are some arbitrary units and not amps. A value of 150 or 200 is suitable.
  \- regenerationCurrent (in milliamps): The motor regeneration current (while it is braking). This parameter is currently not used for anything.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `motorCurrent` (number, required)
- `regenerationCurrent` (number, required)

### `multimove` (~474 tokens)

The multimove command allows you to compose multiple moves one after another. Please note that when the queue becomes empty after all the moves are executed and the motor is not at a standstill then a fatal error will be triggered. [Firmware command "Multimove", group: Motion Control.]
NOTE: moveList is a list of [value, duration_seconds] pairs (max 32): value is degrees/s^2 for acceleration moves (moveTypes bit = 0) or degrees/s for velocity moves (bit = 1); this server converts to firmware units. The final move must bring the motor to a standstill or the firmware raises a fatal error when the queue empties.
This QUEUES the move and returns immediately; poll get_n_queued_items for completion, or use move_to/move_relative which wait. Requires enable_mosfets first.
Parameters:
  \- moveCount: Specify how many moves are being communicated in this one shot.
  \- moveTypes: Each bit specifies if the move is a (bit = 0) MOVE_WITH_ACCELERATION_COMMAND or a (bit = 1) MOVE_WITH_VELOCITY_COMMAND.
  \- moveList: A 2D list in Python format (list of lists). Each item in the list is of type [i32, u32] representing a series of move commands. Each move command specifies the acceleration to move at or the velocity to instantly change to (according to the bits above) and the number of time steps over which this command is to be executed. For example: '[[100, 30000], [-200, 60000]]'. There is a limit of 32 move commands that can be listed in this one multi-move command. Each of the moves takes up one queue spot, so make sure there is enough space in the queue to store all of the commands.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `moveCount` (integer, required)
- `moveList` (string, required)
- `moveTypes` (integer, required)

### `set_safety_limits` (~160 tokens)

Set safety limits (to prevent motion from exceeding set bounds) [Firmware command "Set safety limits", group: Configuration.]
NOTE: Sets firmware position limits; moves beyond them fault the motor.
Parameters:
  \- lowerLimit (in degrees): The lower limit in microsteps.
  \- upperLimit (in degrees): The upper limit in microsteps.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `lowerLimit` (number, required)
- `motor` (string, required)
- `upperLimit` (number, required)

### `ping` (~142 tokens)

Send a payload containing any data and the device will respond with the same data back [Firmware command "Ping", group: Device Management.]
Parameters:
  \- pingData: Any binary data payload to send to the device.
Returns:
  \- responsePayload: The same data that was sent to the device will be returned if all went well.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `pingData` (string, required)

### `control_hall_sensor_statistics` (~137 tokens)

Turn on or off the gathering of statistics for the hall sensors and reset the statistics [Firmware command "Control hall sensor statistics", group: Status & Monitoring.]
Parameters:
  \- control: 0 = turn off statistics gathering, 1 = reset statistics and turn on gathering.
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `control` (integer, required)
- `motor` (string, required)

### `get_hall_sensor_statistics` (~331 tokens)

Read back the statistics gathered from the hall sensors. Useful for checking the hall sensor health and noise in the system. [Firmware command "Get hall sensor statistics", group: Status & Monitoring.]
Returns:
  \- maxHall1: The maximum value of hall sensor 1 encoutered since the last statistics reset.
  \- maxHall2: The maximum value of hall sensor 2 encoutered since the last statistics reset.
  \- maxHall3: The maximum value of hall sensor 3 encoutered since the last statistics reset.
  \- minHall1: The minimum value of hall sensor 1 encoutered since the last statistics reset.
  \- minHall2: The minimum value of hall sensor 2 encoutered since the last statistics reset.
  \- minHall3: The minimum value of hall sensor 3 encoutered since the last statistics reset.
  \- sumHall1: The sum of hall sensor 1 values collected since the last statistics reset.
  \- sumHall2: The sum of hall sensor 2 values collected since the last statistics reset.
  \- sumHall3: The sum of hall sensor 3 values collected since the last statistics reset.
  \- measurementCount: The number of times the hall sensors were measured since the last statistics reset.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_position` (~113 tokens)

Get the current desired position (which may differ a bit from the actual position as measured by the hall sensors) [Firmware command "Get position", group: Status & Monitoring.]
Returns:
  \- position: The current desired position
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `read_multipurpose_buffer` (~144 tokens)

Read whatever is in the multipurpose buffer (the buffer is used for data generated during calibration, going to closed loop mode, and when capturing hall sensor data) [Firmware command "Read multipurpose buffer", group: Other.]
Returns:
  \- bufferData: The data in the buffer (the format and length of the data depends on what was put in the buffer)
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `test_mode` (~267 tokens)

Set or trigger a certain test mode. This is a bit undocumented at the moment. Don't use this unless you are a developer working on test cases. Notable modes: 0 = clear all test modes; 1-9 = motor test modes; 10-13 = LED test modes (locks up the device); 14-73 = trigger fatal errors 0-59; 74 = set the overvoltage-protection threshold to 22 V (production test, should trip on a 24 V supply); 75 = set the overvoltage-protection threshold to 26 V (production test, should not trip on a 24 V supply). A system reset restores the default overvoltage threshold. [Firmware command "Test mode", group: Configuration.]
NOTE: Developer/diagnostic modes; behavior depends on firmware internals.
Parameters:
  \- testMode: The test mode to use or trigger
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `testMode` (integer, required)

### `get_comprehensive_position` (~160 tokens)

Get the desired motor position, hall sensor position, and external encoder position all in one shot [Firmware command "Get comprehensive position", group: Status & Monitoring.]
Returns:
  \- commandedPosition: The commanded position (which may differ from actual)
  \- hallSensorPosition: The hall sensor position (or you could say the actual measured position)
  \- externalEncoderPosition: The external encoder position. This needs special hardware attached to the motor to work
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_supply_voltage` (~115 tokens)

Get the measured voltage of the power supply. [Firmware command "Get supply voltage", group: Status & Monitoring.]
Returns:
  \- supplyVoltage: The voltage. Divide this number by 10 to get the actual voltage in volts.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_max_pid_error` (~129 tokens)

Get the minimum and maximum error value ovserved in the PID control loop since the last read. [Firmware command "Get max PID error", group: Status & Monitoring.]
Returns:
  \- minPidError: The minimum PID error value.
  \- maxPidError: The maximum PID error value.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `vibrate` (~133 tokens)

Cause the motor to start to vary the voltage quickly and therefore to vibrate (or stop). [Firmware command "Vibrate", group: Device Management.]
Parameters:
  \- vibrationLevel: Vibration level (0 = turn off, 1 = turn on).
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `vibrationLevel` (integer, required)

### `identify` (~103 tokens)

Identify your motor by sending this command. The motor's green LED will flash rapidly for 3 seconds. [Firmware command "Identify", group: Device Management.]
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `get_temperature` (~120 tokens)

Get the measured temperature of the motor. [Firmware command "Get temperature", group: Status & Monitoring.]
Returns:
  \- temperature: The temperature in degrees celcius. The accuracy is about +/- 3 degrees celcius and is measured at the motor driver PCB.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)

### `set_pid_constants` (~175 tokens)

Set PID constants for the control loop that will try to maintain the motion trajectory. [Firmware command "Set PID constants", group: Configuration.]
NOTE: Bad gains can make the motor oscillate violently.
Parameters:
  \- kP: The proportional term constant (P)
  \- kI: The integral term constant (I)
  \- kD: The differential term constant (D)
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `kD` (integer, required)
- `kI` (integer, required)
- `kP` (integer, required)
- `motor` (string, required)

### `set_max_allowable_position_deviation` (~161 tokens)

Set the amount of microsteps that the actual motor position (as measured by the hall sensors) is allowed to deviate from the desired position. Throw a fatal error if this is exceeded. [Firmware command "Set max allowable position deviation", group: Configuration.]
Parameters:
  \- maxAllowablePositionDeviation (in degrees): The new maximum allowable position deviation setting
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `maxAllowablePositionDeviation` (number, required)
- `motor` (string, required)

### `get_debug_values` (~500 tokens)

Get debug values including motor control parameters, profiler times, hall sensor data, and other diagnostic information. [Firmware command "Get debug values", group: Status & Monitoring.]
Returns:
  \- maxAcceleration: Maximum acceleration setting
  \- maxVelocity: Maximum velocity setting
  \- currentVelocity: Current velocity
  \- measuredVelocity: Measured velocity
  \- nTimeSteps: Number of time steps left in the current move
  \- debugValue1: Debug value 1
  \- debugValue2: Debug value 2
  \- debugValue3: Debug value 3
  \- debugValue4: Debug value 4
  \- allMotorControlCalculationsProfilerTime: All motor control calculations profiler time
  \- allMotorControlCalculationsProfilerMaxTime: All motor control calculations profiler maximum time
  \- getSensorPositionProfilerTime: Get sensor position profiler time
  \- getSensorPositionProfilerMaxTime: Get sensor position profiler maximum time
  \- computeVelocityProfilerTime: Compute velocity profiler time
  \- computeVelocityProfilerMaxTime: Compute velocity profiler maximum time
  \- motorMovementCalculationsProfilerTime: Motor movement calculations profiler time
  \- motorMovementCalculationsProfilerMaxTime: Motor movement calculations profiler maximum time
  \- motorPhaseCalculationsProfilerTime: Motor phase calculations profiler time
  \- motorPhaseCalculationsProfilerMaxTime: Motor phase calculations profiler maximum time
  \- motorControlLoopPeriodProfilerTime: Motor control loop period profiler time
  \- motorControlLoopPeriodProfilerMaxTime: Motor control loop period profiler maximum time
  \- hallSensor1Voltage: Hall sensor 1 voltage
  \- hallSensor2Voltage: Hall sensor 2 voltage
  \- hallSensor3Voltage: Hall sensor 3 voltage
  \- commutationPositionOffset: Commutation position offset
  \- motorPhasesReversed: Motor phases reversed flag
  \- maxHallPositionDelta: Maximum hall position delta
  \- minHallPositionDelta: Minimum hall position delta
  \- averageHallPositionDelta: Average hall position delta
  \- motorPwmVoltage: Motor PWM…

Input parameters:

- `motor` (string, required)

### `crc32_control` (~146 tokens)

Enable or disable CRC32 checking for commands [Firmware command "CRC32 control", group: Configuration.]
NOTE: Changes protocol framing for ALL subsequent commands; only disable CRC32 if you know why.
Parameters:
  \- enableCrc32: Control value (1 to enable, 0 to disable CRC32 checking)
Returns: success confirmation.
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `enableCrc32` (integer, required)
- `motor` (string, required)

### `get_communication_statistics` (~241 tokens)

Get and optionally reset the CRC32 error counter [Firmware command "Get communication statistics", group: Status & Monitoring.]
Parameters:
  \- resetCounter: Reset flag (1 to reset the counter after reading, 0 to just read)
Returns:
  \- crc32ErrorCount: Number of CRC32 errors detected
  \- packetDecodeErrorCount: Number of packet decode errors detected
  \- firstBitErrorCount: Number of times that the first bit in the first byte of a packet was not 1 as expected
  \- framingErrorCount: Number of framing errors detected during reception from the RS485 interface
  \- overrunErrorCount: Number of overrun errors detected during reception from the RS485 interface
  \- noiseErrorCount: Number of noise errors detected during reception from the RS485 interface
motor: an alias number (e.g. 88), a 16-hex-digit unique ID (e.g. "0123456789ABCDEF"), or "all" to broadcast to every motor on the bus (broadcasts get no responses back).

Input parameters:

- `motor` (string, required)
- `resetCounter` (integer, required)

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp#diagnostics

## Score history

- 2026-09-21: 55
- 2026-09-20: 54
- 2026-09-19: 54
- 2026-09-18: 53
- 2026-09-17: 53
- 2026-09-16: 49
- 2026-09-15: 49
- 2026-09-14: 49
- 2026-09-13: 64
- 2026-09-12: 49
- 2026-09-11: 49
- 2026-09-10: 49
- 2026-09-09: 49

## Common questions

### What is the Gearotons M17 Servomotor MCP server?

Gearotons M17 Servomotor is an MCP server listed in the public MCP registry as io.github.Gearotons/servomotor-mcp. Drive Gearotons M17 open-source servomotors from plain English over RS-485; mock mode, no hardware. This page covers its PyPI package (servomotor-mcp).

### Is the Gearotons M17 Servomotor MCP server safe to use?

Gearotons M17 Servomotor scores 55 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 21 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the Gearotons M17 Servomotor MCP server expose?

Gearotons M17 Servomotor exposes 57 tools: list_serial_ports, connect, disconnect, detect_devices, list_motors, and 52 more. Their descriptions and schemas cost roughly 9,467 tokens of context every time the server is loaded.

### Is the Gearotons M17 Servomotor MCP server still maintained?

Gearotons M17 Servomotor is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the Gearotons M17 Servomotor MCP server under?

Gearotons M17 Servomotor declares the MIT licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/servomotor-mcp/
- Socket report: https://socket.dev/pypi/package/servomotor-mcp
- Repository: https://github.com/Gearotons/servomotor-mcp
- Website: https://gearotons.com/
- Changelog RSS feed: https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp.json
- HTML version of this page: https://verifymcp.io/servers/gearotons-servomotor-mcp/servomotor-mcp
