Simple Rail Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Simple Rail Mcp (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
MCP (Model Context Protocol) server for controlling linear rails via natural language through Claude AI in Cursor.
Control your linear rail with natural language:
You: "Move the rail to position 500mm"
Claude: ✅ Rail moved to 500mm
You: "Move rail to opentrons station"
Claude: ✅ Rail at opentrons stationnpm installEdit index.js lines 32-37:
// For UW PICO controller:
this.RAIL_IP = "192.168.1.101"; // Your controller IP
this.RAIL_PORT = "80";
this.RAIL_ENDPOINT = "/command";
this.COMMAND_TEMPLATE = "G0 X{position} F1000";Set your positions (lines 41-47):
this.POSITIONS = {
"pickup_station": 0,
"opentrons": 500,
"plate_reader": 750,
"storage": 1000,
"home": 0
};Edit .cursor/mcp.json:
{
"mcpServers": {
"rail": {
"command": "node",
"args": ["/absolute/path/to/simple-rail-mcp/index.js"],
"env": {
"RAIL_IP": "192.168.1.101"
}
}
}
}"Move the rail to opentrons"
"Move rail to 500mm"
"Move to home position"Your controller has an HTTP API that forwards G-code via UART.
Test with curl:
curl -X POST http://192.168.1.101/command \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "cmd=G0 X500 F1000"Config:
this.RAIL_IP = "192.168.1.101";
this.RAIL_PORT = "80";
this.RAIL_ENDPOINT = "/command";
this.COMMAND_TEMPLATE = "G0 X{position} F1000";If your controller uses different endpoints/formats:
this.RAIL_IP = "192.168.1.100";
this.RAIL_ENDPOINT = "/api/move";
this.COMMAND_TEMPLATE = '{"position": {position}}'; // JSON formatEdit the POSITIONS object to match your physical setup:
this.POSITIONS = {
"station_a": 0, // First position (mm)
"station_b": 250, // Second position (mm)
"station_c": 500, // Third position (mm)
"home": 0 // Home position
};Adjust wait time after movement (line 54):
this.MOVE_WAIT_TIME = 5; // Wait 5 seconds after sending commandIf your rail is faster or slower, adjust accordingly.
You can override config with environment variables:
{
"mcpServers": {
"rail": {
"command": "node",
"args": ["/path/to/index.js"],
"env": {
"RAIL_IP": "192.168.1.101",
"RAIL_PORT": "80"
}
}
}
}move_rail_and_waitMove linear rail to a position and wait for completion.
Parameters:
position (string) - Named position from POSITIONS config"opentrons", "pickup_station", "home"position_number (number) - Numeric position in mm500, 750.5wait_seconds (number) - Override default wait timeMOVE_WAIT_TIME from configExamples:
// Via Claude in natural language:
"Move rail to opentrons"
"Move rail to 500mm"
"Move to home position"
// Direct tool call (from code):
move_rail_and_wait({ position: "opentrons" })
move_rail_and_wait({ position_number: 500 })
move_rail_and_wait({ position: "storage", wait_seconds: 10 })Common G-code commands for linear rails:
| Command | Description |
|---|---|
G0 X500 F1000 | Move to 500mm at 1000mm/min (fast) |
G1 X500 F500 | Move to 500mm at 500mm/min (controlled) |
G28 X | Home X axis |
G90 | Set absolute positioning mode |
G91 | Set relative positioning mode |
G92 X0 | Set current position as zero |
M114 | Query current position |
M400 | Wait for all moves to complete |
ping 192.168.1.101 curl http://192.168.1.101/command curl -X POST http://192.168.1.101/command -d "cmd=G28 X" # Home first
curl -X POST http://192.168.1.101/command -d "cmd=G0 X500 F1000" curl -X POST http://192.168.1.101/command -d "cmd=G90" # Absolute mode curl -X POST http://192.168.1.101/command -d "cmd=G21"POSITIONS curl -X POST http://192.168.1.101/command -d "cmd=G28 X" node index.js node --version # Should be ≥18.0.0To add support for other controller types, modify the sendHttpCommand method:
async sendHttpCommand(position) {
const gcode = this.COMMAND_TEMPLATE.replace('{position}', position);
const url = `http://${this.RAIL_IP}:${this.RAIL_PORT}${this.RAIL_ENDPOINT}`;
// Customize request format here
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json' // Change as needed
},
body: JSON.stringify({ command: gcode }) // Change format
});
// Customize response parsing here
const data = await response.json();
return data;
}Use with other MCP servers for full automation:
// Example: Pick up plate and move to Opentrons
"Move rail to pickup station" // This MCP server
"Run VLA pickup script" // VLA MCP server
"Move rail to opentrons" // This MCP server
"Upload purple_mixing.py" // Opentrons MCP server
"Start the protocol" // Opentrons MCP serverClaude AI automatically orchestrates all systems!
MIT
Issues and pull requests welcome!
Questions? Open an issue or check the troubleshooting guide.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.