robot-nxt-control
Robot NXT Control MCP
Local MCP server for compatible programmable-brick hardware connected to Windows 11 by USB/WinUSB.
Compatibility and trademarks
This independent project is not affiliated with, sponsored by, or endorsed by the LEGO Group. LEGO, MINDSTORS, and NXT are trademarks of the LEGO Group. They are used in this documentation only to identify compatible hardware, software, protocols, and third-party dependencies; they are not part of this project's name, server identifier, or plugin identifier.
Migration from earlier releases
The old plugin and MCP-server identifier has been replaced by robot-nxt-control, and the
executables are now named robot-nxt-control-mcp, robot-nxt-control-mcp-stdio, and
robot-nxt-control-mcp-http. Reinstall the editable package after pulling this change and
replace earlier MCP configuration entries with the examples below.
Related MCP server: KentraBOT MCP Server
Install in Claude Desktop or Codex desktop (Windows)
Complete the Windows installation first. These desktop
apps start the MCP server themselves, so do not run robot-nxt-control-mcp-stdio.exe manually.
The examples assume this repository is at C:\Users\lukas\workspace\NXT-MCP; replace
that part in every path if your checkout is elsewhere.
Claude Desktop
Fully quit Claude Desktop (including its tray icon).
Open
%APPDATA%\Claude\claude_desktop_config.json. Create the file if it does not exist. If it already has anmcpServersobject, add only therobot-nxt-controlentry below.Save the file and start Claude Desktop again. The server should appear in Settings → Developer → MCP servers.
{
"mcpServers": {
"robot-nxt-control": {
"command": "C:\\Users\\lukas\\workspace\\NXT-MCP\\.venv\\Scripts\\robot-nxt-control-mcp-stdio.exe",
"cwd": "C:\\Users\\lukas\\workspace\\NXT-MCP"
}
}
}The same ready-to-copy configuration is in
packaging/claude-desktop/mcp.json.
Codex desktop
The Codex desktop host and Codex CLI use the shared MCP configuration in
%USERPROFILE%\.codex\config.toml. Add this block (or run the equivalent
codex mcp add command below), then restart the Codex app:
[mcp_servers.robot-nxt-control]
command = "C:\\Users\\lukas\\workspace\\NXT-MCP\\.venv\\Scripts\\robot-nxt-control-mcp-stdio.exe"
cwd = "C:\\Users\\lukas\\workspace\\NXT-MCP"
startup_timeout_sec = 10
tool_timeout_sec = 120PowerShell alternative:
codex mcp add robot-nxt-control -- C:\Users\lukas\workspace\NXT-MCP\.venv\Scripts\robot-nxt-control-mcp-stdio.exe
codex mcp listFor the ChatGPT desktop MCP UI: Settings → MCP servers → Add server, choose
STDIO, enter robot-nxt-control, use the same executable as the command, save, then
restart the app. Local Codex clients support both STDIO and Streamable HTTP and share
this MCP configuration. Official OpenAI MCP documentation
First check
Open a new chat and ask for nxt_info. If it cannot connect, first confirm the robot
works with ./.venv/Scripts/nxt-test.exe --log-level=debug; then verify that every
configured path exists and that the NXT is switched on. Movement tools control real
hardware: begin with nxt_info or query_all_state, then use low power and bounded
movement commands.
MCP transports, hosts, and verification
The same create_server() factory powers both transports. robot-nxt-control-mcp-stdio is the
local-process transport for Claude Desktop, Claude Code, Codex CLI, Codex desktop,
and local Codex plugins. It writes protocol traffic only to stdout.
Use the supplied JSON as a starting configuration, replacing the absolute workspace path after moving the checkout:
Claude Desktop:
packaging/claude-desktop/mcp.jsonClaude Code plugin:
packaging/claude-code/Codex local plugin:
C:\Users\lukas\plugins\robot-nxt-control(created in the personal marketplace)
For protocol testing, start Streamable HTTP on loopback:
.\.venv\Scripts\robot-nxt-control-mcp-http.exe --port 8000
npx @modelcontextprotocol/inspector --cli http://127.0.0.1:8000/mcp --method tools/list
npx @modelcontextprotocol/conformance server --url http://127.0.0.1:8000/mcp --suite activeRun the repository checks with .\.venv\Scripts\python.exe -m pytest. They include an
in-process MCP negotiation, tools/list, annotations, and tools/call test, in
addition to controller and behavior tests. conformance-baseline.yml records only
generic scenarios requiring optional MCP features this focused hardware server does
not advertise; each entry is a burn-down assertion, so the runner flags stale entries.
robot-nxt-control-mcp-http binds to 127.0.0.1 by default and refuses non-loopback binding unless
NXT_MCP_ALLOW_REMOTE=true is explicitly set. A cloud client cannot reach a USB NXT
directly: run this server next to the robot and place a production HTTPS reverse proxy
with OAuth/token validation, authorization, audit logs, and network restrictions in
front of the Streamable HTTP endpoint. Never expose the USB-control endpoint publicly
with only the environment override.
See ARCHITECTURE.md for the module design, MCP and behavior execution flows, USB stack, safety model, and Mermaid diagrams.
Windows 11 installation
Use Python 3.11 x64. From PowerShell:
py -3.11 -m venv .venv
.\.venv\Scripts\python.exe -m pip install --upgrade pip
.\.venv\Scripts\python.exe -m pip install -e ".[test]"1. Install the NXT device driver with Zadig
Turn the NXT on and connect it by USB. In PowerShell, confirm that Windows sees the normal-mode device:
Get-PnpDevice -PresentOnly |
Where-Object InstanceId -match 'VID_0694&PID_0002' |
Format-List Status,FriendlyName,InstanceId,ProblemThe hardware ID must contain USB\VID_0694&PID_0002. If Problem is
CM_PROB_FAILED_INSTALL or Device Manager shows Code 28, the driver is missing.
Download Zadig only from https://zadig.akeo.ie/.
Run Zadig as Administrator.
Select Options > List All Devices.
Select the entry whose USB ID is exactly
0694:0002. Use the ID, not only the displayed device name.Choose WinUSB in the driver selector.
Click Install Driver or Replace Driver.
Disconnect and reconnect the NXT, leaving it switched on.
Do not select 03EB:6124; that is the NXT bootloader/firmware-update mode. Do not
replace drivers for any unrelated USB device. Installing WinUSB may prevent the old
LEGO NXT-G software from talking to the brick until its LEGO/Fantom driver is restored.
2. Install the x64 libusb runtime for PyUSB
WinUSB is the Windows device driver. PyUSB separately needs the user-space
libusb-1.0.dll. The repository includes a helper that downloads the official libusb
1.0.30 archive, verifies its SHA-256, and installs the VS2022 x64 DLL beside this
environment's python.exe:
.\scripts\install-libusb-runtime.ps1The helper requires 7z.exe on PATH. To install manually, download
libusb-1.0.30.7z from the official libusb GitHub release, extract
VS2022\MS64\dll\libusb-1.0.dll, and copy it to .venv\Scripts\libusb-1.0.dll.
Do not use an MS32 DLL with 64-bit Python.
Verify the runtime independently:
$env:PATH = "$PWD\.venv\Scripts;$env:PATH"
.\.venv\Scripts\python.exe -c "import usb.backend.libusb1 as b; assert b.get_backend() is not None; print('libusb OK')"The MCP server automatically adds a DLL installed beside its virtual-environment Python
to its own search path. nxt-test.exe is an external NXT-Python command, so either run
the $env:PATH line above first or activate the virtual environment before using it.
3. Test the brick
Verify the hardware before MCP:
.\.venv\Scripts\nxt-test.exe --log-level=debugA successful test prints the brick name, battery level, protocol version, and firmware
version. If it still reports no brick, recheck the 0694:0002 device in Device Manager
and confirm that its driver is WinUSB.
Firmware
No firmware installation or update is needed when the NXT boots normally and Windows
shows VID 0694 / PID 0002. The MCP server uses standard NXT direct commands and also
reports the installed firmware and protocol versions through nxt_info.
Only perform firmware recovery if the brick cannot boot normally and Windows instead
shows VID 03EB / PID 6124, which is Atmel SAM-BA firmware-update mode. Recovery erases
and rewrites brick firmware and is outside the normal MCP setup:
Do not install the normal NXT WinUSB rule against
03EB:6124.Restore/use the firmware-update driver required by the original LEGO MINDSTORMS NXT software.
In that software, use Tools > Update NXT Firmware with an official NXT firmware image.
After recovery, power-cycle the brick. It must return as
0694:0002; then install WinUSB for that normal-mode device again if necessary.
NXT-Python deliberately does not provide firmware flashing. Do not invoke firmware boot
mode or attempt an update merely to troubleshoot NoBackendError, Code 28, or an MCP
connection failure.
Then open the MCP Inspector:
.\.venv\Scripts\mcp.exe dev src\nxt_mcp\server.pyFor a local MCP host, configure a stdio server with command
.venv\Scripts\robot-nxt-control-mcp.exe and the repository as its working directory.
Declare the sensors attached to the brick before starting the server so the whole-brick snapshot can return typed readings immediately:
$env:NXT_SENSOR_MAP = "1:touch,2:light,4:ultrasonic"
.\.venv\Scripts\robot-nxt-control-mcp.exeCalling read_sensor or a sensor-driven motor command also remembers that port's type
for later snapshots.
High-level tools
move_motor_relative(port="C", power=40, degrees=2000)moves C forward by 2000 encoder degrees. Use negative power for the opposite direction. The adapter uses a tight USB encoder loop because NXT-Python's standardturn()loop polls too slowly for small movements. Use lower power, such as 20, for movements around 45 degrees.zero_motor_position(port="C")defines the current C encoder position as absolute 0.move_motor_absolute(port="C", target_degrees=-90, power=20)then moves to -90. Absolute movement derives direction from the target; itspoweris a positive magnitude.motor_position(port="C")reports the absolute/program-relative encoder position and the raw tacho counters.run_motor(port="C", power=-30)runs continuously in the negative direction until a stop command or a bounded behavior stops it. Withregulated=true,poweris the NXT regulated speed setting, not a calibrated degrees-per-second value.run_motors(ports=["B", "C"], powers=[30, -30])starts a motor group in one MCP call.stop_motors,move_motors_relative, andmove_motors_absoluteoperate on groups in the same way. Lists are positional: each power/degree value belongs to the port at the same index.run_motor_until_sensor(port="B", power=40, sensor_port=1, sensor_type="touch", condition="pressed")runs B until touch S1 is pressed.run_motors_until_sensor(ports=["B", "C"], powers=[40, 40], sensor_port=4, sensor_type="ultrasonic", condition="lte", threshold=20)drives both motors until an obstacle is at most 20 cm away, then stops the entire group.run_motor_until_sensor(port="B", power=40, sensor_port=4, sensor_type="ultrasonic", condition="lte", threshold=20)runs B until an obstacle is at most 20 cm away.query_all_state(format="text")returns one compact text snapshot of the brick, all motor ports, and all sensor ports. Useformat="json"for structured data.cycle_motor_on_touch(port="C", touch_port=1, cycles=5)runs forward until S1 is pressed, reverses until it is released, repeats five times, and beeps after success. Every press and release phase has its own timeout and encoder-travel ceiling.
Every sensor-driven motion has a timeout and an encoder travel limit. Reaching either
limit stops the motor and returns ok: false with the reason. The motor is also stopped
if a sensor or USB read fails.
Extended diagnostics, storage, and telemetry
motor_state(port)informa sobre la regulación, el estado de ejecución, los tacómetros y el estado de salida configurado.drive_sync(left_port, right_port, power, turn_ratio=0)usa la regulación síncrona del firmware NXT para un par de tracción diferencial;wait_motors(...)tiene un plazo y detiene sus puertos al agotarse el tiempo.read_sensor_raw(port, sensor_type?),wait_sensor(...)ysensor_stream(...)exponen diagnósticos acotados, esperas de sensor con anti-rebote y muestras finitas.Para los sensores de luz, color y ultrasónicos, llame a
zero_sensor_reference(port, sensor_type)y después aread_sensor_relative(port, sensor_type). Devuelve el cambio respecto al cero capturado más el valor absoluto. El color usa la intensidad de luz reflejada (no la etiqueta discreta rojo/azul/etc.) para una resta significativa.log_start,log_status,log_stopylog_exportproporcionan telemetría CSV acotada del lado del host. Los canales válidos sonbattery_mv,motor:Aamotor:C, ysensor:1:touch(u otro tipo/puerto de sensor compatible).list_files,read_file,write_fileydelete_filegestionan archivos de usuario NXT acotados. Las escrituras se limitan a.txt,.csv,.daty.rso; la reproducción de sonido usaplay_sound_file(name)ystop_sound().mailbox_send/mailbox_receiveadmiten mensajes de hasta 58 bytes UTF-8;i2c_transactiones una operación opcional de baja velocidad limitada a cargas útiles de solicitud y respuesta de 16 bytes.set_brick_nameykeep_aliveson los comandos directos administrativos compatibles.
El protocolo estándar de comandos directos NXT no puede dibujar en la pantalla LCD del NXT ni leer sus botones. Esas funciones de NXT-G/ROBOTC requieren un programa puente residente en el NXT instalado por separado; este servidor no las expone intencionadamente.
Semántica de posicionamiento de motores
Los contadores del encoder NXT son grados en el eje del motor, no grados de orientación del robot ni milímetros lineales. Las relaciones de transmisión, la circunferencia de las ruedas y el deslizamiento deben gestionarse mediante un comportamiento del robot si se necesitan unidades físicas.
El cero absoluto lo mantiene el contador de rotación relativo al programa del firmware NXT. No es
un sensor de homing y no es persistente: apagar y encender el ladrillo o iniciar/detener un
programa .rxe invalida la referencia. Realice el homing contra un sensor táctil y llame a
zero_motor_position de nuevo antes de confiar en los objetivos absolutos.
Los comandos de grupo inician motores usando paquetes USB consecutivos dentro de un único bloqueo de controlador. Evitan la desviación de ida y vuelta MCP/LLM y monitorizan todos los encoders juntos, pero no son tiempo real estricto ni están sincronizados mecánicamente por fase. Para un robot de dos ruedas esto es apropiado para conducción normal; la sincronización de precisión puede requerir un programa de control residente en el NXT.
Limitación del informe de hardware
El firmware NXT informa del estado configurado de cada puerto, pero no puede saber con seguridad
si un motor inactivo está físicamente conectado. La consulta de todo el ladrillo informa por tanto
de todos los estados A/B/C del firmware en lugar de afirmar la presencia de motores. Los puertos de sensores
que ya han sido configurados por read_sensor o por un comando basado en sensores muestran valores tipados;
otros puertos de sensores muestran su estado de firmware sin procesar. Consultar el estado sin procesar no
reconfigura puertos ni energiza brevemente el hardware.
No use comandos MCP directos de motores mientras un programa .rxe esté controlando los mismos puertos.
Comportamientos Python en el lado del PC a través de MCP
El NXT de serie no ejecuta Python. Este servidor puede en su lugar guardar y ejecutar comportamientos Python restringidos en el PC; cada operación del robot sigue cruzando la frontera del controlador, por lo que los scripts no abren USB, no instancian sensores NXT-Python ni implementan sus propios bucles de sondeo.
Ejemplo de comportamiento:
def run(robot):
robot.configure_sensor(1, "touch")
for _ in range(5):
robot.motor_until("C", 20, 1, "pressed")
robot.motor_until("C", -20, 1, "released")
robot.play_tone(440, 500)
return "completed 5 touch cycles"El mismo ejemplo se incluye como behaviors/touch_cycle.py. Use estas herramientas MCP:
validate_behavior(source)
submit_behavior(name, source)
list_behaviors()
get_behavior(name)
run_behavior(name, timeout_seconds=120)La interfaz robot visible para el script contiene:
configure_sensor(port, sensor_type)
read_sensor(port, sensor_type)
read_sensor_raw(port, sensor_type=None)
zero_sensor_reference(port, sensor_type)
read_sensor_relative(port, sensor_type)
wait_sensor(port, sensor_type, condition, ...)
sensor_stream(port, sensor_type, ...)
log_start(channels, interval_ms=100, duration_seconds=10)
log_status(job_id)
log_stop(job_id)
log_export(job_id)
motor_until(port, power, sensor_port, condition, sensor_type="touch", ...)
motor_for_ticks(port, power, ticks, ...)
motor_position(port)
zero_motor_position(port)
motor_to(port, target_degrees, power=20, ...)
run_motor(port, power, regulated=True)
drive_sync(left_port, right_port, power, turn_ratio=0)
wait_motors(ports, ...)
stop_motor(port, brake=False)
run_motors(ports, powers, regulated=True)
stop_motors(ports, brake=False)
motors_relative(ports, powers, degrees, ...)
motors_absolute(ports, powers, target_degrees, ...)
motors_until(ports, powers, sensor_port, condition, ...)
state(format="text")
play_tone(frequency_hz=440, duration_ms=500)
play_sound_file(name, loop=False)
stop_sound()
sleep(seconds)Las importaciones, clases, manejo de excepciones, acceso a atributos privados y llamadas fuera de los
métodos documentados del robot y las funciones integradas básicas se rechazan. Los scripts están limitados a 64 KiB,
solo uno puede ejecutarse a la vez, y run_behavior acepta un plazo de 1 a 300 segundos. Todos los motores
se detienen cuando un script termina o lanza una excepción.
Esta validación pretende evitar el acceso accidental fuera de la interfaz del robot; no
es una zona de pruebas de seguridad para código hostil. Solo conceda acceso MCP a usuarios locales de confianza.
Establezca NXT_BEHAVIOR_DIR antes de iniciar el servidor para almacenar los comportamientos en un lugar distinto del
directorio behaviors por defecto, bajo el directorio de trabajo del servidor.
Para una demostración de línea de comandos que siga usando MCP stdio en lugar de importar el controlador directamente:
.\.venv\Scripts\python.exe scripts\mcp-behavior-client.py list
.\.venv\Scripts\python.exe scripts\mcp-behavior-client.py submit touch_cycle behaviors\touch_cycle.py
.\.venv\Scripts\python.exe scripts\mcp-behavior-client.py run touch_cycle --timeout 120El comando final realiza movimiento físico. El cliente solo llama a herramientas MCP; el servidor MCP carga el comportamiento y es dueño de toda la comunicación con el NXT.
Prueba sin ladrillo
$env:PYTHONPATH = "src"
py -3.11 -m pytestMaintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables beginner-friendly Python and Pybricks development support through RAG-powered tools that search official documentation, suggest code snippets, and provide version-aware guidance for LEGO robotics programming.
- FlicenseNot gradedqualityDmaintenanceEnables LLMs to control a two-track robot through movement commands, providing independent track control, high-level directional driving (forward, backward, left, right), and emergency stop functionality.
- AlicenseBqualityBmaintenanceEnables LLMs to control a Minecraft bot through the Mineflayer API, allowing for tasks like building, mining, and inventory management via natural language. It supports complex interactions including coordinate-based movement, block manipulation, and real-time game chat.5323Apache 2.0
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to control hardware devices like Arduino, Raspberry Pi, 3D printers, CNC machines, and custom robots via serial ports and HTTP. Provides tools for device discovery, command sending, sensor reading, servo control, G-code execution, and emergency stops with safety features.MIT
Related MCP Connectors
Operate Linux, macOS and Windows from your LLM. Every action runs through an auditable allowlist.
Control Unreal Engine to browse assets, import content, and manage levels and sequences. Automate…
Gateway between LLM agents and world data through eight tools and a bundled endpoint catalog.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Lukx19/NXT-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server