Connect an AI Assistant with the MCP Server
The MoveIt Pro MCP server lets an AI client inspect a Runtime and its workspace. A host-user session can also validate Objectives, create robot configuration packages, build and test the workspace, launch the Runtime, and start and cancel Objectives, with nothing to enable.
Choose where the MCP client runs
Choose a connection based on where the AI client runs and what it needs to do:
| Need | AI client remote from the Runtime | AI client on the Runtime host |
|---|---|---|
| Inspect Objectives, Behaviors, Waypoints, robot state, and logs | HTTPS or stdio over SSH | Local stdio |
| Validate Objectives; create robot configuration packages; build, test, or launch; start and cancel Objectives | Stdio over SSH | Local stdio |
Use authenticated Streamable HTTP for scoped access without an SSH login. The deployment MCP key documented below currently grants inspection tools.
- Remote Runtime: start MoveIt Pro normally. Its REST API serves
https://<runtime-host>:<rest-port>/mcpwith TLS, MCP-key authentication, Host/Origin checks, and admission limits. - AI client: configure the MCP URL, trust for the Runtime certificate,
and bearer key. A stdio-only client such as Claude Desktop can run
mcp-remotelocally as its bridge to that authenticated HTTP endpoint.
Use stdio over SSH for host-user workflows on a remote Runtime. The session runs as the SSH account, adding Objective validation, robot configuration creation, build, test, Runtime launch, and Objective start and cancel tools. The account's SSH credential also grants its normal shell access outside MCP.
Use local stdio for the same host-user workflows when the AI client runs on
the Runtime host. Run moveit_pro mcp install there to configure the client.
Authorization follows the authenticated identity and its scopes. The deployment MCP key is read-only because it is shared. A host-user session, local or over SSH, holds every scope: it is the OS user who could run the same commands by hand. An optional policy file narrows what a session may do.
Robot motion over MCP is limited to starting and cancelling existing Objectives from a host-user session; the deployment MCP key never can. Your MCP client controls tool approval according to its configured permissions; clients may auto-approve calls. The server adds no confirmation prompt. Configure your client's approvals before allowing an agent to start Objectives. For remote robot operation, you can also connect the MoveIt Pro Desktop App to the Runtime over a trusted route such as Tailscale or an SSH tunnel. See Connect with the MoveIt Pro Desktop App.
HTTP tools carry read-only and non-destructive hints. Camera capture and Gemini inspection are not marked idempotent; Gemini inspection declares external interaction. These hints inform client approval policies; scopes and target checks enforce authorization.
Every connection is bound before tool discovery to one deployment, instance, robot, canonical workspace, and robot configuration package. A different target requires a new session. Provider availability can change during the session, but its scopes, visible tools, and target cannot.
What the assistant can see
Tools
| Tool | Returns |
|---|---|
get_capabilities | Which capabilities the session's tools can use right now, plus its principal_type, granted_scopes, and upgrade_paths: the operator steps that unlock more tools. |
list_objectives | Every Objective in the selected robot configuration, optionally filtered by words in its ID, description, or category. |
get_objective | One current Objective's normalized XML and metadata, by ID. With source: true, returns the selected package's original source XML and edit revision instead. |
get_objective_authoring_guide | Customer-shipped Markdown guidance, matched to the installed image. Defaults to path: "create-objective/SKILL.md"; linked guides are readable by path relative to the shipped skills directory. |
list_behaviors | Compact search over the matching Runtime's loaded Behaviors and current source Subtrees; accepts query, offset, and limit. Requires the Runtime. |
get_behavior_details | One Behavior's metadata and loaded ports, by ID. Requires the matching Runtime. |
list_waypoints | Every saved Waypoint, with joint state. |
get_waypoint | One Waypoint, by name. |
get_recent_logs | A bounded tail of ROS node logs or launch stdout, ordered by last write. Optional query filters lines; modified_at reports file freshness and output_truncated reports omitted older output. |
get_execution_status | The matching Objective Server's live state, running Objective, current_goal_id, and UUID-tagged recent_goals, including terminal statuses. |
get_robot_state | The matching robot's current joint positions and velocities. |
list_cameras | Available ROS cameras and registered RGB/depth capabilities. |
capture_observation | Camera image, acquisition timestamp, camera pose, and available frame context. |
locate_points | Measured 3D surface positions for selected image points in a captured frame. |
inspect_scene | Optional Gemini labels, image points, and an annotated image. |
These are available to every authorized client, including over authenticated HTTP. A host-user stdio session, started locally or over SSH, additionally exposes:
| Tool | Returns | Requires |
|---|---|---|
validate_objective | Validation of Objective XML by the same validator the Objective Server uses. level is full or structural_lint. | Local session with the canonical validator installed. full also needs a live matching Runtime manifest. |
create_objective | Validates and creates an Objective source file without overwriting an existing filename or Objective ID. Returns its revision. | Host-user session with workspace:write |
update_objective | Validates and replaces an Objective source file only when expected_revision matches. Returns its new revision. | Host-user session with workspace:write |
create_config | A newly generated package using the session's bound configuration name. | Host-user session |
build_workspace | A job handle for a build of your user workspace. | Host-user session |
test_workspace | A job handle for the workspace test suite. Packages run sequentially, and test failures fail the job. | Host-user session |
get_job_status | State and new output for a build or test job. | Host-user session |
launch_runtime | Launch of the Runtime for the bound target. | Host-user session |
run_objective | Starts an existing Objective on the bound Runtime and returns its goal id. It refuses when another Objective is reported as executing; that check is best effort, since a start from another client in the same instant still preempts. The robot may move, and keeps moving if the session ends. | Host-user session; approvals follow your client's configured permissions |
cancel_objective | Cancels exactly the supplied goal_id; a stale ID never cancels a replacement Objective. | Host-user session |
Keep the goal_id returned by run_objective and pass it to cancel_objective(goal_id). Compare it with get_execution_status.current_goal_id to identify the observed execution, including when two clients start the same Objective. Status is a snapshot, not a reservation: another client can change it immediately. Cancellation applies the UUID selector at the action server and echoes both the requested goal_id and the observed current_goal_id. Unknown or finished goals return cancelled: false; accepted cancellation returns cancelled: true with the Runtime state observed after a bounded wait. That state may describe a different goal. During a transition, status can ask you to retry instead of returning an ambiguous active ID.
Stop the Runtime through MoveIt Pro's terminal or application controls. MCP does not stop it because container shutdown cannot atomically prevent a new Objective from starting; exposing that operation would risk removing robot controllers during execution.
After execution, match the goal_id returned by run_objective in get_execution_status.recent_goals to observe SUCCEEDED, ABORTED, or CANCELED. The list contains at most 20 goals from the Runtime's retained action-status snapshot, not durable history. An absent goal has unknown outcome; IDLE alone never means success. For diagnostics, get_recent_logs(query="<Objective name>") searches the bounded tails of up to 20 recently modified node and launch logs. A successful Objective does not prove physical placement unless its tree includes that verification.
A full validation reports manifest_source: runtime because its plugin
manifest is read from the live, target-authenticated Runtime. It does not trust
a durable manifest cache: later configuration edits, product plugin upgrades,
or workspace builds could make one stale. A full check never silently falls
back to structural_lint; start the matching Runtime and retry when its
manifest is unavailable.
build_workspace and test_workspace return immediately with a job_id
rather than holding the request open for the length of a build. Poll
get_job_status(job_id, output_offset) and pass back the output_offset it
returns to read only what is new, so compiler errors are readable while the
build is still running.
get_capabilities is advisory. Each tool rechecks its required provider and
capabilities immediately before execution. An authorized but unavailable tool
returns a structured result containing available: false, its missing
capabilities, a remedy, remedy_tool naming the authorized tool that resolves
it when one exists, and the immutable target_id.
The default host-network deployment uses a cooperative Agent identity handshake before any ROS-backed result is accepted. It detects a missing, stale, or wrong deployment, but plain DDS cannot prove the identity of a hostile local peer. Named instances use an isolated network namespace and managed DDS configuration. Closing the cooperative deployment's hostile-peer limit requires instance isolation, SROS2, or an authenticated remote Runtime provider.
Observe the robot workspace
Camera tools require a running Runtime. They do not command motion. Camera capture and point measurements work without a Gemini key.
- Call
list_cameras()and select acamera_idfrom the result. - Call
capture_observation(camera_id, reference_frame)with a frame such asbase_linkorworld. The result contains an image the AI client can inspect, metadata, and anobservation_idfor follow-up queries. - Call
locate_points(observation_id, points, target_frame)with points such as[{"x": 0.5, "y": 0.5}]. Coordinates run from zero to one, with the origin at the image's top-left. Choosetarget_framefromavailable_target_frames.
Measurements use the captured depth and transforms even if the robot subsequently
moves. Positions are in meters and describe the visible surface at each selected
pixel. They are not object centers, grasp poses, or collision-checked motion goals.
Missing depth produces an error; an invalid depth pixel returns valid: false and
position: null.
Observations remain available for 120 seconds, with at most four captures retained per MCP server session. The oldest capture is evicted when the limit is reached. The HTTP endpoint shares its server session between clients authorized with the same deployment credential. Reconnects to stdio create a new observation store. Sensor data stays in server memory; camera tools do not save images to disk.
Supported streams use sensor_msgs/msg/Image: RGB/BGR, RGBA/BGRA, or 8-bit monochrome.
Metric lookup requires depth registered to the color image: matching optical frame,
image dimensions, and distortion-free pinhole CameraInfo with identity R and
matching K/P intrinsics. Depth must use 16UC1 millimeters or
32FC1 meters. RGB/depth timestamps must differ by at most 30 milliseconds.
Unregistered depth, nonzero distortion, ambiguous raw/rectified projection, binning,
and cropped calibration disable metric lookup. RGB capture remains available and
reports depth_unavailable_reason; it does not infer a transform or distance. Metadata distinguishes source_width/source_height from the returned JPEG’s
image_width/image_height; normalized coordinates apply to either size.
Source images are limited to 1920 × 1080 pixels;
previews are resized for the AI client while point coordinates remain normalized.
Enable optional Gemini inspection
The connected vision-capable AI client can reason about capture images directly.
To additionally use inspect_scene(observation_id, query), set both
MOVEIT_MCP_GEMINI_ENABLED=1 and GOOGLE_GEMINI_API_KEY in the MCP server's
launch environment and restart that server. This sends the selected image and
query to Google. An existing Gemini key used by Behaviors does not enable MCP
inspection by itself. MOVEIT_MCP_GEMINI_MODEL optionally selects the model;
the default is gemini-robotics-er-2-preview. To use a general-purpose model instead, set this variable to a supported Flash model identifier.
Inspection returns a narrative, labeled normalized image points, and an image
annotated with numbers matching the point list. Labels and points are model
predictions. Pass selected points to locate_points for depth-backed measurements.
If Gemini is disabled, use the image from capture_observation directly.
Create and update Objectives
Ask the assistant to read get_objective_authoring_guide before editing. It serves the same skills bundle shipped to customers, starting with create-objective/SKILL.md. Follow its relative links by resolving them against the current document's path: ../debug-objective/SKILL.md from the overview becomes debug-objective/SKILL.md. This includes the SOP example and linked Behavior, debugging, CLI, and safety guidance. The reader cannot access arbitrary workspace files or execute skills. The assistant should inspect the installed Behavior catalog and existing Objectives, preserve unaffected XML and metadata, and verify Behavior IDs and ports.
create_objective(file_name, objective_xml) accepts a bare .xml filename and complete XML. It writes to the last Objective library owned by the session's selected robot configuration package, inside that package's workspace source directory. It does not write inherited packages or the installed snapshot. The package must declare an objective_library_paths entry and have been built.
For an edit, first call get_objective(objective_id, source=true). Pass its file_name and revision to update_objective(file_name, objective_xml, expected_revision). A stale revision leaves the file intact: read the current source and reapply the change. Updates keep the Objective ID and filename. MCP edits are serialized within that library; external editors do not participate in its advisory lock, so avoid simultaneous editing outside MCP.
Both tools default to validation_level: "full", using the matching Runtime's plugin manifest. Offline work can explicitly request "structural_lint"; this does not verify installed plugins or motion safety. Invalid XML is never written. Neither tool builds, launches, or starts an Objective.
After writing, call get_objective(objective_id) to verify the saved result. Both read modes discover current XML without a build or Runtime restart, and the open Desktop App receives file-change updates. source=true adds the original formatting and edit revision; the default returns normalized XML. Starting the Objective remains a separate tool call governed by your MCP client's approvals.
For node discovery, start with list_behaviors(query="sleep") or another short search. Results contain at most 20 summaries by default (up to 50 with limit), not every Behavior's ports. Use next_offset to continue a search and get_behavior_details(behavior_id) to inspect the few candidates you need. This keeps authoring inside MCP without loading the whole catalog into the conversation.
Resources
moveit-pro://catalog/behaviors— the Behavior catalog as JSON.moveit-pro://config/current— the selected robot configuration.moveit-pro://robot/urdf— the robot URDF; requires the matching Runtime.moveit-pro://objective/{objective_id}— one Objective's parsed JSON.
Remote client: connect from another computer
The HTTP server runs with the REST backend on the Runtime computer. The AI client runs on the client computer and connects with:
- URL:
https://<runtime-host>:<rest-port>/mcp - Header:
Authorization: Bearer <MOVEIT_MCP_HTTP_KEY> - TLS verification for the Runtime certificate or its issuing CA
MOVEIT_MCP_HTTP_KEY is the 64-character lowercase hexadecimal value printed by
moveit_pro mcp http-key on the Runtime computer. It is derived from, but is not
the same as, the frontend key. Do not give an AI client the frontend key: that
credential also authenticates the broader REST backend.
Streamable HTTP is the preferred transport for a remote client. It uses the
deployment's existing TLS certificate and requires
Authorization: Bearer <MOVEIT_MCP_HTTP_KEY> on every MCP request; browser
CORS preflight requests remain unauthenticated. Install or trust the MoveIt Pro
Runtime certificate as described in
Endpoint Security.
HTTP sessions have the read-only deployment tools. They do not receive local
workspace, build, or Runtime-lifecycle authority.
Start the server on the Runtime computer
There is no separate HTTP MCP process to install or start. The /mcp endpoint
starts automatically with the authenticated REST backend.
Start MoveIt Pro normally. The CLI creates and stores the deployment frontend key automatically. Print its domain-separated MCP credential on the Runtime computer when configuring an AI client:
moveit_pro mcp http-key
Rotating the frontend key also rotates this derived MCP key, so update clients after a rotation. For a direct remote connection, allow the exact Host header that the client will send before starting the Runtime:
export MOVEIT_MCP_ALLOWED_HOSTS="robot.example.com:3200"
moveit_pro run -c my_robot_config
The default REST port is 3200; named instances use their assigned REST port.
The discovery service on port 3204 reports those ports. A native MCP client
normally omits Origin. If a browser-based client sends one, also set
MOVEIT_MCP_ALLOWED_ORIGINS to its exact origin before starting the Runtime.
Configure TLS and authentication on the client computer
Verify TLS before allowing the client to send the MCP HTTP key:
-
For a direct hostname or IP address, use a certificate signed by a CA the client trusts and whose subject alternative names cover the MCP URL.
-
The generated Runtime certificate covers loopback names. For a private or tunneled development connection, copy
cert.pemto the client through an authenticated channel such as SSH, trust it only for this connection, and connect through loopback. The generated certificate is at~/.local/share/moveit_pro/tls/cert.pemby default, or underMOVEIT_TLS_CERT_DIRwhen that variable is set. For example:scp <runtime-user>@<runtime-host>:~/.local/share/moveit_pro/tls/cert.pem \/owner-only/path/runtime-cert.pemssh -N -L 13200:127.0.0.1:3200 <runtime-user>@<runtime-host>Keep the tunnel open and use
https://localhost:13200/mcp. Loopback Host values are allowed withoutMOVEIT_MCP_ALLOWED_HOSTS.
The MoveIt Pro Desktop App performs frontend-key-authenticated certificate pairing automatically for its own Electron gateway. That paired certificate, stored key, and local gateway are deliberately not exported to other processes. An MCP client on the same computer is configured separately with its own TLS trust and MCP-only bearer key. The desktop profile's Alternate hostname or IP address also applies only to Electron; set the MCP URL or SSH tunnel to the route that the MCP client should use.
Native HTTP clients must support MoveIt Pro's sessionless MCP 2026-07-28
protocol. The mcp-remote bridge shown below adapts stdio clients to that HTTP
protocol.
Generate either client's remote entry instead of writing it by hand:
moveit_pro mcp install --client claude-desktop --url https://localhost:13200/mcp
The command prints the JSON with a <MOVEIT_MCP_HTTP_KEY> placeholder plus
the remaining setup steps, including what a read-only remote session can and
cannot do. It never writes a client file or embeds the key. Paste the output
into the client configuration on the client computer.
For example, a Cursor user can create ~/.cursor/mcp.json on the
client computer (or .cursor/mcp.json in a project):
{
"mcpServers": {
"moveit-pro": {
"url": "https://robot.example.com:3200/mcp",
"headers": {
"Authorization": "Bearer <MOVEIT_MCP_HTTP_KEY>"
}
}
}
}
Use the client's credential or environment-variable support instead of storing the key in plaintext when available. If the client config contains the key, make the file owner-only.
Claude Desktop's
remote connector flow
is for internet-reachable servers using authless or OAuth authentication. It
does not use the client computer's LAN, VPN, Tailscale route, or SSH tunnel, and
Claude Desktop does not load a remote HTTP server directly from
claude_desktop_config.json. For a private Runtime protected by a MoveIt Pro
MCP bearer key, configure a local stdio-to-HTTP bridge in that file. This
example uses mcp-remote; pin and review the bridge version your organization
approves:
{
"mcpServers": {
"moveit-pro": {
"command": "npx",
"args": [
"-y",
"mcp-remote@0.1.38",
"https://localhost:13200/mcp",
"--transport",
"http-only",
"--header",
"Authorization:${MOVEIT_MCP_AUTHORIZATION}"
],
"env": {
"MOVEIT_MCP_AUTHORIZATION": "Bearer <MOVEIT_MCP_HTTP_KEY>",
"NODE_EXTRA_CA_CERTS": "/absolute/path/to/copied-runtime-cert.pem"
}
}
}
}
mcp-remote@0.1.38 expands ${MOVEIT_MCP_AUTHORIZATION} in the header
argument from the bridge environment. Set it to Bearer followed by the
MoveIt Pro MCP HTTP key, as shown above; Claude Desktop only supplies the
environment to the local bridge.
This bridge runs on the client computer, so it can use the client's private
network and tunnel. Start the SSH tunnel before Claude Desktop. If the tunnel
closes, restore it and restart Claude Desktop so the app respawns the bridge. A
Server disconnected error with ECONNREFUSED on the forwarded local port
means that no tunnel is listening there. Protect the configuration as an
owner-only file and restart Claude Desktop after editing it.
On macOS or WSL, Claude Code can import the same client-local bridge instead of duplicating it:
claude mcp add-from-claude-desktop --scope user
Claude Code applies its own permission policy after connecting. An interactive
session can approve the read tools when first used. A non-interactive session
running with --permission-mode dontAsk must explicitly allow the desired
mcp__moveit-pro__... tools with --allowedTools or in Claude Code settings;
otherwise Claude Code rejects the calls without asking even though the MCP
server marks them read-only.
Codex CLI and the Codex desktop app use the same local MCP configuration. Add
the client-local bridge to the owner-only ~/.codex/config.toml file so the key
is not placed in shell history or the codex mcp add process arguments:
[mcp_servers.moveit-pro]
command = "npx"
args = [
"-y",
"mcp-remote@0.1.38",
"https://localhost:13200/mcp",
"--transport",
"http-only",
"--header",
"Authorization:${MOVEIT_MCP_AUTHORIZATION}",
]
[mcp_servers.moveit-pro.env]
MOVEIT_MCP_AUTHORIZATION = "Bearer <MOVEIT_MCP_HTTP_KEY>"
NODE_EXTRA_CA_CERTS = "/absolute/path/to/copied-runtime-cert.pem"
Here too, mcp-remote expands the authorization value from its environment;
Codex does not need to interpolate the placeholder itself.
Codex also supports env_vars when a separately managed parent environment
provides these values. After changing either desktop client's configuration,
restart the app and open a new conversation so it discovers the new tool
catalog.
Remote host-user session over SSH
SSH runs moveit_pro mcp serve on a remote Runtime under the SSH account. The
AI client starts and stops it with the MCP connection; no persistent MCP
service is needed.
Within MCP, this identity gets every tool by default: inspect, validate, create a configuration package, build, test, launch the Runtime, start an existing Objective, and cancel it. An optional policy only narrows those scopes and the session expiry. The SSH credential separately grants the account's normal shell access.
Prepare the SSH connection
Use a normal, non-root account on the remote Runtime host that owns the
workspace and can access Docker without sudo. Configure SSH to accept the
matching public key for runtime-user. Keep the private key on the AI client.
Verify the Runtime host's fingerprint through a separate trusted channel. Do
not disable host-key verification or store a password in the MCP configuration.
Before adding the strict MCP alias below, enroll the host key interactively:
ssh \
-o StrictHostKeyChecking=ask \
-o PreferredAuthentications=publickey \
-o PasswordAuthentication=no \
-o KbdInteractiveAuthentication=no \
-o IdentitiesOnly=yes \
-i /absolute/path/to/id_ed25519 \
runtime-user@robot.example.com true
Compare the displayed fingerprint with the independently obtained fingerprint.
Only accept an exact match. OpenSSH then records the key in ~/.ssh/known_hosts.
An SSH alias keeps client configurations readable. For example, add this to
the AI client's owner-only ~/.ssh/config:
Host moveit-pro-runtime
HostName robot.example.com
User runtime-user
IdentityFile /absolute/path/to/id_ed25519
IdentitiesOnly yes
StrictHostKeyChecking yes
BatchMode yes
RequestTTY no
ClearAllForwardings yes
ForwardAgent no
ForwardX11 no
After enrollment, verify that the strict, non-interactive alias reaches the expected account:
ssh moveit-pro-runtime /usr/bin/moveit_pro mcp serve --help
Replace /usr/bin/moveit_pro below if command -v moveit_pro on the remote
Runtime host reports a different absolute path.
A private overlay network such as Tailscale needs no other change: point
HostName at the tailnet address. If the Runtime host uses Tailscale SSH, its
ACL rule for this account must not set a check period, because the AI client
starts the command non-interactively.
Configure the MCP client
Save the workspace, robot configuration package, instance, and optional policy as an owner-controlled target profile on the remote Runtime:
moveit_pro mcp target add lab-robot \
--workspace /home/runtime-user/moveit_pro_example_ws \
--config-package my_robot_config
Add --instance <name> for a named deployment. To narrow what the session may
do, create a policy and pass
--policy /home/runtime-user/mcp-policy.json. Reusing a target name replaces
its definition; reconnect to use the replacement.
Generate the client entry without putting target paths in the SSH command:
ssh moveit-pro-runtime /usr/bin/moveit_pro mcp install \
--client cursor \
--target lab-robot \
--ssh-host moveit-pro-runtime \
--print
Use --client claude-desktop to print that client's JSON instead, and
--client-id <name> to label the connecting computer in the audit log; the
default is the client name. Copy the generated moveit-pro entry into the AI
client's owner-only MCP configuration. --ssh-host requires --print because
the remote Runtime cannot edit that configuration.
The generated entry is compact and contains no workspace or policy paths. The
command is the client computer's ssh; the last argument runs through the
remote account's shell, so it is one quoted string:
{
"mcpServers": {
"moveit-pro": {
"command": "/usr/bin/ssh",
"args": [
"-o",
"BatchMode=yes",
"-T",
"moveit-pro-runtime",
"/usr/bin/moveit_pro mcp serve --target lab-robot --client-id cursor"
]
}
}
}
Codex CLI and the Codex desktop app can use the same command in the AI client's
owner-only ~/.codex/config.toml:
[mcp_servers.moveit-pro]
command = "/usr/bin/ssh"
args = [
"-o",
"BatchMode=yes",
"-T",
"moveit-pro-runtime",
"/usr/bin/moveit_pro mcp serve --target lab-robot --client-id codex-over-ssh",
]
The target profile and its paths live on the remote Runtime, in the
owner-only registry ~/.local/state/moveit_pro/mcp/targets.json. MoveIt Pro
validates the policy at session startup and rejects mixing a saved target with
direct target options. Keep the
SSH alias and remote command owner-controlled.
Restart the MCP client after changing its configuration. The client starts a new SSH process and MCP container for each connection. Runtime reads become available when the matching Runtime is running, but workspace reads and host lifecycle tools do not require the REST backend to be running.
Keep the private key on the client computer; agent forwarding is unnecessary. Administrators may further restrict a dedicated SSH key with a forced wrapper and disabled forwarding, but that wrapper must preserve MCP stdout and forward diagnostics on stderr. Non-interactive remote shell startup files must not print banners or other text to stdout, because stdout is reserved for MCP JSON-RPC.
Same machine: install on the Runtime computer
Use stdio when the AI client and the MoveIt Pro workspace are on the same computer. Run the install command on that workspace/Runtime computer, not on a separate laptop running only the MoveIt Pro Desktop App. The Runtime may be stopped when the MCP session starts; workspace tools remain available and Runtime tools become available when the matching Runtime starts. The generated command needs the local workspace, MoveIt Pro installation, and container runtime. The MoveIt Pro Desktop App is not modified by this command.
Run the install and generated serve command as the normal account that owns the
workspace and can access Docker directly. Do not use sudo or run either
command as root; the launcher refuses elevated callers and maps the bootstrap
to the invoking account instead of trusting saved Runtime UID/GID settings.
Install a client entry with an absolute workspace and an explicit robot configuration package:
moveit_pro mcp install \
--client claude-desktop \
--workspace /absolute/path/to/user_ws \
--config-package my_robot_config
For Cursor, use --client cursor. Restart the AI client after installation.
MoveIt Pro merges the moveit-pro entry into the existing owner-only client
configuration without replacing unrelated entries. The AI client starts the
generated moveit_pro mcp serve command; do not start a separate server by
hand during normal use.
Claude Code and Codex can register that same Runtime-local bootstrap directly:
claude mcp add --scope user moveit-pro -- \
moveit_pro mcp serve \
--workspace /absolute/path/to/user_ws \
--config-package my_robot_config \
--client-id claude-code
codex mcp add moveit-pro -- \
moveit_pro mcp serve \
--workspace /absolute/path/to/user_ws \
--config-package my_robot_config \
--client-id codex
Run these commands on the Runtime computer, because the spawned bootstrap uses that computer's workspace and container runtime.
Restrict a host-user session
A host-user session holds every tool by default, whether the client starts the command directly or over SSH. To narrow what one client may do, or to make its authority expire, add an owner-only, target-bound policy. The session then keeps the read tools plus only the scopes the policy lists. For example, a policy that allows building and testing but not launching or starting Objectives:
{
"version": 1,
"policy_id": "local-authoring",
"resource_audience": "moveit-pro-mcp",
"workspace": "/absolute/path/to/user_ws",
"config_package": "my_robot_config",
"instance": null,
"granted_scopes": [
"workspace:write",
"validation:read",
"runtime:config",
"runtime:build",
"runtime:test"
],
"expires_at": "REPLACE_WITH_TIMEZONE_QUALIFIED_ISO_8601"
}
Replace expires_at with a timezone-qualified future timestamp and list only the scopes the client should keep (runtime:launch and runtime:execute are the other two). Use "granted_scopes": [] to retain only read tools. The effective session lifetime is capped at eight hours even if the policy expires later. After expiry, reconnect before making tool calls; renew an expired policy first. Expiry does not stop an Objective already running. Use a new authorized session to cancel it, or use the Runtime's own stop controls. Create the file under the workspace owner's account with an owner-only umask before editing it:
umask 077
touch /absolute/path/to/mcp-policy.json
chmod 600 /absolute/path/to/mcp-policy.json
$EDITOR /absolute/path/to/mcp-policy.json
Then include it when installing the desktop entry:
moveit_pro mcp install \
--client claude-desktop \
--workspace /absolute/path/to/user_ws \
--config-package my_robot_config \
--policy /absolute/path/to/mcp-policy.json
For Claude Code or Codex using direct target options, append --policy to the
moveit_pro mcp serve command. For SSH, save --policy with
moveit_pro mcp target add and reconnect after replacing the profile. Rerun
mcp install after changing an installed same-host entry. A confirmation
key in older policy files is accepted and ignored.
create_config, build_workspace, and test_workspace run the workspace's package generators, build files, and tests as the local OS user, and run_objective can move the robot. Configure your MCP client's tool approvals and keep the operator present or use a simulation target when an agent starts Objectives. cancel_objective is best effort, not an emergency stop. Neither MCP cancellation nor the Runtime's software stop controls replace physical emergency-stop controls.
To print configuration for a project-local file or another MCP client:
moveit_pro mcp install \
--client cursor \
--workspace /absolute/path/to/user_ws \
--config-package my_robot_config \
--print
If the workspace contains exactly one discoverable robot configuration package,
--config-package may be omitted. MoveIt Pro refuses to guess when there are
zero or multiple candidates. Add --instance <name> to bind a named
deployment.
For a named instance, stdio Runtime reads never bind to the host DDS graph.
They are proxied over the session's authenticated host channel to the exact
labeled Agent container of that instance, so get_execution_status,
get_robot_state, and the URDF resource work over stdio just as they do over
the backend's authenticated HTTP endpoint. RUNTIME remains unavailable until
that instance's containers are running.
The generated command runs moveit_pro mcp serve. Each client connection:
- creates an immutable OS-user principal and target binding;
- creates isolated config and private session state;
- starts one
docker compose run --rm --no-deps -Tcontainer; - reserves stdout for MCP JSON-RPC and sends setup diagnostics to stderr;
- verifies the invoking account is non-root, maps that account into the container, and drops entrypoint privileges before the MCP server starts; and
- removes its container, credential, and socket on disconnect.
Containers and runtime directories carry a session ID. The next serve
removes orphaned sessions left by abnormal termination, and session credentials
also have an absolute expiry. Security audit logs are retained separately from
the ephemeral credential directory. Authorized host-control intent is recorded
before any effect and followed by its outcome. Read-only polling stays quiet;
repeated read-side target failures are retained once per session, provider, and
reason instead of growing durable storage with request volume.
Workspace, capabilities, and host-user authority
The stdio session bind-mounts its canonical workspace read/write when its resolved scopes include workspace:write, otherwise read-only. It also mounts isolated materialized configuration, the target log directory, DDS inputs, and—when configured—the private typed provider files. It mounts no Docker socket and no devices. The
container has a reduced capability set only during setup, clears supplementary
groups, enables no-new-privileges, and runs the server as the invoking
host-mapped non-root user. Fixed Runtime probes also use that non-root UID/GID;
they never rely on the Runtime container's default root exec user.
Different workspaces, robot configuration packages, deployments, and instances
receive separate session state. Toolchain and lifecycle operations for the same
canonical workspace use a host advisory exclusion lock. A competing session
receives a structured TOOLCHAIN unavailable result naming the holder session
rather than running a concurrent build.
Host-shell access is already host-user authority; MCP does not turn an MCP HTTP key, ordinary network reachability, or socket reachability into that authority. An SSH stdio session has host-user authority because it authenticates as that host account, not because MCP elevates it. Confirmation of a consequential call is the MCP client's own tool approval; it is never a model-supplied tool argument.
Protocol version
The server speaks the sessionless MCP 2026-07-28 protocol on both transports.
Privacy considerations
Tool and resource results are sent to the connected AI client, which may be an
external service. Camera captures send robot workspace images to that client.
Enabling Gemini inspection additionally sends selected images and queries to Google.
In particular, get_recent_logs forwards log lines. Avoid
writing tokens, passwords, or private endpoint URLs to custom Behavior logs.
Troubleshooting
- HTTP returns
401 Unauthorized. Send the derived key frommoveit_pro mcp http-keyas a bearer token. - HTTP returns
421 Misdirected Request. Add the exact Host header, including its port, toMOVEIT_MCP_ALLOWED_HOSTS. - HTTP returns
503with "MCP endpoint unavailable". The MCP subsystem failed to start with the rest of the backend — the response body carries the reason (for example a misconfigured target identity, audit location, or transport allowlist). Fix the configuration and restart MoveIt Pro; this is not a transient outage. - HTTP returns
403 Invalid Origin header. Add the browser client's exact origin toMOVEIT_MCP_ALLOWED_ORIGINS; native clients should omit Origin. - HTTP returns
408 Request Timeout. The full request body must arrive within 30 seconds; check for a slow or unreliable network link between the client and the deployment. - HTTP returns
413 Request Entity Too Large. Keep a request at most 1 MiB. - HTTP returns
429 Too Many Requests. RespectRetry-After; one worker admits at most 16 concurrent MCP requests. - HTTP returns
504 Gateway Timeout. The server bounds how long a single MCP request may spend processing after upload. A healthy deployment answers well inside that bound; a 504 usually points at unresponsive storage backing the robot configuration or log directories. - TLS verification fails. Trust the backend certificate or its CA. Do not disable verification for a remote deployment.
- SSH authentication or host-key verification fails. Repeat host-key
enrollment, verify the fingerprint, and confirm public-key authentication
through the
moveit-pro-runtimealias. - SSH initialization disconnects. Run the configured SSH command in a
terminal and inspect stderr. Check the
moveit_pro, workspace, and policy paths; Docker access; and shell startup output. - No stdio tools appear. Run the configured stdio or SSH command in a
terminal and inspect stderr. After changing the target, rerun
mcp installor update the SSH command, then restart the client. ACTIVE_CONFIGis unavailable. Run thebuild_workspacetool to rebuild the bound robot configuration package. A successful job atomically refreshes the session's isolated robot configuration before the next read; a build run outside the session, such ascolcon buildin a terminal, does not. Changing the bound robot configuration package still requires a new session. If the refresh fails, run the generatedmoveit_pro mcp servecommand in a terminal and inspect stderr for the robot configuration package error.RUNTIMEis unavailable. Start the matching target. A Runtime answering with missing or different deployment identity is deliberately ignored.- The URDF resource is unavailable. It requires the matching Runtime's
latched
/robot_description.